split settings panes into seperate files
continuous-integration/drone/pr Build is passing Details

This commit is contained in:
Dan Ballard 2024-01-06 11:39:07 -08:00
parent 2abbf223b2
commit 04985ee7eb
5 changed files with 1270 additions and 1068 deletions

View File

@ -0,0 +1,197 @@
import 'dart:collection';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import '../config.dart';
import '../cwtch_icons_icons.dart';
import '../main.dart';
import '../settings.dart';
import '../themes/opaque.dart';
import 'globalsettingsview.dart';
class GlobalSettingsAboutView extends StatefulWidget {
@override
_GlobalSettingsAboutViewState createState() => _GlobalSettingsAboutViewState();
}
class _GlobalSettingsAboutViewState extends State<GlobalSettingsAboutView> {
ScrollController settingsListScrollController = ScrollController();
Widget build(BuildContext context) {
return Consumer<Settings>(builder: (ccontext, settings, child) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints viewportConstraints) {
var appIcon = Icon(Icons.info, color: settings
.current()
.mainTextColor);
return Scrollbar(
key: Key("AboutSettingsView"),
trackVisibility: true,
controller: settingsListScrollController,
child: SingleChildScrollView(
clipBehavior: Clip.antiAlias,
controller: settingsListScrollController,
padding: EdgeInsets.symmetric(vertical: 0, horizontal: 20),
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: viewportConstraints.maxHeight,
),
child: Column(children: [
AboutListTile(
icon: appIcon,
applicationIcon: Padding(
padding: EdgeInsets.all(5),
child: Icon(CwtchIcons.cwtch_knott)),
applicationName: "Cwtch UI",
applicationLegalese:
'\u{a9} 2021-2023 Open Privacy Research Society',
aboutBoxChildren: <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(
24.0 + 10.0 + (appIcon.size ?? 24.0),
16.0,
0.0,
0.0),
// About has 24 padding (ln 389) and there appears to be another 10 of padding in the widget
child: SelectableText(
AppLocalizations.of(context)!
.versionBuilddate
.replaceAll(
"%1", EnvironmentConfig.BUILD_VER)
.replaceAll("%2",
EnvironmentConfig.BUILD_DATE)),
)
]),
SwitchListTile(
// TODO: Translate, Remove, OR Hide Prior to Release
title: Text("Show Performance Overlay"),
subtitle:
Text("Display an overlay graph of render time."),
value: settings.profileMode,
onChanged: (bool value) {
setState(() {
if (value) {
settings.profileMode = value;
} else {
settings.profileMode = value;
}
});
},
activeTrackColor:
settings.theme.defaultButtonActiveColor,
inactiveTrackColor:
settings.theme.defaultButtonDisabledColor,
secondary: Icon(Icons.bar_chart,
color: settings
.current()
.mainTextColor),
),
Visibility(
visible:
EnvironmentConfig.BUILD_VER == dev_version &&
!Platform.isAndroid,
child: SwitchListTile(
title: Text("Show Semantic Debugger"),
subtitle:
Text("Show Accessibility Debugging View"),
value: settings.useSemanticDebugger,
onChanged: (bool value) {
if (value) {
settings.useSemanticDebugger = value;
} else {
settings.useSemanticDebugger = value;
}
saveSettings(context);
},
activeTrackColor:
settings.theme.defaultButtonActiveColor,
inactiveTrackColor:
settings.theme.defaultButtonDisabledColor,
secondary: Icon(Icons.settings_accessibility,
color: settings
.current()
.mainTextColor),
)),
Visibility(
visible: EnvironmentConfig.BUILD_VER == dev_version &&
!Platform.isAndroid,
child: FutureBuilder(
future:
EnvironmentConfig.BUILD_VER != dev_version ||
Platform.isAndroid
? null
: Provider
.of<FlwtchState>(context)
.cwtch
.GetDebugInfo(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Column(
children: [
Text("libCwtch Debug Info: " +
snapshot.data.toString()),
Text("Message Cache Size (Mb): " +
(Provider
.of<FlwtchState>(context)
.profs
.cacheMemUsage() /
(1024 * 1024))
.toString())
],
);
} else {
return Container();
}
},
),
),
Visibility(
visible: EnvironmentConfig.BUILD_VER == dev_version,
child: FutureBuilder(
future: Provider
.of<FlwtchState>(context)
.cwtch
.PlatformChannelInfo(),
builder: (context, snapshot) {
if (snapshot.hasData) {
HashMap<String, String> data = snapshot.data
as HashMap<String, String>;
return getPlatformInfo(settings, data);
}
return Container();
}))
]))));
});
});
}
getPlatformInfo(settings, HashMap<String, String> platformChannelInfo) {
var sortedKeys = platformChannelInfo.keys.toList();
sortedKeys.sort();
var widgets = List<Widget>.empty(growable: true);
sortedKeys.forEach((element) {
widgets.add(ListTile(
leading: Icon(Icons.android, color: settings.current().mainTextColor),
title: Text(element),
subtitle: Text(platformChannelInfo[element]!),
));
});
return Column(
children: widgets,
);
}
// TODO: deprecated ?
/// Construct a version string from Package Info
String constructVersionString(PackageInfo pinfo) {
if (pinfo == null) {
return "";
}
return pinfo.version + "." + pinfo.buildNumber;
}
}

View File

@ -0,0 +1,420 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import '../config.dart';
import '../cwtch_icons_icons.dart';
import '../settings.dart';
import '../themes/cwtch.dart';
import '../themes/opaque.dart';
import 'globalsettingsview.dart';
class GlobalSettingsAppearanceView extends StatefulWidget {
@override
_GlobalSettingsAppearanceViewState createState() => _GlobalSettingsAppearanceViewState();
}
class _GlobalSettingsAppearanceViewState extends State<GlobalSettingsAppearanceView> {
ScrollController settingsListScrollController = ScrollController();
Widget build(BuildContext context) {
return Consumer<Settings>(builder: (ccontext, settings, child) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints viewportConstraints) {
return Scrollbar(
key: Key("AppearanceSettingsView"),
trackVisibility: true,
controller: settingsListScrollController,
child: SingleChildScrollView(
clipBehavior: Clip.antiAlias,
controller: settingsListScrollController,
padding: EdgeInsets.symmetric(vertical: 0, horizontal: 20),
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: viewportConstraints.maxHeight,
),
child: Column(children: [
ListTile(
title: Text(
AppLocalizations.of(context)!.settingLanguage),
leading: Icon(CwtchIcons.change_language,
color: settings
.current()
.mainTextColor),
trailing: Container(
width: MediaQuery
.of(context)
.size
.width / 4,
child: DropdownButton(
key: Key("languagelist"),
isExpanded: true,
value: Provider
.of<Settings>(context)
.locale
.toString(),
onChanged: (String? newValue) {
setState(() {
EnvironmentConfig.debugLog(
"setting language: $newValue");
settings.switchLocaleByCode(newValue!);
saveSettings(context);
});
},
items: AppLocalizations.supportedLocales
.map<DropdownMenuItem<String>>(
(Locale value) {
return DropdownMenuItem<String>(
value: value.toString(),
child: Text(
key: Key("dropdownLanguage" +
value.languageCode),
getLanguageFull(
context,
value.languageCode,
value.countryCode),
style: settings.scaleFonts(
defaultDropDownMenuItemTextStyle),
overflow: TextOverflow.ellipsis,
),
);
}).toList()))),
SwitchListTile(
title:
Text(AppLocalizations.of(context)!.settingTheme),
value: settings
.current()
.mode == mode_light,
onChanged: (bool value) {
if (value) {
settings.setTheme(
settings.theme.theme, mode_light);
} else {
settings.setTheme(
settings.theme.theme, mode_dark);
}
// Save Settings...
saveSettings(context);
},
activeTrackColor: settings.theme.defaultButtonColor,
inactiveTrackColor:
settings.theme.defaultButtonDisabledColor,
secondary: Icon(CwtchIcons.change_theme,
color: settings
.current()
.mainTextColor),
),
ListTile(
title: Text(
AppLocalizations.of(context)!.themeColorLabel),
trailing: Container(
width: MediaQuery
.of(context)
.size
.width / 4,
child: DropdownButton<String>(
key: Key("DropdownTheme"),
isExpanded: true,
value: Provider
.of<Settings>(context)
.theme
.theme,
onChanged: (String? newValue) {
setState(() {
settings.setTheme(
newValue!, settings.theme.mode);
saveSettings(context);
});
},
items: themes.keys
.map<DropdownMenuItem<String>>(
(String themeId) {
return DropdownMenuItem<String>(
value: themeId,
child: Text(
getThemeName(context, themeId),
style: settings.scaleFonts(
defaultDropDownMenuItemTextStyle)), //"ddi_$themeId", key: Key("ddi_$themeId")),
);
}).toList())),
leading: Icon(Icons.palette,
color: settings
.current()
.mainTextColor),
),
ListTile(
title: Text(AppLocalizations.of(context)!
.settingUIColumnPortrait),
leading: Icon(Icons.table_chart,
color: settings
.current()
.mainTextColor),
trailing: Container(
width: MediaQuery
.of(context)
.size
.width / 4,
child: DropdownButton(
isExpanded: true,
value: settings.uiColumnModePortrait
.toString(),
onChanged: (String? newValue) {
settings.uiColumnModePortrait =
Settings.uiColumnModeFromString(
newValue!);
saveSettings(context);
},
items: Settings.uiColumnModeOptions(false)
.map<DropdownMenuItem<String>>(
(DualpaneMode value) {
return DropdownMenuItem<String>(
value: value.toString(),
child: Text(
Settings.uiColumnModeToString(
value, context),
style: settings.scaleFonts(
defaultDropDownMenuItemTextStyle)),
);
}).toList()))),
ListTile(
title: Text(
AppLocalizations.of(context)!
.settingUIColumnLandscape,
textWidthBasis: TextWidthBasis.longestLine,
softWrap: true,
),
leading: Icon(Icons.stay_primary_landscape,
color: settings
.current()
.mainTextColor),
trailing: Container(
width: MediaQuery
.of(context)
.size
.width / 4,
child: Container(
width:
MediaQuery
.of(context)
.size
.width / 4,
child: DropdownButton(
isExpanded: true,
value: settings.uiColumnModeLandscape
.toString(),
onChanged: (String? newValue) {
settings.uiColumnModeLandscape =
Settings.uiColumnModeFromString(
newValue!);
saveSettings(context);
},
items:
Settings.uiColumnModeOptions(true)
.map<DropdownMenuItem<String>>(
(DualpaneMode value) {
return DropdownMenuItem<String>(
value: value.toString(),
child: Text(
Settings.uiColumnModeToString(
value, context),
overflow: TextOverflow.ellipsis,
style: settings.scaleFonts(
defaultDropDownMenuItemTextStyle)),
);
}).toList())))),
ListTile(
title: Text(
AppLocalizations.of(context)!.defaultScalingText),
subtitle: Text(AppLocalizations.of(context)!
.fontScalingDescription),
trailing: Container(
width: MediaQuery
.of(context)
.size
.width / 4,
child: Slider(
onChanged: (double value) {
settings.fontScaling = value;
// Save Settings...
saveSettings(context);
EnvironmentConfig.debugLog(
"Font Scaling: $value");
},
min: 0.5,
divisions: 12,
max: 2.0,
label: '${settings.fontScaling * 100}%',
activeColor:
settings
.current()
.defaultButtonColor,
thumbColor: settings
.current()
.mainTextColor,
overlayColor: MaterialStateProperty.all(
settings
.current()
.mainTextColor),
inactiveColor:
settings.theme.defaultButtonDisabledColor,
value: settings.fontScaling)),
leading: Icon(Icons.format_size,
color: settings
.current()
.mainTextColor),
),
SwitchListTile(
title: Text(
AppLocalizations.of(context)!.streamerModeLabel),
subtitle: Text(AppLocalizations.of(context)!
.descriptionStreamerMode),
value: settings.streamerMode,
onChanged: (bool value) {
settings.setStreamerMode(value);
// Save Settings...
saveSettings(context);
},
activeTrackColor: settings.theme.defaultButtonColor,
inactiveTrackColor:
settings.theme.defaultButtonDisabledColor,
secondary: Icon(CwtchIcons.streamer_bunnymask,
color: settings
.current()
.mainTextColor),
),
SwitchListTile(
title: Text(AppLocalizations.of(context)!
.formattingExperiment),
subtitle: Text(AppLocalizations.of(context)!
.messageFormattingDescription),
value: settings
.isExperimentEnabled(FormattingExperiment),
onChanged: (bool value) {
if (value) {
settings.enableExperiment(FormattingExperiment);
} else {
settings.disableExperiment(FormattingExperiment);
}
saveSettings(context);
},
activeTrackColor:
settings.theme.defaultButtonActiveColor,
inactiveTrackColor:
settings.theme.defaultButtonDisabledColor,
secondary: Icon(Icons.text_fields,
color: settings
.current()
.mainTextColor),
),
]))));
});
});
}
/// A slightly verbose way to extract the full language name from
/// an individual language code. There might be a more efficient way of doing this.
String getLanguageFull(context, String languageCode, String? countryCode) {
if (languageCode == "en") {
return AppLocalizations.of(context)!.localeEn;
}
if (languageCode == "es") {
return AppLocalizations.of(context)!.localeEs;
}
if (languageCode == "fr") {
return AppLocalizations.of(context)!.localeFr;
}
if (languageCode == "pt" && countryCode == "BR") {
return AppLocalizations.of(context)!.localePtBr;
}
if (languageCode == "pt") {
return AppLocalizations.of(context)!.localePt;
}
if (languageCode == "de") {
return AppLocalizations.of(context)!.localeDe;
}
if (languageCode == "el") {
return AppLocalizations.of(context)!.localeEl;
}
if (languageCode == "it") {
return AppLocalizations.of(context)!.localeIt;
}
if (languageCode == "no") {
return AppLocalizations.of(context)!.localeNo;
}
if (languageCode == "pl") {
return AppLocalizations.of(context)!.localePl;
}
if (languageCode == "lb") {
return AppLocalizations.of(context)!.localeLb;
}
if (languageCode == "ru") {
return AppLocalizations.of(context)!.localeRU;
}
if (languageCode == "ro") {
return AppLocalizations.of(context)!.localeRo;
}
if (languageCode == "cy") {
return AppLocalizations.of(context)!.localeCy;
}
if (languageCode == "da") {
return AppLocalizations.of(context)!.localeDa;
}
if (languageCode == "tr") {
return AppLocalizations.of(context)!.localeTr;
}
if (languageCode == "nl") {
return AppLocalizations.of(context)!.localeNl;
}
if (languageCode == "sk") {
return AppLocalizations.of(context)!.localeSk;
}
if (languageCode == "ko") {
return AppLocalizations.of(context)!.localeKo;
}
if (languageCode == "ja") {
return AppLocalizations.of(context)!.localeJa;
}
if (languageCode == "sv") {
return AppLocalizations.of(context)!.localeSv;
}
if (languageCode == "sw") {
return AppLocalizations.of(context)!.localeSw;
}
if (languageCode == "uk") {
return AppLocalizations.of(context)!.localeUk;
}
if (languageCode == "uz") {
return AppLocalizations.of(context)!.localeUzbek;
}
return languageCode;
}
/// Since we don't seem to able to dynamically pull translations, this function maps themes to their names
String getThemeName(context, String theme) {
switch (theme) {
case cwtch_theme:
return AppLocalizations.of(context)!.themeNameCwtch;
case "ghost":
return AppLocalizations.of(context)!.themeNameGhost;
case "mermaid":
return AppLocalizations.of(context)!.themeNameMermaid;
case "midnight":
return AppLocalizations.of(context)!.themeNameMidnight;
case "neon1":
return AppLocalizations.of(context)!.themeNameNeon1;
case "neon2":
return AppLocalizations.of(context)!.themeNameNeon2;
case "pumpkin":
return AppLocalizations.of(context)!.themeNamePumpkin;
case "vampire":
return AppLocalizations.of(context)!.themeNameVampire;
case "witch":
return AppLocalizations.of(context)!.themeNameWitch;
case "juniper":
return "Juniper"; // Juniper is a noun, and doesn't get subject to translation...
}
return theme;
}
}

View File

@ -0,0 +1,242 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import '../config.dart';
import '../cwtch_icons_icons.dart';
import '../settings.dart';
import '../themes/opaque.dart';
import 'globalsettingsview.dart';
class GlobalSettingsBehaviourView extends StatefulWidget {
@override
_GlobalSettingsBehaviourViewState createState() => _GlobalSettingsBehaviourViewState();
}
class _GlobalSettingsBehaviourViewState extends State<GlobalSettingsBehaviourView> {
static const androidSettingsChannel = const MethodChannel('androidSettings');
static const androidSettingsChangeChannel = const MethodChannel('androidSettingsChanged');
ScrollController settingsListScrollController = ScrollController();
bool powerExempt = false;
@override
void initState() {
super.initState();
androidSettingsChangeChannel.setMethodCallHandler(handleSettingsChanged);
if (Platform.isAndroid) {
isBatteryExempt().then((value) => setState(() {
powerExempt = value;
}));
} else {
powerExempt = false;
}
}
// Handler on method channel for MainActivity/onActivityResult to report the user choice when we ask for power exemption
Future<void> handleSettingsChanged(MethodCall call) async {
if (call.method == "powerExemptionChange") {
if (call.arguments) {
setState(() {
powerExempt = true;
});
}
}
}
//* Android Only Requests
Future<bool> isBatteryExempt() async {
return await androidSettingsChannel.invokeMethod('isBatteryExempt', {}) ??
false;
}
Future<void> requestBatteryExemption() async {
await androidSettingsChannel.invokeMethod('requestBatteryExemption', {});
return Future.value();
}
//* End Android Only Requests
Widget build(BuildContext context) {
return Consumer<Settings>(builder: (ccontext, settings, child) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints viewportConstraints) {
return Scrollbar(
key: Key("BehaviourSettingsView"),
trackVisibility: true,
controller: settingsListScrollController,
child: SingleChildScrollView(
clipBehavior: Clip.antiAlias,
controller: settingsListScrollController,
padding: EdgeInsets.symmetric(vertical: 0, horizontal: 20),
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: viewportConstraints.maxHeight,
),
child: Column(children: [
Visibility(
visible: Platform.isAndroid,
child: SwitchListTile(
title: Text(AppLocalizations.of(context)!
.settingAndroidPowerExemption),
subtitle: Text(AppLocalizations.of(context)!
.settingAndroidPowerExemptionDescription),
value: powerExempt,
onChanged: (bool value) {
if (value) {
requestBatteryExemption();
} else {
// We can't ask for it to be turned off, show an informational popup
showBatteryDialog(context);
}
},
activeTrackColor: settings.theme.defaultButtonColor,
inactiveTrackColor:
settings.theme.defaultButtonDisabledColor,
secondary: Icon(Icons.power,
color: settings.current().mainTextColor),
),
),
ListTile(
title: Text(AppLocalizations.of(context)!
.notificationPolicySettingLabel),
subtitle: Text(AppLocalizations.of(context)!
.notificationPolicySettingDescription),
trailing: Container(
width: MediaQuery.of(context).size.width / 4,
child: DropdownButton(
isExpanded: true,
value: settings.notificationPolicy,
onChanged: (NotificationPolicy? newValue) {
settings.notificationPolicy = newValue!;
saveSettings(context);
},
items: NotificationPolicy.values.map<
DropdownMenuItem<NotificationPolicy>>(
(NotificationPolicy value) {
return DropdownMenuItem<NotificationPolicy>(
value: value,
child: Text(
Settings.notificationPolicyToString(
value, context),
overflow: TextOverflow.ellipsis,
style: settings.scaleFonts(
defaultDropDownMenuItemTextStyle)),
);
}).toList())),
leading: Icon(CwtchIcons.chat_bubble_empty_24px,
color: settings.current().mainTextColor),
),
ListTile(
title: Text(AppLocalizations.of(context)!
.notificationContentSettingLabel),
subtitle: Text(AppLocalizations.of(context)!
.notificationContentSettingDescription),
trailing: Container(
width: MediaQuery.of(context).size.width / 4,
child: DropdownButton(
isExpanded: true,
value: settings.notificationContent,
onChanged: (NotificationContent? newValue) {
settings.notificationContent = newValue!;
saveSettings(context);
},
items: NotificationContent.values.map<
DropdownMenuItem<
NotificationContent>>(
(NotificationContent value) {
return DropdownMenuItem<
NotificationContent>(
value: value,
child: Text(
Settings.notificationContentToString(
value, context),
overflow: TextOverflow.ellipsis,
style: settings.scaleFonts(
defaultDropDownMenuItemTextStyle)),
);
}).toList())),
leading: Icon(CwtchIcons.chat_bubble_empty_24px,
color: settings.current().mainTextColor),
),
SwitchListTile(
title: Text(
AppLocalizations.of(context)!.blockUnknownLabel),
subtitle: Text(AppLocalizations.of(context)!
.descriptionBlockUnknownConnections),
value: settings.blockUnknownConnections,
onChanged: (bool value) {
if (value) {
settings.forbidUnknownConnections();
} else {
settings.allowUnknownConnections();
}
// Save Settings...
saveSettings(context);
},
activeTrackColor: settings.theme.defaultButtonColor,
inactiveTrackColor:
settings.theme.defaultButtonDisabledColor,
secondary: Icon(CwtchIcons.block_unknown,
color: settings.current().mainTextColor),
),
SwitchListTile(
title: Text(AppLocalizations.of(context)!
.defaultPreserveHistorySetting),
subtitle: Text(AppLocalizations.of(context)!
.preserveHistorySettingDescription),
value: settings.preserveHistoryByDefault,
onChanged: (bool value) {
if (value) {
settings.setPreserveHistoryDefault();
} else {
settings.setDeleteHistoryDefault();
}
// Save Settings...
saveSettings(context);
},
activeTrackColor: settings.theme.defaultButtonColor,
inactiveTrackColor:
settings.theme.defaultButtonDisabledColor,
secondary: Icon(CwtchIcons.peer_history,
color: settings.current().mainTextColor),
),
]))));
});
});
}
showBatteryDialog(BuildContext context) {
Widget okButton = ElevatedButton(
child: Text(AppLocalizations.of(context)!.okButton),
onPressed: () {
Navigator.of(context).pop();
},
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
title:
Text(AppLocalizations.of(context)!.settingsAndroidPowerReenablePopup),
actions: [
okButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
}

View File

@ -0,0 +1,403 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import '../config.dart';
import '../cwtch_icons_icons.dart';
import '../main.dart';
import '../models/servers.dart';
import '../settings.dart';
import '../themes/opaque.dart';
import '../widgets/folderpicker.dart';
import 'globalsettingsview.dart';
class GlobalSettingsExperimentsView extends StatefulWidget {
@override
_GlobalSettingsExperimentsViewState createState() => _GlobalSettingsExperimentsViewState();
}
class _GlobalSettingsExperimentsViewState extends State<GlobalSettingsExperimentsView> {
ScrollController settingsListScrollController = ScrollController();
Widget build(BuildContext context) {
return Consumer<Settings>(builder: (ccontext, settings, child) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints viewportConstraints) {
return Scrollbar(
key: Key("ExperimentsSettingsView"),
trackVisibility: true,
controller: settingsListScrollController,
child: SingleChildScrollView(
clipBehavior: Clip.antiAlias,
controller: settingsListScrollController,
padding: EdgeInsets.symmetric(vertical: 0, horizontal: 20),
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: viewportConstraints.maxHeight,
),
child: Column(children: [
SwitchListTile(
title: Text(
AppLocalizations.of(context)!.experimentsEnabled),
subtitle: Text(AppLocalizations.of(context)!
.descriptionExperiments),
value: settings.experimentsEnabled,
onChanged: (bool value) {
if (value) {
settings.enableExperiments();
} else {
settings.disableExperiments();
}
// Save Settings...
saveSettings(context);
},
activeTrackColor: settings.theme.defaultButtonColor,
inactiveTrackColor:
settings.theme.defaultButtonDisabledColor,
secondary: Icon(CwtchIcons.enable_experiments,
color: settings
.current()
.mainTextColor),
),
Visibility(
visible: settings.experimentsEnabled,
child: Column(
children: [
SwitchListTile(
title: Text(AppLocalizations.of(context)!
.enableGroups),
subtitle: Text(AppLocalizations.of(context)!
.descriptionExperimentsGroups),
value: settings.isExperimentEnabled(
TapirGroupsExperiment),
onChanged: (bool value) {
if (value) {
settings.enableExperiment(
TapirGroupsExperiment);
} else {
settings.disableExperiment(
TapirGroupsExperiment);
}
// Save Settings...
saveSettings(context);
},
activeTrackColor:
settings.theme.defaultButtonColor,
inactiveTrackColor:
settings.theme.defaultButtonDisabledColor,
secondary: Icon(CwtchIcons.enable_groups,
color: settings
.current()
.mainTextColor),
),
Visibility(
visible:
!Platform.isAndroid && !Platform.isIOS,
child: SwitchListTile(
title: Text(AppLocalizations.of(context)!
.settingServers),
subtitle: Provider
.of<FlwtchState>(
context,
listen: false)
.cwtch
.IsServersCompiled()
? Text(AppLocalizations.of(context)!
.settingServersDescription)
: Text(
"This version of Cwtch has been compiled without support for the server hosting experiment."),
value: Provider
.of<FlwtchState>(context,
listen: false)
.cwtch
.IsServersCompiled() &&
settings.isExperimentEnabled(
ServerManagementExperiment),
onChanged: Provider
.of<FlwtchState>(
context,
listen: false)
.cwtch
.IsServersCompiled()
? (bool value) {
Provider.of<ServerListState>(
context,
listen: false)
.clear();
if (value) {
settings.enableExperiment(
ServerManagementExperiment);
} else {
settings.disableExperiment(
ServerManagementExperiment);
}
// Save Settings...
saveSettings(context);
}
: null,
activeTrackColor:
settings.theme.defaultButtonColor,
inactiveTrackColor: settings
.theme.defaultButtonDisabledColor,
inactiveThumbColor: settings
.theme.defaultButtonDisabledColor,
secondary: Icon(CwtchIcons.dns_24px),
)),
SwitchListTile(
title: Text(AppLocalizations.of(context)!
.settingFileSharing),
subtitle: Text(AppLocalizations.of(context)!
.descriptionFileSharing),
value: settings.isExperimentEnabled(
FileSharingExperiment),
onChanged: (bool value) {
if (value) {
if (checkDownloadDirectory(
context, settings)) {
settings.enableExperiment(
FileSharingExperiment);
} else {
settings.enableExperiment(
FileSharingExperiment);
settings.disableExperiment(
ImagePreviewsExperiment);
}
} else {
settings.disableExperiment(
FileSharingExperiment);
settings.disableExperiment(
ImagePreviewsExperiment);
}
saveSettings(context);
},
activeTrackColor:
settings.theme.defaultButtonColor,
inactiveTrackColor:
settings.theme.defaultButtonDisabledColor,
secondary: Icon(CwtchIcons.attached_file_3,
color: settings
.current()
.mainTextColor),
),
Visibility(
visible: settings.isExperimentEnabled(
FileSharingExperiment),
child: Column(children: [
SwitchListTile(
title: Text(AppLocalizations.of(context)!
.settingImagePreviews),
subtitle: Text(
AppLocalizations.of(context)!
.settingImagePreviewsDescription),
value: settings.isExperimentEnabled(
ImagePreviewsExperiment),
onChanged: (bool value) {
if (value) {
if (checkDownloadDirectory(
context, settings)) {
settings.enableExperiment(
ImagePreviewsExperiment);
} else {
settings.disableExperiment(
ImagePreviewsExperiment);
}
} else {
settings.disableExperiment(
ImagePreviewsExperiment);
}
saveSettings(context);
},
activeTrackColor: settings
.theme.defaultButtonActiveColor,
inactiveTrackColor: settings
.theme.defaultButtonDisabledColor,
secondary: Icon(Icons.photo,
color:
settings
.current()
.mainTextColor),
),
Visibility(
visible: settings.isExperimentEnabled(
ImagePreviewsExperiment) &&
!Platform.isAndroid,
child: CwtchFolderPicker(
testKey: Key("DownloadFolderPicker"),
label: AppLocalizations.of(context)!
.settingDownloadFolder,
initialValue: settings.downloadPath,
textStyle: settings.scaleFonts(
defaultDropDownMenuItemTextStyle),
description: AppLocalizations.of(
context)!
.fileSharingSettingsDownloadFolderDescription,
tooltip: AppLocalizations.of(context)!
.fileSharingSettingsDownloadFolderTooltip,
onSave: (newVal) {
settings.downloadPath = newVal;
saveSettings(context);
},
),
),
]),
),
SwitchListTile(
title: Text(AppLocalizations.of(context)!
.blodeuweddExperimentEnable),
subtitle: Provider
.of<FlwtchState>(context,
listen: false)
.cwtch
.IsBlodeuweddSupported()
? Text(AppLocalizations.of(context)!
.blodeuweddDescription)
: Text(AppLocalizations.of(context)!
.blodeuweddNotSupported),
value: Provider
.of<FlwtchState>(context,
listen: false)
.cwtch
.IsBlodeuweddSupported() &&
settings.isExperimentEnabled(
BlodeuweddExperiment),
onChanged: Provider
.of<FlwtchState>(context,
listen: false)
.cwtch
.IsBlodeuweddSupported()
? (bool value) {
if (value) {
settings.enableExperiment(
BlodeuweddExperiment);
} else {
settings.disableExperiment(
BlodeuweddExperiment);
}
saveSettings(context);
}
: null,
activeTrackColor:
settings.theme.defaultButtonColor,
inactiveTrackColor:
settings.theme.defaultButtonDisabledColor,
inactiveThumbColor:
settings.theme.defaultButtonDisabledColor,
secondary: Icon(Icons.assistant,
color: settings
.current()
.mainTextColor),
),
Visibility(
visible: Provider
.of<FlwtchState>(context,
listen: false)
.cwtch
.IsBlodeuweddSupported() &&
settings.isExperimentEnabled(
BlodeuweddExperiment),
child: CwtchFolderPicker(
testKey: Key("DownloadFolderPicker"),
label: AppLocalizations.of(context)!
.settingDownloadFolder,
initialValue: settings.blodeuweddPath,
description: AppLocalizations.of(context)!
.blodeuweddPath,
tooltip: AppLocalizations.of(context)!
.blodeuweddPath,
onSave: (newVal) {
settings.blodeuweddPath = newVal;
saveSettings(context);
},
),
),
],
)),
Visibility(
visible: settings.experimentsEnabled,
child: SwitchListTile(
title: Text(AppLocalizations.of(context)!
.enableExperimentClickableLinks),
subtitle: Text(AppLocalizations.of(context)!
.experimentClickableLinksDescription),
value: settings.isExperimentEnabled(
ClickableLinksExperiment),
onChanged: (bool value) {
if (value) {
settings.enableExperiment(
ClickableLinksExperiment);
} else {
settings.disableExperiment(
ClickableLinksExperiment);
}
saveSettings(context);
},
activeTrackColor:
settings.theme.defaultButtonActiveColor,
inactiveTrackColor:
settings.theme.defaultButtonDisabledColor,
secondary: Icon(Icons.link,
color: settings
.current()
.mainTextColor),
)),
Visibility(
visible: settings.experimentsEnabled,
child: SwitchListTile(
title: Text(AppLocalizations.of(context)!
.enableExperimentQRCode),
subtitle: Text(AppLocalizations.of(context)!
.experimentQRCodeDescription),
value: settings
.isExperimentEnabled(QRCodeExperiment),
onChanged: (bool value) {
if (value) {
settings.enableExperiment(QRCodeExperiment);
} else {
settings.disableExperiment(QRCodeExperiment);
}
saveSettings(context);
},
activeTrackColor:
settings.theme.defaultButtonActiveColor,
inactiveTrackColor:
settings.theme.defaultButtonDisabledColor,
secondary: Icon(Icons.qr_code,
color: settings
.current()
.mainTextColor),
)),
]))));
});
});
}
bool checkDownloadDirectory(context, settings) {
bool showError = false;
if (settings.downloadPath != "") {
} else {
// check if the default download path exists
var path = Provider.of<FlwtchState>(context, listen: false)
.cwtch
.defaultDownloadPath();
if (path != null) {
settings.downloadPath = path;
} else {
showError = true;
}
}
if (!showError && Directory(settings.downloadPath).existsSync()) {
return true;
} else {
final snackBar = SnackBar(
content: Text(
AppLocalizations.of(context)!.errorDownloadDirectoryDoesNotExist),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
return false;
}
}
}

File diff suppressed because it is too large Load Diff