cwtch-ui/lib/views/globalsettingsview.dart

1157 lines
57 KiB
Dart
Raw Normal View History

import 'dart:collection';
2021-06-24 23:10:45 +00:00
import 'dart:convert';
import 'dart:io';
2021-06-24 23:10:45 +00:00
import 'package:cwtch/cwtch_icons_icons.dart';
2021-11-02 02:29:58 +00:00
import 'package:cwtch/models/servers.dart';
2021-12-14 21:33:30 +00:00
import 'package:cwtch/widgets/folderpicker.dart';
2021-12-15 20:17:13 +00:00
import 'package:cwtch/themes/cwtch.dart';
import 'package:cwtch/themes/opaque.dart';
import 'package:flutter/services.dart';
2021-06-24 23:10:45 +00:00
import 'package:package_info_plus/package_info_plus.dart';
import 'package:flutter/material.dart';
import 'package:cwtch/settings.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import '../main.dart';
import '../config.dart';
/// Global Settings View provides access to modify all the Globally Relevant Settings including Locale, Theme and Experiments.
class GlobalSettingsView extends StatefulWidget {
@override
_GlobalSettingsViewState createState() => _GlobalSettingsViewState();
}
class _GlobalSettingsViewState extends State<GlobalSettingsView> {
static const androidSettingsChannel = const MethodChannel('androidSettings');
2024-01-04 09:53:10 +00:00
static const androidSettingsChangeChannel =
const MethodChannel('androidSettingsChanged');
bool powerExempt = false;
ScrollController settingsListScrollController = ScrollController();
2021-06-24 23:10:45 +00:00
@override
void dispose() {
super.dispose();
}
@override
void initState() {
super.initState();
androidSettingsChangeChannel.setMethodCallHandler(handleSettingsChanged);
if (Platform.isAndroid) {
2022-04-14 22:34:17 +00:00
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 {
2024-01-04 09:53:10 +00:00
return await androidSettingsChannel.invokeMethod('isBatteryExempt', {}) ??
false;
}
Future<void> requestBatteryExemption() async {
await androidSettingsChannel.invokeMethod('requestBatteryExemption', {});
return Future.value();
}
//* End Android Only Requests
2021-06-24 23:10:45 +00:00
@override
Widget build(BuildContext context) {
2024-01-04 09:53:10 +00:00
return DefaultTabController(
length: 4,
child: Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.cwtchSettingsTitle),
bottom: TabBar(
2024-01-04 09:59:51 +00:00
isScrollable: true,
2024-01-04 09:53:10 +00:00
tabs: [
Tab(
2024-01-04 09:59:51 +00:00
key: Key("OpenSettingsAppearance"),
2024-01-04 09:53:10 +00:00
icon: Icon(Icons.palette),
text: AppLocalizations.of(context)!
.settingsGroupAppearance),
Tab(
2024-01-04 09:59:51 +00:00
key: Key("OpenSettingsBehaviour"),
2024-01-04 09:53:10 +00:00
icon: Icon(Icons.settings),
text:
AppLocalizations.of(context)!.settingGroupBehaviour),
Tab(
2024-01-04 09:59:51 +00:00
key: Key("OpenSettingsExperiments"),
2024-01-04 09:53:10 +00:00
icon: Icon(CwtchIcons.enable_experiments),
text: AppLocalizations.of(context)!
.settingsGroupExperiments),
2024-01-04 09:59:51 +00:00
Tab(icon: Icon(Icons.info), text: AppLocalizations.of(context)!
.settingsGroupAbout),
2024-01-04 09:53:10 +00:00
],
)),
body: _buildSettingsList(),
));
2021-06-24 23:10:45 +00:00
}
Widget _buildSettingsList() {
return Consumer<Settings>(builder: (ccontext, settings, child) {
2024-01-04 09:53:10 +00:00
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints viewportConstraints) {
var appIcon = Icon(Icons.info, color: settings.current().mainTextColor);
2024-01-04 09:53:10 +00:00
return TabBarView(children: [
// ***** Appearance
Scrollbar(
2024-01-04 09:59:51 +00:00
key: Key("AppearanceSettingsView"),
2024-01-04 09:53:10 +00:00
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,
2024-01-04 09:53:10 +00:00
child: DropdownButton<String>(
key: Key("DropdownTheme"),
2022-05-11 19:43:54 +00:00
isExpanded: true,
2024-01-04 09:53:10 +00:00
value: Provider.of<Settings>(context)
.theme
.theme,
onChanged: (String? newValue) {
setState(() {
2024-01-04 09:53:10 +00:00
settings.setTheme(
newValue!, settings.theme.mode);
saveSettings(context);
});
},
2024-01-04 09:53:10 +00:00
items: themes.keys
.map<DropdownMenuItem<String>>(
(String themeId) {
return DropdownMenuItem<String>(
2024-01-04 09:53:10 +00:00
value: themeId,
child: Text(
2024-01-04 09:53:10 +00:00
getThemeName(context, themeId),
style: settings.scaleFonts(
defaultDropDownMenuItemTextStyle)), //"ddi_$themeId", key: Key("ddi_$themeId")),
);
2024-01-04 09:53:10 +00:00
}).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);
2024-01-04 09:53:10 +00:00
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),
),
])))),
// **** Behaviour
Scrollbar(
2024-01-04 09:59:51 +00:00
key: Key("BehaviourSettingsView"),
2024-01-04 09:53:10 +00:00
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,
2021-12-15 20:17:13 +00:00
),
2024-01-04 09:53:10 +00:00
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),
2022-02-14 19:00:46 +00:00
trailing: Container(
2022-02-14 19:03:28 +00:00
width: MediaQuery.of(context).size.width / 4,
2022-02-14 19:00:46 +00:00
child: DropdownButton(
2022-05-11 19:43:54 +00:00
isExpanded: true,
2024-01-04 09:53:10 +00:00
value: settings.notificationPolicy,
onChanged: (NotificationPolicy? newValue) {
settings.notificationPolicy = newValue!;
2022-02-14 19:03:28 +00:00
saveSettings(context);
},
2024-01-04 09:53:10 +00:00
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)),
2022-02-14 19:03:28 +00:00
);
2024-01-04 09:53:10 +00:00
}).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,
2024-01-04 09:53:10 +00:00
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,
2022-04-14 22:34:17 +00:00
onChanged: (bool value) {
if (value) {
2024-01-04 09:53:10 +00:00
settings.forbidUnknownConnections();
2022-04-14 22:34:17 +00:00
} else {
2024-01-04 09:53:10 +00:00
settings.allowUnknownConnections();
2022-04-14 22:34:17 +00:00
}
2024-01-04 09:53:10 +00:00
// Save Settings...
saveSettings(context);
2022-04-14 22:34:17 +00:00
},
activeTrackColor: settings.theme.defaultButtonColor,
2024-01-04 09:53:10 +00:00
inactiveTrackColor:
settings.theme.defaultButtonDisabledColor,
secondary: Icon(CwtchIcons.block_unknown,
color: settings.current().mainTextColor),
2022-04-14 22:34:17 +00:00
),
2024-01-04 09:53:10 +00:00
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();
}
2021-06-24 23:10:45 +00:00
2024-01-04 09:53:10 +00:00
// Save Settings...
saveSettings(context);
},
activeTrackColor: settings.theme.defaultButtonColor,
inactiveTrackColor:
settings.theme.defaultButtonDisabledColor,
secondary: Icon(CwtchIcons.peer_history,
color: settings.current().mainTextColor),
),
])))),
2024-01-04 09:53:10 +00:00
// ****** Experiments
Scrollbar(
2024-01-04 09:59:51 +00:00
key: Key("ExperimentsSettingsView"),
2024-01-04 09:53:10 +00:00
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,
2021-06-24 23:10:45 +00:00
),
2024-01-04 09:53:10 +00:00
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);
}
2024-01-04 09:53:10 +00:00
: 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);
}
2022-09-09 19:23:08 +00:00
} else {
2024-01-04 09:53:10 +00:00
settings.disableExperiment(
FileSharingExperiment);
settings.disableExperiment(
ImagePreviewsExperiment);
2022-09-09 19:23:08 +00:00
}
2024-01-04 09:53:10 +00:00
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);
}
2022-09-09 19:23:08 +00:00
} else {
2024-01-04 09:53:10 +00:00
settings.disableExperiment(
ImagePreviewsExperiment);
2022-09-09 19:23:08 +00:00
}
2021-12-17 00:54:53 +00:00
saveSettings(context);
},
2024-01-04 09:53:10 +00:00
activeTrackColor: settings
.theme.defaultButtonActiveColor,
inactiveTrackColor: settings
.theme.defaultButtonDisabledColor,
secondary: Icon(Icons.photo,
color:
settings.current().mainTextColor),
2021-12-14 21:33:30 +00:00
),
2024-01-04 09:53:10 +00:00
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);
}
2024-01-04 09:53:10 +00:00
: null,
activeTrackColor:
settings.theme.defaultButtonColor,
inactiveTrackColor:
settings.theme.defaultButtonDisabledColor,
inactiveThumbColor:
settings.theme.defaultButtonDisabledColor,
secondary: Icon(Icons.assistant,
color: settings.current().mainTextColor),
),
2024-01-04 09:53:10 +00:00
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),
)),
])))),
// **** About
Scrollbar(
2024-01-04 09:59:51 +00:00
key: Key("AboutSettingsView"),
2024-01-04 09:53:10 +00:00
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,
2023-04-18 21:07:10 +00:00
),
2024-01-04 09:53:10 +00:00
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) {
2024-01-04 09:53:10 +00:00
settings.profileMode = value;
} else {
2024-01-04 09:53:10 +00:00
settings.profileMode = value;
}
2024-01-04 09:53:10 +00:00
});
2022-04-14 22:34:17 +00:00
},
2024-01-04 09:53:10 +00:00
activeTrackColor:
settings.theme.defaultButtonActiveColor,
inactiveTrackColor:
settings.theme.defaultButtonDisabledColor,
secondary: Icon(Icons.bar_chart,
color: settings.current().mainTextColor),
2022-04-14 22:34:17 +00:00
),
2024-01-04 09:53:10 +00:00
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;
}
2024-01-04 09:53:10 +00:00
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();
2024-01-04 09:53:10 +00:00
}
},
),
),
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();
}))
]))))
]);
2021-06-24 23:10:45 +00:00
});
});
}
showBatteryDialog(BuildContext context) {
Widget okButton = ElevatedButton(
2022-04-14 22:34:17 +00:00
child: Text(AppLocalizations.of(context)!.okButton),
onPressed: () {
Navigator.of(context).pop();
},
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
2024-01-04 09:53:10 +00:00
title:
Text(AppLocalizations.of(context)!.settingsAndroidPowerReenablePopup),
actions: [
okButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
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,
);
}
2021-06-24 23:10:45 +00:00
}
2022-09-09 19:23:08 +00:00
bool checkDownloadDirectory(context, settings) {
bool showError = false;
if (settings.downloadPath != "") {
} else {
// check if the default download path exists
2024-01-04 09:53:10 +00:00
var path = Provider.of<FlwtchState>(context, listen: false)
.cwtch
.defaultDownloadPath();
2022-09-09 19:23:08 +00:00
if (path != null) {
settings.downloadPath = path;
} else {
showError = true;
}
}
if (!showError && Directory(settings.downloadPath).existsSync()) {
return true;
} else {
final snackBar = SnackBar(
2024-01-04 09:53:10 +00:00
content: Text(
AppLocalizations.of(context)!.errorDownloadDirectoryDoesNotExist),
2022-09-09 19:23:08 +00:00
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
return false;
}
}
2021-06-24 23:10:45 +00:00
/// Construct a version string from Package Info
String constructVersionString(PackageInfo pinfo) {
if (pinfo == null) {
return "";
}
return pinfo.version + "." + pinfo.buildNumber;
}
/// 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) {
2021-06-24 23:10:45 +00:00
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;
}
2021-06-24 23:10:45 +00:00
if (languageCode == "pt") {
return AppLocalizations.of(context)!.localePt;
}
if (languageCode == "de") {
return AppLocalizations.of(context)!.localeDe;
}
if (languageCode == "el") {
return AppLocalizations.of(context)!.localeEl;
}
2021-06-24 23:10:45 +00:00
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;
}
2021-11-10 17:55:51 +00:00
if (languageCode == "ru") {
return AppLocalizations.of(context)!.localeRU;
}
if (languageCode == "ro") {
return AppLocalizations.of(context)!.localeRo;
}
if (languageCode == "cy") {
return AppLocalizations.of(context)!.localeCy;
}
2022-03-03 18:19:42 +00:00
if (languageCode == "da") {
return AppLocalizations.of(context)!.localeDa;
}
2022-07-29 22:20:01 +00:00
if (languageCode == "tr") {
return AppLocalizations.of(context)!.localeTr;
}
2022-09-10 15:11:08 +00:00
if (languageCode == "nl") {
return AppLocalizations.of(context)!.localeNl;
}
2023-02-07 01:02:30 +00:00
if (languageCode == "sk") {
return AppLocalizations.of(context)!.localeSk;
}
2023-03-14 21:46:57 +00:00
if (languageCode == "ko") {
return AppLocalizations.of(context)!.localeKo;
}
if (languageCode == "ja") {
return AppLocalizations.of(context)!.localeJa;
}
2023-05-22 16:11:52 +00:00
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;
}
2021-06-24 23:10:45 +00:00
return languageCode;
}
2021-12-15 20:17:13 +00:00
/// 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) {
2021-12-15 22:29:27 +00:00
case cwtch_theme:
return AppLocalizations.of(context)!.themeNameCwtch;
case "ghost":
2021-12-15 22:29:27 +00:00
return AppLocalizations.of(context)!.themeNameGhost;
case "mermaid":
2021-12-15 22:29:27 +00:00
return AppLocalizations.of(context)!.themeNameMermaid;
case "midnight":
2021-12-15 22:29:27 +00:00
return AppLocalizations.of(context)!.themeNameMidnight;
case "neon1":
2021-12-15 22:29:27 +00:00
return AppLocalizations.of(context)!.themeNameNeon1;
case "neon2":
2021-12-15 22:29:27 +00:00
return AppLocalizations.of(context)!.themeNameNeon2;
case "pumpkin":
2021-12-15 22:29:27 +00:00
return AppLocalizations.of(context)!.themeNamePumpkin;
case "vampire":
2021-12-15 22:29:27 +00:00
return AppLocalizations.of(context)!.themeNameVampire;
case "witch":
2021-12-15 22:29:27 +00:00
return AppLocalizations.of(context)!.themeNameWitch;
case "juniper":
return "Juniper"; // Juniper is a noun, and doesn't get subject to translation...
2021-12-15 20:17:13 +00:00
}
return theme;
}
2021-06-24 23:10:45 +00:00
/// Send an UpdateGlobalSettings to the Event Bus
saveSettings(context) {
var settings = Provider.of<Settings>(context, listen: false);
2024-01-04 09:53:10 +00:00
Provider.of<FlwtchState>(context, listen: false)
.cwtch
.UpdateSettings(jsonEncode(settings.asJson()));
2021-06-24 23:10:45 +00:00
}