238 lines
11 KiB
Dart
238 lines
11 KiB
Dart
import 'dart:io';
|
|
import 'dart:ui';
|
|
import 'dart:core';
|
|
|
|
import 'package:cwtch/themes/cwtch.dart';
|
|
import 'package:cwtch/themes/yamltheme.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:cwtch/settings.dart';
|
|
import 'package:flutter/services.dart';
|
|
|
|
const mode_light = "light";
|
|
const mode_dark = "dark";
|
|
|
|
final TextStyle defaultSmallTextStyle = TextStyle(fontFamily: "Inter", fontWeight: FontWeight.normal, fontSize: 10);
|
|
final TextStyle defaultMessageTextStyle = TextStyle(fontFamily: "Inter", fontWeight: FontWeight.w400, fontSize: 13, fontFamilyFallback: [Platform.isWindows ? 'Segoe UI Emoji' : "Noto Color Emoji"]);
|
|
final TextStyle defaultFormLabelTextStyle = TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, fontSize: 20);
|
|
final TextStyle defaultTextStyle = TextStyle(fontFamily: "Inter", fontWeight: FontWeight.w500, fontSize: 12);
|
|
final TextStyle defaultTextButtonStyle = defaultTextStyle.copyWith(fontWeight: FontWeight.bold);
|
|
final TextStyle defaultDropDownMenuItemTextStyle = TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, fontSize: 16);
|
|
|
|
Map<String, Map<String, OpaqueThemeType>> themes = Map();
|
|
|
|
LoadAssetThemes() async {
|
|
themes = await loadYamlThemes();
|
|
}
|
|
|
|
OpaqueThemeType getTheme(String themeId, String mode) {
|
|
if (themeId == "") {
|
|
themeId = cwtch_theme;
|
|
}
|
|
if (themeId == mode_light) {
|
|
themeId = cwtch_theme;
|
|
mode = mode_light;
|
|
}
|
|
if (themeId == mode_dark) {
|
|
themeId = cwtch_theme;
|
|
mode = mode_dark;
|
|
}
|
|
|
|
var theme = themes[themeId]?[mode] ?? themes[themeId]?[flipMode(mode)];
|
|
return theme ?? CwtchDark();
|
|
}
|
|
|
|
String flipMode(String mode) {
|
|
if (mode == mode_dark) {
|
|
return mode_light;
|
|
}
|
|
return mode_dark;
|
|
}
|
|
|
|
Color lighten(Color color, [double amount = 0.15]) {
|
|
final hsl = HSLColor.fromColor(color);
|
|
final hslLight = hsl.withLightness((hsl.lightness + amount).clamp(0.0, 1.0));
|
|
|
|
return hslLight.toColor();
|
|
}
|
|
|
|
Color darken(Color color, [double amount = 0.15]) {
|
|
final hsl = HSLColor.fromColor(color);
|
|
final hslDarken = hsl.withLightness((hsl.lightness - amount).clamp(0.0, 1.0));
|
|
|
|
return hslDarken.toColor();
|
|
}
|
|
|
|
abstract class OpaqueThemeType {
|
|
static final Color red = Color(0xFFFF0000);
|
|
|
|
get theme => "dummy";
|
|
get mode => mode_light;
|
|
|
|
// Main screen background color (message pane, item rows)
|
|
get backgroundMainColor => red;
|
|
|
|
// pane colors (settings)
|
|
get backgroundPaneColor => red;
|
|
|
|
get topbarColor => red;
|
|
|
|
get mainTextColor => red;
|
|
|
|
// pressed row, offline heart
|
|
get hilightElementColor => red;
|
|
// Selected Row
|
|
get backgroundHilightElementColor => red;
|
|
// Faded text color for suggestions in textfields
|
|
// Todo: implement way more places
|
|
get sendHintTextColor => red;
|
|
|
|
get defaultButtonColor => red;
|
|
get defaultButtonActiveColor => /*mode == mode_light ? darken(defaultButtonColor) :*/ lighten(defaultButtonColor);
|
|
get defaultButtonTextColor => red;
|
|
get defaultButtonDisabledColor => red;
|
|
get textfieldBackgroundColor => red;
|
|
get textfieldBorderColor => red;
|
|
get textfieldHintColor => red;
|
|
get textfieldErrorColor => red;
|
|
get scrollbarDefaultColor => red;
|
|
get portraitBackgroundColor => red;
|
|
get portraitOnlineBorderColor => red;
|
|
get portraitOfflineBorderColor => red;
|
|
get portraitBlockedBorderColor => red;
|
|
get portraitBlockedTextColor => red;
|
|
get portraitContactBadgeColor => red;
|
|
get portraitContactBadgeTextColor => red;
|
|
get portraitProfileBadgeColor => red;
|
|
get portraitProfileBadgeTextColor => red;
|
|
|
|
get portraitOnlineAwayColor => Color(0xFFFFF59D);
|
|
get portraitOnlineBusyColor => Color(0xFFEF9A9A);
|
|
|
|
// dropshaddpow
|
|
// todo: probably should not be reply icon color in messagerow
|
|
get dropShadowColor => red;
|
|
|
|
get toolbarIconColor => red;
|
|
get messageFromMeBackgroundColor => red;
|
|
get messageFromMeTextColor => red;
|
|
get messageFromOtherBackgroundColor => red;
|
|
get messageFromOtherTextColor => red;
|
|
|
|
// Sizes
|
|
double contactOnionTextSize() {
|
|
return 18;
|
|
}
|
|
}
|
|
|
|
ThemeData mkThemeData(Settings opaque) {
|
|
return ThemeData(
|
|
hoverColor: opaque.current().backgroundHilightElementColor.withOpacity(0.5),
|
|
visualDensity: VisualDensity.adaptivePlatformDensity,
|
|
primarySwatch: Colors.red,
|
|
primaryIconTheme: IconThemeData(
|
|
color: opaque.current().mainTextColor,
|
|
),
|
|
primaryColor: opaque.current().mainTextColor,
|
|
canvasColor: opaque.current().backgroundMainColor,
|
|
backgroundColor: opaque.current().backgroundMainColor,
|
|
highlightColor: opaque.current().hilightElementColor,
|
|
iconTheme: IconThemeData(
|
|
color: opaque.current().toolbarIconColor,
|
|
),
|
|
cardColor: opaque.current().backgroundMainColor,
|
|
appBarTheme: AppBarTheme(
|
|
systemOverlayStyle: SystemUiOverlayStyle(
|
|
// Status bar color
|
|
statusBarColor: opaque.current().topbarColor,
|
|
// Status bar brightness (optional)
|
|
statusBarIconBrightness: opaque.current().mode == mode_light ? Brightness.dark : Brightness.light, // For Android (dark icons)
|
|
statusBarBrightness: opaque.current().mode == mode_light ? Brightness.dark : Brightness.light, // For iOS (dark icons)
|
|
),
|
|
backgroundColor: opaque.current().topbarColor,
|
|
iconTheme: IconThemeData(
|
|
color: opaque.current().mainTextColor,
|
|
),
|
|
titleTextStyle: TextStyle(fontWeight: FontWeight.bold, fontFamily: "Inter", color: opaque.current().mainTextColor, fontSize: opaque.fontScaling * 18.0),
|
|
actionsIconTheme: IconThemeData(
|
|
color: opaque.current().mainTextColor,
|
|
)),
|
|
|
|
//bottomNavigationBarTheme: BottomNavigationBarThemeData(type: BottomNavigationBarType.fixed, backgroundColor: opaque.current().backgroundHilightElementColor), // Can't determine current use
|
|
textButtonTheme: TextButtonThemeData(
|
|
style: ButtonStyle(
|
|
backgroundColor: MaterialStateProperty.all(opaque.current().defaultButtonColor),
|
|
foregroundColor: MaterialStateProperty.all(opaque.current().defaultButtonTextColor),
|
|
overlayColor: MaterialStateProperty.all(opaque.current().defaultButtonActiveColor),
|
|
padding: MaterialStateProperty.all(EdgeInsets.all(20))),
|
|
),
|
|
hintColor: opaque.current().textfieldHintColor,
|
|
elevatedButtonTheme: ElevatedButtonThemeData(
|
|
style: ButtonStyle(
|
|
backgroundColor: MaterialStateProperty.resolveWith((states) => states.contains(MaterialState.disabled) ? opaque.current().defaultButtonDisabledColor : opaque.current().defaultButtonColor),
|
|
foregroundColor: MaterialStateProperty.all(opaque.current().defaultButtonTextColor),
|
|
overlayColor: MaterialStateProperty.resolveWith((states) => (states.contains(MaterialState.pressed) && states.contains(MaterialState.hovered))
|
|
? opaque.current().defaultButtonActiveColor
|
|
: states.contains(MaterialState.disabled)
|
|
? opaque.current().defaultButtonDisabledColor
|
|
: null),
|
|
enableFeedback: true,
|
|
textStyle: MaterialStateProperty.all(opaque.scaleFonts(defaultTextButtonStyle)),
|
|
padding: MaterialStateProperty.all(EdgeInsets.all(20)),
|
|
shape: MaterialStateProperty.all(RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(6.0),
|
|
)),
|
|
),
|
|
),
|
|
|
|
scrollbarTheme: ScrollbarThemeData(thumbVisibility: MaterialStateProperty.all(false), thumbColor: MaterialStateProperty.all(opaque.current().scrollbarDefaultColor)),
|
|
tabBarTheme: TabBarTheme(
|
|
labelColor: opaque.current().mainTextColor,
|
|
unselectedLabelColor: opaque.current().mainTextColor,
|
|
indicator: UnderlineTabIndicator(borderSide: BorderSide(color: opaque.current().defaultButtonActiveColor)),
|
|
labelStyle: opaque.scaleFonts(defaultTextButtonStyle),
|
|
unselectedLabelStyle: opaque.scaleFonts(defaultTextStyle),
|
|
),
|
|
dialogTheme: DialogTheme(
|
|
backgroundColor: opaque.current().backgroundPaneColor,
|
|
titleTextStyle: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, color: opaque.current().mainTextColor),
|
|
contentTextStyle: TextStyle(
|
|
fontFamily: "Inter",
|
|
color: opaque.current().mainTextColor,
|
|
)),
|
|
textTheme: TextTheme(
|
|
// NOTE: The following font scales were arrived at after consulting the material text scale
|
|
// docs: https://m3.material.io/styles/typography/type-scale-tokens and some trial and error
|
|
displaySmall: TextStyle(fontFamily: "Inter", fontSize: opaque.fontScaling * 14.0, color: opaque.current().mainTextColor),
|
|
displayMedium: TextStyle(fontFamily: "Inter", fontSize: opaque.fontScaling * 16.0, color: opaque.current().mainTextColor),
|
|
displayLarge: TextStyle(fontFamily: "Inter", fontSize: opaque.fontScaling * 18.0, color: opaque.current().mainTextColor),
|
|
titleSmall: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, fontSize: opaque.fontScaling * 16.0, color: opaque.current().mainTextColor),
|
|
titleLarge: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, fontSize: opaque.fontScaling * 18.0, color: opaque.current().mainTextColor),
|
|
titleMedium: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, fontSize: opaque.fontScaling * 20.0, color: opaque.current().mainTextColor),
|
|
bodySmall: TextStyle(fontFamily: "Inter", fontSize: opaque.fontScaling * 12.0, color: opaque.current().mainTextColor),
|
|
bodyMedium: TextStyle(fontFamily: "Inter", fontSize: opaque.fontScaling * 14.0, color: opaque.current().mainTextColor),
|
|
bodyLarge: TextStyle(fontFamily: "Inter", fontSize: opaque.fontScaling * 16.0, color: opaque.current().mainTextColor),
|
|
headlineSmall: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, fontSize: opaque.fontScaling * 24.0, color: opaque.current().mainTextColor),
|
|
headlineMedium: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, fontSize: opaque.fontScaling * 26.0, color: opaque.current().mainTextColor),
|
|
headlineLarge: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, fontSize: opaque.fontScaling * 28.0, color: opaque.current().mainTextColor),
|
|
labelSmall: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.w100, fontSize: opaque.fontScaling * 14.0, color: opaque.current().mainTextColor),
|
|
labelMedium: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.w300, fontSize: opaque.fontScaling * 16.0, color: opaque.current().mainTextColor),
|
|
labelLarge: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.w200, fontSize: opaque.fontScaling * 18.0, color: opaque.current().mainTextColor),
|
|
),
|
|
switchTheme: SwitchThemeData(
|
|
overlayColor: MaterialStateProperty.all(opaque.current().defaultButtonActiveColor),
|
|
thumbColor: MaterialStateProperty.all(opaque.current().mainTextColor),
|
|
trackColor: MaterialStateProperty.all(opaque.current().dropShadowColor),
|
|
),
|
|
// the only way to change the text Selection Context Menu Color ?!
|
|
brightness: opaque.current().mode == mode_dark ? Brightness.dark : Brightness.light,
|
|
floatingActionButtonTheme: FloatingActionButtonThemeData(
|
|
foregroundColor: opaque.current().mainTextColor,
|
|
backgroundColor: opaque.current().defaultButtonColor,
|
|
hoverColor: opaque.current().defaultButtonActiveColor,
|
|
enableFeedback: true,
|
|
splashColor: opaque.current().defaultButtonActiveColor),
|
|
textSelectionTheme: TextSelectionThemeData(
|
|
cursorColor: opaque.current().defaultButtonActiveColor, selectionColor: opaque.current().defaultButtonActiveColor, selectionHandleColor: opaque.current().defaultButtonActiveColor),
|
|
);
|
|
}
|