LCOV - code coverage report
Current view: top level - lib/themes - opaque.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 97 179 54.2 %
Date: 2024-02-26 20:09:01 Functions: 0 0 -

          Line data    Source code
       1             : import 'dart:io';
       2             : import 'dart:core';
       3             : 
       4             : import 'package:cwtch/themes/cwtch.dart';
       5             : import 'package:cwtch/themes/yamltheme.dart';
       6             : import 'package:flutter/material.dart';
       7             : import 'package:cwtch/settings.dart';
       8             : import 'package:flutter/services.dart';
       9             : import 'package:path/path.dart' as path;
      10             : 
      11             : const custom_themes_subdir = "themes";
      12             : 
      13             : const mode_light = "light";
      14             : const mode_dark = "dark";
      15             : 
      16           0 : final TextStyle defaultSmallTextStyle = TextStyle(fontFamily: "Inter", fontWeight: FontWeight.normal, fontSize: 10);
      17           0 : final TextStyle defaultMessageTextStyle = TextStyle(fontFamily: "Inter", fontWeight: FontWeight.w400, fontSize: 13, fontFamilyFallback: [Platform.isWindows ? 'Segoe UI Emoji' : "Noto Color Emoji"]);
      18           3 : final TextStyle defaultFormLabelTextStyle = TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, fontSize: 20);
      19          12 : final TextStyle defaultTextStyle = TextStyle(fontFamily: "Inter", fontWeight: FontWeight.w500, fontSize: 12);
      20          16 : final TextStyle defaultTextButtonStyle = defaultTextStyle.copyWith(fontWeight: FontWeight.bold);
      21           0 : final TextStyle defaultDropDownMenuItemTextStyle = TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, fontSize: 16);
      22             : 
      23             : class ThemeLoader extends ChangeNotifier {
      24             :   Map<String, Map<String, OpaqueThemeType>> themes = Map();
      25             : 
      26           0 :   LoadThemes(String cwtchDir) async {
      27           0 :     themes.clear(); // clear themes...
      28           0 :     loadBuiltinThemes().then((builtinThemes) {
      29           0 :       themes.addAll(builtinThemes);
      30           0 :       notifyListeners();
      31           0 :       loadCustomThemes(path.join(cwtchDir, custom_themes_subdir)).then((customThemes) {
      32           0 :         themes.addAll(customThemes);
      33           0 :         notifyListeners();
      34             :       });
      35             :     });
      36             :   }
      37             : 
      38           4 :   OpaqueThemeType getTheme(String? themeId, String? mode) {
      39             :     if (themeId == null) {
      40             :       themeId = cwtch_theme;
      41             :     }
      42           4 :     if (themeId == mode_light) {
      43             :       mode = mode_light;
      44             :     }
      45           4 :     if (themeId == mode_dark) {
      46             :       mode = mode_dark;
      47             :     }
      48          16 :     var theme = themes[themeId]?[mode] ?? themes[themeId]?[flipMode(mode ?? mode_dark)];
      49           4 :     return theme ?? CwtchDark();
      50             :   }
      51             : 
      52           0 :   String flipMode(String mode) {
      53           0 :     if (mode == mode_dark) {
      54             :       return mode_light;
      55             :     }
      56             :     return mode_dark;
      57             :   }
      58             : }
      59             : 
      60           4 : Color lighten(Color color, [double amount = 0.15]) {
      61           4 :   final hsl = HSLColor.fromColor(color);
      62          16 :   final hslLight = hsl.withLightness((hsl.lightness + amount).clamp(0.0, 1.0));
      63             : 
      64           4 :   return hslLight.toColor();
      65             : }
      66             : 
      67           0 : Color darken(Color color, [double amount = 0.15]) {
      68           0 :   final hsl = HSLColor.fromColor(color);
      69           0 :   final hslDarken = hsl.withLightness((hsl.lightness - amount).clamp(0.0, 1.0));
      70             : 
      71           0 :   return hslDarken.toColor();
      72             : }
      73             : 
      74             : abstract class OpaqueThemeType {
      75           0 :   static final Color red = Color(0xFFFF0000);
      76             : 
      77           0 :   get theme => "dummy";
      78           0 :   get mode => mode_light;
      79             : 
      80             :   // Main screen background color (message pane, item rows)
      81           0 :   get backgroundMainColor => red;
      82             : 
      83             :   // pane colors (settings)
      84           0 :   get backgroundPaneColor => red;
      85             : 
      86           0 :   get topbarColor => red;
      87             : 
      88           0 :   get mainTextColor => red;
      89             : 
      90             :   // pressed row, offline heart
      91           0 :   get hilightElementColor => red;
      92             :   // Selected Row
      93           0 :   get backgroundHilightElementColor => red;
      94             :   // Faded text color for suggestions in textfields
      95             :   // Todo: implement way more places
      96           0 :   get sendHintTextColor => red;
      97             : 
      98           0 :   get defaultButtonColor => red;
      99          12 :   get defaultButtonActiveColor => /*mode == mode_light ? darken(defaultButtonColor) :*/ lighten(defaultButtonColor);
     100           0 :   get defaultButtonTextColor => red;
     101           0 :   get defaultButtonDisabledColor => red;
     102           0 :   get textfieldBackgroundColor => red;
     103           0 :   get textfieldBorderColor => red;
     104           0 :   get textfieldHintColor => red;
     105           0 :   get textfieldErrorColor => red;
     106           0 :   get textfieldSelectionColor => red;
     107           0 :   get scrollbarDefaultColor => red;
     108           0 :   get portraitBackgroundColor => red;
     109           0 :   get portraitOnlineBorderColor => red;
     110           0 :   get portraitOfflineBorderColor => red;
     111           0 :   get portraitBlockedBorderColor => red;
     112           0 :   get portraitBlockedTextColor => red;
     113           0 :   get portraitContactBadgeColor => red;
     114           0 :   get portraitContactBadgeTextColor => red;
     115           0 :   get portraitProfileBadgeColor => red;
     116           0 :   get portraitProfileBadgeTextColor => red;
     117             : 
     118           0 :   get portraitOnlineAwayColor => Color(0xFFFFF59D);
     119           0 :   get portraitOnlineBusyColor => Color(0xFFEF9A9A);
     120             : 
     121             :   // dropshaddpow
     122             :   // todo: probably should not be reply icon color in messagerow
     123           0 :   get dropShadowColor => red;
     124             : 
     125           0 :   get toolbarIconColor => red;
     126           0 :   get chatReactionIconColor => red;
     127           0 :   get messageFromMeBackgroundColor => red;
     128           0 :   get messageFromMeTextColor => red;
     129           0 :   get messageFromOtherBackgroundColor => red;
     130           0 :   get messageFromOtherTextColor => red;
     131           0 :   get messageSelectionColor => red;
     132             : 
     133           0 :   get menuBackgroundColor => red;
     134             : 
     135           0 :   get snackbarBackgroundColor => red;
     136           0 :   get snackbarTextColor => red;
     137             : 
     138             :   // Images
     139             : 
     140           0 :   get chatImageColor => red;
     141           0 :   get chatImage => null;
     142             : 
     143           0 :   ImageProvider loadImage(String key, {BuildContext? context}) {
     144           0 :     return AssetImage("");
     145             :   }
     146             : 
     147             :   // Sizes
     148           0 :   double contactOnionTextSize() {
     149             :     return 18;
     150             :   }
     151             : }
     152             : 
     153             : // Borrowed from Stackoverflow
     154           0 : MaterialColor getMaterialColor(Color color) {
     155           0 :   final int red = color.red;
     156           0 :   final int green = color.green;
     157           0 :   final int blue = color.blue;
     158             : 
     159           0 :   final Map<int, Color> shades = {
     160           0 :     50: Color.fromRGBO(red, green, blue, .1),
     161           0 :     100: Color.fromRGBO(red, green, blue, .2),
     162           0 :     200: Color.fromRGBO(red, green, blue, .3),
     163           0 :     300: Color.fromRGBO(red, green, blue, .4),
     164           0 :     400: Color.fromRGBO(red, green, blue, .5),
     165           0 :     500: Color.fromRGBO(red, green, blue, .6),
     166           0 :     600: Color.fromRGBO(red, green, blue, .7),
     167           0 :     700: Color.fromRGBO(red, green, blue, .8),
     168           0 :     800: Color.fromRGBO(red, green, blue, .9),
     169           0 :     900: Color.fromRGBO(red, green, blue, 1),
     170             :   };
     171             : 
     172           0 :   return MaterialColor(color.value, shades);
     173             : }
     174             : 
     175           4 : ThemeData mkThemeData(Settings opaque) {
     176           4 :   return ThemeData(
     177          12 :       hoverColor: opaque.current().backgroundHilightElementColor.withOpacity(0.5),
     178           4 :       visualDensity: VisualDensity.adaptivePlatformDensity,
     179           4 :       primaryIconTheme: IconThemeData(
     180           8 :         color: opaque.current().mainTextColor,
     181             :       ),
     182           8 :       primaryColor: opaque.current().mainTextColor,
     183           8 :       canvasColor: opaque.current().backgroundMainColor,
     184           8 :       highlightColor: opaque.current().hilightElementColor,
     185           4 :       iconTheme: IconThemeData(
     186           8 :         color: opaque.current().toolbarIconColor,
     187             :       ),
     188           8 :       cardColor: opaque.current().backgroundMainColor,
     189           4 :       appBarTheme: AppBarTheme(
     190           4 :           systemOverlayStyle: SystemUiOverlayStyle(
     191             :             // Status bar color
     192           8 :             statusBarColor: opaque.current().topbarColor,
     193             :             // Status bar brightness (optional)
     194          12 :             statusBarIconBrightness: opaque.current().mode == mode_light ? Brightness.dark : Brightness.light, // For Android (dark icons)
     195          12 :             statusBarBrightness: opaque.current().mode == mode_light ? Brightness.dark : Brightness.light, // For iOS (dark icons)
     196             :           ),
     197           8 :           backgroundColor: opaque.current().topbarColor,
     198           4 :           iconTheme: IconThemeData(
     199           8 :             color: opaque.current().mainTextColor,
     200             :           ),
     201          20 :           titleTextStyle: TextStyle(fontWeight: FontWeight.bold, fontFamily: "Inter", color: opaque.current().mainTextColor, fontSize: opaque.fontScaling * 18.0),
     202           4 :           actionsIconTheme: IconThemeData(
     203           8 :             color: opaque.current().mainTextColor,
     204             :           )),
     205             : 
     206             :       //bottomNavigationBarTheme: BottomNavigationBarThemeData(type: BottomNavigationBarType.fixed, backgroundColor: opaque.current().backgroundHilightElementColor),  // Can't determine current use
     207           4 :       textButtonTheme: TextButtonThemeData(
     208           4 :         style: ButtonStyle(
     209          12 :             backgroundColor: MaterialStateProperty.all(opaque.current().defaultButtonColor),
     210          12 :             foregroundColor: MaterialStateProperty.all(opaque.current().defaultButtonTextColor),
     211          12 :             overlayColor: MaterialStateProperty.all(opaque.current().defaultButtonActiveColor),
     212           8 :             padding: MaterialStateProperty.all(EdgeInsets.all(20))),
     213             :       ),
     214           8 :       hintColor: opaque.current().textfieldHintColor,
     215           4 :       elevatedButtonTheme: ElevatedButtonThemeData(
     216           4 :         style: ButtonStyle(
     217           4 :           backgroundColor: MaterialStateProperty.resolveWith((states) => states.contains(MaterialState.disabled) ? opaque.current().defaultButtonDisabledColor : opaque.current().defaultButtonColor),
     218          12 :           foregroundColor: MaterialStateProperty.all(opaque.current().defaultButtonTextColor),
     219           4 :           overlayColor: MaterialStateProperty.resolveWith((states) => (states.contains(MaterialState.pressed) && states.contains(MaterialState.hovered))
     220           0 :               ? opaque.current().defaultButtonActiveColor
     221           0 :               : states.contains(MaterialState.disabled)
     222           0 :                   ? opaque.current().defaultButtonDisabledColor
     223             :                   : null),
     224             :           enableFeedback: true,
     225          12 :           textStyle: MaterialStateProperty.all(opaque.scaleFonts(defaultTextButtonStyle)),
     226           8 :           padding: MaterialStateProperty.all(EdgeInsets.all(20)),
     227           8 :           shape: MaterialStateProperty.all(RoundedRectangleBorder(
     228           4 :             borderRadius: BorderRadius.circular(6.0),
     229             :           )),
     230             :         ),
     231             :       ),
     232          20 :       scrollbarTheme: ScrollbarThemeData(thumbVisibility: MaterialStateProperty.all(false), thumbColor: MaterialStateProperty.all(opaque.current().scrollbarDefaultColor)),
     233           4 :       tabBarTheme: TabBarTheme(
     234           8 :         labelColor: opaque.current().mainTextColor,
     235           8 :         unselectedLabelColor: opaque.current().mainTextColor,
     236          16 :         indicator: UnderlineTabIndicator(borderSide: BorderSide(color: opaque.current().defaultButtonActiveColor)),
     237           8 :         labelStyle: opaque.scaleFonts(defaultTextButtonStyle),
     238           8 :         unselectedLabelStyle: opaque.scaleFonts(defaultTextStyle),
     239             :       ),
     240           4 :       dialogTheme: DialogTheme(
     241           8 :           backgroundColor: opaque.current().backgroundPaneColor,
     242          12 :           titleTextStyle: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, color: opaque.current().mainTextColor),
     243           4 :           contentTextStyle: TextStyle(
     244             :             fontFamily: "Inter",
     245           8 :             color: opaque.current().mainTextColor,
     246             :           )),
     247           4 :       textTheme: TextTheme(
     248             :         // NOTE: The following font scales were arrived at after consulting the material text scale
     249             :         // docs: https://m3.material.io/styles/typography/type-scale-tokens and some trial and error
     250          20 :         displaySmall: TextStyle(fontFamily: "Inter", fontSize: opaque.fontScaling * 14.0, color: opaque.current().mainTextColor),
     251          20 :         displayMedium: TextStyle(fontFamily: "Inter", fontSize: opaque.fontScaling * 16.0, color: opaque.current().mainTextColor),
     252          20 :         displayLarge: TextStyle(fontFamily: "Inter", fontSize: opaque.fontScaling * 18.0, color: opaque.current().mainTextColor),
     253          20 :         titleSmall: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, fontSize: opaque.fontScaling * 16.0, color: opaque.current().mainTextColor),
     254          20 :         titleLarge: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, fontSize: opaque.fontScaling * 18.0, color: opaque.current().mainTextColor),
     255          20 :         titleMedium: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, fontSize: opaque.fontScaling * 20.0, color: opaque.current().mainTextColor),
     256          20 :         bodySmall: TextStyle(fontFamily: "Inter", fontSize: opaque.fontScaling * 12.0, color: opaque.current().mainTextColor),
     257          20 :         bodyMedium: TextStyle(fontFamily: "Inter", fontSize: opaque.fontScaling * 14.0, color: opaque.current().mainTextColor),
     258          20 :         bodyLarge: TextStyle(fontFamily: "Inter", fontSize: opaque.fontScaling * 16.0, color: opaque.current().mainTextColor),
     259          20 :         headlineSmall: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, fontSize: opaque.fontScaling * 24.0, color: opaque.current().mainTextColor),
     260          20 :         headlineMedium: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, fontSize: opaque.fontScaling * 26.0, color: opaque.current().mainTextColor),
     261          20 :         headlineLarge: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.bold, fontSize: opaque.fontScaling * 28.0, color: opaque.current().mainTextColor),
     262          20 :         labelSmall: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.w100, fontSize: opaque.fontScaling * 14.0, color: opaque.current().mainTextColor),
     263          20 :         labelMedium: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.w300, fontSize: opaque.fontScaling * 16.0, color: opaque.current().mainTextColor),
     264          20 :         labelLarge: TextStyle(fontFamily: "Inter", fontWeight: FontWeight.w200, fontSize: opaque.fontScaling * 18.0, color: opaque.current().mainTextColor),
     265             :       ),
     266           4 :       switchTheme: SwitchThemeData(
     267          12 :         overlayColor: MaterialStateProperty.all(opaque.current().defaultButtonActiveColor),
     268          12 :         thumbColor: MaterialStateProperty.all(opaque.current().mainTextColor),
     269          12 :         trackColor: MaterialStateProperty.all(opaque.current().dropShadowColor),
     270             :       ),
     271             :       // the only way to change the text Selection Context Menu Color ?!
     272          12 :       brightness: opaque.current().mode == mode_dark ? Brightness.dark : Brightness.light,
     273           4 :       floatingActionButtonTheme: FloatingActionButtonThemeData(
     274           8 :           foregroundColor: opaque.current().mainTextColor,
     275           8 :           backgroundColor: opaque.current().defaultButtonColor,
     276           8 :           hoverColor: opaque.current().defaultButtonActiveColor,
     277             :           enableFeedback: true,
     278           8 :           splashColor: opaque.current().defaultButtonActiveColor),
     279           4 :       textSelectionTheme: TextSelectionThemeData(
     280          24 :           cursorColor: opaque.current().textfieldSelectionColor, selectionColor: opaque.current().textfieldSelectionColor, selectionHandleColor: opaque.current().textfieldSelectionColor),
     281           4 :       popupMenuTheme: PopupMenuThemeData(
     282          12 :         color: opaque.current().backgroundPaneColor.withOpacity(0.9),
     283             :       ),
     284           4 :       snackBarTheme: SnackBarThemeData(
     285           8 :         backgroundColor: opaque.current().snackbarBackgroundColor,
     286          12 :         contentTextStyle: TextStyle(color: opaque.current().snackbarTextColor),
     287             :       ));
     288             : }

Generated by: LCOV version 1.14