diff --git a/assets/cwtch.png b/assets/cwtch.png new file mode 100644 index 0000000..1c43cba Binary files /dev/null and b/assets/cwtch.png differ diff --git a/assets/knott.png b/assets/knott.png new file mode 100644 index 0000000..148b91a Binary files /dev/null and b/assets/knott.png differ diff --git a/lib/cwtch/ffi.dart b/lib/cwtch/ffi.dart index c110e7f..ddd07ec 100644 --- a/lib/cwtch/ffi.dart +++ b/lib/cwtch/ffi.dart @@ -75,7 +75,7 @@ class CwtchFfi implements Cwtch { var startCwtchC = library.lookup>("c_StartCwtch"); // ignore: non_constant_identifier_names final StartCwtch = startCwtchC.asFunction(); - StartCwtch(Utf8.toUtf8(cwtchDir), cwtchDir.length, Utf8.toUtf8(""), 0); + StartCwtch(cwtchDir.toNativeUtf8(), cwtchDir.length, "".toNativeUtf8(), 0); // Spawn an isolate to listen to events from libcwtch-go and then dispatch them when received on main thread to cwtchNotifier var _receivePort = ReceivePort(); @@ -110,7 +110,7 @@ class CwtchFfi implements Cwtch { while (true) { Pointer result = GetAppbusEvent(); - String event = Utf8.fromUtf8(result); + String event = result.toDartString(); yield event; } } @@ -121,7 +121,7 @@ class CwtchFfi implements Cwtch { // ignore: non_constant_identifier_names final SelectProfile = selectProfileC.asFunction(); - SelectProfile(Utf8.toUtf8(onion), onion.length); + SelectProfile(onion.toNativeUtf8(), onion.length); } // ignore: non_constant_identifier_names @@ -129,7 +129,7 @@ class CwtchFfi implements Cwtch { var createProfileC = library.lookup>("c_CreateProfile"); // ignore: non_constant_identifier_names final CreateProfile = createProfileC.asFunction(); - CreateProfile(Utf8.toUtf8(nick), nick.length, Utf8.toUtf8(pass), pass.length); + CreateProfile(nick.toNativeUtf8(), nick.length, pass.toNativeUtf8(), pass.length); } // ignore: non_constant_identifier_names @@ -137,7 +137,7 @@ class CwtchFfi implements Cwtch { var loadProfileC = library.lookup>("c_LoadProfiles"); // ignore: non_constant_identifier_names final LoadProfiles = loadProfileC.asFunction(); - LoadProfiles(Utf8.toUtf8(pass), pass.length); + LoadProfiles(pass.toNativeUtf8(), pass.length); } Future ACNEvents() async { @@ -147,7 +147,7 @@ class CwtchFfi implements Cwtch { final ACNEvents = acnEventsC.asFunction(); Pointer result = ACNEvents(); - String event = Utf8.fromUtf8(result); + String event = result.toDartString(); return event; } @@ -159,7 +159,7 @@ class CwtchFfi implements Cwtch { final ContactEvents = acnEventsC.asFunction(); Pointer result = ContactEvents(); - String event = Utf8.fromUtf8(result); + String event = result.toDartString(); return event; } @@ -169,7 +169,7 @@ class CwtchFfi implements Cwtch { final GetProfiles = getProfilesC.asFunction(); Pointer jsonProfilesBytes = GetProfiles(); - String jsonProfiles = Utf8.fromUtf8(jsonProfilesBytes); + String jsonProfiles = jsonProfilesBytes.toDartString(); return jsonProfiles; } @@ -177,8 +177,8 @@ class CwtchFfi implements Cwtch { var getContactsC = library.lookup>("c_GetContacts"); // ignore: non_constant_identifier_names final GetContacts = getContactsC.asFunction(); - Pointer jsonContactBytes = GetContacts(Utf8.toUtf8(onion), onion.length); - String jsonContacts = Utf8.fromUtf8(jsonContactBytes); + Pointer jsonContactBytes = GetContacts(onion.toNativeUtf8(), onion.length); + String jsonContacts = jsonContactBytes.toDartString(); return jsonContacts; } @@ -187,7 +187,7 @@ class CwtchFfi implements Cwtch { // ignore: non_constant_identifier_names final NumMessages = numMessagesC.asFunction(); - int num = NumMessages(Utf8.toUtf8(profile), profile.length, Utf8.toUtf8(handle), handle.length); + int num = NumMessages(profile.toNativeUtf8(), profile.length, handle.toNativeUtf8(), handle.length); return num; } @@ -196,8 +196,8 @@ class CwtchFfi implements Cwtch { // ignore: non_constant_identifier_names final GetMessage = getMessageC.asFunction(); - Pointer jsonMessageBytes = GetMessage(Utf8.toUtf8(profile), profile.length, Utf8.toUtf8(handle), handle.length, index); - String jsonMessage = Utf8.fromUtf8(jsonMessageBytes); + Pointer jsonMessageBytes = GetMessage(profile.toNativeUtf8(), profile.length, handle.toNativeUtf8(), handle.length, index); + String jsonMessage = jsonMessageBytes.toDartString(); return jsonMessage; } @@ -206,8 +206,8 @@ class CwtchFfi implements Cwtch { // ignore: non_constant_identifier_names final GetMessages = getMessagesC.asFunction(); - Pointer jsonMessagesBytes = GetMessages(Utf8.toUtf8(profile), profile.length, Utf8.toUtf8(handle), handle.length, start, end); - String jsonMessages = Utf8.fromUtf8(jsonMessagesBytes); + Pointer jsonMessagesBytes = GetMessages(profile.toNativeUtf8(), profile.length, handle.toNativeUtf8(), handle.length, start, end); + String jsonMessages = jsonMessagesBytes.toDartString(); return jsonMessages; } @@ -216,6 +216,6 @@ class CwtchFfi implements Cwtch { var sendAppBusEvent = library.lookup>("c_SendProfileEvent"); // ignore: non_constant_identifier_names final SendAppBusEvent = sendAppBusEvent.asFunction(); - SendAppBusEvent(Utf8.toUtf8(onion), onion.length, Utf8.toUtf8(json), json.length); + SendAppBusEvent(onion.toNativeUtf8(), onion.length, json.toNativeUtf8(), json.length); } } \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 057e59d..90d04e5 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,7 @@ import 'package:flutter_app/cwtch/ffi.dart'; import 'package:flutter_app/cwtch/gomobile.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_app/settings.dart'; import 'package:flutter_app/views/triplecolview.dart'; import 'package:provider/provider.dart'; import 'cwtch/cwtch.dart'; @@ -36,6 +37,7 @@ class FlwtchState extends State { initState() { super.initState(); cwtchInit = false; + profs = ProfileListState(); var cwtchNotifier = new CwtchNotifier(profs); @@ -54,6 +56,7 @@ class FlwtchState extends State { appStatus = AppModel(cwtch: cwtch); } + ChangeNotifierProvider getSettingsProvider() => ChangeNotifierProvider(create: (context) => Settings(Locale("en", ''))); ChangeNotifierProvider getOpaqueProvider() => ChangeNotifierProvider(create: (context) => OpaqueTheme(Opaque.dark)); Provider getFlwtchStateProvider() => Provider(create: (_) => this); ChangeNotifierProvider getProfileListProvider() => ChangeNotifierProvider(create: (context) => profs); @@ -62,17 +65,13 @@ class FlwtchState extends State { Widget build(BuildContext context) { appStatus = AppModel(cwtch: cwtch); - final newTextTheme = Theme.of(context).textTheme.apply( - bodyColor: Opaque.current().mainTextColor(), - displayColor: Opaque.current().mainTextColor(), - ); - return MultiProvider( - providers: [getFlwtchStateProvider(), getProfileListProvider(), getOpaqueProvider()], + providers: [getFlwtchStateProvider(), getProfileListProvider(), getOpaqueProvider(), getSettingsProvider()], builder: (context, widget) { + Provider.of(context).initPackageInfo(); return Consumer( builder: (context, opaque, child) => MaterialApp( - locale: Locale("en",''), + locale: Provider.of(context).locale, localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, title: 'Cwtch', @@ -83,7 +82,39 @@ class FlwtchState extends State { canvasColor: opaque.current().backgroundPaneColor(), accentColor: opaque.current().defaultButtonColor(), buttonColor: opaque.current().defaultButtonColor(), - textTheme: newTextTheme, + backgroundColor: opaque.current().backgroundMainColor(), + iconTheme: IconThemeData ( + color: opaque.current().mainTextColor(), + ), + cardColor: opaque.current().backgroundMainColor(), + textButtonTheme: TextButtonThemeData ( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all(opaque.current().defaultButtonColor()), + foregroundColor: MaterialStateProperty.all(opaque.current().defaultButtonTextColor()), + overlayColor: MaterialStateProperty.all(opaque.current().defaultButtonActiveColor()), + padding: MaterialStateProperty.all(EdgeInsets.all(20)) + ), + ), + dialogTheme: DialogTheme ( + backgroundColor: opaque.current().backgroundPaneColor(), + titleTextStyle: TextStyle( color: opaque.current().mainTextColor()), + contentTextStyle: TextStyle( color: opaque.current().mainTextColor()) + ), + textTheme: TextTheme( + headline1: TextStyle( color: opaque.current().mainTextColor()), + headline2: TextStyle( color: opaque.current().mainTextColor()), + headline3: TextStyle( color: opaque.current().mainTextColor()), + headline4: TextStyle( color: opaque.current().mainTextColor()), + headline5: TextStyle( color: opaque.current().mainTextColor()), + headline6: TextStyle( color: opaque.current().mainTextColor()), + bodyText1: TextStyle( color: opaque.current().mainTextColor()), + bodyText2: TextStyle( color: opaque.current().mainTextColor()), + subtitle1: TextStyle( color: opaque.current().mainTextColor()), + subtitle2: TextStyle( color: opaque.current().mainTextColor()), + caption: TextStyle( color: opaque.current().mainTextColor()), + button: TextStyle( color: opaque.current().mainTextColor()), + overline: TextStyle( color: opaque.current().mainTextColor()) + ), ), // from dan: home: cwtchInit == true ? ProfileMgrView(cwtch) : SplashView(), // from erinn: home: columns.length == 3 ? TripleColumnView() : ProfileMgrView(), diff --git a/lib/settings.dart b/lib/settings.dart new file mode 100644 index 0000000..fd47200 --- /dev/null +++ b/lib/settings.dart @@ -0,0 +1,25 @@ +import 'dart:ui'; +import 'dart:core'; + +import 'package:flutter/material.dart'; +import 'package:package_info_plus/package_info_plus.dart'; + +class Settings extends ChangeNotifier { + Locale locale; + + PackageInfo packageInfo; + + initPackageInfo() { + PackageInfo.fromPlatform().then((PackageInfo newPackageInfo) { + packageInfo = newPackageInfo; + notifyListeners(); + }); + } + + switchLocale(Locale newLocale) { + locale = newLocale; + notifyListeners(); + } + + Settings(this.locale); +} \ No newline at end of file diff --git a/lib/views/globalsettingsview.dart b/lib/views/globalsettingsview.dart index c5c3b9f..8fa91b0 100644 --- a/lib/views/globalsettingsview.dart +++ b/lib/views/globalsettingsview.dart @@ -1,19 +1,21 @@ +import 'dart:io'; +import 'package:package_info_plus/package_info_plus.dart'; import 'package:flutter/material.dart'; import 'package:flutter_app/opaque.dart'; +import 'package:flutter_app/settings.dart'; import 'package:provider/provider.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import '../main.dart'; + class GlobalSettingsView extends StatefulWidget { @override _GlobalSettingsViewState createState() => _GlobalSettingsViewState(); } class _GlobalSettingsViewState extends State { - final myController = TextEditingController(); - @override void dispose() { - myController.dispose(); super.dispose(); } @@ -28,40 +30,80 @@ class _GlobalSettingsViewState extends State { } Widget _buildSettingsList() { - return Consumer( - builder: (context, theme, child) { - return Center(child: Column( - children: [ - Text(AppLocalizations.of(context).settingLanguage), - TextField( - controller: myController, - onChanged: (text) { - print("First text field: $text"); - }, - ), - Text(AppLocalizations.of(context).settingInterfaceZoom), - SwitchListTile( - title: Text('Theme', - style: TextStyle(color: theme.current().mainTextColor())), - value: theme.current() == Opaque.light, - onChanged: (bool value) { - if (value) { - theme.setLight(); - } else { - theme.setDark(); - } - }, - secondary: Icon(Icons.lightbulb_outline, - color: theme.current().mainTextColor()), - ), - Text(AppLocalizations.of(context).experimentsEnabled), - Text("Text magnification reference"),//dev - Text("Acknowledgements"),//todo - Text(AppLocalizations.of(context).version), - Text(AppLocalizations.of(context).builddate), - ] - )); - } - ); + return Consumer(builder: (context, theme, child) { + return Center( + child: Column(children: [ + ListTile( + title: Text(AppLocalizations.of(context).settingLanguage, style: TextStyle(color: theme.current().mainTextColor())), + leading: Icon(Icons.language, color: theme.current().mainTextColor()), + trailing: DropdownButton( + value: Provider.of(context).locale.languageCode, + onChanged: (String newValue) { + setState(() { + Provider.of(context, listen: false).switchLocale(Locale(newValue, '')); + }); + }, + items: AppLocalizations.supportedLocales.map>((Locale value) { + return DropdownMenuItem( + value: value.languageCode, + child: Text(getLanguageFull(context, value.languageCode)), + ); + }).toList())), + SwitchListTile( + title: Text(AppLocalizations.of(context).settingTheme, style: TextStyle(color: theme.current().mainTextColor())), + value: theme.current() == Opaque.light, + onChanged: (bool value) { + if (value) { + theme.setLight(); + } else { + theme.setDark(); + } + }, + secondary: Icon(Icons.lightbulb_outline, color: theme.current().mainTextColor()), + ), + AboutListTile( + icon: Icon(Icons.info, color: theme.current().mainTextColor()), + applicationIcon: Padding( + padding: EdgeInsets.all(20), + child: Image( + image: AssetImage("assets/knott.png"), + width: 128, + height: 128, + )), + applicationName: "Cwtch (Flutter UI)", + applicationVersion: AppLocalizations.of(context).version.replaceAll("%1", constructVersionString(Provider.of(context).packageInfo)), + applicationLegalese: '\u{a9} 2021 Open Privacy Research Society', + ), + ])); + }); } } + +String constructVersionString(PackageInfo pinfo) { + if (pinfo == null) { + return ""; + } + return pinfo.version + "." + pinfo.buildNumber; +} + +String getLanguageFull(context, String languageCode) { + 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") { + return AppLocalizations.of(context).localePt; + } + if (languageCode == "de") { + return AppLocalizations.of(context).localeDe; + } + if (languageCode == "it") { + return AppLocalizations.of(context).localeIt; + } + return languageCode; +} diff --git a/pubspec.lock b/pubspec.lock index e96e324..20f4452 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -21,42 +21,42 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.5.0-nullsafety.3" + version: "2.5.0" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.3" + version: "2.1.0" characters: dependency: transitive description: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.5" + version: "1.1.0" charcode: dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.3" + version: "1.2.0" clock: dependency: transitive description: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.3" + version: "1.1.0" collection: dependency: transitive description: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0-nullsafety.5" + version: "1.15.0" convert: dependency: transitive description: @@ -84,21 +84,21 @@ packages: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.3" + version: "1.2.0" ffi: dependency: "direct main" description: name: ffi url: "https://pub.dartlang.org" source: hosted - version: "0.1.3" + version: "1.0.0" file: dependency: transitive description: name: file url: "https://pub.dartlang.org" source: hosted - version: "6.0.0-nullsafety.4" + version: "6.1.0" flutter: dependency: "direct main" description: flutter @@ -115,12 +115,17 @@ packages: name: flutter_lokalise url: "https://pub.dartlang.org" source: hosted - version: "0.1.1" + version: "0.1.3" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" freezed_annotation: dependency: transitive description: @@ -134,21 +139,28 @@ packages: name: http url: "https://pub.dartlang.org" source: hosted - version: "0.12.2" + version: "0.13.0" http_parser: dependency: transitive description: name: http_parser url: "https://pub.dartlang.org" source: hosted - version: "3.1.4" + version: "4.0.0" intl: dependency: transitive description: name: intl url: "https://pub.dartlang.org" source: hosted - version: "0.17.0-nullsafety.2" + version: "0.17.0" + js: + dependency: transitive + description: + name: js + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.3" json_annotation: dependency: transitive description: @@ -169,14 +181,14 @@ packages: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.10-nullsafety.3" + version: "0.12.10" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.6" + version: "1.3.0" nested: dependency: transitive description: @@ -184,48 +196,90 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.0.4" + package_info_plus: + dependency: "direct main" + description: + name: package_info_plus + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + package_info_plus_linux: + dependency: transitive + description: + name: package_info_plus_linux + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + package_info_plus_macos: + dependency: transitive + description: + name: package_info_plus_macos + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + package_info_plus_web: + dependency: transitive + description: + name: package_info_plus_web + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + package_info_plus_windows: + dependency: transitive + description: + name: package_info_plus_windows + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.3" + version: "1.8.0" path_provider: dependency: "direct main" description: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "1.6.27" + version: "2.0.1" path_provider_linux: dependency: transitive description: name: path_provider_linux url: "https://pub.dartlang.org" source: hosted - version: "0.0.1+2" + version: "2.0.0" path_provider_macos: dependency: transitive description: name: path_provider_macos url: "https://pub.dartlang.org" source: hosted - version: "0.0.4+8" + version: "2.0.0" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "2.0.1" path_provider_windows: dependency: transitive description: name: path_provider_windows url: "https://pub.dartlang.org" source: hosted - version: "0.0.4+3" + version: "2.0.0" pedantic: dependency: transitive description: @@ -246,14 +300,14 @@ packages: name: plugin_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "2.0.0" process: dependency: transitive description: name: process url: "https://pub.dartlang.org" source: hosted - version: "4.0.0-nullsafety.4" + version: "4.1.0" provider: dependency: "direct main" description: @@ -279,28 +333,28 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.4" + version: "1.8.1" stack_trace: dependency: transitive description: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.10.0-nullsafety.6" + version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.3" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.3" + version: "1.1.0" string_unescape: dependency: transitive description: @@ -314,42 +368,42 @@ packages: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.3" + version: "1.2.0" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.19-nullsafety.6" + version: "0.2.19" typed_data: dependency: transitive description: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.5" + version: "1.3.0" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.5" + version: "2.1.0" win32: dependency: transitive description: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "1.7.4" + version: "2.0.0" xdg_directories: dependency: transitive description: name: xdg_directories url: "https://pub.dartlang.org" source: hosted - version: "0.1.2" + version: "0.2.0" yaml: dependency: transitive description: @@ -358,5 +412,5 @@ packages: source: hosted version: "2.2.1" sdks: - dart: ">=2.12.0-0.0 <3.0.0" - flutter: ">=1.16.0" + dart: ">=2.12.0-259.9.beta <3.0.0" + flutter: ">=1.20.0" diff --git a/pubspec.yaml b/pubspec.yaml index e93ce47..ec288c7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -24,6 +24,7 @@ dependencies: flutter: sdk: flutter provider: "4.3.2+3" + package_info_plus: ^1.0.0 #intl_translation: any flutter_localizations: sdk: flutter @@ -31,8 +32,9 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.0 - ffi: ^0.1.3 - path_provider: ^1.6.27 + ffi: ^1.0.0 + path_provider: ^2.0.0 + dev_dependencies: flutter_test: @@ -75,6 +77,7 @@ flutter: # https://flutter.dev/assets-and-images/#from-packages assets: + - assets/ - assets/profiles/ # To add custom fonts to your application, add a fonts section here,