LCOV - code coverage report
Current view: top level - lib/views - globalsettingsappearanceview.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 279 0.0 %
Date: 2024-09-24 21:50:54 Functions: 0 0 -

          Line data    Source code
       1             : import 'dart:io';
       2             : 
       3             : import 'package:flutter/material.dart';
       4             : import 'package:provider/provider.dart';
       5             : import 'package:flutter_gen/gen_l10n/app_localizations.dart';
       6             : import 'package:path/path.dart' as path;
       7             : 
       8             : import '../config.dart';
       9             : import '../controllers/filesharing.dart';
      10             : import '../cwtch_icons_icons.dart';
      11             : import '../main.dart';
      12             : import '../models/appstate.dart';
      13             : import '../settings.dart';
      14             : import '../themes/cwtch.dart';
      15             : import '../themes/opaque.dart';
      16             : import '../themes/yamltheme.dart';
      17             : import 'globalsettingsview.dart';
      18             : 
      19             : class GlobalSettingsAppearanceView extends StatefulWidget {
      20           0 :   @override
      21           0 :   _GlobalSettingsAppearanceViewState createState() => _GlobalSettingsAppearanceViewState();
      22             : }
      23             : 
      24             : class _GlobalSettingsAppearanceViewState extends State<GlobalSettingsAppearanceView> {
      25             :   ScrollController settingsListScrollController = ScrollController();
      26             : 
      27           0 :   Widget build(BuildContext context) {
      28           0 :     return Consumer<Settings>(builder: (ccontext, settings, child) {
      29           0 :       return LayoutBuilder(builder: (BuildContext context, BoxConstraints viewportConstraints) {
      30           0 :         return Scrollbar(
      31           0 :             key: Key("AppearanceSettingsView"),
      32             :             trackVisibility: true,
      33           0 :             controller: settingsListScrollController,
      34           0 :             child: SingleChildScrollView(
      35             :                 clipBehavior: Clip.antiAlias,
      36           0 :                 controller: settingsListScrollController,
      37           0 :                 child: ConstrainedBox(
      38           0 :                     constraints: BoxConstraints(minHeight: viewportConstraints.maxHeight, maxWidth: viewportConstraints.maxWidth),
      39           0 :                     child: Container(
      40           0 :                         color: settings.theme.backgroundPaneColor,
      41           0 :                         child: Column(children: [
      42           0 :                           ListTile(
      43           0 :                               title: Text(AppLocalizations.of(context)!.settingLanguage),
      44           0 :                               leading: Icon(CwtchIcons.change_language, color: settings.current().mainTextColor),
      45           0 :                               trailing: Container(
      46           0 :                                   width: MediaQuery.of(context).size.width / 4,
      47           0 :                                   child: DropdownButton(
      48           0 :                                       key: Key("languagelist"),
      49             :                                       isExpanded: true,
      50           0 :                                       value: Provider.of<Settings>(context).locale.toString(),
      51           0 :                                       onChanged: (String? newValue) {
      52           0 :                                         setState(() {
      53           0 :                                           EnvironmentConfig.debugLog("setting language: $newValue");
      54           0 :                                           settings.switchLocaleByCode(newValue!);
      55           0 :                                           saveSettings(context);
      56             :                                         });
      57             :                                       },
      58           0 :                                       items: AppLocalizations.supportedLocales.map<DropdownMenuItem<String>>((Locale value) {
      59           0 :                                         return DropdownMenuItem<String>(
      60           0 :                                           value: value.toString(),
      61           0 :                                           child: Text(
      62           0 :                                             key: Key("dropdownLanguage" + value.languageCode),
      63           0 :                                             getLanguageFull(context, value.languageCode, value.countryCode),
      64           0 :                                             style: settings.scaleFonts(defaultDropDownMenuItemTextStyle),
      65             :                                             overflow: TextOverflow.ellipsis,
      66             :                                           ),
      67             :                                         );
      68           0 :                                       }).toList()))),
      69           0 :                           SwitchListTile(
      70           0 :                             title: Text(AppLocalizations.of(context)!.settingTheme),
      71           0 :                             value: settings.current().mode == mode_light,
      72           0 :                             onChanged: (bool value) {
      73             :                               if (value) {
      74           0 :                                 settings.setTheme(settings.themeId ?? "cwtch", mode_light);
      75             :                               } else {
      76           0 :                                 settings.setTheme(settings.themeId ?? "cwtch", mode_dark);
      77             :                               }
      78             : 
      79             : // Save Settings...
      80           0 :                               saveSettings(context);
      81             :                             },
      82           0 :                             activeTrackColor: settings.theme.defaultButtonColor,
      83           0 :                             inactiveTrackColor: settings.theme.defaultButtonDisabledColor,
      84           0 :                             secondary: Icon(CwtchIcons.change_theme, color: settings.current().mainTextColor),
      85             :                           ),
      86           0 :                           ListTile(
      87           0 :                             title: Text(AppLocalizations.of(context)!.themeColorLabel),
      88           0 :                             trailing: Container(
      89           0 :                                 width: MediaQuery.of(context).size.width / 4,
      90           0 :                                 child: DropdownButton<String>(
      91           0 :                                     key: Key("DropdownTheme"),
      92             :                                     isExpanded: true,
      93           0 :                                     value: Provider.of<Settings>(context).themeId,
      94           0 :                                     onChanged: (String? newValue) {
      95           0 :                                       setState(() {
      96           0 :                                         settings.setTheme(newValue!, settings.theme.mode);
      97           0 :                                         saveSettings(context);
      98             :                                       });
      99             :                                     },
     100           0 :                                     items: settings.themeloader.themes.keys.map<DropdownMenuItem<String>>((String themeId) {
     101           0 :                                       return DropdownMenuItem<String>(
     102             :                                         value: themeId,
     103             :                                         child:
     104           0 :                                             Text(getThemeName(context, settings, themeId), style: settings.scaleFonts(defaultDropDownMenuItemTextStyle)), //"ddi_$themeId", key: Key("ddi_$themeId")),
     105             :                                       );
     106           0 :                                     }).toList())),
     107           0 :                             leading: Icon(Icons.palette, color: settings.current().mainTextColor),
     108             :                           ),
     109           0 :                           Visibility(
     110             :                               // TODO: Android support needs gomobile support for reading / writing themes, and ideally importing from a .zip or .tar.gz
     111           0 :                               visible: !Platform.isAndroid,
     112           0 :                               child: ListTile(
     113           0 :                                   leading: Icon(Icons.palette, color: Provider.of<Settings>(context).theme.messageFromMeTextColor),
     114           0 :                                   title: Text(AppLocalizations.of(context)!.settingsImportThemeTitle),
     115           0 :                                   subtitle: Text(AppLocalizations.of(context)!.settingsImportThemeDescription),
     116             :                                   //AppLocalizations.of(
     117             :                                   //context)!
     118             :                                   //.fileSharingSettingsDownloadFolderDescription,
     119           0 :                                   trailing: Container(
     120           0 :                                       width: MediaQuery.of(context).size.width / 4,
     121           0 :                                       child: OutlinedButton.icon(
     122           0 :                                         label: Text(AppLocalizations.of(context)!.settingsImportThemeButton),
     123           0 :                                         onPressed: Provider.of<AppState>(context).disableFilePicker
     124             :                                             ? null
     125           0 :                                             : () async {
     126           0 :                                                 if (Platform.isAndroid) {
     127             :                                                   return;
     128             :                                                 }
     129           0 :                                                 var selectedDirectory = await showSelectDirectoryPicker(context);
     130             :                                                 if (selectedDirectory != null) {
     131           0 :                                                   selectedDirectory += path.separator;
     132           0 :                                                   final customThemeDir = path.join(await Provider.of<FlwtchState>(context, listen: false).cwtch.getCwtchDir(), custom_themes_subdir);
     133           0 :                                                   importThemeCheck(context, settings, customThemeDir, selectedDirectory);
     134             :                                                 } else {
     135             :                                                   // User canceled the picker
     136             :                                                 }
     137             :                                               },
     138             :                                         //onChanged: widget.onSave,
     139           0 :                                         icon: Icon(Icons.folder),
     140             :                                         //tooltip: widget.tooltip,
     141             :                                       )))),
     142           0 :                           SwitchListTile(
     143           0 :                             title: Text(AppLocalizations.of(context)!.settingsThemeImages),
     144           0 :                             subtitle: Text(AppLocalizations.of(context)!.settingsThemeImagesDescription),
     145           0 :                             value: settings.themeImages,
     146           0 :                             onChanged: (bool value) {
     147           0 :                               settings.themeImages = value; // Save Settings...
     148           0 :                               saveSettings(context);
     149             :                             },
     150           0 :                             activeTrackColor: settings.theme.defaultButtonColor,
     151           0 :                             inactiveTrackColor: settings.theme.defaultButtonDisabledColor,
     152           0 :                             secondary: Icon(Icons.image, color: settings.current().mainTextColor),
     153             :                           ),
     154           0 :                           ListTile(
     155           0 :                               title: Text(AppLocalizations.of(context)!.settingUIColumnPortrait),
     156           0 :                               leading: Icon(Icons.table_chart, color: settings.current().mainTextColor),
     157           0 :                               trailing: Container(
     158           0 :                                   width: MediaQuery.of(context).size.width / 4,
     159           0 :                                   child: DropdownButton(
     160             :                                       isExpanded: true,
     161           0 :                                       value: settings.uiColumnModePortrait.toString(),
     162           0 :                                       onChanged: (String? newValue) {
     163           0 :                                         settings.uiColumnModePortrait = Settings.uiColumnModeFromString(newValue!);
     164           0 :                                         saveSettings(context);
     165             :                                       },
     166           0 :                                       items: Settings.uiColumnModeOptions(false).map<DropdownMenuItem<String>>((DualpaneMode value) {
     167           0 :                                         return DropdownMenuItem<String>(
     168           0 :                                           value: value.toString(),
     169           0 :                                           child: Text(Settings.uiColumnModeToString(value, context), style: settings.scaleFonts(defaultDropDownMenuItemTextStyle)),
     170             :                                         );
     171           0 :                                       }).toList()))),
     172           0 :                           ListTile(
     173           0 :                               title: Text(
     174           0 :                                 AppLocalizations.of(context)!.settingUIColumnLandscape,
     175             :                                 textWidthBasis: TextWidthBasis.longestLine,
     176             :                                 softWrap: true,
     177             :                               ),
     178           0 :                               leading: Icon(Icons.stay_primary_landscape, color: settings.current().mainTextColor),
     179           0 :                               trailing: Container(
     180           0 :                                   width: MediaQuery.of(context).size.width / 4,
     181           0 :                                   child: Container(
     182           0 :                                       width: MediaQuery.of(context).size.width / 4,
     183           0 :                                       child: DropdownButton(
     184             :                                           isExpanded: true,
     185           0 :                                           value: settings.uiColumnModeLandscape.toString(),
     186           0 :                                           onChanged: (String? newValue) {
     187           0 :                                             settings.uiColumnModeLandscape = Settings.uiColumnModeFromString(newValue!);
     188           0 :                                             saveSettings(context);
     189             :                                           },
     190           0 :                                           items: Settings.uiColumnModeOptions(true).map<DropdownMenuItem<String>>((DualpaneMode value) {
     191           0 :                                             return DropdownMenuItem<String>(
     192           0 :                                               value: value.toString(),
     193           0 :                                               child: Text(Settings.uiColumnModeToString(value, context), overflow: TextOverflow.ellipsis, style: settings.scaleFonts(defaultDropDownMenuItemTextStyle)),
     194             :                                             );
     195           0 :                                           }).toList())))),
     196           0 :                           ListTile(
     197           0 :                             title: Text(AppLocalizations.of(context)!.defaultScalingText),
     198           0 :                             subtitle: Text(AppLocalizations.of(context)!.fontScalingDescription),
     199           0 :                             trailing: Container(
     200           0 :                                 width: MediaQuery.of(context).size.width / 4,
     201           0 :                                 child: Slider(
     202           0 :                                     onChanged: (double value) {
     203           0 :                                       settings.fontScaling = value;
     204             : // Save Settings...
     205           0 :                                       saveSettings(context);
     206           0 :                                       EnvironmentConfig.debugLog("Font Scaling: $value");
     207             :                                     },
     208             :                                     min: 0.5,
     209             :                                     divisions: 12,
     210             :                                     max: 2.0,
     211           0 :                                     label: '${settings.fontScaling * 100}%',
     212           0 :                                     value: settings.fontScaling)),
     213           0 :                             leading: Icon(Icons.format_size, color: settings.current().mainTextColor),
     214             :                           ),
     215           0 :                           SwitchListTile(
     216           0 :                             title: Text(AppLocalizations.of(context)!.streamerModeLabel),
     217           0 :                             subtitle: Text(AppLocalizations.of(context)!.descriptionStreamerMode),
     218           0 :                             value: settings.streamerMode,
     219           0 :                             onChanged: (bool value) {
     220           0 :                               settings.setStreamerMode(value);
     221             : // Save Settings...
     222           0 :                               saveSettings(context);
     223             :                             },
     224           0 :                             activeTrackColor: settings.theme.defaultButtonColor,
     225           0 :                             inactiveTrackColor: settings.theme.defaultButtonDisabledColor,
     226           0 :                             secondary: Icon(CwtchIcons.streamer_bunnymask, color: settings.current().mainTextColor),
     227             :                           ),
     228           0 :                           SwitchListTile(
     229           0 :                             title: Text(AppLocalizations.of(context)!.formattingExperiment),
     230           0 :                             subtitle: Text(AppLocalizations.of(context)!.messageFormattingDescription),
     231           0 :                             value: settings.isExperimentEnabled(FormattingExperiment),
     232           0 :                             onChanged: (bool value) {
     233             :                               if (value) {
     234           0 :                                 settings.enableExperiment(FormattingExperiment);
     235             :                               } else {
     236           0 :                                 settings.disableExperiment(FormattingExperiment);
     237             :                               }
     238           0 :                               saveSettings(context);
     239             :                             },
     240           0 :                             activeTrackColor: settings.theme.defaultButtonColor,
     241           0 :                             inactiveTrackColor: settings.theme.defaultButtonDisabledColor,
     242           0 :                             secondary: Icon(Icons.text_fields, color: settings.current().mainTextColor),
     243             :                           ),
     244             :                         ])))));
     245             :       });
     246             :     });
     247             :   }
     248             : 
     249             :   /// A slightly verbose way to extract the full language name from
     250             :   /// an individual language code. There might be a more efficient way of doing this.
     251           0 :   String getLanguageFull(context, String languageCode, String? countryCode) {
     252           0 :     if (languageCode == "en") {
     253           0 :       return AppLocalizations.of(context)!.localeEn;
     254             :     }
     255           0 :     if (languageCode == "es") {
     256           0 :       return AppLocalizations.of(context)!.localeEs;
     257             :     }
     258           0 :     if (languageCode == "fr") {
     259           0 :       return AppLocalizations.of(context)!.localeFr;
     260             :     }
     261           0 :     if (languageCode == "pt" && countryCode == "BR") {
     262           0 :       return AppLocalizations.of(context)!.localePtBr;
     263             :     }
     264           0 :     if (languageCode == "pt") {
     265           0 :       return AppLocalizations.of(context)!.localePt;
     266             :     }
     267           0 :     if (languageCode == "de") {
     268           0 :       return AppLocalizations.of(context)!.localeDe;
     269             :     }
     270           0 :     if (languageCode == "el") {
     271           0 :       return AppLocalizations.of(context)!.localeEl;
     272             :     }
     273           0 :     if (languageCode == "it") {
     274           0 :       return AppLocalizations.of(context)!.localeIt;
     275             :     }
     276           0 :     if (languageCode == "no") {
     277           0 :       return AppLocalizations.of(context)!.localeNo;
     278             :     }
     279           0 :     if (languageCode == "pl") {
     280           0 :       return AppLocalizations.of(context)!.localePl;
     281             :     }
     282           0 :     if (languageCode == "lb") {
     283           0 :       return AppLocalizations.of(context)!.localeLb;
     284             :     }
     285           0 :     if (languageCode == "ru") {
     286           0 :       return AppLocalizations.of(context)!.localeRU;
     287             :     }
     288           0 :     if (languageCode == "ro") {
     289           0 :       return AppLocalizations.of(context)!.localeRo;
     290             :     }
     291           0 :     if (languageCode == "cy") {
     292           0 :       return AppLocalizations.of(context)!.localeCy;
     293             :     }
     294           0 :     if (languageCode == "da") {
     295           0 :       return AppLocalizations.of(context)!.localeDa;
     296             :     }
     297           0 :     if (languageCode == "tr") {
     298           0 :       return AppLocalizations.of(context)!.localeTr;
     299             :     }
     300           0 :     if (languageCode == "nl") {
     301           0 :       return AppLocalizations.of(context)!.localeNl;
     302             :     }
     303           0 :     if (languageCode == "sk") {
     304           0 :       return AppLocalizations.of(context)!.localeSk;
     305             :     }
     306           0 :     if (languageCode == "ko") {
     307           0 :       return AppLocalizations.of(context)!.localeKo;
     308             :     }
     309           0 :     if (languageCode == "ja") {
     310           0 :       return AppLocalizations.of(context)!.localeJa;
     311             :     }
     312           0 :     if (languageCode == "sv") {
     313           0 :       return AppLocalizations.of(context)!.localeSv;
     314             :     }
     315           0 :     if (languageCode == "sw") {
     316           0 :       return AppLocalizations.of(context)!.localeSw;
     317             :     }
     318           0 :     if (languageCode == "uk") {
     319           0 :       return AppLocalizations.of(context)!.localeUk;
     320             :     }
     321           0 :     if (languageCode == "uz") {
     322           0 :       return AppLocalizations.of(context)!.localeUzbek;
     323             :     }
     324             :     return languageCode;
     325             :   }
     326             : 
     327             :   /// Since we don't seem to able to dynamically pull translations, this function maps themes to their names
     328           0 :   String getThemeName(context, Settings settings, String theme) {
     329             :     switch (theme) {
     330           0 :       case cwtch_theme:
     331           0 :         return AppLocalizations.of(context)!.themeNameCwtch;
     332           0 :       case "ghost":
     333           0 :         return AppLocalizations.of(context)!.themeNameGhost;
     334           0 :       case "mermaid":
     335           0 :         return AppLocalizations.of(context)!.themeNameMermaid;
     336           0 :       case "midnight":
     337           0 :         return AppLocalizations.of(context)!.themeNameMidnight;
     338           0 :       case "neon1":
     339           0 :         return AppLocalizations.of(context)!.themeNameNeon1;
     340           0 :       case "neon2":
     341           0 :         return AppLocalizations.of(context)!.themeNameNeon2;
     342           0 :       case "pumpkin":
     343           0 :         return AppLocalizations.of(context)!.themeNamePumpkin;
     344           0 :       case "vampire":
     345           0 :         return AppLocalizations.of(context)!.themeNameVampire;
     346           0 :       case "witch":
     347           0 :         return AppLocalizations.of(context)!.themeNameWitch;
     348           0 :       case "juniper":
     349             :         return "Juniper"; // Juniper is a noun, and doesn't get subject to translation...
     350             :     }
     351           0 :     return settings.themeloader.themes[theme]?[mode_light]?.theme ?? settings.themeloader.themes[theme]?[mode_dark]?.theme ?? theme;
     352             :   }
     353             : 
     354           0 :   void importThemeCheck(BuildContext context, Settings settings, String themesDir, String newThemeDirectory) async {
     355             :     // check is theme
     356           0 :     final srcDir = Directory(newThemeDirectory);
     357           0 :     String themeName = path.basename(newThemeDirectory);
     358             : 
     359           0 :     File themeFile = File(path.join(newThemeDirectory, "theme.yml"));
     360             : 
     361           0 :     if (!themeFile.existsSync()) {
     362             :       // error, isnt valid theme, no .yml theme file found
     363           0 :       SnackBar err = SnackBar(content: Text(AppLocalizations.of(context)!.settingsThemeErrorInvalid.replaceAll("\$themeName", themeName)));
     364           0 :       ScaffoldMessenger.of(context).showSnackBar(err);
     365             :       return;
     366             :     }
     367             : 
     368           0 :     Directory targetDir = Directory(path.join(themesDir, themeName));
     369             :     // check if exists
     370           0 :     if (settings.themeloader.themes.containsKey(themeName) || targetDir.existsSync()) {
     371           0 :       _modalConfirmOverwriteCustomTheme(srcDir, targetDir, themesDir, themeName, settings);
     372             :     } else {
     373           0 :       importTheme(srcDir, targetDir, themesDir, themeName, settings);
     374             :     }
     375             :   }
     376             : 
     377           0 :   void importTheme(Directory srcDir, Directory targetDir, String themesDir, String themeName, Settings settings) async {
     378           0 :     if (!targetDir.existsSync()) {
     379           0 :       targetDir = await targetDir.create();
     380             :     }
     381             : 
     382             :     // importTheme(newVal)
     383           0 :     await for (var entity in srcDir.list(recursive: false)) {
     384           0 :       if (entity is File) {
     385           0 :         entity.copySync(path.join(targetDir.path, path.basename(entity.path)));
     386             :       }
     387             :     }
     388             : 
     389           0 :     var data = await loadFileYamlTheme(path.join(targetDir.path, "theme.yml"), targetDir.path);
     390             :     if (data != null) {
     391           0 :       settings.themeloader.themes[themeName] = data;
     392             :     }
     393             : 
     394           0 :     if (settings.current().theme == themeName) {
     395           0 :       settings.setTheme(themeName, settings.current().mode);
     396             :     }
     397             :   }
     398             : 
     399           0 :   void _modalConfirmOverwriteCustomTheme(Directory srcDir, Directory targetDir, String themesDir, String themeName, Settings settings) {
     400           0 :     showModalBottomSheet<void>(
     401           0 :         context: context,
     402             :         isScrollControlled: true,
     403           0 :         builder: (BuildContext context) {
     404           0 :           return Padding(
     405           0 :               padding: MediaQuery.of(context).viewInsets,
     406           0 :               child: RepaintBoundary(
     407           0 :                   child: Container(
     408           0 :                       height: Platform.isAndroid ? 250 : 200, // bespoke value courtesy of the [TextField] docs
     409           0 :                       child: Center(
     410           0 :                           child: Padding(
     411           0 :                               padding: EdgeInsets.all(10.0),
     412           0 :                               child: Column(mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: <Widget>[
     413           0 :                                 Text(AppLocalizations.of(context)!.settingThemeOverwriteQuestion.replaceAll("\$themeName", themeName)),
     414           0 :                                 SizedBox(
     415             :                                   height: 20,
     416             :                                 ),
     417           0 :                                 Row(
     418             :                                   mainAxisAlignment: MainAxisAlignment.spaceEvenly,
     419           0 :                                   children: [
     420           0 :                                     Spacer(),
     421           0 :                                     Expanded(
     422           0 :                                         child: ElevatedButton(
     423           0 :                                       child: Text(AppLocalizations.of(context)!.settingThemeOverwriteConfirm, semanticsLabel: AppLocalizations.of(context)!.settingThemeOverwriteConfirm),
     424           0 :                                       onPressed: () {
     425           0 :                                         importTheme(srcDir, targetDir, themesDir, themeName, settings);
     426             : 
     427           0 :                                         Navigator.pop(context);
     428             :                                       },
     429             :                                     )),
     430           0 :                                     SizedBox(
     431             :                                       width: 20,
     432             :                                     ),
     433           0 :                                     Expanded(
     434           0 :                                         child: ElevatedButton(
     435           0 :                                       child: Text(AppLocalizations.of(context)!.cancel, semanticsLabel: AppLocalizations.of(context)!.cancel),
     436           0 :                                       onPressed: () {
     437           0 :                                         Navigator.pop(context);
     438             :                                       },
     439             :                                     )),
     440           0 :                                     Spacer(),
     441             :                                   ],
     442             :                                 )
     443             :                               ]))))));
     444             :         });
     445             :   }
     446             : }

Generated by: LCOV version 1.14