Formatting + Initial Integration of Enhanced Permissions

This commit is contained in:
Sarah Jamie Lewis 2024-01-15 12:27:30 -08:00
parent 111bceab5d
commit 7397ad0ee2
12 changed files with 560 additions and 866 deletions

View File

@ -2,6 +2,8 @@
// Details: https://docs.openprivacy.ca/cwtch-security-handbook/profile_encryption_and_storage.html // Details: https://docs.openprivacy.ca/cwtch-security-handbook/profile_encryption_and_storage.html
import 'dart:collection'; import 'dart:collection';
import '../models/acl.dart';
const DefaultPassword = "be gay do crime"; const DefaultPassword = "be gay do crime";
const LastMessageSeenTimeKey = "profile.lastMessageSeenTime"; const LastMessageSeenTimeKey = "profile.lastMessageSeenTime";
@ -159,5 +161,7 @@ abstract class Cwtch {
void PublishServerUpdate(String onion); void PublishServerUpdate(String onion);
Future<void> ConfigureConnections(String onion, bool listen, bool peers, bool servers); Future<void> ConfigureConnections(String onion, bool listen, bool peers, bool servers);
Future<AccessControlList> GetConversationAccessControlList(String profile, int conversation);
bool IsLoaded(); bool IsLoaded();
} }

View File

@ -5,6 +5,7 @@ import 'dart:io';
import 'dart:isolate'; import 'dart:isolate';
import 'dart:io' show Platform; import 'dart:io' show Platform;
import 'package:cwtch/cwtch/cwtchNotifier.dart'; import 'package:cwtch/cwtch/cwtchNotifier.dart';
import 'package:cwtch/models/acl.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:ffi/ffi.dart'; import 'package:ffi/ffi.dart';
@ -1141,4 +1142,17 @@ class CwtchFfi implements Cwtch {
EnvironmentConfig.debugLog("Checking that the FFI Interface is Correctly Loaded... $check"); EnvironmentConfig.debugLog("Checking that the FFI Interface is Correctly Loaded... $check");
return check; return check;
} }
@override
Future<AccessControlList> GetConversationAccessControlList(String profile, int conversation) {
var getConversationACLC = library.lookup<NativeFunction<get_json_blob_from_str_int_function>>("c_GetConversationAccessControlList");
// ignore: non_constant_identifier_names
final GetConversationACL = getConversationACLC.asFunction<GetJsonBlobFromStrIntFn>();
final utf8profile = profile.toNativeUtf8();
Pointer<Utf8> aclRaw = GetConversationACL(utf8profile, utf8profile.length, conversation);
AccessControlList acl = AccessControl.FromJson(aclRaw.toDartString());
_UnsafeFreePointerAnyUseOfThisFunctionMustBeDoubleApproved(aclRaw);
malloc.free(utf8profile);
return Future.value(acl);
}
} }

View File

@ -2,6 +2,7 @@ import 'dart:collection';
import 'dart:convert'; import 'dart:convert';
import 'package:cwtch/config.dart'; import 'package:cwtch/config.dart';
import 'package:cwtch/models/acl.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'dart:async'; import 'dart:async';
@ -479,4 +480,12 @@ class CwtchGomobile implements Cwtch {
bool IsLoaded() { bool IsLoaded() {
return true; return true;
} }
@override
Future<AccessControlList> GetConversationAccessControlList(String profile, int conversation) async {
return await cwtchPlatform.invokeMethod("GetConversationAttribute", {"ProfileOnion": profile, "conversation": conversation}).then((dynamic json) {
AccessControlList acl = AccessControl.FromJson(json);
return acl;
});
}
} }

24
lib/models/acl.dart Normal file
View File

@ -0,0 +1,24 @@
import 'dart:convert';
typedef AccessControlList = Map<String, AccessControl>;
class AccessControl {
bool Blocked = false;
bool AutoConnect = false;
bool ExchangeAttributes = false;
bool ShareFiles = false;
bool RenderImages = false;
AccessControl({this.Blocked = false, this.AutoConnect = false, this.ExchangeAttributes = false, this.ShareFiles = false, this.RenderImages = false});
static AccessControlList FromJson(String json) {
Map<String, dynamic> accessControlList = jsonDecode(json);
return accessControlList.map((key, value) => MapEntry(
key,
AccessControl(
Blocked: value["Blocked"], ExchangeAttributes: value["ExchangeAttributes"], AutoConnect: value["AutoConnect"], RenderImages: value["RenderImages"], ShareFiles: value["ShareFiles"])));
}
Map<String, dynamic> toJson() {
return {'Blocked': Blocked, 'AutoConnect': AutoConnect, 'ExchangeAttributes': ExchangeAttributes, 'ShareFiles': ShareFiles, 'RenderImages': RenderImages};
}
}

View File

@ -123,7 +123,9 @@ abstract class OpaqueThemeType {
get chatImage => null; get chatImage => null;
ImageProvider loadImage(String key, {BuildContext? context}) { return AssetImage(""); } ImageProvider loadImage(String key, {BuildContext? context}) {
return AssetImage("");
}
// Sizes // Sizes
double contactOnionTextSize() { double contactOnionTextSize() {

View File

@ -149,10 +149,7 @@ class YmlTheme extends OpaqueThemeType {
} }
if (context != null) { if (context != null) {
File af = File(path.join(Provider File af = File(path.join(Provider.of<FlwtchState>(context, listen: false).cwtch.getAssetsDir(), key));
.of<FlwtchState>(context, listen: false)
.cwtch
.getAssetsDir(), key));
if (af.existsSync()) { if (af.existsSync()) {
return FileImage(af); return FileImage(af);
} }

View File

@ -19,154 +19,104 @@ class GlobalSettingsAboutView extends StatefulWidget {
} }
class _GlobalSettingsAboutViewState extends State<GlobalSettingsAboutView> { class _GlobalSettingsAboutViewState extends State<GlobalSettingsAboutView> {
ScrollController settingsListScrollController = ScrollController(); ScrollController settingsListScrollController = ScrollController();
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Consumer<Settings>(builder: (ccontext, settings, child) { return Consumer<Settings>(builder: (ccontext, settings, child) {
return LayoutBuilder( return LayoutBuilder(builder: (BuildContext context, BoxConstraints viewportConstraints) {
builder: (BuildContext context, BoxConstraints viewportConstraints) { var appIcon = Icon(Icons.info, color: settings.current().mainTextColor);
var appIcon = Icon(Icons.info, color: settings return Scrollbar(
.current() key: Key("AboutSettingsView"),
.mainTextColor); trackVisibility: true,
return Scrollbar( controller: settingsListScrollController,
key: Key("AboutSettingsView"), child: SingleChildScrollView(
trackVisibility: true, clipBehavior: Clip.antiAlias,
controller: settingsListScrollController, controller: settingsListScrollController,
child: SingleChildScrollView( padding: EdgeInsets.symmetric(vertical: 0, horizontal: 20),
clipBehavior: Clip.antiAlias, child: ConstrainedBox(
controller: settingsListScrollController, constraints: BoxConstraints(
padding: EdgeInsets.symmetric(vertical: 0, horizontal: 20), minHeight: viewportConstraints.maxHeight,
child: ConstrainedBox( ),
constraints: BoxConstraints( child: Column(children: [
minHeight: viewportConstraints.maxHeight, AboutListTile(
), icon: appIcon,
child: Column(children: [ applicationIcon: Padding(padding: EdgeInsets.all(5), child: Icon(CwtchIcons.cwtch_knott)),
AboutListTile( applicationName: "Cwtch UI",
icon: appIcon, applicationLegalese: '\u{a9} 2021-2023 Open Privacy Research Society',
applicationIcon: Padding( aboutBoxChildren: <Widget>[
padding: EdgeInsets.all(5), Padding(
child: Icon(CwtchIcons.cwtch_knott)), padding: EdgeInsets.fromLTRB(24.0 + 10.0 + (appIcon.size ?? 24.0), 16.0, 0.0, 0.0),
applicationName: "Cwtch UI", // About has 24 padding (ln 389) and there appears to be another 10 of padding in the widget
applicationLegalese: child: SelectableText(AppLocalizations.of(context)!.versionBuilddate.replaceAll("%1", EnvironmentConfig.BUILD_VER).replaceAll("%2", EnvironmentConfig.BUILD_DATE)),
'\u{a9} 2021-2023 Open Privacy Research Society', )
aboutBoxChildren: <Widget>[ ]),
Padding( SwitchListTile(
padding: EdgeInsets.fromLTRB( // TODO: Translate, Remove, OR Hide Prior to Release
24.0 + 10.0 + (appIcon.size ?? 24.0), title: Text("Show Performance Overlay"),
16.0, subtitle: Text("Display an overlay graph of render time."),
0.0, value: settings.profileMode,
0.0), onChanged: (bool value) {
// About has 24 padding (ln 389) and there appears to be another 10 of padding in the widget setState(() {
child: SelectableText( if (value) {
AppLocalizations.of(context)! settings.profileMode = value;
.versionBuilddate } else {
.replaceAll( settings.profileMode = value;
"%1", EnvironmentConfig.BUILD_VER) }
.replaceAll("%2", });
EnvironmentConfig.BUILD_DATE)), },
) activeTrackColor: settings.theme.defaultButtonActiveColor,
]), inactiveTrackColor: settings.theme.defaultButtonDisabledColor,
SwitchListTile( secondary: Icon(Icons.bar_chart, color: settings.current().mainTextColor),
// TODO: Translate, Remove, OR Hide Prior to Release ),
title: Text("Show Performance Overlay"), Visibility(
subtitle: visible: EnvironmentConfig.BUILD_VER == dev_version && !Platform.isAndroid,
Text("Display an overlay graph of render time."), child: SwitchListTile(
value: settings.profileMode, title: Text("Show Semantic Debugger"),
subtitle: Text("Show Accessibility Debugging View"),
value: settings.useSemanticDebugger,
onChanged: (bool value) { onChanged: (bool value) {
setState(() { if (value) {
if (value) { settings.useSemanticDebugger = value;
settings.profileMode = value; } else {
} else { settings.useSemanticDebugger = value;
settings.profileMode = value; }
} saveSettings(context);
});
}, },
activeTrackColor: activeTrackColor: settings.theme.defaultButtonActiveColor,
settings.theme.defaultButtonActiveColor, inactiveTrackColor: settings.theme.defaultButtonDisabledColor,
inactiveTrackColor: secondary: Icon(Icons.settings_accessibility, color: settings.current().mainTextColor),
settings.theme.defaultButtonDisabledColor, )),
secondary: Icon(Icons.bar_chart, Visibility(
color: settings visible: EnvironmentConfig.BUILD_VER == dev_version && !Platform.isAndroid,
.current() child: FutureBuilder(
.mainTextColor), future: EnvironmentConfig.BUILD_VER != dev_version || Platform.isAndroid ? null : Provider.of<FlwtchState>(context).cwtch.GetDebugInfo(),
), builder: (context, snapshot) {
Visibility( if (snapshot.hasData) {
visible: return Column(
EnvironmentConfig.BUILD_VER == dev_version && children: [
!Platform.isAndroid, Text("libCwtch Debug Info: " + snapshot.data.toString()),
child: SwitchListTile( Text("Message Cache Size (Mb): " + (Provider.of<FlwtchState>(context).profs.cacheMemUsage() / (1024 * 1024)).toString())
title: Text("Show Semantic Debugger"), ],
subtitle: );
Text("Show Accessibility Debugging View"), } else {
value: settings.useSemanticDebugger, return Container();
onChanged: (bool value) { }
if (value) { },
settings.useSemanticDebugger = value; ),
} else { ),
settings.useSemanticDebugger = value; Visibility(
} visible: EnvironmentConfig.BUILD_VER == dev_version,
saveSettings(context); child: FutureBuilder(
}, future: Provider.of<FlwtchState>(context).cwtch.PlatformChannelInfo(),
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) { builder: (context, snapshot) {
if (snapshot.hasData) { if (snapshot.hasData) {
return Column( HashMap<String, String> data = snapshot.data as HashMap<String, String>;
children: [ return getPlatformInfo(settings, data);
Text("libCwtch Debug Info: " +
snapshot.data.toString()),
Text("Message Cache Size (Mb): " +
(Provider
.of<FlwtchState>(context)
.profs
.cacheMemUsage() /
(1024 * 1024))
.toString())
],
);
} else {
return Container();
} }
}, 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();
}))
]))));
});
}); });
} }
@ -194,4 +144,4 @@ class _GlobalSettingsAboutViewState extends State<GlobalSettingsAboutView> {
} }
return pinfo.version + "." + pinfo.buildNumber; return pinfo.version + "." + pinfo.buildNumber;
} }
} }

View File

@ -15,301 +15,186 @@ class GlobalSettingsAppearanceView extends StatefulWidget {
} }
class _GlobalSettingsAppearanceViewState extends State<GlobalSettingsAppearanceView> { class _GlobalSettingsAppearanceViewState extends State<GlobalSettingsAppearanceView> {
ScrollController settingsListScrollController = ScrollController(); ScrollController settingsListScrollController = ScrollController();
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Consumer<Settings>(builder: (ccontext, settings, child) { return Consumer<Settings>(builder: (ccontext, settings, child) {
return LayoutBuilder( return LayoutBuilder(builder: (BuildContext context, BoxConstraints viewportConstraints) {
builder: (BuildContext context, BoxConstraints viewportConstraints) { return Scrollbar(
return Scrollbar( key: Key("AppearanceSettingsView"),
key: Key("AppearanceSettingsView"), trackVisibility: true,
trackVisibility: true, controller: settingsListScrollController,
child: SingleChildScrollView(
clipBehavior: Clip.antiAlias,
controller: settingsListScrollController, controller: settingsListScrollController,
child: SingleChildScrollView( padding: EdgeInsets.symmetric(vertical: 0, horizontal: 20),
clipBehavior: Clip.antiAlias, child: ConstrainedBox(
controller: settingsListScrollController, constraints: BoxConstraints(
padding: EdgeInsets.symmetric(vertical: 0, horizontal: 20), minHeight: viewportConstraints.maxHeight,
child: ConstrainedBox( ),
constraints: BoxConstraints( child: Column(children: [
minHeight: viewportConstraints.maxHeight, ListTile(
), title: Text(AppLocalizations.of(context)!.settingLanguage),
child: Column(children: [ leading: Icon(CwtchIcons.change_language, color: settings.current().mainTextColor),
ListTile( trailing: Container(
title: Text( width: MediaQuery.of(context).size.width / 4,
AppLocalizations.of(context)!.settingLanguage), child: DropdownButton(
leading: Icon(CwtchIcons.change_language, key: Key("languagelist"),
color: settings isExpanded: true,
.current() value: Provider.of<Settings>(context).locale.toString(),
.mainTextColor), onChanged: (String? newValue) {
trailing: Container( setState(() {
width: MediaQuery EnvironmentConfig.debugLog("setting language: $newValue");
.of(context) settings.switchLocaleByCode(newValue!);
.size saveSettings(context);
.width / 4, });
child: DropdownButton( },
key: Key("languagelist"), items: AppLocalizations.supportedLocales.map<DropdownMenuItem<String>>((Locale value) {
isExpanded: true, return DropdownMenuItem<String>(
value: Provider value: value.toString(),
.of<Settings>(context) child: Text(
.locale key: Key("dropdownLanguage" + value.languageCode),
.toString(), getLanguageFull(context, value.languageCode, value.countryCode),
onChanged: (String? newValue) { style: settings.scaleFonts(defaultDropDownMenuItemTextStyle),
setState(() { overflow: TextOverflow.ellipsis,
EnvironmentConfig.debugLog( ),
"setting language: $newValue"); );
settings.switchLocaleByCode(newValue!); }).toList()))),
saveSettings(context); SwitchListTile(
}); title: Text(AppLocalizations.of(context)!.settingTheme),
}, value: settings.current().mode == mode_light,
items: AppLocalizations.supportedLocales onChanged: (bool value) {
.map<DropdownMenuItem<String>>( if (value) {
(Locale value) { settings.setTheme(settings.theme.theme, mode_light);
return DropdownMenuItem<String>( } else {
value: value.toString(), settings.setTheme(settings.theme.theme, mode_dark);
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... // Save Settings...
saveSettings(context); saveSettings(context);
}, },
activeTrackColor: settings.theme.defaultButtonColor, activeTrackColor: settings.theme.defaultButtonColor,
inactiveTrackColor: inactiveTrackColor: settings.theme.defaultButtonDisabledColor,
settings.theme.defaultButtonDisabledColor, secondary: Icon(CwtchIcons.change_theme, color: settings.current().mainTextColor),
secondary: Icon(CwtchIcons.change_theme, ),
color: settings ListTile(
.current() title: Text(AppLocalizations.of(context)!.themeColorLabel),
.mainTextColor), 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,
), ),
ListTile( leading: Icon(Icons.stay_primary_landscape, color: settings.current().mainTextColor),
title: Text( trailing: Container(
AppLocalizations.of(context)!.themeColorLabel), width: MediaQuery.of(context).size.width / 4,
trailing: Container( child: Container(
width: MediaQuery width: MediaQuery.of(context).size.width / 4,
.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( child: DropdownButton(
isExpanded: true, isExpanded: true,
value: settings.uiColumnModePortrait value: settings.uiColumnModeLandscape.toString(),
.toString(),
onChanged: (String? newValue) { onChanged: (String? newValue) {
settings.uiColumnModePortrait = settings.uiColumnModeLandscape = Settings.uiColumnModeFromString(newValue!);
Settings.uiColumnModeFromString(
newValue!);
saveSettings(context); saveSettings(context);
}, },
items: Settings.uiColumnModeOptions(false) items: Settings.uiColumnModeOptions(true).map<DropdownMenuItem<String>>((DualpaneMode value) {
.map<DropdownMenuItem<String>>( return DropdownMenuItem<String>(
(DualpaneMode value) { value: value.toString(),
return DropdownMenuItem<String>( child: Text(Settings.uiColumnModeToString(value, context), overflow: TextOverflow.ellipsis, style: settings.scaleFonts(defaultDropDownMenuItemTextStyle)),
value: value.toString(), );
child: Text( }).toList())))),
Settings.uiColumnModeToString( ListTile(
value, context), title: Text(AppLocalizations.of(context)!.defaultScalingText),
style: settings.scaleFonts( subtitle: Text(AppLocalizations.of(context)!.fontScalingDescription),
defaultDropDownMenuItemTextStyle)), trailing: Container(
); width: MediaQuery.of(context).size.width / 4,
}).toList()))), child: Slider(
ListTile( onChanged: (double value) {
title: Text( settings.fontScaling = value;
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... // Save Settings...
saveSettings(context); saveSettings(context);
EnvironmentConfig.debugLog( EnvironmentConfig.debugLog("Font Scaling: $value");
"Font Scaling: $value"); },
}, min: 0.5,
min: 0.5, divisions: 12,
divisions: 12, max: 2.0,
max: 2.0, label: '${settings.fontScaling * 100}%',
label: '${settings.fontScaling * 100}%', activeColor: settings.current().defaultButtonColor,
activeColor: thumbColor: settings.current().mainTextColor,
settings overlayColor: MaterialStateProperty.all(settings.current().mainTextColor),
.current() inactiveColor: settings.theme.defaultButtonDisabledColor,
.defaultButtonColor, value: settings.fontScaling)),
thumbColor: settings leading: Icon(Icons.format_size, color: settings.current().mainTextColor),
.current() ),
.mainTextColor, SwitchListTile(
overlayColor: MaterialStateProperty.all( title: Text(AppLocalizations.of(context)!.streamerModeLabel),
settings subtitle: Text(AppLocalizations.of(context)!.descriptionStreamerMode),
.current() value: settings.streamerMode,
.mainTextColor), onChanged: (bool value) {
inactiveColor: settings.setStreamerMode(value);
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... // Save Settings...
saveSettings(context); saveSettings(context);
}, },
activeTrackColor: settings.theme.defaultButtonColor, activeTrackColor: settings.theme.defaultButtonColor,
inactiveTrackColor: inactiveTrackColor: settings.theme.defaultButtonDisabledColor,
settings.theme.defaultButtonDisabledColor, secondary: Icon(CwtchIcons.streamer_bunnymask, color: settings.current().mainTextColor),
secondary: Icon(CwtchIcons.streamer_bunnymask, ),
color: settings SwitchListTile(
.current() title: Text(AppLocalizations.of(context)!.formattingExperiment),
.mainTextColor), subtitle: Text(AppLocalizations.of(context)!.messageFormattingDescription),
), value: settings.isExperimentEnabled(FormattingExperiment),
SwitchListTile( onChanged: (bool value) {
title: Text(AppLocalizations.of(context)! if (value) {
.formattingExperiment), settings.enableExperiment(FormattingExperiment);
subtitle: Text(AppLocalizations.of(context)! } else {
.messageFormattingDescription), settings.disableExperiment(FormattingExperiment);
value: settings }
.isExperimentEnabled(FormattingExperiment), saveSettings(context);
onChanged: (bool value) { },
if (value) { activeTrackColor: settings.theme.defaultButtonActiveColor,
settings.enableExperiment(FormattingExperiment); inactiveTrackColor: settings.theme.defaultButtonDisabledColor,
} else { secondary: Icon(Icons.text_fields, color: settings.current().mainTextColor),
settings.disableExperiment(FormattingExperiment); ),
} ]))));
saveSettings(context); });
},
activeTrackColor:
settings.theme.defaultButtonActiveColor,
inactiveTrackColor:
settings.theme.defaultButtonDisabledColor,
secondary: Icon(Icons.text_fields,
color: settings
.current()
.mainTextColor),
),
]))));
});
}); });
} }

View File

@ -20,7 +20,6 @@ class _GlobalSettingsBehaviourViewState extends State<GlobalSettingsBehaviourVie
static const androidSettingsChannel = const MethodChannel('androidSettings'); static const androidSettingsChannel = const MethodChannel('androidSettings');
static const androidSettingsChangeChannel = const MethodChannel('androidSettingsChanged'); static const androidSettingsChangeChannel = const MethodChannel('androidSettingsChanged');
ScrollController settingsListScrollController = ScrollController(); ScrollController settingsListScrollController = ScrollController();
bool powerExempt = false; bool powerExempt = false;
@ -31,8 +30,8 @@ class _GlobalSettingsBehaviourViewState extends State<GlobalSettingsBehaviourVie
if (Platform.isAndroid) { if (Platform.isAndroid) {
isBatteryExempt().then((value) => setState(() { isBatteryExempt().then((value) => setState(() {
powerExempt = value; powerExempt = value;
})); }));
} else { } else {
powerExempt = false; powerExempt = false;
} }
@ -51,8 +50,7 @@ class _GlobalSettingsBehaviourViewState extends State<GlobalSettingsBehaviourVie
//* Android Only Requests //* Android Only Requests
Future<bool> isBatteryExempt() async { Future<bool> isBatteryExempt() async {
return await androidSettingsChannel.invokeMethod('isBatteryExempt', {}) ?? return await androidSettingsChannel.invokeMethod('isBatteryExempt', {}) ?? false;
false;
} }
Future<void> requestBatteryExemption() async { Future<void> requestBatteryExemption() async {
@ -62,11 +60,9 @@ class _GlobalSettingsBehaviourViewState extends State<GlobalSettingsBehaviourVie
//* End Android Only Requests //* End Android Only Requests
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Consumer<Settings>(builder: (ccontext, settings, child) { return Consumer<Settings>(builder: (ccontext, settings, child) {
return LayoutBuilder( return LayoutBuilder(builder: (BuildContext context, BoxConstraints viewportConstraints) {
builder: (BuildContext context, BoxConstraints viewportConstraints) {
return Scrollbar( return Scrollbar(
key: Key("BehaviourSettingsView"), key: Key("BehaviourSettingsView"),
trackVisibility: true, trackVisibility: true,
@ -83,10 +79,8 @@ class _GlobalSettingsBehaviourViewState extends State<GlobalSettingsBehaviourVie
Visibility( Visibility(
visible: Platform.isAndroid, visible: Platform.isAndroid,
child: SwitchListTile( child: SwitchListTile(
title: Text(AppLocalizations.of(context)! title: Text(AppLocalizations.of(context)!.settingAndroidPowerExemption),
.settingAndroidPowerExemption), subtitle: Text(AppLocalizations.of(context)!.settingAndroidPowerExemptionDescription),
subtitle: Text(AppLocalizations.of(context)!
.settingAndroidPowerExemptionDescription),
value: powerExempt, value: powerExempt,
onChanged: (bool value) { onChanged: (bool value) {
if (value) { if (value) {
@ -97,17 +91,13 @@ class _GlobalSettingsBehaviourViewState extends State<GlobalSettingsBehaviourVie
} }
}, },
activeTrackColor: settings.theme.defaultButtonColor, activeTrackColor: settings.theme.defaultButtonColor,
inactiveTrackColor: inactiveTrackColor: settings.theme.defaultButtonDisabledColor,
settings.theme.defaultButtonDisabledColor, secondary: Icon(Icons.power, color: settings.current().mainTextColor),
secondary: Icon(Icons.power,
color: settings.current().mainTextColor),
), ),
), ),
ListTile( ListTile(
title: Text(AppLocalizations.of(context)! title: Text(AppLocalizations.of(context)!.notificationPolicySettingLabel),
.notificationPolicySettingLabel), subtitle: Text(AppLocalizations.of(context)!.notificationPolicySettingDescription),
subtitle: Text(AppLocalizations.of(context)!
.notificationPolicySettingDescription),
trailing: Container( trailing: Container(
width: MediaQuery.of(context).size.width / 4, width: MediaQuery.of(context).size.width / 4,
child: DropdownButton( child: DropdownButton(
@ -117,27 +107,17 @@ class _GlobalSettingsBehaviourViewState extends State<GlobalSettingsBehaviourVie
settings.notificationPolicy = newValue!; settings.notificationPolicy = newValue!;
saveSettings(context); saveSettings(context);
}, },
items: NotificationPolicy.values.map< items: NotificationPolicy.values.map<DropdownMenuItem<NotificationPolicy>>((NotificationPolicy value) {
DropdownMenuItem<NotificationPolicy>>( return DropdownMenuItem<NotificationPolicy>(
(NotificationPolicy value) { value: value,
return DropdownMenuItem<NotificationPolicy>( child: Text(Settings.notificationPolicyToString(value, context), overflow: TextOverflow.ellipsis, style: settings.scaleFonts(defaultDropDownMenuItemTextStyle)),
value: value, );
child: Text( }).toList())),
Settings.notificationPolicyToString( leading: Icon(CwtchIcons.chat_bubble_empty_24px, color: settings.current().mainTextColor),
value, context),
overflow: TextOverflow.ellipsis,
style: settings.scaleFonts(
defaultDropDownMenuItemTextStyle)),
);
}).toList())),
leading: Icon(CwtchIcons.chat_bubble_empty_24px,
color: settings.current().mainTextColor),
), ),
ListTile( ListTile(
title: Text(AppLocalizations.of(context)! title: Text(AppLocalizations.of(context)!.notificationContentSettingLabel),
.notificationContentSettingLabel), subtitle: Text(AppLocalizations.of(context)!.notificationContentSettingDescription),
subtitle: Text(AppLocalizations.of(context)!
.notificationContentSettingDescription),
trailing: Container( trailing: Container(
width: MediaQuery.of(context).size.width / 4, width: MediaQuery.of(context).size.width / 4,
child: DropdownButton( child: DropdownButton(
@ -147,29 +127,17 @@ class _GlobalSettingsBehaviourViewState extends State<GlobalSettingsBehaviourVie
settings.notificationContent = newValue!; settings.notificationContent = newValue!;
saveSettings(context); saveSettings(context);
}, },
items: NotificationContent.values.map< items: NotificationContent.values.map<DropdownMenuItem<NotificationContent>>((NotificationContent value) {
DropdownMenuItem< return DropdownMenuItem<NotificationContent>(
NotificationContent>>( value: value,
(NotificationContent value) { child: Text(Settings.notificationContentToString(value, context), overflow: TextOverflow.ellipsis, style: settings.scaleFonts(defaultDropDownMenuItemTextStyle)),
return DropdownMenuItem< );
NotificationContent>( }).toList())),
value: value, leading: Icon(CwtchIcons.chat_bubble_empty_24px, color: settings.current().mainTextColor),
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( SwitchListTile(
title: Text( title: Text(AppLocalizations.of(context)!.blockUnknownLabel),
AppLocalizations.of(context)!.blockUnknownLabel), subtitle: Text(AppLocalizations.of(context)!.descriptionBlockUnknownConnections),
subtitle: Text(AppLocalizations.of(context)!
.descriptionBlockUnknownConnections),
value: settings.blockUnknownConnections, value: settings.blockUnknownConnections,
onChanged: (bool value) { onChanged: (bool value) {
if (value) { if (value) {
@ -182,16 +150,12 @@ class _GlobalSettingsBehaviourViewState extends State<GlobalSettingsBehaviourVie
saveSettings(context); saveSettings(context);
}, },
activeTrackColor: settings.theme.defaultButtonColor, activeTrackColor: settings.theme.defaultButtonColor,
inactiveTrackColor: inactiveTrackColor: settings.theme.defaultButtonDisabledColor,
settings.theme.defaultButtonDisabledColor, secondary: Icon(CwtchIcons.block_unknown, color: settings.current().mainTextColor),
secondary: Icon(CwtchIcons.block_unknown,
color: settings.current().mainTextColor),
), ),
SwitchListTile( SwitchListTile(
title: Text(AppLocalizations.of(context)! title: Text(AppLocalizations.of(context)!.defaultPreserveHistorySetting),
.defaultPreserveHistorySetting), subtitle: Text(AppLocalizations.of(context)!.preserveHistorySettingDescription),
subtitle: Text(AppLocalizations.of(context)!
.preserveHistorySettingDescription),
value: settings.preserveHistoryByDefault, value: settings.preserveHistoryByDefault,
onChanged: (bool value) { onChanged: (bool value) {
if (value) { if (value) {
@ -204,13 +168,11 @@ class _GlobalSettingsBehaviourViewState extends State<GlobalSettingsBehaviourVie
saveSettings(context); saveSettings(context);
}, },
activeTrackColor: settings.theme.defaultButtonColor, activeTrackColor: settings.theme.defaultButtonColor,
inactiveTrackColor: inactiveTrackColor: settings.theme.defaultButtonDisabledColor,
settings.theme.defaultButtonDisabledColor, secondary: Icon(CwtchIcons.peer_history, color: settings.current().mainTextColor),
secondary: Icon(CwtchIcons.peer_history,
color: settings.current().mainTextColor),
), ),
])))); ]))));
}); });
}); });
} }
@ -224,8 +186,7 @@ class _GlobalSettingsBehaviourViewState extends State<GlobalSettingsBehaviourVie
// set up the AlertDialog // set up the AlertDialog
AlertDialog alert = AlertDialog( AlertDialog alert = AlertDialog(
title: title: Text(AppLocalizations.of(context)!.settingsAndroidPowerReenablePopup),
Text(AppLocalizations.of(context)!.settingsAndroidPowerReenablePopup),
actions: [ actions: [
okButton, okButton,
], ],
@ -239,4 +200,4 @@ class _GlobalSettingsBehaviourViewState extends State<GlobalSettingsBehaviourVie
}, },
); );
} }
} }

View File

@ -19,358 +19,224 @@ class GlobalSettingsExperimentsView extends StatefulWidget {
} }
class _GlobalSettingsExperimentsViewState extends State<GlobalSettingsExperimentsView> { class _GlobalSettingsExperimentsViewState extends State<GlobalSettingsExperimentsView> {
ScrollController settingsListScrollController = ScrollController(); ScrollController settingsListScrollController = ScrollController();
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Consumer<Settings>(builder: (ccontext, settings, child) { return Consumer<Settings>(builder: (ccontext, settings, child) {
return LayoutBuilder( return LayoutBuilder(builder: (BuildContext context, BoxConstraints viewportConstraints) {
builder: (BuildContext context, BoxConstraints viewportConstraints) { return Scrollbar(
return Scrollbar( key: Key("ExperimentsSettingsView"),
key: Key("ExperimentsSettingsView"), trackVisibility: true,
trackVisibility: true, controller: settingsListScrollController,
child: SingleChildScrollView(
clipBehavior: Clip.antiAlias,
controller: settingsListScrollController, controller: settingsListScrollController,
child: SingleChildScrollView( padding: EdgeInsets.symmetric(vertical: 0, horizontal: 20),
clipBehavior: Clip.antiAlias, child: ConstrainedBox(
controller: settingsListScrollController, constraints: BoxConstraints(
padding: EdgeInsets.symmetric(vertical: 0, horizontal: 20), minHeight: viewportConstraints.maxHeight,
child: ConstrainedBox( ),
constraints: BoxConstraints( child: Column(children: [
minHeight: viewportConstraints.maxHeight, SwitchListTile(
), title: Text(AppLocalizations.of(context)!.experimentsEnabled),
child: Column(children: [ subtitle: Text(AppLocalizations.of(context)!.descriptionExperiments),
SwitchListTile( value: settings.experimentsEnabled,
title: Text( onChanged: (bool value) {
AppLocalizations.of(context)!.experimentsEnabled), if (value) {
subtitle: Text(AppLocalizations.of(context)! settings.enableExperiments();
.descriptionExperiments), } else {
value: settings.experimentsEnabled, settings.disableExperiments();
onChanged: (bool value) { }
if (value) { // Save Settings...
settings.enableExperiments(); saveSettings(context);
} else { },
settings.disableExperiments(); activeTrackColor: settings.theme.defaultButtonColor,
} inactiveTrackColor: settings.theme.defaultButtonDisabledColor,
// Save Settings... secondary: Icon(CwtchIcons.enable_experiments, color: settings.current().mainTextColor),
saveSettings(context); ),
}, Visibility(
activeTrackColor: settings.theme.defaultButtonColor, visible: settings.experimentsEnabled,
inactiveTrackColor: child: Column(
settings.theme.defaultButtonDisabledColor, children: [
secondary: Icon(CwtchIcons.enable_experiments, SwitchListTile(
color: settings title: Text(AppLocalizations.of(context)!.enableGroups),
.current() subtitle: Text(AppLocalizations.of(context)!.descriptionExperimentsGroups),
.mainTextColor), value: settings.isExperimentEnabled(TapirGroupsExperiment),
), onChanged: (bool value) {
Visibility( if (value) {
visible: settings.experimentsEnabled, settings.enableExperiment(TapirGroupsExperiment);
child: Column( } else {
children: [ settings.disableExperiment(TapirGroupsExperiment);
SwitchListTile( }
title: Text(AppLocalizations.of(context)! // Save Settings...
.enableGroups), saveSettings(context);
subtitle: Text(AppLocalizations.of(context)! },
.descriptionExperimentsGroups), activeTrackColor: settings.theme.defaultButtonColor,
value: settings.isExperimentEnabled( inactiveTrackColor: settings.theme.defaultButtonDisabledColor,
TapirGroupsExperiment), secondary: Icon(CwtchIcons.enable_groups, color: settings.current().mainTextColor),
onChanged: (bool value) { ),
if (value) { Visibility(
settings.enableExperiment( visible: !Platform.isAndroid && !Platform.isIOS,
TapirGroupsExperiment); child: SwitchListTile(
} else { title: Text(AppLocalizations.of(context)!.settingServers),
settings.disableExperiment( subtitle: Provider.of<FlwtchState>(context, listen: false).cwtch.IsServersCompiled()
TapirGroupsExperiment); ? Text(AppLocalizations.of(context)!.settingServersDescription)
} : Text("This version of Cwtch has been compiled without support for the server hosting experiment."),
// Save Settings... value: Provider.of<FlwtchState>(context, listen: false).cwtch.IsServersCompiled() && settings.isExperimentEnabled(ServerManagementExperiment),
saveSettings(context); onChanged: Provider.of<FlwtchState>(context, listen: false).cwtch.IsServersCompiled()
},
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) { ? (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 (value) {
settings.enableExperiment( if (checkDownloadDirectory(context, settings)) {
BlodeuweddExperiment); settings.enableExperiment(ImagePreviewsExperiment);
} else {
settings.disableExperiment(ImagePreviewsExperiment);
}
} else { } else {
settings.disableExperiment( settings.disableExperiment(ImagePreviewsExperiment);
BlodeuweddExperiment);
} }
saveSettings(context); saveSettings(context);
} },
: null, activeTrackColor: settings.theme.defaultButtonActiveColor,
activeTrackColor: inactiveTrackColor: settings.theme.defaultButtonDisabledColor,
settings.theme.defaultButtonColor, secondary: Icon(Icons.photo, color: settings.current().mainTextColor),
inactiveTrackColor:
settings.theme.defaultButtonDisabledColor,
inactiveThumbColor:
settings.theme.defaultButtonDisabledColor,
secondary: Icon(Icons.assistant,
color: settings
.current()
.mainTextColor),
), ),
Visibility( Visibility(
visible: Provider visible: settings.isExperimentEnabled(ImagePreviewsExperiment) && !Platform.isAndroid,
.of<FlwtchState>(context,
listen: false)
.cwtch
.IsBlodeuweddSupported() &&
settings.isExperimentEnabled(
BlodeuweddExperiment),
child: CwtchFolderPicker( child: CwtchFolderPicker(
testKey: Key("DownloadFolderPicker"), testKey: Key("DownloadFolderPicker"),
label: AppLocalizations.of(context)! label: AppLocalizations.of(context)!.settingDownloadFolder,
.settingDownloadFolder, initialValue: settings.downloadPath,
initialValue: settings.blodeuweddPath, textStyle: settings.scaleFonts(defaultDropDownMenuItemTextStyle),
description: AppLocalizations.of(context)! description: AppLocalizations.of(context)!.fileSharingSettingsDownloadFolderDescription,
.blodeuweddPath, tooltip: AppLocalizations.of(context)!.fileSharingSettingsDownloadFolderTooltip,
tooltip: AppLocalizations.of(context)!
.blodeuweddPath,
onSave: (newVal) { onSave: (newVal) {
settings.blodeuweddPath = newVal; settings.downloadPath = newVal;
saveSettings(context); saveSettings(context);
}, },
), ),
), ),
], ]),
)), ),
Visibility( SwitchListTile(
visible: settings.experimentsEnabled, title: Text(AppLocalizations.of(context)!.blodeuweddExperimentEnable),
child: SwitchListTile( subtitle: Provider.of<FlwtchState>(context, listen: false).cwtch.IsBlodeuweddSupported()
title: Text(AppLocalizations.of(context)! ? Text(AppLocalizations.of(context)!.blodeuweddDescription)
.enableExperimentClickableLinks), : Text(AppLocalizations.of(context)!.blodeuweddNotSupported),
subtitle: Text(AppLocalizations.of(context)! value: Provider.of<FlwtchState>(context, listen: false).cwtch.IsBlodeuweddSupported() && settings.isExperimentEnabled(BlodeuweddExperiment),
.experimentClickableLinksDescription), onChanged: Provider.of<FlwtchState>(context, listen: false).cwtch.IsBlodeuweddSupported()
value: settings.isExperimentEnabled( ? (bool value) {
ClickableLinksExperiment), if (value) {
onChanged: (bool value) { settings.enableExperiment(BlodeuweddExperiment);
if (value) { } else {
settings.enableExperiment( settings.disableExperiment(BlodeuweddExperiment);
ClickableLinksExperiment); }
} else { saveSettings(context);
settings.disableExperiment( }
ClickableLinksExperiment); : null,
} activeTrackColor: settings.theme.defaultButtonColor,
saveSettings(context); inactiveTrackColor: settings.theme.defaultButtonDisabledColor,
}, inactiveThumbColor: settings.theme.defaultButtonDisabledColor,
activeTrackColor: secondary: Icon(Icons.assistant, color: settings.current().mainTextColor),
settings.theme.defaultButtonActiveColor, ),
inactiveTrackColor: Visibility(
settings.theme.defaultButtonDisabledColor, visible: Provider.of<FlwtchState>(context, listen: false).cwtch.IsBlodeuweddSupported() && settings.isExperimentEnabled(BlodeuweddExperiment),
secondary: Icon(Icons.link, child: CwtchFolderPicker(
color: settings testKey: Key("DownloadFolderPicker"),
.current() label: AppLocalizations.of(context)!.settingDownloadFolder,
.mainTextColor), initialValue: settings.blodeuweddPath,
)), description: AppLocalizations.of(context)!.blodeuweddPath,
Visibility( tooltip: AppLocalizations.of(context)!.blodeuweddPath,
visible: settings.experimentsEnabled, onSave: (newVal) {
child: SwitchListTile( settings.blodeuweddPath = newVal;
title: Text(AppLocalizations.of(context)! saveSettings(context);
.enableExperimentQRCode), },
subtitle: Text(AppLocalizations.of(context)! ),
.experimentQRCodeDescription), ),
value: settings ],
.isExperimentEnabled(QRCodeExperiment), )),
onChanged: (bool value) { Visibility(
if (value) { visible: settings.experimentsEnabled,
settings.enableExperiment(QRCodeExperiment); child: SwitchListTile(
} else { title: Text(AppLocalizations.of(context)!.enableExperimentClickableLinks),
settings.disableExperiment(QRCodeExperiment); subtitle: Text(AppLocalizations.of(context)!.experimentClickableLinksDescription),
} value: settings.isExperimentEnabled(ClickableLinksExperiment),
saveSettings(context); onChanged: (bool value) {
}, if (value) {
activeTrackColor: settings.enableExperiment(ClickableLinksExperiment);
settings.theme.defaultButtonActiveColor, } else {
inactiveTrackColor: settings.disableExperiment(ClickableLinksExperiment);
settings.theme.defaultButtonDisabledColor, }
secondary: Icon(Icons.qr_code, saveSettings(context);
color: settings },
.current() activeTrackColor: settings.theme.defaultButtonActiveColor,
.mainTextColor), 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),
)),
]))));
});
}); });
} }
@ -379,9 +245,7 @@ class _GlobalSettingsExperimentsViewState extends State<GlobalSettingsExperiment
if (settings.downloadPath != "") { if (settings.downloadPath != "") {
} else { } else {
// check if the default download path exists // check if the default download path exists
var path = Provider.of<FlwtchState>(context, listen: false) var path = Provider.of<FlwtchState>(context, listen: false).cwtch.defaultDownloadPath();
.cwtch
.defaultDownloadPath();
if (path != null) { if (path != null) {
settings.downloadPath = path; settings.downloadPath = path;
} else { } else {
@ -393,11 +257,10 @@ class _GlobalSettingsExperimentsViewState extends State<GlobalSettingsExperiment
return true; return true;
} else { } else {
final snackBar = SnackBar( final snackBar = SnackBar(
content: Text( content: Text(AppLocalizations.of(context)!.errorDownloadDirectoryDoesNotExist),
AppLocalizations.of(context)!.errorDownloadDirectoryDoesNotExist),
); );
ScaffoldMessenger.of(context).showSnackBar(snackBar); ScaffoldMessenger.of(context).showSnackBar(snackBar);
return false; return false;
} }
} }
} }

View File

@ -27,7 +27,6 @@ class GlobalSettingsView extends StatefulWidget {
} }
class _GlobalSettingsViewState extends State<GlobalSettingsView> { class _GlobalSettingsViewState extends State<GlobalSettingsView> {
ScrollController settingsListScrollController = ScrollController(); ScrollController settingsListScrollController = ScrollController();
@override @override
@ -35,7 +34,6 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
super.dispose(); super.dispose();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return DefaultTabController( return DefaultTabController(
@ -46,23 +44,10 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
bottom: TabBar( bottom: TabBar(
isScrollable: true, isScrollable: true,
tabs: [ tabs: [
Tab( Tab(key: Key("OpenSettingsAppearance"), icon: Icon(Icons.palette), text: AppLocalizations.of(context)!.settingsGroupAppearance),
key: Key("OpenSettingsAppearance"), Tab(key: Key("OpenSettingsBehaviour"), icon: Icon(Icons.settings), text: AppLocalizations.of(context)!.settingGroupBehaviour),
icon: Icon(Icons.palette), Tab(key: Key("OpenSettingsExperiments"), icon: Icon(CwtchIcons.enable_experiments), text: AppLocalizations.of(context)!.settingsGroupExperiments),
text: AppLocalizations.of(context)! Tab(icon: Icon(Icons.info), text: AppLocalizations.of(context)!.settingsGroupAbout),
.settingsGroupAppearance),
Tab(
key: Key("OpenSettingsBehaviour"),
icon: Icon(Icons.settings),
text:
AppLocalizations.of(context)!.settingGroupBehaviour),
Tab(
key: Key("OpenSettingsExperiments"),
icon: Icon(CwtchIcons.enable_experiments),
text: AppLocalizations.of(context)!
.settingsGroupExperiments),
Tab(icon: Icon(Icons.info), text: AppLocalizations.of(context)!
.settingsGroupAbout),
], ],
)), )),
body: _buildSettingsList(), body: _buildSettingsList(),
@ -71,15 +56,11 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
Widget _buildSettingsList() { Widget _buildSettingsList() {
return Consumer<Settings>(builder: (ccontext, settings, child) { return Consumer<Settings>(builder: (ccontext, settings, child) {
return LayoutBuilder( return LayoutBuilder(builder: (BuildContext context, BoxConstraints viewportConstraints) {
builder: (BuildContext context, BoxConstraints viewportConstraints) {
return TabBarView(children: [ return TabBarView(children: [
GlobalSettingsAppearanceView(), GlobalSettingsAppearanceView(),
GlobalSettingsBehaviourView(), GlobalSettingsBehaviourView(),
GlobalSettingsExperimentsView(), GlobalSettingsExperimentsView(),
GlobalSettingsAboutView(), GlobalSettingsAboutView(),
]); ]);
}); });
@ -90,7 +71,5 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
/// Send an UpdateGlobalSettings to the Event Bus /// Send an UpdateGlobalSettings to the Event Bus
saveSettings(context) { saveSettings(context) {
var settings = Provider.of<Settings>(context, listen: false); var settings = Provider.of<Settings>(context, listen: false);
Provider.of<FlwtchState>(context, listen: false) Provider.of<FlwtchState>(context, listen: false).cwtch.UpdateSettings(jsonEncode(settings.asJson()));
.cwtch
.UpdateSettings(jsonEncode(settings.asJson()));
} }

View File

@ -92,6 +92,12 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
); );
}).toList(); }).toList();
ProfileInfoState profileInfoState = Provider.of<ProfileInfoState>(context, listen: false);
ContactInfoState contact = Provider.of<ContactInfoState>(context, listen: false);
Provider.of<FlwtchState>(context, listen: false).cwtch.GetConversationAccessControlList(profileInfoState.onion, contact.identifier).then((value) {
EnvironmentConfig.debugLog("acl: ${jsonEncode(value)}");
});
return Scrollbar( return Scrollbar(
trackVisibility: true, trackVisibility: true,
controller: peerSettingsScrollController, controller: peerSettingsScrollController,