From 2d66e426243cac64b27f1b36abf5a33f7a75b9d7 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Thu, 25 Nov 2021 18:13:36 -0800 Subject: [PATCH 01/20] support for server metrics --- lib/cwtch/cwtchNotifier.dart | 6 ++++++ lib/l10n/intl_fr.arb | 1 + lib/models/servers.dart | 31 ++++++++++++++++++++++++++++ lib/views/addeditservers.dart | 39 ++++++++++++++++++++++++++++------- 4 files changed, 69 insertions(+), 8 deletions(-) diff --git a/lib/cwtch/cwtchNotifier.dart b/lib/cwtch/cwtchNotifier.dart index d3c01c55..29ec9ce4 100644 --- a/lib/cwtch/cwtchNotifier.dart +++ b/lib/cwtch/cwtchNotifier.dart @@ -79,6 +79,12 @@ class CwtchNotifier { server.setRunning(data["Intent"] == "running"); } break; + case "ServerStatsUpdate": + EnvironmentConfig.debugLog("ServerStatsUpdate $data"); + var totalMessages = int.parse(data["TotalMessages"]); + var connections = int.parse(data["Connections"]); + serverListState.updateServerStats(data["Identity"], totalMessages, connections); + break; case "GroupCreated": // Retrieve Server Status from Cache... String status = ""; diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index 66c5b046..218346d3 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -8,6 +8,7 @@ "serverConnectionsLabel": "Connexion", "manageKnownServersShort": "Serveurs", "manageKnownServersLong": "Gérer les serveurs connus", + "displayNameTooltip": "Veuillez entrer un nom d'usage s'il vous plaît", "manageKnownServersButton": "Gérer les serveurs connus", "importLocalServerSelectText": "Sélectionnez le serveur local", "importLocalServerLabel": "Importer un serveur hébergé localement", diff --git a/lib/models/servers.dart b/lib/models/servers.dart index 2850668b..cd059cbf 100644 --- a/lib/models/servers.dart +++ b/lib/models/servers.dart @@ -39,11 +39,34 @@ class ServerListState extends ChangeNotifier { notifyListeners(); } + void updateServerStats(String onion, int newTotalMessages, int newConnections) { + var server = getServer(onion); + if (server != null) { + server.setStats(newTotalMessages, newConnections); + resort(); + notifyListeners(); + } + } + void delete(String onion) { _servers.removeWhere((element) => element.onion == onion); notifyListeners(); } + void resort() { + _servers.sort((ServerInfoState a, ServerInfoState b) { + // return -1 = a first in list + // return 1 = b first in list + if (a.totalMessages > b.totalMessages) { + return -1; + } else if (b.totalMessages > a.totalMessages) { + return 1; + } + + return 0; + }); + } + List get servers => _servers.sublist(0); //todo: copy?? dont want caller able to bypass changenotifier } @@ -55,6 +78,8 @@ class ServerInfoState extends ChangeNotifier { bool running; bool autoStart; bool isEncrypted; + int totalMessages = 0; + int connections = 0; ServerInfoState({required this.onion, required this.serverBundle, required this.running, required this.description, required this.autoStart, required this.isEncrypted}); @@ -72,4 +97,10 @@ class ServerInfoState extends ChangeNotifier { description = val; notifyListeners(); } + + void setStats(int newTotalMessages, int newConnections) { + totalMessages = newTotalMessages; + connections = newConnections; + notifyListeners(); + } } diff --git a/lib/views/addeditservers.dart b/lib/views/addeditservers.dart index b2a5cacf..aec67bfe 100644 --- a/lib/views/addeditservers.dart +++ b/lib/views/addeditservers.dart @@ -81,20 +81,14 @@ class _AddEditServerViewState extends State { child: Form( key: _formKey, child: Container( - margin: EdgeInsets.fromLTRB(30, 0, 30, 10), - padding: EdgeInsets.fromLTRB(20, 0, 20, 10), + margin: EdgeInsets.fromLTRB(30, 5, 30, 10), + padding: EdgeInsets.fromLTRB(20, 5, 20, 10), child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Onion Visibility( visible: serverInfoState.onion.isNotEmpty, child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox( - height: 20, - ), CwtchLabel(label: AppLocalizations.of(context)!.serverAddress), - SizedBox( - height: 20, - ), SelectableText(serverInfoState.onion) ])), @@ -156,6 +150,35 @@ class _AddEditServerViewState extends State { secondary: Icon(CwtchIcons.favorite_24dp, color: settings.current().mainTextColor()), ), + // metrics + Visibility( + visible: serverInfoState.onion.isNotEmpty, + child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + SizedBox( + height: 20, + ), + Text(AppLocalizations.of(context)!.serverMetricsLabel, style: Provider.of(context).biggerFont), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ + Text(AppLocalizations.of(context)!.serverTotalMessagesLabel), + ]), + Text(serverInfoState.totalMessages.toString()) + ]), + + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ + Text(AppLocalizations.of(context)!.serverConnectionsLabel), + ]), + Text(serverInfoState.connections.toString()) + ]), + + + ])), + // ***** Password ***** // use password toggle From 3b893d4f1564971f828274f486e28c8150ddba2c Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Tue, 14 Dec 2021 10:34:37 -0600 Subject: [PATCH 02/20] gate profile servers on groups or servers experiment --- lib/l10n/intl_fr.arb | 3 +-- lib/views/contactsview.dart | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index 218346d3..5f4b6fc2 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -8,7 +8,6 @@ "serverConnectionsLabel": "Connexion", "manageKnownServersShort": "Serveurs", "manageKnownServersLong": "Gérer les serveurs connus", - "displayNameTooltip": "Veuillez entrer un nom d'usage s'il vous plaît", "manageKnownServersButton": "Gérer les serveurs connus", "importLocalServerSelectText": "Sélectionnez le serveur local", "importLocalServerLabel": "Importer un serveur hébergé localement", @@ -267,4 +266,4 @@ "newBulletinLabel": "Nouveau bulletin", "createGroupBtn": "Créer", "createGroupTitle": "Créer un groupe" -} \ No newline at end of file +} diff --git a/lib/views/contactsview.dart b/lib/views/contactsview.dart index a05ef4df..e6e13c19 100644 --- a/lib/views/contactsview.dart +++ b/lib/views/contactsview.dart @@ -114,7 +114,7 @@ class _ContactsViewState extends State { })); // Manage known Servers - if (Provider.of(context, listen: false).isExperimentEnabled(ServerManagementExperiment)) { + if (Provider.of(context, listen: false).isExperimentEnabled(TapirGroupsExperiment) || Provider.of(context, listen: false).isExperimentEnabled(ServerManagementExperiment)) { actions.add(IconButton( icon: Icon(CwtchIcons.dns_24px), tooltip: AppLocalizations.of(context)!.manageKnownServersButton, From f6a4d5c3fa0fb76ada017a057d0a04b85fe21c1a Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Mon, 6 Dec 2021 17:40:10 -0800 Subject: [PATCH 03/20] removing unused theme definitions --- lib/main.dart | 3 +- lib/main_test.dart | 2 +- lib/opaque.dart | 1455 ----------------------------- lib/settings.dart | 3 +- lib/themes/cwtch.dart | 275 ++++++ lib/themes/opaque.dart | 226 +++++ lib/views/addeditprofileview.dart | 2 +- lib/widgets/profileimage.dart | 2 +- regenerate_opaque_theme.sh | 50 - test/buttontextfield_test.dart | 2 +- test/cwtchlabel_test.dart | 2 +- test/profileimage_test.dart | 2 +- test/textfield_test.dart | 2 +- 13 files changed, 512 insertions(+), 1514 deletions(-) delete mode 100644 lib/opaque.dart create mode 100644 lib/themes/cwtch.dart create mode 100644 lib/themes/opaque.dart delete mode 100755 regenerate_opaque_theme.sh diff --git a/lib/main.dart b/lib/main.dart index 9ab2ad4b..64557091 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'package:cwtch/config.dart'; import 'package:cwtch/notification_manager.dart'; +import 'package:cwtch/themes/cwtch.dart'; import 'package:cwtch/views/messageview.dart'; import 'package:cwtch/widgets/rightshiftfixer.dart'; import 'package:flutter/foundation.dart'; @@ -21,7 +22,7 @@ import 'models/servers.dart'; import 'views/profilemgrview.dart'; import 'views/splashView.dart'; import 'dart:io' show Platform, exit; -import 'opaque.dart'; +import 'themes/opaque.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; var globalSettings = Settings(Locale("en", ''), OpaqueDark()); diff --git a/lib/main_test.dart b/lib/main_test.dart index a2551891..07f02c72 100644 --- a/lib/main_test.dart +++ b/lib/main_test.dart @@ -5,7 +5,7 @@ import 'package:cwtch/errorHandler.dart'; import 'package:cwtch/settings.dart'; import 'licenses.dart'; import 'main.dart'; -import 'opaque.dart'; +import 'themes/opaque.dart'; import 'dart:convert'; import 'dart:io'; diff --git a/lib/opaque.dart b/lib/opaque.dart deleted file mode 100644 index fc984217..00000000 --- a/lib/opaque.dart +++ /dev/null @@ -1,1455 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT BY HAND AS CHANGES WILL BE OVERRIDDEN. -// TO EDIT THE THEME, SEE https://git.openprivacy.ca/openprivacy/opaque/ -// FOR HOW THIS FILE IS GENERATED, SEE ../regenerate_opaque_theme.sh - -import 'dart:ui'; -import 'dart:core'; - -import 'package:flutter/material.dart'; -import 'package:cwtch/settings.dart'; - -abstract class OpaqueThemeType { - static final Color red = Color(0xFFFF0000); - - String identifier() { - return "dummy"; - } - - Color backgroundMainColor() { - return red; - } - - Color backgroundPaneColor() { - return red; - } - - Color backgroundHilightElementColor() { - return red; - } - - Color dividerColor() { - return red; - } - - Color mainTextColor() { - return red; - } - - Color altTextColor() { - return red; - } - - Color hilightElementTextColor() { - return red; - } - - Color defaultButtonColor() { - return red; - } - - Color defaultButtonActiveColor() { - return red; - } - - Color defaultButtonTextColor() { - return red; - } - - Color defaultButtonDisabledColor() { - return red; - } - - Color defaultButtonDisabledTextColor() { - return red; - } - - Color altButtonColor() { - return red; - } - - Color altButtonTextColor() { - return red; - } - - Color altButtonDisabledColor() { - return red; - } - - Color altButtonDisabledTextColor() { - return red; - } - - Color textfieldBackgroundColor() { - return red; - } - - Color textfieldBorderColor() { - return red; - } - - Color textfieldTextColor() { - return red; - } - - Color textfieldErrorColor() { - return red; - } - - Color textfieldButtonColor() { - return red; - } - - Color textfieldButtonTextColor() { - return red; - } - - Color scrollbarDefaultColor() { - return red; - } - - Color scrollbarActiveColor() { - return red; - } - - Color portraitOnlineBorderColor() { - return red; - } - - Color portraitOnlineBackgroundColor() { - return red; - } - - Color portraitOnlineTextColor() { - return red; - } - - Color portraitConnectingBorderColor() { - return red; - } - - Color portraitConnectingBackgroundColor() { - return red; - } - - Color portraitConnectingTextColor() { - return red; - } - - Color portraitOfflineBorderColor() { - return red; - } - - Color portraitOfflineBackgroundColor() { - return red; - } - - Color portraitOfflineTextColor() { - return red; - } - - Color portraitBlockedBorderColor() { - return red; - } - - Color portraitBlockedBackgroundColor() { - return red; - } - - Color portraitBlockedTextColor() { - return red; - } - - Color portraitOnlineBadgeColor() { - return red; - } - - Color portraitOfflineBadgeColor() { - return red; - } - - Color portraitContactBadgeColor() { - return red; - } - - Color portraitContactBadgeTextColor() { - return red; - } - - Color portraitProfileBadgeColor() { - return red; - } - - Color portraitProfileBadgeTextColor() { - return red; - } - - Color portraitOverlayOfflineColor() { - return red; - } - - Color dropShadowColor() { - return red; - } - - Color dropShadowPaneColor() { - return red; - } - - Color toggleColor() { - return red; - } - - Color toggleOnColor() { - return red; - } - - Color toggleOffColor() { - return red; - } - - Color sliderButtonColor() { - return red; - } - - Color sliderBarLeftColor() { - return red; - } - - Color sliderBarRightColor() { - return red; - } - - Color boxCheckedColor() { - return red; - } - - Color toolbarIconColor() { - return red; - } - - Color toolbarMainColor() { - return red; - } - - Color toolbarAltColor() { - return red; - } - - Color statusbarDisconnectedInternetColor() { - return red; - } - - Color statusbarDisconnectedInternetFontColor() { - return red; - } - - Color statusbarDisconnectedTorFontColor() { - return red; - } - - Color statusbarDisconnectedTorColor() { - return red; - } - - Color statusbarConnectingColor() { - return red; - } - - Color statusbarConnectingFontColor() { - return red; - } - - Color statusbarOnlineColor() { - return red; - } - - Color statusbarOnlineFontColor() { - return red; - } - - Color chatOverlayWarningTextColor() { - return red; - } - - Color messageFromMeBackgroundColor() { - return red; - } - - Color messageFromMeTextColor() { - return red; - } - - Color messageFromOtherBackgroundColor() { - return red; - } - - Color messageFromOtherTextColor() { - return red; - } - - Color messageStatusNormalColor() { - return red; - } - - Color messageStatusBlockedColor() { - return red; - } - - Color messageStatusBlockedTextColor() { - return red; - } - - Color messageStatusAlertColor() { - return red; - } - - Color messageStatusAlertTextColor() { - return red; - } - - // ... more to come - - // Sizes - - double contactOnionTextSize() { - return 18; - } -} - -class OpaqueDark extends OpaqueThemeType { - static final Color darkGreyPurple = Color(0xFF281831); - static final Color deepPurple = Color(0xFF422850); - static final Color mauvePurple = Color(0xFF8E64A5); - static final Color purple = Color(0xFFDFB9DE); - static final Color whitePurple = Color(0xFFE3DFE4); - static final Color softPurple = Color(0xFFFDF3FC); - static final Color pink = Color(0xFFE85DA1); - static final Color hotPink = Color(0xFFD01972); - static final Color lightGrey = Color(0xFF9E9E9E); - static final Color softGreen = Color(0xFFA0FFB0); - static final Color softRed = Color(0xFFFFA0B0); - - String identifier() { - return "dark"; - } - - Color backgroundMainColor() { - return darkGreyPurple; - } - - Color backgroundPaneColor() { - return darkGreyPurple; - } - - Color backgroundHilightElementColor() { - return deepPurple; - } - - Color dividerColor() { - return deepPurple; - } - - Color mainTextColor() { - return whitePurple; - } - - Color altTextColor() { - return mauvePurple; - } - - Color hilightElementTextColor() { - return purple; - } - - Color defaultButtonColor() { - return hotPink; - } - - Color defaultButtonActiveColor() { - return pink; - } - - Color defaultButtonTextColor() { - return whitePurple; - } - - Color defaultButtonDisabledColor() { - return lightGrey; - } - - Color defaultButtonDisabledTextColor() { - return darkGreyPurple; - } - - Color altButtonColor() { - return darkGreyPurple; - } - - Color altButtonTextColor() { - return purple; - } - - Color altButtonDisabledColor() { - return darkGreyPurple; - } - - Color altButtonDisabledTextColor() { - return purple; - } - - Color textfieldBackgroundColor() { - return deepPurple; - } - - Color textfieldBorderColor() { - return deepPurple; - } - - Color textfieldTextColor() { - return purple; - } - - Color textfieldErrorColor() { - return hotPink; - } - - Color textfieldButtonColor() { - return purple; - } - - Color textfieldButtonTextColor() { - return darkGreyPurple; - } - - Color scrollbarDefaultColor() { - return purple; - } - - Color scrollbarActiveColor() { - return hotPink; - } - - Color portraitOnlineBorderColor() { - return whitePurple; - } - - Color portraitOnlineBackgroundColor() { - return whitePurple; - } - - Color portraitOnlineTextColor() { - return whitePurple; - } - - Color portraitConnectingBorderColor() { - return purple; - } //mauvePurple - - Color portraitConnectingBackgroundColor() { - return purple; - } //darkGreyPurple - - Color portraitConnectingTextColor() { - return purple; - } - - Color portraitOfflineBorderColor() { - return purple; - } - - Color portraitOfflineBackgroundColor() { - return purple; - } - - Color portraitOfflineTextColor() { - return purple; - } - - Color portraitBlockedBorderColor() { - return lightGrey; - } - - Color portraitBlockedBackgroundColor() { - return lightGrey; - } - - Color portraitBlockedTextColor() { - return lightGrey; - } - - Color portraitOnlineBadgeColor() { - return softGreen; - } - - Color portraitOfflineBadgeColor() { - return softRed; - } - - Color portraitContactBadgeColor() { - return hotPink; - } - - Color portraitContactBadgeTextColor() { - return whitePurple; - } - - Color portraitProfileBadgeColor() { - return mauvePurple; - } - - Color portraitProfileBadgeTextColor() { - return darkGreyPurple; - } - - Color portraitOverlayOfflineColor() { - return mauvePurple; - } - - Color dropShadowColor() { - return mauvePurple; - } - - Color dropShadowPaneColor() { - return darkGreyPurple; - } - - Color toggleColor() { - return darkGreyPurple; - } - - Color toggleOnColor() { - return whitePurple; - } - - Color toggleOffColor() { - return deepPurple; - } - - Color sliderButtonColor() { - return whitePurple; - } - - Color sliderBarLeftColor() { - return mauvePurple; - } - - Color sliderBarRightColor() { - return mauvePurple; - } - - Color boxCheckedColor() { - return hotPink; - } - - Color toolbarIconColor() { - return whitePurple; - } - - Color toolbarMainColor() { - return darkGreyPurple; - } - - Color toolbarAltColor() { - return deepPurple; - } - - Color statusbarDisconnectedInternetColor() { - return whitePurple; - } - - Color statusbarDisconnectedInternetFontColor() { - return deepPurple; - } - - Color statusbarDisconnectedTorColor() { - return darkGreyPurple; - } - - Color statusbarDisconnectedTorFontColor() { - return whitePurple; - } - - Color statusbarConnectingColor() { - return deepPurple; - } - - Color statusbarConnectingFontColor() { - return whitePurple; - } - - Color statusbarOnlineColor() { - return mauvePurple; - } - - Color statusbarOnlineFontColor() { - return whitePurple; - } - - Color chatOverlayWarningTextColor() { - return purple; - } - - Color messageFromMeBackgroundColor() { - return mauvePurple; - } - - Color messageFromMeTextColor() { - return whitePurple; - } - - Color messageFromOtherBackgroundColor() { - return deepPurple; - } - - Color messageFromOtherTextColor() { - return whitePurple; - } - - Color messageStatusNormalColor() { - return deepPurple; - } - - Color messageStatusBlockedColor() { - return lightGrey; - } - - Color messageStatusBlockedTextColor() { - return whitePurple; - } - - Color messageStatusAlertColor() { - return mauvePurple; - } - - Color messageStatusAlertTextColor() { - return whitePurple; - } -} - -class OpaqueLight extends OpaqueThemeType { - static final Color whitePurple = Color(0xFFFFFDFF); - static final Color softPurple = Color(0xFFFDF3FC); - static final Color purple = Color(0xFFDFB9DE); - static final Color brightPurple = Color(0xFFD1B0E0); - static final Color darkPurple = Color(0xFF350052); - static final Color greyPurple = Color(0xFF775F84); - static final Color pink = Color(0xFFE85DA1); - static final Color hotPink = Color(0xFFD01972); - static final Color lightGrey = Color(0xFFB3B6B3); - static final Color softGreen = Color(0xFFA0FFB0); - static final Color softRed = Color(0xFFFFA0B0); - - String identifier() { - return "light"; - } - - Color backgroundMainColor() { - return whitePurple; - } - - Color backgroundPaneColor() { - return softPurple; - } - - Color backgroundHilightElementColor() { - return softPurple; - } - - Color dividerColor() { - return purple; - } - - Color mainTextColor() { - return darkPurple; - } - - Color altTextColor() { - return purple; - } - - Color hilightElementTextColor() { - return darkPurple; - } - - Color defaultButtonColor() { - return hotPink; - } - - Color defaultButtonActiveColor() { - return pink; - } - - Color defaultButtonTextColor() { - return whitePurple; - } - - Color defaultButtonDisabledColor() { - return lightGrey; - } - - Color defaultButtonDisabledTextColor() { - return whitePurple; - } - - Color altButtonColor() { - return whitePurple; - } - - Color altButtonTextColor() { - return purple; - } - - Color altButtonDisabledColor() { - return softPurple; - } - - Color altButtonDisabledTextColor() { - return purple; - } - - Color textfieldBackgroundColor() { - return purple; - } - - Color textfieldBorderColor() { - return purple; - } - - Color textfieldTextColor() { - return purple; - } - - Color textfieldErrorColor() { - return hotPink; - } - - Color textfieldButtonColor() { - return hotPink; - } - - Color textfieldButtonTextColor() { - return whitePurple; - } - - Color scrollbarDefaultColor() { - return darkPurple; - } - - Color scrollbarActiveColor() { - return hotPink; - } - - Color portraitOnlineBorderColor() { - return greyPurple; - } - - Color portraitOnlineBackgroundColor() { - return greyPurple; - } - - Color portraitOnlineTextColor() { - return darkPurple; - } - - Color portraitConnectingBorderColor() { - return greyPurple; - } - - Color portraitConnectingBackgroundColor() { - return greyPurple; - } - - Color portraitConnectingTextColor() { - return greyPurple; - } - - Color portraitOfflineBorderColor() { - return greyPurple; - } //purple - - Color portraitOfflineBackgroundColor() { - return greyPurple; - } //purple - - Color portraitOfflineTextColor() { - return greyPurple; - } //purple - - Color portraitBlockedBorderColor() { - return lightGrey; - } - - Color portraitBlockedBackgroundColor() { - return lightGrey; - } - - Color portraitBlockedTextColor() { - return lightGrey; - } - - Color portraitOnlineBadgeColor() { - return softGreen; - } - - Color portraitOfflineBadgeColor() { - return softRed; - } - - Color portraitContactBadgeColor() { - return hotPink; - } - - Color portraitContactBadgeTextColor() { - return whitePurple; - } - - Color portraitProfileBadgeColor() { - return brightPurple; - } - - Color portraitProfileBadgeTextColor() { - return whitePurple; - } - - Color portraitOverlayOfflineColor() { - return whitePurple; - } - - Color dropShadowColor() { - return purple; - } - - Color dropShadowPaneColor() { - return purple; - } - - Color toggleColor() { - return whitePurple; - } - - Color toggleOnColor() { - return hotPink; - } - - Color toggleOffColor() { - return purple; - } - - Color sliderButtonColor() { - return pink; - } - - Color sliderBarLeftColor() { - return purple; - } - - Color sliderBarRightColor() { - return purple; - } - - Color boxCheckedColor() { - return darkPurple; - } - - Color toolbarIconColor() { - return darkPurple; - } - - Color toolbarMainColor() { - return whitePurple; - } - - Color toolbarAltColor() { - return softPurple; - } - - Color statusbarDisconnectedInternetColor() { - return softPurple; - } - - Color statusbarDisconnectedInternetFontColor() { - return darkPurple; - } - - Color statusbarDisconnectedTorColor() { - return purple; - } - - Color statusbarDisconnectedTorFontColor() { - return darkPurple; - } - - Color statusbarConnectingColor() { - return greyPurple; - } - - Color statusbarConnectingFontColor() { - return whitePurple; - } - - Color statusbarOnlineColor() { - return darkPurple; - } - - Color statusbarOnlineFontColor() { - return whitePurple; - } - - Color chatOverlayWarningTextColor() { - return purple; - } - - Color messageFromMeBackgroundColor() { - return brightPurple; - } - - Color messageFromMeTextColor() { - return mainTextColor(); - } - - Color messageFromOtherBackgroundColor() { - return purple; - } - - Color messageFromOtherTextColor() { - return darkPurple; - } - - Color messageStatusNormalColor() { - return purple; - } - - Color messageStatusBlockedColor() { - return lightGrey; - } - - Color messageStatusBlockedTextColor() { - return whitePurple; - } - - Color messageStatusAlertColor() { - return hotPink; - } - - Color messageStatusAlertTextColor() { - return whitePurple; - } -} - -ThemeData mkThemeData(Settings opaque) { - return ThemeData( - visualDensity: VisualDensity.adaptivePlatformDensity, - primarySwatch: Colors.red, - primaryIconTheme: IconThemeData( - color: opaque.current().mainTextColor(), - ), - primaryColor: opaque.current().backgroundMainColor(), - canvasColor: opaque.current().backgroundPaneColor(), - backgroundColor: opaque.current().backgroundMainColor(), - highlightColor: opaque.current().hilightElementTextColor(), - iconTheme: IconThemeData( - color: opaque.current().toolbarIconColor(), - ), - cardColor: opaque.current().backgroundMainColor(), - appBarTheme: AppBarTheme( - backgroundColor: opaque.current().backgroundPaneColor(), - iconTheme: IconThemeData( - color: opaque.current().mainTextColor(), - ), - titleTextStyle: TextStyle( - color: opaque.current().mainTextColor(), - ), - actionsIconTheme: IconThemeData( - color: opaque.current().mainTextColor(), - )), - bottomNavigationBarTheme: BottomNavigationBarThemeData(type: BottomNavigationBarType.fixed, backgroundColor: opaque.current().backgroundHilightElementColor()), - 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))), - ), - elevatedButtonTheme: ElevatedButtonThemeData( - style: ButtonStyle( - backgroundColor: MaterialStateProperty.resolveWith((states) => states.contains(MaterialState.disabled) ? opaque.current().defaultButtonDisabledColor() : opaque.current().defaultButtonColor()), - foregroundColor: MaterialStateProperty.all(opaque.current().defaultButtonTextColor()), - overlayColor: MaterialStateProperty.resolveWith((states) => (states.contains(MaterialState.pressed) && states.contains(MaterialState.hovered)) - ? opaque.current().defaultButtonActiveColor() - : states.contains(MaterialState.disabled) - ? opaque.current().defaultButtonDisabledColor() - : null), - enableFeedback: true, - splashFactory: InkRipple.splashFactory, - padding: MaterialStateProperty.all(EdgeInsets.all(20)), - shape: MaterialStateProperty.all(RoundedRectangleBorder( - borderRadius: BorderRadius.circular(18.0), - )), - ), - ), - scrollbarTheme: ScrollbarThemeData( - isAlwaysShown: false, thumbColor: MaterialStateProperty.all(opaque.current().scrollbarActiveColor()), trackColor: MaterialStateProperty.all(opaque.current().scrollbarDefaultColor())), - tabBarTheme: TabBarTheme(indicator: UnderlineTabIndicator(borderSide: BorderSide(color: opaque.current().defaultButtonActiveColor()))), - 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())), - switchTheme: SwitchThemeData( - overlayColor: MaterialStateProperty.all(opaque.current().defaultButtonActiveColor()), - thumbColor: MaterialStateProperty.all(opaque.current().mainTextColor()), - trackColor: MaterialStateProperty.all(opaque.current().dropShadowColor()), - ), - floatingActionButtonTheme: FloatingActionButtonThemeData( - backgroundColor: opaque.current().defaultButtonColor(), - hoverColor: opaque.current().defaultButtonActiveColor(), - enableFeedback: true, - splashColor: opaque.current().defaultButtonActiveColor()), - textSelectionTheme: TextSelectionThemeData( - cursorColor: opaque.current().defaultButtonActiveColor(), selectionColor: opaque.current().defaultButtonActiveColor(), selectionHandleColor: opaque.current().defaultButtonActiveColor()), - ); -} - -/* - -OpaqueThemeType _current = CwtchDark(); - -void setDark() { - _current = CwtchDark(); -} - -void setLight() { - _current = CwtchLight(); -} - -OpaqueThemeType current() { - if (_current == null) { - setDark(); - } - return _current; -} - -class Opaque extends OpaqueThemeType { - Color backgroundMainColor() { - return current().backgroundMainColor(); - } - - Color backgroundPaneColor() { - return current().backgroundPaneColor(); - } - - Color backgroundHilightElementColor() { - return current().backgroundHilightElementColor(); - } - - Color dividerColor() { - return current().dividerColor(); - } - - Color mainTextColor() { - return current().mainTextColor(); - } - - Color altTextColor() { - return current().altTextColor(); - } - - Color hilightElementTextColor() { - return current().hilightElementTextColor(); - } - - Color defaultButtonColor() { - return current().defaultButtonColor(); - } - - Color defaultButtonActiveColor() { - return current().defaultButtonActiveColor(); - } - - Color defaultButtonTextColor() { - return current().defaultButtonTextColor(); - } - - Color defaultButtonDisabledColor() { - return current().defaultButtonDisabledColor(); - } - - Color defaultButtonDisabledTextColor() { - return current().defaultButtonDisabledTextColor(); - } - - Color altButtonColor() { - return current().altButtonColor(); - } - - Color altButtonTextColor() { - return current().altButtonTextColor(); - } - - Color altButtonDisabledColor() { - return current().altButtonDisabledColor(); - } - - Color altButtonDisabledTextColor() { - return current().altButtonDisabledTextColor(); - } - - Color textfieldBackgroundColor() { - return current().textfieldBackgroundColor(); - } - - Color textfieldBorderColor() { - return current().textfieldBorderColor(); - } - - Color textfieldTextColor() { - return current().textfieldTextColor(); - } - - Color textfieldErrorColor() { - return current().textfieldErrorColor(); - } - - Color textfieldButtonColor() { - return current().textfieldButtonColor(); - } - - Color textfieldButtonTextColor() { - return current().textfieldButtonTextColor(); - } - - Color dropShadowColor() { - return current().dropShadowColor(); - } - - Color dropShadowPaneColor() { - return current().dropShadowPaneColor(); - } - - Color portraitOnlineBorderColor() { - return current().portraitOnlineBorderColor(); - } - - Color portraitOnlineBackgroundColor() { - return current().portraitOnlineBackgroundColor(); - } - - Color portraitOnlineTextColor() { - return current().portraitOnlineTextColor(); - } - - Color portraitConnectingBorderColor() { - return current().portraitConnectingBorderColor(); - } - - Color portraitConnectingBackgroundColor() { - return current().portraitConnectingBackgroundColor(); - } - - Color portraitConnectingTextColor() { - return current().portraitConnectingTextColor(); - } - - Color portraitOfflineBorderColor() { - return current().portraitOfflineBorderColor(); - } - - Color portraitOfflineBackgroundColor() { - return current().portraitOfflineBackgroundColor(); - } - - Color portraitOfflineTextColor() { - return current().portraitOfflineTextColor(); - } - - Color portraitBlockedBorderColor() { - return current().portraitBlockedBorderColor(); - } - - Color portraitBlockedBackgroundColor() { - return current().portraitBlockedBackgroundColor(); - } - - Color portraitBlockedTextColor() { - return current().portraitBlockedTextColor(); - } - - Color portraitOnlineBadgeColor() { - return current().portraitOnlineBadgeColor(); - } - - Color portraitOfflineBadgeColor() { - return current().portraitOfflineBadgeColor(); - } - - Color portraitContactBadgeColor() { - return current().portraitContactBadgeColor(); - } - - Color portraitContactBadgeTextColor() { - return current().portraitContactBadgeTextColor(); - } - - Color portraitProfileBadgeColor() { - return current().portraitProfileBadgeColor(); - } - - Color portraitProfileBadgeTextColor() { - return current().portraitProfileBadgeTextColor(); - } - - Color portraitOverlayOfflineColor() { - return current().portraitOverlayOfflineColor(); - } - - Color toggleColor() { - return current().toggleColor(); - } - - Color toggleOffColor() { - return current().toggleOffColor(); - } - - Color toggleOnColor() { - return current().toggleOnColor(); - } - - Color sliderButtonColor() { - return current().sliderButtonColor(); - } - - Color sliderBarLeftColor() { - return current().sliderBarLeftColor(); - } - - Color sliderBarRightColor() { - return current().sliderBarRightColor(); - } - - Color boxCheckedColor() { - return current().boxCheckedColor(); - } - - Color toolbarIconColor() { - return current().toolbarIconColor(); - } - - Color toolbarMainColor() { - return current().toolbarMainColor(); - } - - Color toolbarAltColor() { - return current().toolbarAltColor(); - } - - Color statusbarDisconnectedInternetColor() { - return current().statusbarDisconnectedInternetColor(); - } - - Color statusbarDisconnectedInternetFontColor() { - return current().statusbarDisconnectedInternetFontColor(); - } - - Color statusbarDisconnectedTorFontColor() { - return current().statusbarDisconnectedTorFontColor(); - } - - Color statusbarDisconnectedTorColor() { - return current().statusbarDisconnectedTorColor(); - } - - Color statusbarConnectingColor() { - return current().statusbarConnectingColor(); - } - - Color statusbarConnectingFontColor() { - return current().statusbarConnectingFontColor(); - } - - Color statusbarOnlineColor() { - return current().statusbarOnlineColor(); - } - - Color statusbarOnlineFontColor() { - return current().statusbarOnlineFontColor(); - } - - Color chatOverlayWarningTextColor() { - return current().chatOverlayWarningTextColor(); - } - - Color messageFromMeBackgroundColor() { - return current().messageFromMeBackgroundColor(); - } - - Color messageFromMeTextColor() { - return current().messageFromMeTextColor(); - } - - Color messageFromOtherBackgroundColor() { - return current().messageFromOtherBackgroundColor(); - } - - Color messageFromOtherTextColor() { - return current().messageFromOtherTextColor(); - } - - Color messageStatusNormalColor() { - return current().messageStatusNormalColor(); - } - - Color messageStatusBlockedColor() { - return current().messageStatusBlockedColor(); - } - - Color messageStatusBlockedTextColor() { - return current().messageStatusBlockedTextColor(); - } - - Color messageStatusAlertColor() { - return current().messageStatusAlertColor(); - } - - Color messageStatusAlertTextColor() { - return current().messageStatusAlertTextColor(); - } - - Color scrollbarDefaultColor() { - return current().scrollbarDefaultColor(); - } - - Color scrollbarActiveColor() { - return current().scrollbarActiveColor(); - } - - var sidePaneMinSizeBase = [200, 400, 600]; - int sidePaneMinSize() { - return sidePaneMinSizeBase[p[scale]] + 200 /*for debugging*/; - } - - var chatPaneMinSizeBase = [300, 400, 500]; - int chatPaneMinSize() { - return chatPaneMinSizeBase[p[scale]]; - } - - int doublePaneMinSize() { - return sidePaneMinSize() + chatPaneMinSize(); - } - - static late OpaqueThemeType _current; - //static final OpaqueThemeType dark = CwtchDark(); - //static final OpaqueThemeType light = CwtchLight(); - - - int scale = 2; - static final String gcdOS = "linux"; - - var p = [0, 1, 1, 1, 2]; - var t = [0, 0, 1, 2, 2]; - - var paddingMinimalBase = [1, 4, 6]; - int paddingMinimal() { - return paddingMinimalBase[p[scale]]; - } - - var paddingSmallBase = [3, 10, 15]; - int paddingSmall() { - return paddingSmallBase[p[scale]]; - } - - var paddingStandardBase = [8, 20, 30]; - int paddingStandard() { - return paddingStandardBase[p[scale]]; - } - - var paddingLargeBase = [10, 30, 40]; - int paddingLarge() { - return paddingLargeBase[p[scale]]; - } - - var paddingClickTargetBase = gcdOS == "android" ? [10, 40, 100] : [3, 10, 15]; - int paddingClickTarget() { - return paddingClickTargetBase[p[scale]]; - } - - var textSmallPtBase = [8, 12, 16]; - int textSmallPt() { - return textSmallPtBase[t[scale]]; - } - - var textMediumPtBase = [10, 16, 24]; - int textMediumPt() { - return textMediumPtBase[t[scale]]; - } - - var textLargePtBase = [16, 24, 32]; - int textLargePt() { - return textLargePtBase[t[scale]]; - } - - var textSubHeaderPtBase = [12, 18, 26]; - int textSubHeaderPt() { - return textHeaderPtBase[t[scale]]; - } - - var textHeaderPtBase = [16, 24, 32]; - int textHeaderPt() { - return textHeaderPtBase[t[scale]]; - } - - var uiIconSizeSBase = [8, 16, 24]; - int uiIconSizeS() { - return uiIconSizeSBase[p[scale]]; - } - - var uiIconSizeMBase = [24, 32, 48]; - int uiIconSizeM() { - return uiIconSizeMBase[p[scale]]; - } - - var uiIconSizeLBase = [32, 48, 60]; - int uiIconSizeL() { - return uiIconSizeLBase[p[scale]]; - } - - var uiEmojiSizeBase = [24, 32, 48]; - int uiEmojiSize() { - return uiEmojiSizeBase[p[scale]]; - } - - var contactPortraitSizeBase = [60, 72, 84]; - int contactPortraitSize() { - return contactPortraitSizeBase[p[scale]]; - } - - int badgeTextSize() { - return 12; - } - - int statusTextSize() { - return 12; - } - - int chatSize() { - return textMediumPt(); - } - - int tabSize() { - return textMediumPt(); - } -} - -*/ diff --git a/lib/settings.dart b/lib/settings.dart index 7397ce39..a9579723 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -2,10 +2,11 @@ import 'dart:collection'; import 'dart:ui'; import 'dart:core'; +import 'package:cwtch/themes/cwtch.dart'; import 'package:flutter/material.dart'; import 'package:package_info_plus/package_info_plus.dart'; -import 'opaque.dart'; +import 'themes/opaque.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; const TapirGroupsExperiment = "tapir-groups-experiment"; diff --git a/lib/themes/cwtch.dart b/lib/themes/cwtch.dart new file mode 100644 index 00000000..df718ba1 --- /dev/null +++ b/lib/themes/cwtch.dart @@ -0,0 +1,275 @@ +import 'dart:ui'; +import 'dart:core'; + +import 'package:flutter/material.dart'; + +import 'opaque.dart'; + +class OpaqueDark extends OpaqueThemeType { + static final Color darkGreyPurple = Color(0xFF281831); + static final Color deepPurple = Color(0xFF422850); + static final Color mauvePurple = Color(0xFF8E64A5); + static final Color purple = Color(0xFFDFB9DE); + static final Color whitePurple = Color(0xFFE3DFE4); + static final Color softPurple = Color(0xFFFDF3FC); + static final Color pink = Color(0xFFE85DA1); + static final Color hotPink = Color(0xFFD01972); + static final Color lightGrey = Color(0xFF9E9E9E); + static final Color softGreen = Color(0xFFA0FFB0); + static final Color softRed = Color(0xFFFFA0B0); + + String identifier() { + return "dark"; + } + + Color backgroundMainColor() { + return darkGreyPurple; + } + + Color backgroundPaneColor() { + return darkGreyPurple; + } + + Color backgroundHilightElementColor() { + return deepPurple; + } + + Color mainTextColor() { + return whitePurple; + } + + Color altTextColor() { + return mauvePurple; + } + + Color hilightElementTextColor() { + return purple; + } + + Color defaultButtonColor() { + return hotPink; + } + + Color defaultButtonActiveColor() { + return pink; + } + + Color defaultButtonTextColor() { + return whitePurple; + } + + Color defaultButtonDisabledTextColor() { + return darkGreyPurple; + } + + Color textfieldBackgroundColor() { + return deepPurple; + } + + Color textfieldBorderColor() { + return deepPurple; + } + + Color textfieldErrorColor() { + return hotPink; + } + + Color scrollbarDefaultColor() { + return purple; + } + + Color scrollbarActiveColor() { + return hotPink; + } + + Color portraitOnlineBorderColor() { + return whitePurple; + } + + Color portraitOfflineBorderColor() { + return purple; + } + + Color portraitBlockedBorderColor() { + return lightGrey; + } + + Color portraitBlockedTextColor() { + return lightGrey; + } + + Color portraitContactBadgeColor() { + return hotPink; + } + + Color portraitContactBadgeTextColor() { + return whitePurple; + } + + Color portraitProfileBadgeColor() { + return mauvePurple; + } + + Color portraitProfileBadgeTextColor() { + return darkGreyPurple; + } + + Color dropShadowColor() { + return mauvePurple; + } + + Color toolbarIconColor() { + return whitePurple; + } + + Color messageFromMeBackgroundColor() { + return mauvePurple; + } + + Color messageFromMeTextColor() { + return whitePurple; + } + + Color messageFromOtherBackgroundColor() { + return deepPurple; + } + + Color messageFromOtherTextColor() { + return whitePurple; + } +} + +class OpaqueLight extends OpaqueThemeType { + static final Color whitePurple = Color(0xFFFFFDFF); + static final Color softPurple = Color(0xFFFDF3FC); + static final Color purple = Color(0xFFDFB9DE); + static final Color brightPurple = Color(0xFFD1B0E0); + static final Color darkPurple = Color(0xFF350052); + static final Color greyPurple = Color(0xFF775F84); + static final Color pink = Color(0xFFE85DA1); + static final Color hotPink = Color(0xFFD01972); + static final Color lightGrey = Color(0xFFB3B6B3); + static final Color softGreen = Color(0xFFA0FFB0); + static final Color softRed = Color(0xFFFFA0B0); + + String identifier() { + return "light"; + } + + Color backgroundMainColor() { + return whitePurple; + } + + Color backgroundPaneColor() { + return softPurple; + } + + Color backgroundHilightElementColor() { + return softPurple; + } + + Color mainTextColor() { + return darkPurple; + } + + Color altTextColor() { + return purple; + } + + Color hilightElementTextColor() { + return darkPurple; + } + + Color defaultButtonColor() { + return hotPink; + } + + Color defaultButtonActiveColor() { + return pink; + } + + Color defaultButtonTextColor() { + return whitePurple; + } + + Color defaultButtonDisabledColor() { + return lightGrey; + } + + Color textfieldBackgroundColor() { + return purple; + } + + Color textfieldBorderColor() { + return purple; + } + + Color textfieldErrorColor() { + return hotPink; + } + + Color scrollbarDefaultColor() { + return darkPurple; + } + + Color scrollbarActiveColor() { + return hotPink; + } + + Color portraitOnlineBorderColor() { + return greyPurple; + } + + Color portraitOfflineBorderColor() { + return greyPurple; + } + + + Color portraitBlockedBorderColor() { + return lightGrey; + } + + Color portraitBlockedTextColor() { + return lightGrey; + } + + Color portraitContactBadgeColor() { + return hotPink; + } + + Color portraitContactBadgeTextColor() { + return whitePurple; + } + + Color portraitProfileBadgeColor() { + return brightPurple; + } + + Color portraitProfileBadgeTextColor() { + return whitePurple; + } + + Color dropShadowColor() { + return purple; + } + + Color toolbarIconColor() { + return darkPurple; + } + + Color messageFromMeBackgroundColor() { + return brightPurple; + } + + Color messageFromMeTextColor() { + return mainTextColor(); + } + + Color messageFromOtherBackgroundColor() { + return purple; + } + + Color messageFromOtherTextColor() { + return darkPurple; + } +} \ No newline at end of file diff --git a/lib/themes/opaque.dart b/lib/themes/opaque.dart new file mode 100644 index 00000000..a117f41e --- /dev/null +++ b/lib/themes/opaque.dart @@ -0,0 +1,226 @@ +import 'dart:ui'; +import 'dart:core'; + +import 'package:flutter/material.dart'; +import 'package:cwtch/settings.dart'; + +abstract class OpaqueThemeType { + static final Color red = Color(0xFFFF0000); + + String identifier() { + return "dummy"; + } + + Color backgroundMainColor() { + return red; + } + + Color backgroundPaneColor() { + return red; + } + + Color backgroundHilightElementColor() { + return red; + } + + Color mainTextColor() { + return red; + } + + Color altTextColor() { + return red; + } + + Color hilightElementTextColor() { + return red; + } + + Color defaultButtonColor() { + return red; + } + + Color defaultButtonActiveColor() { + return red; + } + + Color defaultButtonTextColor() { + return red; + } + + Color defaultButtonDisabledColor() { + return red; + } + + Color textfieldBackgroundColor() { + return red; + } + + Color textfieldBorderColor() { + return red; + } + + Color textfieldErrorColor() { + return red; + } + + Color scrollbarDefaultColor() { + return red; + } + + Color scrollbarActiveColor() { + return red; + } + + Color portraitOnlineBorderColor() { + return red; + } + + Color portraitOfflineBorderColor() { + return red; + } + + Color portraitBlockedBorderColor() { + return red; + } + + Color portraitBlockedTextColor() { + return red; + } + + Color portraitContactBadgeColor() { + return red; + } + + Color portraitContactBadgeTextColor() { + return red; + } + + Color portraitProfileBadgeColor() { + return red; + } + + Color portraitProfileBadgeTextColor() { + return red; + } + + Color dropShadowColor() { + return red; + } + + Color toolbarIconColor() { + return red; + } + + Color messageFromMeBackgroundColor() { + return red; + } + + Color messageFromMeTextColor() { + return red; + } + + Color messageFromOtherBackgroundColor() { + return red; + } + + Color messageFromOtherTextColor() { + return red; + } + + // ... more to come + + // Sizes + + double contactOnionTextSize() { + return 18; + } +} + + + +ThemeData mkThemeData(Settings opaque) { + return ThemeData( + visualDensity: VisualDensity.adaptivePlatformDensity, + primarySwatch: Colors.red, + primaryIconTheme: IconThemeData( + color: opaque.current().mainTextColor(), + ), + primaryColor: opaque.current().backgroundMainColor(), + canvasColor: opaque.current().backgroundPaneColor(), + backgroundColor: opaque.current().backgroundMainColor(), + highlightColor: opaque.current().hilightElementTextColor(), + iconTheme: IconThemeData( + color: opaque.current().toolbarIconColor(), + ), + cardColor: opaque.current().backgroundMainColor(), + appBarTheme: AppBarTheme( + backgroundColor: opaque.current().backgroundPaneColor(), + iconTheme: IconThemeData( + color: opaque.current().mainTextColor(), + ), + titleTextStyle: TextStyle( + color: opaque.current().mainTextColor(), + ), + actionsIconTheme: IconThemeData( + color: opaque.current().mainTextColor(), + )), + bottomNavigationBarTheme: BottomNavigationBarThemeData(type: BottomNavigationBarType.fixed, backgroundColor: opaque.current().backgroundHilightElementColor()), + 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))), + ), + elevatedButtonTheme: ElevatedButtonThemeData( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.resolveWith((states) => states.contains(MaterialState.disabled) ? opaque.current().defaultButtonDisabledColor() : opaque.current().defaultButtonColor()), + foregroundColor: MaterialStateProperty.all(opaque.current().defaultButtonTextColor()), + overlayColor: MaterialStateProperty.resolveWith((states) => (states.contains(MaterialState.pressed) && states.contains(MaterialState.hovered)) + ? opaque.current().defaultButtonActiveColor() + : states.contains(MaterialState.disabled) + ? opaque.current().defaultButtonDisabledColor() + : null), + enableFeedback: true, + splashFactory: InkRipple.splashFactory, + padding: MaterialStateProperty.all(EdgeInsets.all(20)), + shape: MaterialStateProperty.all(RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18.0), + )), + ), + ), + scrollbarTheme: ScrollbarThemeData( + isAlwaysShown: false, thumbColor: MaterialStateProperty.all(opaque.current().scrollbarActiveColor()), trackColor: MaterialStateProperty.all(opaque.current().scrollbarDefaultColor())), + tabBarTheme: TabBarTheme(indicator: UnderlineTabIndicator(borderSide: BorderSide(color: opaque.current().defaultButtonActiveColor()))), + 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())), + switchTheme: SwitchThemeData( + overlayColor: MaterialStateProperty.all(opaque.current().defaultButtonActiveColor()), + thumbColor: MaterialStateProperty.all(opaque.current().mainTextColor()), + trackColor: MaterialStateProperty.all(opaque.current().dropShadowColor()), + ), + floatingActionButtonTheme: FloatingActionButtonThemeData( + backgroundColor: opaque.current().defaultButtonColor(), + hoverColor: opaque.current().defaultButtonActiveColor(), + enableFeedback: true, + splashColor: opaque.current().defaultButtonActiveColor()), + textSelectionTheme: TextSelectionThemeData( + cursorColor: opaque.current().defaultButtonActiveColor(), selectionColor: opaque.current().defaultButtonActiveColor(), selectionHandleColor: opaque.current().defaultButtonActiveColor()), + ); +} diff --git a/lib/views/addeditprofileview.dart b/lib/views/addeditprofileview.dart index 03084ca2..20a4cec5 100644 --- a/lib/views/addeditprofileview.dart +++ b/lib/views/addeditprofileview.dart @@ -16,7 +16,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import '../cwtch_icons_icons.dart'; import '../errorHandler.dart'; import '../main.dart'; -import '../opaque.dart'; +import '../themes/opaque.dart'; import '../settings.dart'; class AddEditProfileView extends StatefulWidget { diff --git a/lib/widgets/profileimage.dart b/lib/widgets/profileimage.dart index 1516f3e0..7593bc67 100644 --- a/lib/widgets/profileimage.dart +++ b/lib/widgets/profileimage.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:cwtch/opaque.dart'; +import 'package:cwtch/themes/opaque.dart'; import 'package:provider/provider.dart'; import '../settings.dart'; diff --git a/regenerate_opaque_theme.sh b/regenerate_opaque_theme.sh deleted file mode 100755 index e4ff06d7..00000000 --- a/regenerate_opaque_theme.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash - -themes="/home/erinn/go/src/git.openprivacy.ca/openprivacy/opaque/theme" -outfile="./lib/opaque.dart" - -if [ -e "$outfile" ]; then - mv "$outfile" "${outfile}.bak" -fi - -echo "// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT BY HAND AS CHANGES WILL BE OVERRIDDEN." > "$outfile" -echo "// TO EDIT THE THEME, SEE https://git.openprivacy.ca/openprivacy/opaque/" >> "$outfile" -echo "// FOR HOW THIS FILE IS GENERATED, SEE ../regenerate_opaque_theme.sh" >> "$outfile" - -sed 's/import QtQuick 2\.0//g' "${themes}/ThemeType.qml" | \ - sed "s/QtObject ./import 'dart:ui\';\nimport 'dart:core';\nabstract class OpaqueThemeType {\n static final Color red = Color(0xFFFF0000);/g" | \ - sed 's/\(property color\|var\)/Color/g' | \ - sed 's/\(:\| =\) ".*"/(){return red;}/g' >> "$outfile" - -echo -e "\n\n" >> "$outfile" - -sed 's/ThemeType/class CwtchDark extends OpaqueThemeType/g' "${themes}/CwtchDark.qml" | \ - sed 's/readonly property color \(.*\): "#\(\w*\)"/static final Color \1 = Color(0xFF\2);/g' | \ - sed 's/\(\w*\): \(\w*\)/Color \1() { return \2; }/g' >> "$outfile" - -echo -e "\n\n" >> "$outfile" - -sed 's/ThemeType/class CwtchLight extends OpaqueThemeType/g' "${themes}/CwtchLight.qml" | \ - sed 's/readonly property color \(.*\): "#\(\w*\)"/static final Color \1 = Color(0xFF\2);/g' | \ - sed 's/\(\w*\): \(\w*\)/Color \1() { return \2; }/g' >> "$outfile" - -echo -e "\n\n" >> "$outfile" - -sed 's/\(pragma Singleton\|import QtQuick 2\.0\)//g' "${themes}/Theme.qml" | \ - sed 's|//.*$||g' | \ - sed 's/theme\./current./g' | \ - sed 's/property color/property Color/g' | \ - sed 's/readonly property Color \(.*\): \([a-zA-Z0-9._]*\)/Color \1() { return \2(); }/g' | \ - #to preserve int values: #static int \1() { return \2; }/g' | \ - sed 's/readonly property int \(.*\): \(.*\)/int \1() { return \2; }/g' | \ - sed 's/readonly property variant \([a-zA-Z0-9._]*\): \(.*\)$/var \1 = \2;/g' | \ - sed 's/color/Color/g' | \ - sed 's/: \(.+\)/ = \1;/g' | \ - sed 's/property ThemeType \(\w*\): \(.*\)../static final OpaqueThemeType \1 = \2();/g' | \ - sed 's/final OpaqueThemeType theme = .*$/Opaque current() { return dark; }/' | \ - sed 's/^.*themeScaleNew.*$/int scale = 2;\n static final String gcdOS = "linux";/g' | \ - sed 's/gcd.os/gcdOS/g' | \ - sed 's/return \([a-zA-Z]\+\) ;/return \1();/g' | \ - sed 's/return \([a-zA-Z]\+\) + \([a-zA-Z]\+\);/return \1() + \2();/g' | \ - sed 's/Item/class Opaque extends OpaqueThemeType/' | \ - sed 's/current\./current()./g' >> "$outfile" diff --git a/test/buttontextfield_test.dart b/test/buttontextfield_test.dart index 2f750035..55361c2e 100644 --- a/test/buttontextfield_test.dart +++ b/test/buttontextfield_test.dart @@ -6,7 +6,7 @@ // tree, read text, and verify that the values of widget properties are correct. import 'package:flutter/material.dart'; -import 'package:cwtch/opaque.dart'; +import 'package:cwtch/themes/opaque.dart'; import 'package:cwtch/settings.dart'; import 'package:cwtch/widgets/buttontextfield.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/test/cwtchlabel_test.dart b/test/cwtchlabel_test.dart index d0d077a1..7ac0bd19 100644 --- a/test/cwtchlabel_test.dart +++ b/test/cwtchlabel_test.dart @@ -6,7 +6,7 @@ // tree, read text, and verify that the values of widget properties are correct. import 'package:flutter/material.dart'; -import 'package:cwtch/opaque.dart'; +import 'package:cwtch/themes/opaque.dart'; import 'package:cwtch/settings.dart'; import 'package:cwtch/widgets/cwtchlabel.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/test/profileimage_test.dart b/test/profileimage_test.dart index 9a841f9b..cf582241 100644 --- a/test/profileimage_test.dart +++ b/test/profileimage_test.dart @@ -6,7 +6,7 @@ // tree, read text, and verify that the values of widget properties are correct. import 'package:flutter/material.dart'; -import 'package:cwtch/opaque.dart'; +import 'package:cwtch/themes/opaque.dart'; import 'package:cwtch/settings.dart'; import 'package:cwtch/widgets/profileimage.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/test/textfield_test.dart b/test/textfield_test.dart index 9a0f0525..97d65844 100644 --- a/test/textfield_test.dart +++ b/test/textfield_test.dart @@ -6,7 +6,7 @@ // tree, read text, and verify that the values of widget properties are correct. import 'package:flutter/material.dart'; -import 'package:cwtch/opaque.dart'; +import 'package:cwtch/themes/opaque.dart'; import 'package:cwtch/settings.dart'; import 'package:cwtch/widgets/textfield.dart'; import 'package:flutter_test/flutter_test.dart'; From 194ade9aa681aa94de362601faa13a62ca94d7e2 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Wed, 8 Dec 2021 21:40:40 -0800 Subject: [PATCH 04/20] refactor light and dark onto existing new color scheme; fix message editor top strip color; tweak color field semantics --- lib/themes/cwtch.dart | 161 ++++++++++++++++++------------ lib/themes/opaque.dart | 28 ++++-- lib/views/addcontactview.dart | 4 +- lib/views/addeditprofileview.dart | 2 +- lib/views/addeditservers.dart | 22 ++-- lib/views/contactsview.dart | 2 +- lib/views/groupsettingsview.dart | 4 +- lib/views/messageview.dart | 6 +- lib/widgets/messagelist.dart | 3 +- lib/widgets/profileimage.dart | 2 +- lib/widgets/textfield.dart | 8 +- test/textfield_test.dart | 4 +- 12 files changed, 150 insertions(+), 96 deletions(-) diff --git a/lib/themes/cwtch.dart b/lib/themes/cwtch.dart index df718ba1..6c66a8f4 100644 --- a/lib/themes/cwtch.dart +++ b/lib/themes/cwtch.dart @@ -5,29 +5,45 @@ import 'package:flutter/material.dart'; import 'opaque.dart'; +final Color darkGreyPurple = Color(0xFF281831); +final Color deepPurple = Color(0xFF422850); +final Color mauvePurple = Color(0xFF8E64A5); +final Color whiteishPurple = Color(0xFFE3DFE4); +final Color lightGrey = Color(0xFF9E9E9E); +final Color softGreen = Color(0xFFA0FFB0); +final Color softRed = Color(0xFFFFA0B0); + +final Color whitePurple = Color(0xFFFFFDFF); +final Color softPurple = Color(0xFFFDF3FC); +final Color purple = Color(0xFFDFB9DE); +final Color brightPurple = Color(0xFFD1B0E0); // not in new: portrait badge color +final Color darkPurple = Color(0xFF350052); +final Color greyPurple = Color(0xFF775F84); // not in new: portrait borders +final Color pink = Color(0xFFE85DA1); // not in new: active button color +final Color hotPink = Color(0xFFD20070); // Color(0xFFD01972); +final Color softGrey = Color(0xFFB3B6B3); // not in new theme: blocked +//static final Color softGreen = Color(0xFFA0FFB0); +//static final Color softRed = Color(0xFFFFA0B0); + class OpaqueDark extends OpaqueThemeType { - static final Color darkGreyPurple = Color(0xFF281831); - static final Color deepPurple = Color(0xFF422850); - static final Color mauvePurple = Color(0xFF8E64A5); - static final Color purple = Color(0xFFDFB9DE); - static final Color whitePurple = Color(0xFFE3DFE4); - static final Color softPurple = Color(0xFFFDF3FC); - static final Color pink = Color(0xFFE85DA1); - static final Color hotPink = Color(0xFFD01972); - static final Color lightGrey = Color(0xFF9E9E9E); - static final Color softGreen = Color(0xFFA0FFB0); - static final Color softRed = Color(0xFFFFA0B0); + static final Color background = darkGreyPurple; + static final Color header = darkGreyPurple; + static final Color userBubble = mauvePurple; + static final Color peerBubble = deepPurple; + static final Color font = whiteishPurple; + static final Color settings = whiteishPurple; + static final Color accent = hotPink; String identifier() { - return "dark"; + return mode_dark; } Color backgroundMainColor() { - return darkGreyPurple; + return background; // darkGreyPurple; } Color backgroundPaneColor() { - return darkGreyPurple; + return header; //darkGreyPurple; } Color backgroundHilightElementColor() { @@ -35,19 +51,19 @@ class OpaqueDark extends OpaqueThemeType { } Color mainTextColor() { - return whitePurple; + return font; //whiteishPurple; } - Color altTextColor() { + Color sendHintTextColor() { return mauvePurple; } - Color hilightElementTextColor() { + Color hilightElementColor() { return purple; } Color defaultButtonColor() { - return hotPink; + return accent; //hotPink; } Color defaultButtonActiveColor() { @@ -55,7 +71,11 @@ class OpaqueDark extends OpaqueThemeType { } Color defaultButtonTextColor() { - return whitePurple; + return whiteishPurple; + } + + Color defaultButtonDisabledColor() { + return lightGrey; } Color defaultButtonDisabledTextColor() { @@ -70,6 +90,10 @@ class OpaqueDark extends OpaqueThemeType { return deepPurple; } + Color textfieldHintColor() { + return mainTextColor(); //TODO pick + } + Color textfieldErrorColor() { return hotPink; } @@ -78,12 +102,12 @@ class OpaqueDark extends OpaqueThemeType { return purple; } - Color scrollbarActiveColor() { - return hotPink; + Color portraitBackgroundColor() { + return deepPurple; } Color portraitOnlineBorderColor() { - return whitePurple; + return whiteishPurple; } Color portraitOfflineBorderColor() { @@ -103,7 +127,7 @@ class OpaqueDark extends OpaqueThemeType { } Color portraitContactBadgeTextColor() { - return whitePurple; + return whiteishPurple; } Color portraitProfileBadgeColor() { @@ -119,81 +143,86 @@ class OpaqueDark extends OpaqueThemeType { } Color toolbarIconColor() { - return whitePurple; + return settings; //whiteishPurple; } Color messageFromMeBackgroundColor() { - return mauvePurple; + return userBubble; // mauvePurple; } Color messageFromMeTextColor() { - return whitePurple; + return font; //whiteishPurple; } Color messageFromOtherBackgroundColor() { - return deepPurple; + return peerBubble; //deepPurple; } Color messageFromOtherTextColor() { - return whitePurple; + return font; //whiteishPurple; } } class OpaqueLight extends OpaqueThemeType { - static final Color whitePurple = Color(0xFFFFFDFF); - static final Color softPurple = Color(0xFFFDF3FC); - static final Color purple = Color(0xFFDFB9DE); - static final Color brightPurple = Color(0xFFD1B0E0); - static final Color darkPurple = Color(0xFF350052); - static final Color greyPurple = Color(0xFF775F84); - static final Color pink = Color(0xFFE85DA1); - static final Color hotPink = Color(0xFFD01972); - static final Color lightGrey = Color(0xFFB3B6B3); - static final Color softGreen = Color(0xFFA0FFB0); - static final Color softRed = Color(0xFFFFA0B0); + static final Color background = whitePurple; + static final Color header = softPurple; + static final Color userBubble = purple; + static final Color peerBubble = softPurple; + static final Color font = darkPurple; + static final Color settings = darkPurple; + static final Color accent = hotPink; + String identifier() { - return "light"; + return mode_light; } + // Main screen background color (message pane, item rows) Color backgroundMainColor() { - return whitePurple; + return background; //whitePurple; } + // Top pane ane pane colors (settings) Color backgroundPaneColor() { - return softPurple; + return header; //softPurple; } + // Selected row color Color backgroundHilightElementColor() { + // Todo: lighten? cant + // hm... in light its the top pane color. but in dark its unique return softPurple; } + // Main text color Color mainTextColor() { - return darkPurple; + return settings; } - Color altTextColor() { + // Faded text color for suggestions in textfields + Color sendHintTextColor() { return purple; } - Color hilightElementTextColor() { - return darkPurple; + // pressed row, offline heart + Color hilightElementColor() { + return purple; //darkPurple; // todo shouldn't be this, too dark, makes font unreadable } Color defaultButtonColor() { - return hotPink; + return accent; // hotPink; } Color defaultButtonActiveColor() { - return pink; + return pink; // todo: lighten in light, darken in dark } Color defaultButtonTextColor() { - return whitePurple; + return whitePurple; // ? } Color defaultButtonDisabledColor() { - return lightGrey; + return softGrey; } Color textfieldBackgroundColor() { @@ -203,17 +232,22 @@ class OpaqueLight extends OpaqueThemeType { Color textfieldBorderColor() { return purple; } + + Color textfieldHintColor() { + return font; //TODO pick + } Color textfieldErrorColor() { return hotPink; } + // todo button Color scrollbarDefaultColor() { - return darkPurple; + return accent; } - Color scrollbarActiveColor() { - return hotPink; + Color portraitBackgroundColor() { + return softPurple; } Color portraitOnlineBorderColor() { @@ -224,27 +258,28 @@ class OpaqueLight extends OpaqueThemeType { return greyPurple; } - Color portraitBlockedBorderColor() { - return lightGrey; + return softGrey; } Color portraitBlockedTextColor() { - return lightGrey; + return softGrey; } Color portraitContactBadgeColor() { - return hotPink; + return accent; } Color portraitContactBadgeTextColor() { - return whitePurple; + return whitePurple; // todo button color } + // TODO del Color portraitProfileBadgeColor() { return brightPurple; } + // TODO del Color portraitProfileBadgeTextColor() { return whitePurple; } @@ -254,22 +289,22 @@ class OpaqueLight extends OpaqueThemeType { } Color toolbarIconColor() { - return darkPurple; + return settings; //darkPurple; } Color messageFromMeBackgroundColor() { - return brightPurple; + return userBubble; //brightPurple; } Color messageFromMeTextColor() { - return mainTextColor(); + return font; //mainTextColor(); } Color messageFromOtherBackgroundColor() { - return purple; + return peerBubble; //purple; } Color messageFromOtherTextColor() { - return darkPurple; + return font; //darkPurple; } } \ No newline at end of file diff --git a/lib/themes/opaque.dart b/lib/themes/opaque.dart index a117f41e..40058392 100644 --- a/lib/themes/opaque.dart +++ b/lib/themes/opaque.dart @@ -4,6 +4,9 @@ import 'dart:core'; import 'package:flutter/material.dart'; import 'package:cwtch/settings.dart'; +const mode_light = "light"; +const mode_dark = "dark"; + abstract class OpaqueThemeType { static final Color red = Color(0xFFFF0000); @@ -11,14 +14,17 @@ abstract class OpaqueThemeType { return "dummy"; } + // Main screen background color (message pane, item rows) Color backgroundMainColor() { return red; } + // Top pane ane pane colors (settings) Color backgroundPaneColor() { return red; } + // Selected Row Color backgroundHilightElementColor() { return red; } @@ -27,11 +33,14 @@ abstract class OpaqueThemeType { return red; } - Color altTextColor() { + // Faded text color for suggestions in textfields + // Todo: implement way more places + Color sendHintTextColor() { return red; } - Color hilightElementTextColor() { + // pressed row, offline heart + Color hilightElementColor() { return red; } @@ -59,6 +68,10 @@ abstract class OpaqueThemeType { return red; } + Color textfieldHintColor() { + return red; + } + Color textfieldErrorColor() { return red; } @@ -67,7 +80,7 @@ abstract class OpaqueThemeType { return red; } - Color scrollbarActiveColor() { + Color portraitBackgroundColor() { return red; } @@ -103,6 +116,8 @@ abstract class OpaqueThemeType { return red; } + // dropshaddpow + // todo: probably should not be reply icon color in messagerow Color dropShadowColor() { return red; } @@ -148,7 +163,7 @@ ThemeData mkThemeData(Settings opaque) { primaryColor: opaque.current().backgroundMainColor(), canvasColor: opaque.current().backgroundPaneColor(), backgroundColor: opaque.current().backgroundMainColor(), - highlightColor: opaque.current().hilightElementTextColor(), + highlightColor: opaque.current().hilightElementColor(), iconTheme: IconThemeData( color: opaque.current().toolbarIconColor(), ), @@ -164,7 +179,7 @@ ThemeData mkThemeData(Settings opaque) { actionsIconTheme: IconThemeData( color: opaque.current().mainTextColor(), )), - bottomNavigationBarTheme: BottomNavigationBarThemeData(type: BottomNavigationBarType.fixed, backgroundColor: opaque.current().backgroundHilightElementColor()), + //bottomNavigationBarTheme: BottomNavigationBarThemeData(type: BottomNavigationBarType.fixed, backgroundColor: opaque.current().backgroundHilightElementColor()), // Can't determine current use textButtonTheme: TextButtonThemeData( style: ButtonStyle( backgroundColor: MaterialStateProperty.all(opaque.current().defaultButtonColor()), @@ -172,6 +187,7 @@ ThemeData mkThemeData(Settings opaque) { overlayColor: MaterialStateProperty.all(opaque.current().defaultButtonActiveColor()), padding: MaterialStateProperty.all(EdgeInsets.all(20))), ), + hintColor: opaque.current().textfieldHintColor(), elevatedButtonTheme: ElevatedButtonThemeData( style: ButtonStyle( backgroundColor: MaterialStateProperty.resolveWith((states) => states.contains(MaterialState.disabled) ? opaque.current().defaultButtonDisabledColor() : opaque.current().defaultButtonColor()), @@ -190,7 +206,7 @@ ThemeData mkThemeData(Settings opaque) { ), ), scrollbarTheme: ScrollbarThemeData( - isAlwaysShown: false, thumbColor: MaterialStateProperty.all(opaque.current().scrollbarActiveColor()), trackColor: MaterialStateProperty.all(opaque.current().scrollbarDefaultColor())), + isAlwaysShown: false, thumbColor: MaterialStateProperty.all(opaque.current().scrollbarDefaultColor())), tabBarTheme: TabBarTheme(indicator: UnderlineTabIndicator(borderSide: BorderSide(color: opaque.current().defaultButtonActiveColor()))), dialogTheme: DialogTheme( backgroundColor: opaque.current().backgroundPaneColor(), diff --git a/lib/views/addcontactview.dart b/lib/views/addcontactview.dart index 8485058f..c073f0f5 100644 --- a/lib/views/addcontactview.dart +++ b/lib/views/addcontactview.dart @@ -163,7 +163,7 @@ class _AddContactViewState extends State { } }); }, - labelText: '', + hintText: '', ) ]))); } @@ -215,7 +215,7 @@ class _AddContactViewState extends State { ), CwtchTextField( controller: ctrlrGroupName, - labelText: AppLocalizations.of(context)!.groupNameLabel, + hintText: AppLocalizations.of(context)!.groupNameLabel, onChanged: (newValue) {}, validator: (value) {}, ), diff --git a/lib/views/addeditprofileview.dart b/lib/views/addeditprofileview.dart index 20a4cec5..e92b9c7e 100644 --- a/lib/views/addeditprofileview.dart +++ b/lib/views/addeditprofileview.dart @@ -104,7 +104,7 @@ class _AddEditProfileViewState extends State { CwtchTextField( controller: ctrlrNick, autofocus: false, - labelText: AppLocalizations.of(context)!.yourDisplayName, + hintText: AppLocalizations.of(context)!.yourDisplayName, validator: (value) { if (value.isEmpty) { return AppLocalizations.of(context)!.displayNameTooltip; diff --git a/lib/views/addeditservers.dart b/lib/views/addeditservers.dart index aec67bfe..011903c5 100644 --- a/lib/views/addeditservers.dart +++ b/lib/views/addeditservers.dart @@ -117,7 +117,7 @@ class _AddEditServerViewState extends State { Visibility( visible: serverInfoState.onion.isNotEmpty, child: SwitchListTile( - title: Text(AppLocalizations.of(context)!.serverEnabled, style: TextStyle(color: settings.current().mainTextColor())), + title: Text(AppLocalizations.of(context)!.serverEnabled, style: TextStyle(color: settings.current().mainTextColor)), subtitle: Text(AppLocalizations.of(context)!.serverEnabledDescription), value: serverInfoState.running, onChanged: (bool value) { @@ -128,14 +128,14 @@ class _AddEditServerViewState extends State { Provider.of(context, listen: false).cwtch.StopServer(serverInfoState.onion); } }, - activeTrackColor: settings.theme.defaultButtonActiveColor(), - inactiveTrackColor: settings.theme.defaultButtonDisabledColor(), - secondary: Icon(CwtchIcons.negative_heart_24px, color: settings.current().mainTextColor()), + activeTrackColor: settings.theme.defaultButtonActiveColor, + inactiveTrackColor: settings.theme.defaultButtonDisabledColor, + secondary: Icon(CwtchIcons.negative_heart_24px, color: settings.current().mainTextColor), )), // Auto start SwitchListTile( - title: Text(AppLocalizations.of(context)!.serverAutostartLabel, style: TextStyle(color: settings.current().mainTextColor())), + title: Text(AppLocalizations.of(context)!.serverAutostartLabel, style: TextStyle(color: settings.current().mainTextColor)), subtitle: Text(AppLocalizations.of(context)!.serverAutostartDescription), value: serverInfoState.autoStart, onChanged: (bool value) { @@ -145,9 +145,9 @@ class _AddEditServerViewState extends State { Provider.of(context, listen: false).cwtch.SetServerAttribute(serverInfoState.onion, "autostart", value ? "true" : "false"); } }, - activeTrackColor: settings.theme.defaultButtonActiveColor(), - inactiveTrackColor: settings.theme.defaultButtonDisabledColor(), - secondary: Icon(CwtchIcons.favorite_24dp, color: settings.current().mainTextColor()), + activeTrackColor: settings.theme.defaultButtonActiveColor, + inactiveTrackColor: settings.theme.defaultButtonDisabledColor, + secondary: Icon(CwtchIcons.favorite_24dp, color: settings.current().mainTextColor), ), // metrics @@ -190,13 +190,13 @@ class _AddEditServerViewState extends State { ), Checkbox( value: usePassword, - fillColor: MaterialStateProperty.all(settings.current().defaultButtonColor()), - activeColor: settings.current().defaultButtonActiveColor(), + fillColor: MaterialStateProperty.all(settings.current().defaultButtonColor), + activeColor: settings.current().defaultButtonActiveColor, onChanged: _handleSwitchPassword, ), Text( AppLocalizations.of(context)!.radioUsePassword, - style: TextStyle(color: settings.current().mainTextColor()), + style: TextStyle(color: settings.current().mainTextColor), ), SizedBox( height: 20, diff --git a/lib/views/contactsview.dart b/lib/views/contactsview.dart index e6e13c19..87c6cee6 100644 --- a/lib/views/contactsview.dart +++ b/lib/views/contactsview.dart @@ -139,7 +139,7 @@ class _ContactsViewState extends State { Widget _buildFilterable() { Widget txtfield = CwtchTextField( controller: ctrlrFilter, - labelText: AppLocalizations.of(context)!.search, + hintText: AppLocalizations.of(context)!.search, onChanged: (newVal) { Provider.of(context, listen: false).filter = newVal; }, diff --git a/lib/views/groupsettingsview.dart b/lib/views/groupsettingsview.dart index 463a99b2..6407c4ef 100644 --- a/lib/views/groupsettingsview.dart +++ b/lib/views/groupsettingsview.dart @@ -101,7 +101,7 @@ class _GroupSettingsViewState extends State { ), CwtchTextField( controller: ctrlrGroupAddr, - labelText: '', + hintText: '', validator: (value) {}, ) ]), @@ -116,7 +116,7 @@ class _GroupSettingsViewState extends State { CwtchTextField( controller: TextEditingController(text: Provider.of(context, listen: false).server), validator: (value) {}, - labelText: '', + hintText: '', ) ]), diff --git a/lib/views/messageview.dart b/lib/views/messageview.dart index 539bebfb..231170fe 100644 --- a/lib/views/messageview.dart +++ b/lib/views/messageview.dart @@ -104,6 +104,7 @@ class _MessageViewState extends State { return WillPopScope( onWillPop: _onWillPop, child: Scaffold( + backgroundColor: Provider.of(context).theme.backgroundMainColor(), floatingActionButton: appState.unreadMessagesBelow ? FloatingActionButton( child: Icon(Icons.arrow_downward), @@ -253,7 +254,7 @@ class _MessageViewState extends State { enabled: !isOffline, decoration: InputDecoration( hintText: isOffline ? "" : AppLocalizations.of(context)!.placeholderEnterMessage, - hintStyle: TextStyle(color: Provider.of(context).theme.altTextColor()), + hintStyle: TextStyle(color: Provider.of(context).theme.sendHintTextColor()), enabledBorder: InputBorder.none, focusedBorder: InputBorder.none, enabled: true, @@ -313,7 +314,8 @@ class _MessageViewState extends State { children = [composeBox]; } - return Column(mainAxisSize: MainAxisSize.min, children: children); + return Container( + color: Provider.of(context).theme.backgroundMainColor(), child: Column(mainAxisSize: MainAxisSize.min, children: children)); } // Send the message if enter is pressed without the shift key... diff --git a/lib/widgets/messagelist.dart b/lib/widgets/messagelist.dart index 365a75fc..f56f9c66 100644 --- a/lib/widgets/messagelist.dart +++ b/lib/widgets/messagelist.dart @@ -35,6 +35,7 @@ class _MessageListState extends State { return RepaintBoundary( child: Container( + color: Provider.of(context).theme.backgroundMainColor(), child: Column(children: [ Visibility( visible: showMessageWarning, @@ -65,7 +66,7 @@ class _MessageListState extends State { fit: BoxFit.scaleDown, alignment: Alignment.center, image: AssetImage("assets/core/negative_heart_512px.png"), - colorFilter: ColorFilter.mode(Provider.of(context).theme.hilightElementTextColor(), BlendMode.srcIn))), + colorFilter: ColorFilter.mode(Provider.of(context).theme.hilightElementColor(), BlendMode.srcIn))), // Don't load messages for syncing server... child: loadMessages ? ScrollablePositionedList.builder( diff --git a/lib/widgets/profileimage.dart b/lib/widgets/profileimage.dart index 7593bc67..00001370 100644 --- a/lib/widgets/profileimage.dart +++ b/lib/widgets/profileimage.dart @@ -32,7 +32,7 @@ class _ProfileImageState extends State { ? BlendMode.softLight : BlendMode.darken : BlendMode.srcOut, - color: Provider.of(context).theme.backgroundHilightElementColor(), + color: Provider.of(context).theme.portraitBackgroundColor(), isAntiAlias: true, width: widget.diameter, height: widget.diameter, diff --git a/lib/widgets/textfield.dart b/lib/widgets/textfield.dart index 64b4f020..f3803391 100644 --- a/lib/widgets/textfield.dart +++ b/lib/widgets/textfield.dart @@ -7,9 +7,9 @@ doNothing(String x) {} // Provides a styled Text Field for use in Form Widgets. // Callers must provide a text controller, label helper text and a validator. class CwtchTextField extends StatefulWidget { - CwtchTextField({required this.controller, required this.labelText, this.validator, this.autofocus = false, this.onChanged = doNothing}); + CwtchTextField({required this.controller, required this.hintText, this.validator, this.autofocus = false, this.onChanged = doNothing}); final TextEditingController controller; - final String labelText; + final String hintText; final FormFieldValidator? validator; final Function(String) onChanged; final bool autofocus; @@ -42,12 +42,12 @@ class _CwtchTextFieldState extends State { enableIMEPersonalizedLearning: false, focusNode: _focusNode, decoration: InputDecoration( - labelText: widget.labelText, - labelStyle: TextStyle(color: theme.current().mainTextColor(), backgroundColor: theme.current().textfieldBackgroundColor()), + hintText: widget.hintText, floatingLabelBehavior: FloatingLabelBehavior.never, filled: true, focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor(), width: 3.0)), focusedErrorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor(), width: 3.0)), + errorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor(), width: 3.0)), errorStyle: TextStyle( color: theme.current().textfieldErrorColor(), diff --git a/test/textfield_test.dart b/test/textfield_test.dart index 97d65844..a133cb1e 100644 --- a/test/textfield_test.dart +++ b/test/textfield_test.dart @@ -27,7 +27,7 @@ void main() { tester.binding.window.physicalSizeTestValue = Size(800, 300); final TextEditingController ctrlr1 = TextEditingController(); - Widget testWidget = CwtchTextField(controller: ctrlr1, validator: (value) { }, labelText: '',); + Widget testWidget = CwtchTextField(controller: ctrlr1, validator: (value) { }, hintText: '',); Widget testHarness = MultiProvider( providers:[getSettingsEnglishDark()], @@ -69,7 +69,7 @@ void main() { Widget testWidget = CwtchTextField( controller: ctrlr1, - labelText: strLabel1, + hintText: strLabel1, validator: (value) { if (value == null || value == "") return strFail1; final number = num.tryParse(value); From 53e79f5b9d496d3a5d8aa7557affeec41f5097cb Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Thu, 9 Dec 2021 20:22:55 -0800 Subject: [PATCH 05/20] refactor themes from methods to get fields; add theme selector; add neon1 --- lib/main.dart | 2 +- lib/settings.dart | 19 +- lib/themes/cwtch.dart | 342 +++++----------------- lib/themes/neon1.dart | 126 ++++++++ lib/themes/opaque.dart | 284 ++++++++---------- lib/views/addeditprofileview.dart | 8 +- lib/views/addeditservers.dart | 1 + lib/views/contactsview.dart | 4 +- lib/views/globalsettingsview.dart | 104 ++++--- lib/views/messageview.dart | 18 +- lib/views/peersettingsview.dart | 12 +- lib/views/profilemgrview.dart | 8 +- lib/views/serversview.dart | 2 +- lib/views/splashView.dart | 2 +- lib/widgets/buttontextfield.dart | 20 +- lib/widgets/contactrow.dart | 26 +- lib/widgets/cwtchlabel.dart | 2 +- lib/widgets/filebubble.dart | 30 +- lib/widgets/invitationbubble.dart | 14 +- lib/widgets/messagebubble.dart | 12 +- lib/widgets/messagebubbledecorations.dart | 8 +- lib/widgets/messagelist.dart | 8 +- lib/widgets/messagerow.dart | 15 +- lib/widgets/passwordfield.dart | 20 +- lib/widgets/profileimage.dart | 4 +- lib/widgets/profilerow.dart | 8 +- lib/widgets/quotedmessage.dart | 12 +- lib/widgets/serverrow.dart | 10 +- lib/widgets/textfield.dart | 12 +- lib/widgets/tor_icon.dart | 2 +- test/profileimage_test.dart | 6 +- 31 files changed, 525 insertions(+), 616 deletions(-) create mode 100644 lib/themes/neon1.dart diff --git a/lib/main.dart b/lib/main.dart index 64557091..3c3f27bd 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -25,7 +25,7 @@ import 'dart:io' show Platform, exit; import 'themes/opaque.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -var globalSettings = Settings(Locale("en", ''), OpaqueDark()); +var globalSettings = Settings(Locale("en", ''), CwtchDark()); var globalErrorHandler = ErrorHandler(); var globalTorStatus = TorStatus(); var globalAppState = AppState(); diff --git a/lib/settings.dart b/lib/settings.dart index a9579723..30c6a59d 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -37,15 +37,9 @@ class Settings extends ChangeNotifier { bool blockUnknownConnections = false; bool streamerMode = false; - /// Set the dark theme. - void setDark() { - theme = OpaqueDark(); - notifyListeners(); - } - /// Set the Light theme. - void setLight() { - theme = OpaqueLight(); + void setTheme(String themeId, String mode) { + theme = getTheme(themeId, mode); notifyListeners(); } @@ -70,11 +64,12 @@ class Settings extends ChangeNotifier { /// be sent to the function and new settings will be instantiated based on the contents. handleUpdate(dynamic settings) { // Set Theme and notify listeners - if (settings["Theme"] == "light") { + this.setTheme(settings["Theme"], settings["ThemeMode"] ?? mode_dark); + /*if (settings["Theme"] == "light") { this.setLight(); } else { this.setDark(); - } + }*/ // Set Locale and notify listeners switchLocale(Locale(settings["Locale"])); @@ -230,11 +225,11 @@ class Settings extends ChangeNotifier { /// Convert this Settings object to a JSON representation for serialization on the /// event bus. dynamic asJson() { - var themeString = theme.identifier(); return { "Locale": this.locale.languageCode, - "Theme": themeString, + "Theme": theme.theme, + "ThemeMode": theme.mode, "PreviousPid": -1, "BlockUnknownConnections": blockUnknownConnections, "StreamerMode": streamerMode, diff --git a/lib/themes/cwtch.dart b/lib/themes/cwtch.dart index 6c66a8f4..8d904c36 100644 --- a/lib/themes/cwtch.dart +++ b/lib/themes/cwtch.dart @@ -5,6 +5,9 @@ import 'package:flutter/material.dart'; import 'opaque.dart'; +final cwtch_name = "Cwtch"; // todo translate +final cwtch_theme = "cwtch"; + final Color darkGreyPurple = Color(0xFF281831); final Color deepPurple = Color(0xFF422850); final Color mauvePurple = Color(0xFF8E64A5); @@ -25,7 +28,15 @@ final Color softGrey = Color(0xFFB3B6B3); // not in new theme: blocked //static final Color softGreen = Color(0xFFA0FFB0); //static final Color softRed = Color(0xFFFFA0B0); -class OpaqueDark extends OpaqueThemeType { +OpaqueThemeType GetCwtchTheme(String mode) { + if (mode == mode_dark) { + return CwtchDark(); + } else { + return CwtchLight(); + } +} + +class CwtchDark extends OpaqueThemeType { static final Color background = darkGreyPurple; static final Color header = darkGreyPurple; static final Color userBubble = mauvePurple; @@ -34,136 +45,44 @@ class OpaqueDark extends OpaqueThemeType { static final Color settings = whiteishPurple; static final Color accent = hotPink; - String identifier() { - return mode_dark; - } + get name => cwtch_name; + get theme => cwtch_theme; + get mode => mode_dark; - Color backgroundMainColor() { - return background; // darkGreyPurple; - } - - Color backgroundPaneColor() { - return header; //darkGreyPurple; - } - - Color backgroundHilightElementColor() { - return deepPurple; - } - - Color mainTextColor() { - return font; //whiteishPurple; - } - - Color sendHintTextColor() { - return mauvePurple; - } - - Color hilightElementColor() { - return purple; - } - - Color defaultButtonColor() { - return accent; //hotPink; - } - - Color defaultButtonActiveColor() { - return pink; - } - - Color defaultButtonTextColor() { - return whiteishPurple; - } - - Color defaultButtonDisabledColor() { - return lightGrey; - } - - Color defaultButtonDisabledTextColor() { - return darkGreyPurple; - } - - Color textfieldBackgroundColor() { - return deepPurple; - } - - Color textfieldBorderColor() { - return deepPurple; - } - - Color textfieldHintColor() { - return mainTextColor(); //TODO pick - } - - Color textfieldErrorColor() { - return hotPink; - } - - Color scrollbarDefaultColor() { - return purple; - } - - Color portraitBackgroundColor() { - return deepPurple; - } - - Color portraitOnlineBorderColor() { - return whiteishPurple; - } - - Color portraitOfflineBorderColor() { - return purple; - } - - Color portraitBlockedBorderColor() { - return lightGrey; - } - - Color portraitBlockedTextColor() { - return lightGrey; - } - - Color portraitContactBadgeColor() { - return hotPink; - } - - Color portraitContactBadgeTextColor() { - return whiteishPurple; - } - - Color portraitProfileBadgeColor() { - return mauvePurple; - } - - Color portraitProfileBadgeTextColor() { - return darkGreyPurple; - } - - Color dropShadowColor() { - return mauvePurple; - } - - Color toolbarIconColor() { - return settings; //whiteishPurple; - } - - Color messageFromMeBackgroundColor() { - return userBubble; // mauvePurple; - } - - Color messageFromMeTextColor() { - return font; //whiteishPurple; - } - - Color messageFromOtherBackgroundColor() { - return peerBubble; //deepPurple; - } - - Color messageFromOtherTextColor() { - return font; //whiteishPurple; - } + get backgroundMainColor => background; // darkGreyPurple; + get backgroundPaneColor => header; //darkGreyPurple; + get backgroundHilightElementColor => deepPurple; + get mainTextColor => font; //whiteishPurple; + get sendHintTextColor => mauvePurple; + get hilightElementColor => purple; + get defaultButtonColor => accent; //hotPink; + get defaultButtonActiveColor => pink; + get defaultButtonTextColor => whiteishPurple; + get defaultButtonDisabledColor => lightGrey; + get defaultButtonDisabledTextColor => darkGreyPurple; + get textfieldBackgroundColor => deepPurple; + get textfieldBorderColor => deepPurple; + get textfieldHintColor => mainTextColor; //TODO pick + get textfieldErrorColor => hotPink; + get scrollbarDefaultColor => purple; + get portraitBackgroundColor => deepPurple; + get portraitOnlineBorderColor => whiteishPurple; + get portraitOfflineBorderColor => purple; + get portraitBlockedBorderColor => lightGrey; + get portraitBlockedTextColor => lightGrey; + get portraitContactBadgeColor => hotPink; + get portraitContactBadgeTextColor => whiteishPurple; + get portraitProfileBadgeColor => mauvePurple; + get portraitProfileBadgeTextColor => darkGreyPurple; + get dropShadowColor => mauvePurple; + get toolbarIconColor => settings; //whiteishPurple; + get messageFromMeBackgroundColor => userBubble; // mauvePurple; + get messageFromMeTextColor => font; //whiteishPurple; + get messageFromOtherBackgroundColor => peerBubble; //deepPurple; + get messageFromOtherTextColor => font; //whiteishPurple; } -class OpaqueLight extends OpaqueThemeType { +class CwtchLight extends OpaqueThemeType { static final Color background = whitePurple; static final Color header = softPurple; static final Color userBubble = purple; @@ -172,139 +91,38 @@ class OpaqueLight extends OpaqueThemeType { static final Color settings = darkPurple; static final Color accent = hotPink; + get name => cwtch_name; + get theme => cwtch_theme; + get mode => mode_light; - String identifier() { - return mode_light; - } - - // Main screen background color (message pane, item rows) - Color backgroundMainColor() { - return background; //whitePurple; - } - - // Top pane ane pane colors (settings) - Color backgroundPaneColor() { - return header; //softPurple; - } - - // Selected row color - Color backgroundHilightElementColor() { - // Todo: lighten? cant - // hm... in light its the top pane color. but in dark its unique - return softPurple; - } - - // Main text color - Color mainTextColor() { - return settings; - } - - // Faded text color for suggestions in textfields - Color sendHintTextColor() { - return purple; - } - - // pressed row, offline heart - Color hilightElementColor() { - return purple; //darkPurple; // todo shouldn't be this, too dark, makes font unreadable - } - - Color defaultButtonColor() { - return accent; // hotPink; - } - - Color defaultButtonActiveColor() { - return pink; // todo: lighten in light, darken in dark - } - - Color defaultButtonTextColor() { - return whitePurple; // ? - } - - Color defaultButtonDisabledColor() { - return softGrey; - } - - Color textfieldBackgroundColor() { - return purple; - } - - Color textfieldBorderColor() { - return purple; - } - - Color textfieldHintColor() { - return font; //TODO pick - } - - Color textfieldErrorColor() { - return hotPink; - } - - // todo button - Color scrollbarDefaultColor() { - return accent; - } - - Color portraitBackgroundColor() { - return softPurple; - } - - Color portraitOnlineBorderColor() { - return greyPurple; - } - - Color portraitOfflineBorderColor() { - return greyPurple; - } - - Color portraitBlockedBorderColor() { - return softGrey; - } - - Color portraitBlockedTextColor() { - return softGrey; - } - - Color portraitContactBadgeColor() { - return accent; - } - - Color portraitContactBadgeTextColor() { - return whitePurple; // todo button color - } - - // TODO del - Color portraitProfileBadgeColor() { - return brightPurple; - } - - // TODO del - Color portraitProfileBadgeTextColor() { - return whitePurple; - } - - Color dropShadowColor() { - return purple; - } - - Color toolbarIconColor() { - return settings; //darkPurple; - } - - Color messageFromMeBackgroundColor() { - return userBubble; //brightPurple; - } - - Color messageFromMeTextColor() { - return font; //mainTextColor(); - } - - Color messageFromOtherBackgroundColor() { - return peerBubble; //purple; - } - - Color messageFromOtherTextColor() { - return font; //darkPurple; - } + get backgroundMainColor => background; //whitePurple; + get backgroundPaneColor => header; //softPurple; + get backgroundHilightElementColor => softPurple; + get mainTextColor => settings; + get sendHintTextColor => purple; + get hilightElementColor => purple; //darkPurple; // todo shouldn't be this, too dark, makes font unreadable + get defaultButtonColor => accent; // hotPink; + get defaultButtonActiveColor => pink; // todo: lighten in light, darken in dark + get defaultButtonTextColor => whitePurple; // ? + get defaultButtonDisabledColor => softGrey; + get textfieldBackgroundColor => purple; + get textfieldBorderColor => purple; + get textfieldHintColor => font; //TODO pick + get textfieldErrorColor => hotPink; + get scrollbarDefaultColor => accent; + get portraitBackgroundColor => softPurple; + get portraitOnlineBorderColor => greyPurple; + get portraitOfflineBorderColor => greyPurple; + get portraitBlockedBorderColor => softGrey; + get portraitBlockedTextColor => softGrey; + get portraitContactBadgeColor => accent; + get portraitContactBadgeTextColor => whitePurple; + get portraitProfileBadgeColor => brightPurple; + get portraitProfileBadgeTextColor => whitePurple; + get dropShadowColor => purple; + get toolbarIconColor => settings; //darkPurple; + get messageFromMeBackgroundColor => userBubble; //brightPurple; + get messageFromMeTextColor => font; //mainTextColor; + get messageFromOtherBackgroundColor => peerBubble; //purple; + get messageFromOtherTextColor => font; //darkPurple; } \ No newline at end of file diff --git a/lib/themes/neon1.dart b/lib/themes/neon1.dart new file mode 100644 index 00000000..f3b2a505 --- /dev/null +++ b/lib/themes/neon1.dart @@ -0,0 +1,126 @@ +import 'dart:ui'; +import 'dart:core'; + +import 'package:flutter/material.dart'; + +import 'opaque.dart'; + +final neon1_theme = "neon1"; +final neon1_name = "Neon1"; //Todo translate + +final Color darkGreyPurple = Color(0xFF281831); +final Color deepPurple = Color(0xFF422850); +final Color mauvePurple = Color(0xFF8E64A5); +final Color whiteishPurple = Color(0xFFE3DFE4); +final Color lightGrey = Color(0xFF9E9E9E); + +final Color whitePurple = Color(0xFFFFFDFF); +final Color softPurple = Color(0xFFFDF3FC); +final Color purple = Color(0xFFDFB9DE); +final Color brightPurple = Color(0xFFD1B0E0); // not in new: portrait badge color +final Color darkPurple = Color(0xFF350052); +final Color greyPurple = Color(0xFF775F84); // not in new: portrait borders +final Color pink = Color(0xFFE85DA1); // not in new: active button color +final Color hotPink = Color(0xFFD20070); // Color(0xFFD01972); +final Color softGrey = Color(0xFFB3B6B3); // not in new theme: blocked +//static final Color softGreen = Color(0xFFA0FFB0); +//static final Color softRed = Color(0xFFFFA0B0); + +OpaqueThemeType GetNeon1Theme(String mode) { + if (mode == mode_dark) { + return Neon1Dark(); + } else { + return Neon1Light(); + } +} + +class Neon1Dark extends OpaqueThemeType { + static final Color background = Color(0xFF290826); + static final Color header = Color(0xFF290826); + static final Color userBubble = Color(0xFFD20070); + static final Color peerBubble = Color(0xFF26A9A4); + static final Color font = Color(0xFFFFFFFF); + static final Color settings = Color(0xFFFFFDFF); + static final Color accent = Color(0xFFA604FE); + + get name => neon1_name; + get theme => neon1_theme; + get mode => mode_dark; + + get backgroundMainColor => background; // darkGreyPurple; + get backgroundPaneColor => header; //darkGreyPurple; + get backgroundHilightElementColor => deepPurple; + get mainTextColor => font; //whiteishPurple; + get sendHintTextColor => mauvePurple; + get hilightElementColor => purple; + get defaultButtonColor => accent; //hotPink; + get defaultButtonActiveColor => pink; + get defaultButtonTextColor => whiteishPurple; + get defaultButtonDisabledColor => lightGrey; + get defaultButtonDisabledTextColor => darkGreyPurple; + get textfieldBackgroundColor => deepPurple; + get textfieldBorderColor => deepPurple; + get textfieldHintColor => mainTextColor; //TODO pick + get textfieldErrorColor => hotPink; + get scrollbarDefaultColor => purple; + get portraitBackgroundColor => deepPurple; + get portraitOnlineBorderColor => whiteishPurple; + get portraitOfflineBorderColor => purple; + get portraitBlockedBorderColor => lightGrey; + get portraitBlockedTextColor => lightGrey; + get portraitContactBadgeColor => hotPink; + get portraitContactBadgeTextColor => whiteishPurple; + get portraitProfileBadgeColor => mauvePurple; + get portraitProfileBadgeTextColor => darkGreyPurple; + get dropShadowColor => mauvePurple; + get toolbarIconColor => settings; //whiteishPurple; + get messageFromMeBackgroundColor => userBubble; // mauvePurple; + get messageFromMeTextColor => font; //whiteishPurple; + get messageFromOtherBackgroundColor => peerBubble; //deepPurple; + get messageFromOtherTextColor => font; //whiteishPurple; +} + +class Neon1Light extends OpaqueThemeType { + static final Color background = Color(0xFFFFFDFF); + static final Color header = Color(0xFFFF94C2); + static final Color userBubble = Color(0xFFFF94C2); + static final Color peerBubble = Color(0xFFE7F6F6); + static final Color font = Color(0xFF290826); + static final Color settings = Color(0xFF290826); + static final Color accent = Color(0xFFA604FE); + + get name => neon1_name; + get theme => neon1_theme; + get mode => mode_light; + + get backgroundMainColor => background; //whitePurple; + get backgroundPaneColor => header; //softPurple; + get backgroundHilightElementColor => softPurple; + get mainTextColor => settings; + get sendHintTextColor => purple; + get hilightElementColor => purple; //darkPurple; // todo shouldn't be this, too dark, makes font unreadable + get defaultButtonColor => accent; // hotPink; + get defaultButtonActiveColor => pink; // todo: lighten in light, darken in dark + get defaultButtonTextColor => whitePurple; // ? + get defaultButtonDisabledColor => softGrey; + get textfieldBackgroundColor => purple; + get textfieldBorderColor => purple; + get textfieldHintColor => font; //TODO pick + get textfieldErrorColor => hotPink; + get scrollbarDefaultColor => accent; + get portraitBackgroundColor => softPurple; + get portraitOnlineBorderColor => greyPurple; + get portraitOfflineBorderColor => greyPurple; + get portraitBlockedBorderColor => softGrey; + get portraitBlockedTextColor => softGrey; + get portraitContactBadgeColor => accent; + get portraitContactBadgeTextColor => whitePurple; + get portraitProfileBadgeColor => brightPurple; + get portraitProfileBadgeTextColor => whitePurple; + get dropShadowColor => purple; + get toolbarIconColor => settings; //darkPurple; + get messageFromMeBackgroundColor => userBubble; //brightPurple; + get messageFromMeTextColor => font; //mainTextColor; + get messageFromOtherBackgroundColor => peerBubble; //purple; + get messageFromOtherTextColor => font; //darkPurple; +} \ No newline at end of file diff --git a/lib/themes/opaque.dart b/lib/themes/opaque.dart index 40058392..bd037c08 100644 --- a/lib/themes/opaque.dart +++ b/lib/themes/opaque.dart @@ -1,148 +1,100 @@ import 'dart:ui'; import 'dart:core'; +import 'package:cwtch/themes/cwtch.dart'; +import 'package:cwtch/themes/neon1.dart'; import 'package:flutter/material.dart'; import 'package:cwtch/settings.dart'; const mode_light = "light"; const mode_dark = "dark"; +final themes = { cwtch_theme: {mode_light: CwtchLight(), mode_dark: CwtchDark()}, + neon1_theme: {mode_light: Neon1Light(), mode_dark: Neon1Dark()}, +}; + +OpaqueThemeType getTheme(String themeId, String mode) { + if (themeId == "") { + themeId = cwtch_theme; + } + if (themeId == mode_light) { + themeId = cwtch_theme; + mode = mode_light; + } + if (themeId == mode_dark) { + themeId = cwtch_theme; + mode = mode_dark; + } + + var theme = themes[themeId]?[mode]; + return theme ?? CwtchDark(); +} + +Color lighten(Color color, [double amount = 0.15]) { + final hsl = HSLColor.fromColor(color); + final hslLight = hsl.withLightness((hsl.lightness + amount).clamp(0.0, 1.0)); + + return hslLight.toColor(); +} + +Color darken(Color color, [double amount = 0.15]) { + final hsl = HSLColor.fromColor(color); + final hslDarken = hsl.withLightness((hsl.lightness - amount).clamp(0.0, 1.0)); + + return hslDarken.toColor(); +} + abstract class OpaqueThemeType { static final Color red = Color(0xFFFF0000); - String identifier() { - return "dummy"; - } + get name => "Dummy"; + get theme => "dummy"; + get mode => mode_light; // Main screen background color (message pane, item rows) - Color backgroundMainColor() { - return red; - } + get backgroundMainColor => red; // Top pane ane pane colors (settings) - Color backgroundPaneColor() { - return red; - } + get backgroundPaneColor => red; - // Selected Row - Color backgroundHilightElementColor() { - return red; - } - - Color mainTextColor() { - return red; - } - - // Faded text color for suggestions in textfields - // Todo: implement way more places - Color sendHintTextColor() { - return red; - } + get mainTextColor => red; // pressed row, offline heart - Color hilightElementColor() { - return red; - } + get hilightElementColor => red; + // Selected Row + get backgroundHilightElementColor => red; + // Faded text color for suggestions in textfields + // Todo: implement way more places + get sendHintTextColor => red; - Color defaultButtonColor() { - return red; - } - - Color defaultButtonActiveColor() { - return red; - } - - Color defaultButtonTextColor() { - return red; - } - - Color defaultButtonDisabledColor() { - return red; - } - - Color textfieldBackgroundColor() { - return red; - } - - Color textfieldBorderColor() { - return red; - } - - Color textfieldHintColor() { - return red; - } - - Color textfieldErrorColor() { - return red; - } - - Color scrollbarDefaultColor() { - return red; - } - - Color portraitBackgroundColor() { - return red; - } - - Color portraitOnlineBorderColor() { - return red; - } - - Color portraitOfflineBorderColor() { - return red; - } - - Color portraitBlockedBorderColor() { - return red; - } - - Color portraitBlockedTextColor() { - return red; - } - - Color portraitContactBadgeColor() { - return red; - } - - Color portraitContactBadgeTextColor() { - return red; - } - - Color portraitProfileBadgeColor() { - return red; - } - - Color portraitProfileBadgeTextColor() { - return red; - } + get defaultButtonColor => red; + get defaultButtonActiveColor => mode == mode_light ? lighten(defaultButtonColor) : darken(defaultButtonColor); + get defaultButtonTextColor => red; + get defaultButtonDisabledColor => red; + get textfieldBackgroundColor => red; + get textfieldBorderColor => red; + get textfieldHintColor => red; + get textfieldErrorColor => red; + get scrollbarDefaultColor => red; + get portraitBackgroundColor => red; + get portraitOnlineBorderColor => red; + get portraitOfflineBorderColor => red; + get portraitBlockedBorderColor => red; + get portraitBlockedTextColor => red; + get portraitContactBadgeColor => red; + get portraitContactBadgeTextColor => red; + get portraitProfileBadgeColor => red; + get portraitProfileBadgeTextColor => red; // dropshaddpow // todo: probably should not be reply icon color in messagerow - Color dropShadowColor() { - return red; - } + get dropShadowColor => red; - Color toolbarIconColor() { - return red; - } - - Color messageFromMeBackgroundColor() { - return red; - } - - Color messageFromMeTextColor() { - return red; - } - - Color messageFromOtherBackgroundColor() { - return red; - } - - Color messageFromOtherTextColor() { - return red; - } - - // ... more to come + get toolbarIconColor => red; + get messageFromMeBackgroundColor => red; + get messageFromMeTextColor => red; + get messageFromOtherBackgroundColor => red; + get messageFromOtherTextColor => red; // Sizes @@ -151,51 +103,49 @@ abstract class OpaqueThemeType { } } - - ThemeData mkThemeData(Settings opaque) { return ThemeData( visualDensity: VisualDensity.adaptivePlatformDensity, primarySwatch: Colors.red, primaryIconTheme: IconThemeData( - color: opaque.current().mainTextColor(), + color: opaque.current().mainTextColor, ), - primaryColor: opaque.current().backgroundMainColor(), - canvasColor: opaque.current().backgroundPaneColor(), - backgroundColor: opaque.current().backgroundMainColor(), - highlightColor: opaque.current().hilightElementColor(), + primaryColor: opaque.current().backgroundMainColor, + canvasColor: opaque.current().backgroundPaneColor, + backgroundColor: opaque.current().backgroundMainColor, + highlightColor: opaque.current().hilightElementColor, iconTheme: IconThemeData( - color: opaque.current().toolbarIconColor(), + color: opaque.current().toolbarIconColor, ), - cardColor: opaque.current().backgroundMainColor(), + cardColor: opaque.current().backgroundMainColor, appBarTheme: AppBarTheme( - backgroundColor: opaque.current().backgroundPaneColor(), + backgroundColor: opaque.current().backgroundPaneColor, iconTheme: IconThemeData( - color: opaque.current().mainTextColor(), + color: opaque.current().mainTextColor, ), titleTextStyle: TextStyle( - color: opaque.current().mainTextColor(), + color: opaque.current().mainTextColor, ), actionsIconTheme: IconThemeData( - color: opaque.current().mainTextColor(), + color: opaque.current().mainTextColor, )), //bottomNavigationBarTheme: BottomNavigationBarThemeData(type: BottomNavigationBarType.fixed, backgroundColor: opaque.current().backgroundHilightElementColor()), // Can't determine current use textButtonTheme: TextButtonThemeData( style: ButtonStyle( - backgroundColor: MaterialStateProperty.all(opaque.current().defaultButtonColor()), - foregroundColor: MaterialStateProperty.all(opaque.current().defaultButtonTextColor()), - overlayColor: MaterialStateProperty.all(opaque.current().defaultButtonActiveColor()), + backgroundColor: MaterialStateProperty.all(opaque.current().defaultButtonColor), + foregroundColor: MaterialStateProperty.all(opaque.current().defaultButtonTextColor), + overlayColor: MaterialStateProperty.all(opaque.current().defaultButtonActiveColor), padding: MaterialStateProperty.all(EdgeInsets.all(20))), ), - hintColor: opaque.current().textfieldHintColor(), + hintColor: opaque.current().textfieldHintColor, elevatedButtonTheme: ElevatedButtonThemeData( style: ButtonStyle( - backgroundColor: MaterialStateProperty.resolveWith((states) => states.contains(MaterialState.disabled) ? opaque.current().defaultButtonDisabledColor() : opaque.current().defaultButtonColor()), - foregroundColor: MaterialStateProperty.all(opaque.current().defaultButtonTextColor()), + backgroundColor: MaterialStateProperty.resolveWith((states) => states.contains(MaterialState.disabled) ? opaque.current().defaultButtonDisabledColor : opaque.current().defaultButtonColor), + foregroundColor: MaterialStateProperty.all(opaque.current().defaultButtonTextColor), overlayColor: MaterialStateProperty.resolveWith((states) => (states.contains(MaterialState.pressed) && states.contains(MaterialState.hovered)) - ? opaque.current().defaultButtonActiveColor() + ? opaque.current().defaultButtonActiveColor : states.contains(MaterialState.disabled) - ? opaque.current().defaultButtonDisabledColor() + ? opaque.current().defaultButtonDisabledColor : null), enableFeedback: true, splashFactory: InkRipple.splashFactory, @@ -206,37 +156,37 @@ ThemeData mkThemeData(Settings opaque) { ), ), scrollbarTheme: ScrollbarThemeData( - isAlwaysShown: false, thumbColor: MaterialStateProperty.all(opaque.current().scrollbarDefaultColor())), - tabBarTheme: TabBarTheme(indicator: UnderlineTabIndicator(borderSide: BorderSide(color: opaque.current().defaultButtonActiveColor()))), + isAlwaysShown: false, thumbColor: MaterialStateProperty.all(opaque.current().scrollbarDefaultColor)), + tabBarTheme: TabBarTheme(indicator: UnderlineTabIndicator(borderSide: BorderSide(color: opaque.current().defaultButtonActiveColor))), dialogTheme: DialogTheme( - backgroundColor: opaque.current().backgroundPaneColor(), - titleTextStyle: TextStyle(color: opaque.current().mainTextColor()), - contentTextStyle: TextStyle(color: opaque.current().mainTextColor())), + 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())), + 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)), switchTheme: SwitchThemeData( - overlayColor: MaterialStateProperty.all(opaque.current().defaultButtonActiveColor()), - thumbColor: MaterialStateProperty.all(opaque.current().mainTextColor()), - trackColor: MaterialStateProperty.all(opaque.current().dropShadowColor()), + overlayColor: MaterialStateProperty.all(opaque.current().defaultButtonActiveColor), + thumbColor: MaterialStateProperty.all(opaque.current().mainTextColor), + trackColor: MaterialStateProperty.all(opaque.current().dropShadowColor), ), floatingActionButtonTheme: FloatingActionButtonThemeData( - backgroundColor: opaque.current().defaultButtonColor(), - hoverColor: opaque.current().defaultButtonActiveColor(), + backgroundColor: opaque.current().defaultButtonColor, + hoverColor: opaque.current().defaultButtonActiveColor, enableFeedback: true, - splashColor: opaque.current().defaultButtonActiveColor()), + splashColor: opaque.current().defaultButtonActiveColor), textSelectionTheme: TextSelectionThemeData( - cursorColor: opaque.current().defaultButtonActiveColor(), selectionColor: opaque.current().defaultButtonActiveColor(), selectionHandleColor: opaque.current().defaultButtonActiveColor()), + cursorColor: opaque.current().defaultButtonActiveColor, selectionColor: opaque.current().defaultButtonActiveColor, selectionHandleColor: opaque.current().defaultButtonActiveColor), ); } diff --git a/lib/views/addeditprofileview.dart b/lib/views/addeditprofileview.dart index e92b9c7e..f3dc72dc 100644 --- a/lib/views/addeditprofileview.dart +++ b/lib/views/addeditprofileview.dart @@ -91,7 +91,7 @@ class _AddEditProfileViewState extends State { imagePath: Provider.of(context).imagePath, diameter: 120, maskOut: false, - border: theme.theme.portraitOnlineBorderColor(), + border: theme.theme.portraitOnlineBorderColor, badgeTextColor: Colors.red, badgeColor: Colors.red, ) @@ -145,13 +145,13 @@ class _AddEditProfileViewState extends State { child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ Checkbox( value: usePassword, - fillColor: MaterialStateProperty.all(theme.current().defaultButtonColor()), - activeColor: theme.current().defaultButtonActiveColor(), + fillColor: MaterialStateProperty.all(theme.current().defaultButtonColor), + activeColor: theme.current().defaultButtonActiveColor, onChanged: _handleSwitchPassword, ), Text( AppLocalizations.of(context)!.radioUsePassword, - style: TextStyle(color: theme.current().mainTextColor()), + style: TextStyle(color: theme.current().mainTextColor), ), SizedBox( height: 20, diff --git a/lib/views/addeditservers.dart b/lib/views/addeditservers.dart index 011903c5..415866b7 100644 --- a/lib/views/addeditservers.dart +++ b/lib/views/addeditservers.dart @@ -33,6 +33,7 @@ class _AddEditServerViewState extends State { final ctrlrOnion = TextEditingController(text: ""); late bool usePassword; + //late bool deleted; @override diff --git a/lib/views/contactsview.dart b/lib/views/contactsview.dart index 87c6cee6..0c59122e 100644 --- a/lib/views/contactsview.dart +++ b/lib/views/contactsview.dart @@ -78,7 +78,7 @@ class _ContactsViewState extends State { ProfileImage( imagePath: Provider.of(context).imagePath, diameter: 42, - border: Provider.of(context).current().portraitOnlineBorderColor(), + border: Provider.of(context).current().portraitOnlineBorderColor, badgeTextColor: Colors.red, badgeColor: Colors.red, ), @@ -87,7 +87,7 @@ class _ContactsViewState extends State { ), Expanded( child: Text("%1 » %2".replaceAll("%1", Provider.of(context).nickname).replaceAll("%2", AppLocalizations.of(context)!.titleManageContacts), - overflow: TextOverflow.ellipsis, style: TextStyle(color: Provider.of(context).current().mainTextColor()))), + overflow: TextOverflow.ellipsis, style: TextStyle(color: Provider.of(context).current().mainTextColor))), ])), actions: getActions(context), ), diff --git a/lib/views/globalsettingsview.dart b/lib/views/globalsettingsview.dart index 22d02dfc..66b14ec2 100644 --- a/lib/views/globalsettingsview.dart +++ b/lib/views/globalsettingsview.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'dart:io'; import 'package:cwtch/cwtch_icons_icons.dart'; import 'package:cwtch/models/servers.dart'; +import 'package:cwtch/themes/opaque.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:flutter/material.dart'; import 'package:cwtch/settings.dart'; @@ -36,7 +37,7 @@ class _GlobalSettingsViewState extends State { Widget _buildSettingsList() { return Consumer(builder: (context, settings, child) { return LayoutBuilder(builder: (BuildContext context, BoxConstraints viewportConstraints) { - var appIcon = Icon(Icons.info, color: settings.current().mainTextColor()); + var appIcon = Icon(Icons.info, color: settings.current().mainTextColor); return Scrollbar( isAlwaysShown: true, child: SingleChildScrollView( @@ -47,8 +48,8 @@ class _GlobalSettingsViewState extends State { ), child: Column(children: [ ListTile( - title: Text(AppLocalizations.of(context)!.settingLanguage, style: TextStyle(color: settings.current().mainTextColor())), - leading: Icon(CwtchIcons.change_language, color: settings.current().mainTextColor()), + title: Text(AppLocalizations.of(context)!.settingLanguage, style: TextStyle(color: settings.current().mainTextColor)), + leading: Icon(CwtchIcons.change_language, color: settings.current().mainTextColor), trailing: DropdownButton( value: Provider.of(context).locale.languageCode, onChanged: (String? newValue) { @@ -64,25 +65,42 @@ class _GlobalSettingsViewState extends State { ); }).toList())), SwitchListTile( - title: Text(AppLocalizations.of(context)!.settingTheme, style: TextStyle(color: settings.current().mainTextColor())), - value: settings.current().identifier() == "light", + title: Text(AppLocalizations.of(context)!.settingTheme, style: TextStyle(color: settings.current().mainTextColor)), + value: settings.current().mode == mode_light, onChanged: (bool value) { if (value) { - settings.setLight(); + settings.setTheme(settings.theme.theme, mode_light); } else { - settings.setDark(); + settings.setTheme(settings.theme.theme, mode_dark); } // Save Settings... saveSettings(context); }, - activeTrackColor: settings.theme.defaultButtonActiveColor(), - inactiveTrackColor: settings.theme.defaultButtonDisabledColor(), - secondary: Icon(CwtchIcons.change_theme, color: settings.current().mainTextColor()), + activeTrackColor: settings.theme.defaultButtonActiveColor, + inactiveTrackColor: settings.theme.defaultButtonDisabledColor, + secondary: Icon(CwtchIcons.change_theme, color: settings.current().mainTextColor), ), ListTile( - title: Text(AppLocalizations.of(context)!.settingUIColumnPortrait, style: TextStyle(color: settings.current().mainTextColor())), - leading: Icon(Icons.table_chart, color: settings.current().mainTextColor()), + title: Text("Colour Theme"), + //AppLocalizations.of(context)!.settingTheme)), + trailing: DropdownButton( + value: Provider.of(context).theme.theme, + onChanged: (String? newValue) { + setState(() { + settings.setTheme(newValue!, settings.theme.mode); + saveSettings(context); + }); + }, + items: themes.keys.map>((String themeId) { + return DropdownMenuItem( + value: themeId, + child: Text(themes[themeId]?[mode_light]?.name ?? "Unknown"), //todo translate + ); + }).toList())), + ListTile( + title: Text(AppLocalizations.of(context)!.settingUIColumnPortrait, style: TextStyle(color: settings.current().mainTextColor)), + leading: Icon(Icons.table_chart, color: settings.current().mainTextColor), trailing: DropdownButton( value: settings.uiColumnModePortrait.toString(), onChanged: (String? newValue) { @@ -100,9 +118,9 @@ class _GlobalSettingsViewState extends State { AppLocalizations.of(context)!.settingUIColumnLandscape, textWidthBasis: TextWidthBasis.longestLine, softWrap: true, - style: TextStyle(color: settings.current().mainTextColor()), + style: TextStyle(color: settings.current().mainTextColor), ), - leading: Icon(Icons.table_chart, color: settings.current().mainTextColor()), + leading: Icon(Icons.table_chart, color: settings.current().mainTextColor), trailing: Container( width: 200.0, child: DropdownButton( @@ -122,7 +140,7 @@ class _GlobalSettingsViewState extends State { ); }).toList()))), SwitchListTile( - title: Text(AppLocalizations.of(context)!.blockUnknownLabel, style: TextStyle(color: settings.current().mainTextColor())), + title: Text(AppLocalizations.of(context)!.blockUnknownLabel, style: TextStyle(color: settings.current().mainTextColor)), subtitle: Text(AppLocalizations.of(context)!.descriptionBlockUnknownConnections), value: settings.blockUnknownConnections, onChanged: (bool value) { @@ -135,12 +153,12 @@ class _GlobalSettingsViewState extends State { // Save Settings... saveSettings(context); }, - activeTrackColor: settings.theme.defaultButtonActiveColor(), - inactiveTrackColor: settings.theme.defaultButtonDisabledColor(), - secondary: Icon(CwtchIcons.block_unknown, color: settings.current().mainTextColor()), + activeTrackColor: settings.theme.defaultButtonActiveColor, + inactiveTrackColor: settings.theme.defaultButtonDisabledColor, + secondary: Icon(CwtchIcons.block_unknown, color: settings.current().mainTextColor), ), SwitchListTile( - title: Text(AppLocalizations.of(context)!.streamerModeLabel, style: TextStyle(color: settings.current().mainTextColor())), + title: Text(AppLocalizations.of(context)!.streamerModeLabel, style: TextStyle(color: settings.current().mainTextColor)), subtitle: Text(AppLocalizations.of(context)!.descriptionStreamerMode), value: settings.streamerMode, onChanged: (bool value) { @@ -148,12 +166,12 @@ class _GlobalSettingsViewState extends State { // Save Settings... saveSettings(context); }, - activeTrackColor: settings.theme.defaultButtonActiveColor(), - inactiveTrackColor: settings.theme.defaultButtonDisabledColor(), - secondary: Icon(CwtchIcons.streamer_bunnymask, color: settings.current().mainTextColor()), + activeTrackColor: settings.theme.defaultButtonActiveColor, + inactiveTrackColor: settings.theme.defaultButtonDisabledColor, + secondary: Icon(CwtchIcons.streamer_bunnymask, color: settings.current().mainTextColor), ), SwitchListTile( - title: Text(AppLocalizations.of(context)!.experimentsEnabled, style: TextStyle(color: settings.current().mainTextColor())), + title: Text(AppLocalizations.of(context)!.experimentsEnabled, style: TextStyle(color: settings.current().mainTextColor)), subtitle: Text(AppLocalizations.of(context)!.descriptionExperiments), value: settings.experimentsEnabled, onChanged: (bool value) { @@ -165,16 +183,16 @@ class _GlobalSettingsViewState extends State { // Save Settings... saveSettings(context); }, - activeTrackColor: settings.theme.defaultButtonActiveColor(), - inactiveTrackColor: settings.theme.defaultButtonDisabledColor(), - secondary: Icon(CwtchIcons.enable_experiments, color: settings.current().mainTextColor()), + activeTrackColor: settings.theme.defaultButtonActiveColor, + 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, style: TextStyle(color: settings.current().mainTextColor())), + title: Text(AppLocalizations.of(context)!.enableGroups, style: TextStyle(color: settings.current().mainTextColor)), subtitle: Text(AppLocalizations.of(context)!.descriptionExperimentsGroups), value: settings.isExperimentEnabled(TapirGroupsExperiment), onChanged: (bool value) { @@ -186,14 +204,14 @@ class _GlobalSettingsViewState extends State { // Save Settings... saveSettings(context); }, - activeTrackColor: settings.theme.defaultButtonActiveColor(), - inactiveTrackColor: settings.theme.defaultButtonDisabledColor(), - secondary: Icon(CwtchIcons.enable_groups, color: settings.current().mainTextColor()), + activeTrackColor: settings.theme.defaultButtonActiveColor, + 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, style: TextStyle(color: settings.current().mainTextColor())), + title: Text(AppLocalizations.of(context)!.settingServers, style: TextStyle(color: settings.current().mainTextColor)), subtitle: Text(AppLocalizations.of(context)!.settingServersDescription), value: settings.isExperimentEnabled(ServerManagementExperiment), onChanged: (bool value) { @@ -206,12 +224,12 @@ class _GlobalSettingsViewState extends State { // Save Settings... saveSettings(context); }, - activeTrackColor: settings.theme.defaultButtonActiveColor(), - inactiveTrackColor: settings.theme.defaultButtonDisabledColor(), - secondary: Icon(CwtchIcons.dns_24px, color: settings.current().mainTextColor()), + activeTrackColor: settings.theme.defaultButtonActiveColor, + inactiveTrackColor: settings.theme.defaultButtonDisabledColor, + secondary: Icon(CwtchIcons.dns_24px, color: settings.current().mainTextColor), )), SwitchListTile( - title: Text(AppLocalizations.of(context)!.settingFileSharing, style: TextStyle(color: settings.current().mainTextColor())), + title: Text(AppLocalizations.of(context)!.settingFileSharing, style: TextStyle(color: settings.current().mainTextColor)), subtitle: Text(AppLocalizations.of(context)!.descriptionFileSharing), value: settings.isExperimentEnabled(FileSharingExperiment), onChanged: (bool value) { @@ -222,9 +240,9 @@ class _GlobalSettingsViewState extends State { } saveSettings(context); }, - activeTrackColor: settings.theme.defaultButtonActiveColor(), - inactiveTrackColor: settings.theme.defaultButtonDisabledColor(), - secondary: Icon(Icons.attach_file, color: settings.current().mainTextColor()), + activeTrackColor: settings.theme.defaultButtonActiveColor, + inactiveTrackColor: settings.theme.defaultButtonDisabledColor, + secondary: Icon(Icons.attach_file, color: settings.current().mainTextColor), ), SwitchListTile( title: Text(AppLocalizations.of(context)!.enableExperimentClickableLinks, style: TextStyle(color: settings.current().mainTextColor())), @@ -238,9 +256,9 @@ class _GlobalSettingsViewState extends State { } saveSettings(context); }, - activeTrackColor: settings.theme.defaultButtonActiveColor(), - inactiveTrackColor: settings.theme.defaultButtonDisabledColor(), - secondary: Icon(Icons.link, color: settings.current().mainTextColor()), + activeTrackColor: settings.theme.defaultButtonActiveColor, + inactiveTrackColor: settings.theme.defaultButtonDisabledColor, + secondary: Icon(Icons.link, color: settings.current().mainTextColor), ), ], )), @@ -251,8 +269,8 @@ class _GlobalSettingsViewState extends State { applicationLegalese: '\u{a9} 2021 Open Privacy Research Society', aboutBoxChildren: [ 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 + 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)), ) ]), diff --git a/lib/views/messageview.dart b/lib/views/messageview.dart index 231170fe..516aadd3 100644 --- a/lib/views/messageview.dart +++ b/lib/views/messageview.dart @@ -104,7 +104,7 @@ class _MessageViewState extends State { return WillPopScope( onWillPop: _onWillPop, child: Scaffold( - backgroundColor: Provider.of(context).theme.backgroundMainColor(), + backgroundColor: Provider.of(context).theme.backgroundMainColor, floatingActionButton: appState.unreadMessagesBelow ? FloatingActionButton( child: Icon(Icons.arrow_downward), @@ -121,7 +121,7 @@ class _MessageViewState extends State { ProfileImage( imagePath: Provider.of(context).imagePath, diameter: 42, - border: Provider.of(context).current().portraitOnlineBorderColor(), + border: Provider.of(context).current().portraitOnlineBorderColor, badgeTextColor: Colors.red, badgeColor: Colors.red, ), @@ -226,7 +226,7 @@ class _MessageViewState extends State { bool isOffline = Provider.of(context).isOnline() == false; var composeBox = Container( - color: Provider.of(context).theme.backgroundMainColor(), + color: Provider.of(context).theme.backgroundMainColor, padding: EdgeInsets.all(2), margin: EdgeInsets.all(2), height: 100, @@ -234,7 +234,7 @@ class _MessageViewState extends State { children: [ Expanded( child: Container( - decoration: BoxDecoration(border: Border(top: BorderSide(color: Provider.of(context).theme.defaultButtonActiveColor()))), + decoration: BoxDecoration(border: Border(top: BorderSide(color: Provider.of(context).theme.defaultButtonActiveColor))), child: RawKeyboardListener( focusNode: FocusNode(), onKey: handleKeyPress, @@ -254,12 +254,12 @@ class _MessageViewState extends State { enabled: !isOffline, decoration: InputDecoration( hintText: isOffline ? "" : AppLocalizations.of(context)!.placeholderEnterMessage, - hintStyle: TextStyle(color: Provider.of(context).theme.sendHintTextColor()), + hintStyle: TextStyle(color: Provider.of(context).theme.sendHintTextColor), enabledBorder: InputBorder.none, focusedBorder: InputBorder.none, enabled: true, suffixIcon: ElevatedButton( - child: Icon(CwtchIcons.send_24px, size: 24, color: Provider.of(context).theme.defaultButtonTextColor()), + child: Icon(CwtchIcons.send_24px, size: 24, color: Provider.of(context).theme.defaultButtonTextColor), onPressed: isOffline ? null : _sendMessage, ))), )))), @@ -279,8 +279,8 @@ class _MessageViewState extends State { margin: EdgeInsets.all(5), padding: EdgeInsets.all(5), color: message.getMetadata().senderHandle != Provider.of(context).selectedProfile - ? Provider.of(context).theme.messageFromOtherBackgroundColor() - : Provider.of(context).theme.messageFromMeBackgroundColor(), + ? Provider.of(context).theme.messageFromOtherBackgroundColor + : Provider.of(context).theme.messageFromMeBackgroundColor, child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ Stack(children: [ Align( @@ -315,7 +315,7 @@ class _MessageViewState extends State { } return Container( - color: Provider.of(context).theme.backgroundMainColor(), child: Column(mainAxisSize: MainAxisSize.min, children: children)); + color: Provider.of(context).theme.backgroundMainColor, child: Column(mainAxisSize: MainAxisSize.min, children: children)); } // Send the message if enter is pressed without the shift key... diff --git a/lib/views/peersettingsview.dart b/lib/views/peersettingsview.dart index 506c1706..0e02df17 100644 --- a/lib/views/peersettingsview.dart +++ b/lib/views/peersettingsview.dart @@ -105,7 +105,7 @@ class _PeerSettingsViewState extends State { height: 20, ), SwitchListTile( - title: Text(AppLocalizations.of(context)!.blockBtn, style: TextStyle(color: settings.current().mainTextColor())), + title: Text(AppLocalizations.of(context)!.blockBtn, style: TextStyle(color: settings.current().mainTextColor)), value: Provider.of(context).isBlocked, onChanged: (bool blocked) { // Save local blocked status @@ -137,14 +137,14 @@ class _PeerSettingsViewState extends State { Provider.of(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson); } }, - activeTrackColor: settings.theme.defaultButtonActiveColor(), - inactiveTrackColor: settings.theme.defaultButtonDisabledColor(), - secondary: Icon(CwtchIcons.block_peer, color: settings.current().mainTextColor()), + activeTrackColor: settings.theme.defaultButtonActiveColor, + inactiveTrackColor: settings.theme.defaultButtonDisabledColor, + secondary: Icon(CwtchIcons.block_peer, color: settings.current().mainTextColor), ), ListTile( - title: Text(AppLocalizations.of(context)!.savePeerHistory, style: TextStyle(color: settings.current().mainTextColor())), + title: Text(AppLocalizations.of(context)!.savePeerHistory, style: TextStyle(color: settings.current().mainTextColor)), subtitle: Text(AppLocalizations.of(context)!.savePeerHistoryDescription), - leading: Icon(CwtchIcons.peer_history, color: settings.current().mainTextColor()), + leading: Icon(CwtchIcons.peer_history, color: settings.current().mainTextColor), trailing: DropdownButton( value: Provider.of(context).savePeerHistory == "DefaultDeleteHistory" ? AppLocalizations.of(context)!.dontSavePeerHistory diff --git a/lib/views/profilemgrview.dart b/lib/views/profilemgrview.dart index e4a6eba0..da72472c 100644 --- a/lib/views/profilemgrview.dart +++ b/lib/views/profilemgrview.dart @@ -46,20 +46,20 @@ class _ProfileMgrViewState extends State { return Provider.of(context, listen: false).cwtchIsClosing; }, child: Scaffold( - backgroundColor: settings.theme.backgroundMainColor(), + backgroundColor: settings.theme.backgroundMainColor, appBar: AppBar( title: Row(children: [ Icon( CwtchIcons.cwtch_knott, size: 36, - color: settings.theme.mainTextColor(), + color: settings.theme.mainTextColor, ), SizedBox( width: 10, ), Expanded( child: Text(MediaQuery.of(context).size.width > 600 ? AppLocalizations.of(context)!.titleManageProfiles : AppLocalizations.of(context)!.titleManageProfilesShort, - style: TextStyle(color: settings.current().mainTextColor()))) + style: TextStyle(color: settings.current().mainTextColor))) ]), actions: getActions(), ), @@ -93,7 +93,7 @@ class _ProfileMgrViewState extends State { // Unlock Profiles actions.add(IconButton( icon: Icon(CwtchIcons.lock_open_24px), - color: Provider.of(context).profiles.isEmpty ? Provider.of(context).theme.defaultButtonColor() : Provider.of(context).theme.mainTextColor(), + color: Provider.of(context).profiles.isEmpty ? Provider.of(context).theme.defaultButtonColor : Provider.of(context).theme.mainTextColor, tooltip: AppLocalizations.of(context)!.tooltipUnlockProfiles, onPressed: _modalUnlockProfiles, )); diff --git a/lib/views/serversview.dart b/lib/views/serversview.dart index 148d1daf..5e943b43 100644 --- a/lib/views/serversview.dart +++ b/lib/views/serversview.dart @@ -77,7 +77,7 @@ class _ServersView extends State { // Unlock Profiles actions.add(IconButton( icon: Icon(CwtchIcons.lock_open_24px), - color: Provider.of(context).servers.isEmpty ? Provider.of(context).theme.defaultButtonColor() : Provider.of(context).theme.mainTextColor(), + color: Provider.of(context).servers.isEmpty ? Provider.of(context).theme.defaultButtonColor : Provider.of(context).theme.mainTextColor, tooltip: AppLocalizations.of(context)!.tooltipUnlockProfiles, onPressed: _modalUnlockServers, )); diff --git a/lib/views/splashView.dart b/lib/views/splashView.dart index a5642f2d..4f495066 100644 --- a/lib/views/splashView.dart +++ b/lib/views/splashView.dart @@ -28,7 +28,7 @@ class SplashView extends StatelessWidget { padding: const EdgeInsets.all(20.0), child: Text(appState.appError == "" ? "Loading Cwtch..." : appState.appError, style: TextStyle( - fontSize: 16.0, color: appState.appError == "" ? Provider.of(context).theme.mainTextColor() : Provider.of(context).theme.textfieldErrorColor())), + fontSize: 16.0, color: appState.appError == "" ? Provider.of(context).theme.mainTextColor : Provider.of(context).theme.textfieldErrorColor)), ), Image(image: AssetImage("assets/Open_Privacy_Logo_lightoutline.png")), ])), diff --git a/lib/widgets/buttontextfield.dart b/lib/widgets/buttontextfield.dart index cd1cdb09..4c3ad2d2 100644 --- a/lib/widgets/buttontextfield.dart +++ b/lib/widgets/buttontextfield.dart @@ -48,23 +48,23 @@ class _CwtchButtonTextFieldState extends State { padding: EdgeInsets.fromLTRB(0.0, 4.0, 2.0, 2.0), tooltip: widget.tooltip, enableFeedback: true, - color: theme.current().mainTextColor(), - highlightColor: theme.current().defaultButtonColor(), - focusColor: theme.current().defaultButtonActiveColor(), - splashColor: theme.current().defaultButtonActiveColor(), + color: theme.current().mainTextColor, + highlightColor: theme.current().defaultButtonColor, + focusColor: theme.current().defaultButtonActiveColor, + splashColor: theme.current().defaultButtonActiveColor, ), floatingLabelBehavior: FloatingLabelBehavior.never, filled: true, - fillColor: theme.current().textfieldBackgroundColor(), - focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor(), width: 3.0)), - focusedErrorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor(), width: 3.0)), - errorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor(), width: 3.0)), + fillColor: theme.current().textfieldBackgroundColor, + focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor, width: 3.0)), + focusedErrorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor, width: 3.0)), + errorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor, width: 3.0)), errorStyle: TextStyle( - color: theme.current().textfieldErrorColor(), + color: theme.current().textfieldErrorColor, fontWeight: FontWeight.bold, ), contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0), - enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor(), width: 3.0))), + enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor, width: 3.0))), ); }); } diff --git a/lib/widgets/contactrow.dart b/lib/widgets/contactrow.dart index 93bbb655..ff1e963f 100644 --- a/lib/widgets/contactrow.dart +++ b/lib/widgets/contactrow.dart @@ -23,7 +23,7 @@ class _ContactRowState extends State { var contact = Provider.of(context); return Card( clipBehavior: Clip.antiAlias, - color: Provider.of(context).selectedConversation == contact.onion ? Provider.of(context).theme.backgroundHilightElementColor() : null, + color: Provider.of(context).selectedConversation == contact.onion ? Provider.of(context).theme.backgroundHilightElementColor : null, borderOnForeground: false, margin: EdgeInsets.all(0.0), child: InkWell( @@ -32,16 +32,16 @@ class _ContactRowState extends State { padding: const EdgeInsets.all(6.0), //border size child: ProfileImage( badgeCount: contact.unreadMessages, - badgeColor: Provider.of(context).theme.portraitContactBadgeColor(), - badgeTextColor: Provider.of(context).theme.portraitContactBadgeTextColor(), + badgeColor: Provider.of(context).theme.portraitContactBadgeColor, + badgeTextColor: Provider.of(context).theme.portraitContactBadgeTextColor, diameter: 64.0, imagePath: contact.imagePath, maskOut: !contact.isOnline(), border: contact.isOnline() - ? Provider.of(context).theme.portraitOnlineBorderColor() + ? Provider.of(context).theme.portraitOnlineBorderColor : contact.isBlocked - ? Provider.of(context).theme.portraitBlockedBorderColor() - : Provider.of(context).theme.portraitOfflineBorderColor()), + ? Provider.of(context).theme.portraitBlockedBorderColor + : Provider.of(context).theme.portraitOfflineBorderColor), ), Expanded( child: Padding( @@ -55,20 +55,20 @@ class _ContactRowState extends State { style: TextStyle( fontSize: Provider.of(context).theme.contactOnionTextSize(), color: contact.isBlocked - ? Provider.of(context).theme.portraitBlockedTextColor() - : Provider.of(context).theme.mainTextColor()), //Provider.of(context).biggerFont, + ? Provider.of(context).theme.portraitBlockedTextColor + : Provider.of(context).theme.mainTextColor), //Provider.of(context).biggerFont, softWrap: true, overflow: TextOverflow.visible, ), Visibility( visible: contact.isGroup && contact.status == "Authenticated", child: LinearProgressIndicator( - color: Provider.of(context).theme.defaultButtonActiveColor(), + color: Provider.of(context).theme.defaultButtonActiveColor, )), Visibility( visible: !Provider.of(context).streamerMode, child: Text(contact.onion, - style: TextStyle(color: contact.isBlocked ? Provider.of(context).theme.portraitBlockedTextColor() : Provider.of(context).theme.mainTextColor())), + style: TextStyle(color: contact.isBlocked ? Provider.of(context).theme.portraitBlockedTextColor : Provider.of(context).theme.mainTextColor)), ) ], ))), @@ -81,7 +81,7 @@ class _ContactRowState extends State { iconSize: 16, icon: Icon( Icons.favorite, - color: Provider.of(context).theme.mainTextColor(), + color: Provider.of(context).theme.mainTextColor, ), tooltip: AppLocalizations.of(context)!.tooltipAcceptContactRequest, onPressed: _btnApprove, @@ -89,7 +89,7 @@ class _ContactRowState extends State { IconButton( padding: EdgeInsets.zero, iconSize: 16, - icon: Icon(Icons.delete, color: Provider.of(context).theme.mainTextColor()), + icon: Icon(Icons.delete, color: Provider.of(context).theme.mainTextColor), tooltip: AppLocalizations.of(context)!.tooltipRejectContactRequest, onPressed: _btnReject, ) @@ -98,7 +98,7 @@ class _ContactRowState extends State { ? IconButton( padding: EdgeInsets.zero, iconSize: 16, - icon: Icon(Icons.block, color: Provider.of(context).theme.mainTextColor()), + icon: Icon(Icons.block, color: Provider.of(context).theme.mainTextColor), onPressed: () {}, ) : Text(dateToNiceString(contact.lastMessageTime))), diff --git a/lib/widgets/cwtchlabel.dart b/lib/widgets/cwtchlabel.dart index b354c778..07ac3874 100644 --- a/lib/widgets/cwtchlabel.dart +++ b/lib/widgets/cwtchlabel.dart @@ -18,7 +18,7 @@ class _CwtchLabelState extends State { return Consumer(builder: (context, theme, child) { return Text( widget.label, - style: TextStyle(fontSize: 20, color: theme.current().mainTextColor()), + style: TextStyle(fontSize: 20, color: theme.current().mainTextColor), ); }); } diff --git a/lib/widgets/filebubble.dart b/lib/widgets/filebubble.dart index ea26052a..d9e0a44e 100644 --- a/lib/widgets/filebubble.dart +++ b/lib/widgets/filebubble.dart @@ -61,7 +61,7 @@ class FileBubbleState extends State { var wdgSender = Center( widthFactor: 1, child: SelectableText(senderDisplayStr + '\u202F', - style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of(context).theme.messageFromMeTextColor() : Provider.of(context).theme.messageFromOtherTextColor()))); + style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor))); var wdgMessage = !showFileSharing ? Text(AppLocalizations.of(context)!.messageEnableFileSharing) @@ -84,7 +84,7 @@ class FileBubbleState extends State { } else { wdgDecorations = LinearProgressIndicator( value: Provider.of(context).downloadProgress(widget.fileKey()), - color: Provider.of(context).theme.defaultButtonActiveColor(), + color: Provider.of(context).theme.defaultButtonActiveColor, ); } } else if (flagStarted) { @@ -114,9 +114,9 @@ class FileBubbleState extends State { widthFactor: 1.0, child: Container( decoration: BoxDecoration( - color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor() : Provider.of(context).theme.messageFromOtherBackgroundColor(), + color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor, border: - Border.all(color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor() : Provider.of(context).theme.messageFromOtherBackgroundColor(), width: 1), + Border.all(color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor, width: 1), borderRadius: BorderRadius.only( topLeft: Radius.circular(borderRadiousEh), topRight: Radius.circular(borderRadiousEh), @@ -196,7 +196,7 @@ class FileBubbleState extends State { SelectableText( chrome + '\u202F', style: TextStyle( - color: Provider.of(context).theme.messageFromMeTextColor(), + color: Provider.of(context).theme.messageFromMeTextColor, ), textAlign: TextAlign.left, maxLines: 2, @@ -205,7 +205,7 @@ class FileBubbleState extends State { SelectableText( fileName + '\u202F', style: TextStyle( - color: Provider.of(context).theme.messageFromMeTextColor(), + color: Provider.of(context).theme.messageFromMeTextColor, fontWeight: FontWeight.bold, overflow: TextOverflow.ellipsis, ), @@ -216,7 +216,7 @@ class FileBubbleState extends State { SelectableText( prettyBytes(fileSize) + '\u202F' + '\n', style: TextStyle( - color: Provider.of(context).theme.messageFromMeTextColor(), + color: Provider.of(context).theme.messageFromMeTextColor, ), textAlign: TextAlign.left, maxLines: 2, @@ -225,7 +225,7 @@ class FileBubbleState extends State { subtitle: SelectableText( 'sha512: ' + rootHash + '\u202F', style: TextStyle( - color: Provider.of(context).theme.messageFromMeTextColor(), + color: Provider.of(context).theme.messageFromMeTextColor, fontSize: 10, fontFamily: "monospace", ), @@ -233,7 +233,7 @@ class FileBubbleState extends State { maxLines: 4, textWidthBasis: TextWidthBasis.parent, ), - leading: Icon(Icons.attach_file, size: 32, color: Provider.of(context).theme.messageFromMeTextColor())); + leading: Icon(Icons.attach_file, size: 32, color: Provider.of(context).theme.messageFromMeTextColor)); } // Construct an file chrome @@ -244,7 +244,7 @@ class FileBubbleState extends State { SelectableText( chrome + '\u202F', style: TextStyle( - color: Provider.of(context).theme.messageFromOtherTextColor(), + color: Provider.of(context).theme.messageFromOtherTextColor, ), textAlign: TextAlign.left, maxLines: 2, @@ -253,7 +253,7 @@ class FileBubbleState extends State { SelectableText( fileName + '\u202F', style: TextStyle( - color: Provider.of(context).theme.messageFromOtherTextColor(), + color: Provider.of(context).theme.messageFromOtherTextColor, fontWeight: FontWeight.bold, overflow: TextOverflow.ellipsis, ), @@ -264,7 +264,7 @@ class FileBubbleState extends State { SelectableText( AppLocalizations.of(context)!.labelFilesize + ': ' + prettyBytes(fileSize) + '\u202F' + '\n', style: TextStyle( - color: Provider.of(context).theme.messageFromOtherTextColor(), + color: Provider.of(context).theme.messageFromOtherTextColor, ), textAlign: TextAlign.left, maxLines: 2, @@ -273,7 +273,7 @@ class FileBubbleState extends State { subtitle: SelectableText( 'sha512: ' + rootHash + '\u202F', style: TextStyle( - color: Provider.of(context).theme.messageFromMeTextColor(), + color: Provider.of(context).theme.messageFromMeTextColor, fontSize: 10, fontFamily: "monospace", ), @@ -281,13 +281,13 @@ class FileBubbleState extends State { maxLines: 4, textWidthBasis: TextWidthBasis.parent, ), - leading: Icon(Icons.attach_file, size: 32, color: Provider.of(context).theme.messageFromOtherTextColor()), + leading: Icon(Icons.attach_file, size: 32, color: Provider.of(context).theme.messageFromOtherTextColor), trailing: Visibility( visible: speed != "0 B/s", child: SelectableText( speed + '\u202F', style: TextStyle( - color: Provider.of(context).theme.messageFromMeTextColor(), + color: Provider.of(context).theme.messageFromMeTextColor, ), textAlign: TextAlign.left, maxLines: 1, diff --git a/lib/widgets/invitationbubble.dart b/lib/widgets/invitationbubble.dart index 483ed833..e8ced225 100644 --- a/lib/widgets/invitationbubble.dart +++ b/lib/widgets/invitationbubble.dart @@ -56,7 +56,7 @@ class InvitationBubbleState extends State { var wdgSender = Center( widthFactor: 1, child: SelectableText(senderDisplayStr + '\u202F', - style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of(context).theme.messageFromMeTextColor() : Provider.of(context).theme.messageFromOtherTextColor()))); + style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor))); // If we receive an invite for ourselves, treat it as a bug. The UI no longer allows this so it could have only come from // some kind of malfeasance. @@ -96,9 +96,9 @@ class InvitationBubbleState extends State { widthFactor: 1.0, child: Container( decoration: BoxDecoration( - color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor() : Provider.of(context).theme.messageFromOtherBackgroundColor(), + color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor, border: - Border.all(color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor() : Provider.of(context).theme.messageFromOtherBackgroundColor(), width: 1), + Border.all(color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor, width: 1), borderRadius: BorderRadius.only( topLeft: Radius.circular(borderRadiousEh), topRight: Radius.circular(borderRadiousEh), @@ -149,7 +149,7 @@ class InvitationBubbleState extends State { SelectableText( chrome + '\u202F', style: TextStyle( - color: Provider.of(context).theme.messageFromMeTextColor(), + color: Provider.of(context).theme.messageFromMeTextColor, ), textAlign: TextAlign.left, maxLines: 2, @@ -158,7 +158,7 @@ class InvitationBubbleState extends State { SelectableText( targetName + '\u202F', style: TextStyle( - color: Provider.of(context).theme.messageFromMeTextColor(), + color: Provider.of(context).theme.messageFromMeTextColor, ), textAlign: TextAlign.left, maxLines: 2, @@ -173,7 +173,7 @@ class InvitationBubbleState extends State { SelectableText( chrome + '\u202F', style: TextStyle( - color: Provider.of(context).theme.messageFromOtherTextColor(), + color: Provider.of(context).theme.messageFromOtherTextColor, ), textAlign: TextAlign.left, textWidthBasis: TextWidthBasis.longestLine, @@ -181,7 +181,7 @@ class InvitationBubbleState extends State { ), SelectableText( targetName + '\u202F', - style: TextStyle(color: Provider.of(context).theme.messageFromOtherTextColor()), + style: TextStyle(color: Provider.of(context).theme.messageFromOtherTextColor), textAlign: TextAlign.left, maxLines: 2, textWidthBasis: TextWidthBasis.longestLine, diff --git a/lib/widgets/messagebubble.dart b/lib/widgets/messagebubble.dart index f05908ed..ba4ecb95 100644 --- a/lib/widgets/messagebubble.dart +++ b/lib/widgets/messagebubble.dart @@ -48,7 +48,7 @@ class MessageBubbleState extends State { } } var wdgSender = SelectableText(senderDisplayStr, - style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of(context).theme.messageFromMeTextColor() : Provider.of(context).theme.messageFromOtherTextColor())); + style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor)); var wdgMessage; @@ -58,7 +58,7 @@ class MessageBubbleState extends State { //key: Key(myKey), focusNode: _focus, style: TextStyle( - color: fromMe ? Provider.of(context).theme.messageFromMeTextColor() : Provider.of(context).theme.messageFromOtherTextColor(), + color: fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor, ), textAlign: TextAlign.left, textWidthBasis: TextWidthBasis.longestLine, @@ -75,10 +75,10 @@ class MessageBubbleState extends State { //key: Key(myKey), focusNode: _focus, style: TextStyle( - color: fromMe ? Provider.of(context).theme.messageFromMeTextColor() : Provider.of(context).theme.messageFromOtherTextColor(), + color: fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor, ), linkStyle: TextStyle( - color: Provider.of(context).current().mainTextColor(), + color: Provider.of(context).current().mainTextColor, ), textAlign: TextAlign.left, textWidthBasis: TextWidthBasis.longestLine, @@ -97,11 +97,11 @@ class MessageBubbleState extends State { decoration: BoxDecoration( color: error ? malformedColor - : (fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor() : Provider.of(context).theme.messageFromOtherBackgroundColor()), + : (fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor), border: Border.all( color: error ? malformedColor - : (fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor() : Provider.of(context).theme.messageFromOtherBackgroundColor()), + : (fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor), width: 1), borderRadius: BorderRadius.only( topLeft: Radius.circular(borderRadiousEh), diff --git a/lib/widgets/messagebubbledecorations.dart b/lib/widgets/messagebubbledecorations.dart index 22ba1e91..3c2ee679 100644 --- a/lib/widgets/messagebubbledecorations.dart +++ b/lib/widgets/messagebubbledecorations.dart @@ -26,7 +26,7 @@ class _MessageBubbleDecoration extends State { children: [ Text(widget.prettyDate, style: - TextStyle(fontSize: 9.0, color: widget.fromMe ? Provider.of(context).theme.messageFromMeTextColor() : Provider.of(context).theme.messageFromOtherTextColor()), + TextStyle(fontSize: 9.0, color: widget.fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor), textAlign: widget.fromMe ? TextAlign.right : TextAlign.left), !widget.fromMe ? SizedBox(width: 1, height: 1) @@ -35,14 +35,14 @@ class _MessageBubbleDecoration extends State { child: widget.ackd == true ? Tooltip( message: AppLocalizations.of(context)!.acknowledgedLabel, - child: Icon(Icons.check_circle_outline, color: Provider.of(context).theme.messageFromMeTextColor(), size: 16)) + child: Icon(Icons.check_circle_outline, color: Provider.of(context).theme.messageFromMeTextColor, size: 16)) : (widget.errored == true ? Tooltip( message: AppLocalizations.of(context)!.couldNotSendMsgError, - child: Icon(Icons.error_outline, color: Provider.of(context).theme.messageFromMeTextColor(), size: 16)) + child: Icon(Icons.error_outline, color: Provider.of(context).theme.messageFromMeTextColor, size: 16)) : Tooltip( message: AppLocalizations.of(context)!.pendingLabel, - child: Icon(Icons.hourglass_bottom_outlined, color: Provider.of(context).theme.messageFromMeTextColor(), size: 16)))) + child: Icon(Icons.hourglass_bottom_outlined, color: Provider.of(context).theme.messageFromMeTextColor, size: 16)))) ], )); } diff --git a/lib/widgets/messagelist.dart b/lib/widgets/messagelist.dart index f56f9c66..32a81b73 100644 --- a/lib/widgets/messagelist.dart +++ b/lib/widgets/messagelist.dart @@ -35,15 +35,15 @@ class _MessageListState extends State { return RepaintBoundary( child: Container( - color: Provider.of(context).theme.backgroundMainColor(), + color: Provider.of(context).theme.backgroundMainColor, child: Column(children: [ Visibility( visible: showMessageWarning, child: Container( padding: EdgeInsets.all(5.0), - color: Provider.of(context).theme.defaultButtonActiveColor(), + color: Provider.of(context).theme.defaultButtonActiveColor, child: DefaultTextStyle( - style: TextStyle(color: Provider.of(context).theme.defaultButtonTextColor()), + style: TextStyle(color: Provider.of(context).theme.defaultButtonTextColor), child: showSyncing ? Text(AppLocalizations.of(context)!.serverNotSynced, textAlign: TextAlign.center) : showOfflineWarning @@ -66,7 +66,7 @@ class _MessageListState extends State { fit: BoxFit.scaleDown, alignment: Alignment.center, image: AssetImage("assets/core/negative_heart_512px.png"), - colorFilter: ColorFilter.mode(Provider.of(context).theme.hilightElementColor(), BlendMode.srcIn))), + colorFilter: ColorFilter.mode(Provider.of(context).theme.hilightElementColor, BlendMode.srcIn))), // Don't load messages for syncing server... child: loadMessages ? ScrollablePositionedList.builder( diff --git a/lib/widgets/messagerow.dart b/lib/widgets/messagerow.dart index 9941fb52..98f353c2 100644 --- a/lib/widgets/messagerow.dart +++ b/lib/widgets/messagerow.dart @@ -85,7 +85,7 @@ class MessageRowState extends State with SingleTickerProviderStateMi onPressed: () { Provider.of(context, listen: false).selectedIndex = Provider.of(context, listen: false).messageID; }, - icon: Icon(Icons.reply, color: Provider.of(context).theme.dropShadowColor()))); + icon: Icon(Icons.reply, color: Provider.of(context).theme.dropShadowColor))); Widget wdgSpacer = Flexible(child: SizedBox(width: 60, height: 10)); var widgetRow = []; @@ -96,7 +96,7 @@ class MessageRowState extends State with SingleTickerProviderStateMi actualMessage, ]; } else if (isBlocked && !showBlockedMessage) { - Color blockedMessageBackground = Provider.of(context).theme.messageFromOtherBackgroundColor(); + Color blockedMessageBackground = Provider.of(context).theme.messageFromOtherBackgroundColor; Widget wdgPortrait = Padding(padding: EdgeInsets.all(4.0), child: Icon(CwtchIcons.account_blocked)); widgetRow = [ wdgPortrait, @@ -118,7 +118,7 @@ class MessageRowState extends State with SingleTickerProviderStateMi AppLocalizations.of(context)!.blockedMessageMessage, //key: Key(myKey), style: TextStyle( - color: Provider.of(context).theme.messageFromOtherTextColor(), + color: Provider.of(context).theme.messageFromOtherTextColor, ), textAlign: TextAlign.center, textWidthBasis: TextWidthBasis.longestLine, @@ -152,8 +152,9 @@ class MessageRowState extends State with SingleTickerProviderStateMi diameter: 48.0, imagePath: Provider.of(context).senderImage ?? contact.imagePath, //maskOut: contact.status != "Authenticated", - border: contact.status == "Authenticated" ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor(), - badgeTextColor: Colors.red, badgeColor: Colors.red, + border: contact.status == "Authenticated" ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor, + badgeTextColor: Colors.red, + badgeColor: Colors.red, tooltip: isContact ? AppLocalizations.of(context)!.contactGoto.replaceFirst("%1", senderDisplayStr) : AppLocalizations.of(context)!.addContact, ))); @@ -216,8 +217,8 @@ class MessageRowState extends State with SingleTickerProviderStateMi Widget _bubbleNew() { return Container( decoration: BoxDecoration( - color: Provider.of(context).theme.messageFromMeBackgroundColor(), - border: Border.all(color: Provider.of(context).theme.messageFromMeBackgroundColor(), width: 1), + color: Provider.of(context).theme.messageFromMeBackgroundColor, + border: Border.all(color: Provider.of(context).theme.messageFromMeBackgroundColor, width: 1), borderRadius: BorderRadius.only( topLeft: Radius.circular(8), topRight: Radius.circular(8), diff --git a/lib/widgets/passwordfield.dart b/lib/widgets/passwordfield.dart index acd79787..e8cedd9d 100644 --- a/lib/widgets/passwordfield.dart +++ b/lib/widgets/passwordfield.dart @@ -53,21 +53,21 @@ class _CwtchTextFieldState extends State { }, icon: Icon((obscureText ? CwtchIcons.eye_closed : CwtchIcons.eye_open), semanticLabel: label), tooltip: label, - color: theme.current().mainTextColor(), - highlightColor: theme.current().defaultButtonColor(), - focusColor: theme.current().defaultButtonActiveColor(), - splashColor: theme.current().defaultButtonActiveColor(), + color: theme.current().mainTextColor, + highlightColor: theme.current().defaultButtonColor, + focusColor: theme.current().defaultButtonActiveColor, + splashColor: theme.current().defaultButtonActiveColor, ), errorStyle: TextStyle( - color: theme.current().textfieldErrorColor(), + color: theme.current().textfieldErrorColor, fontWeight: FontWeight.bold, ), - focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor(), width: 3.0)), - focusedErrorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor(), width: 3.0)), - errorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor(), width: 3.0)), + focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor, width: 3.0)), + focusedErrorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor, width: 3.0)), + errorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor, width: 3.0)), filled: true, - fillColor: theme.current().textfieldBackgroundColor(), - enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor(), width: 3.0)), + fillColor: theme.current().textfieldBackgroundColor, + enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor, width: 3.0)), ), ); }); diff --git a/lib/widgets/profileimage.dart b/lib/widgets/profileimage.dart index 00001370..f790a520 100644 --- a/lib/widgets/profileimage.dart +++ b/lib/widgets/profileimage.dart @@ -28,11 +28,11 @@ class _ProfileImageState extends State { filterQuality: FilterQuality.medium, // We need some theme specific blending here...we might want to consider making this a theme level attribute colorBlendMode: !widget.maskOut - ? Provider.of(context).theme.identifier() == "dark" + ? Provider.of(context).theme.mode == mode_dark ? BlendMode.softLight : BlendMode.darken : BlendMode.srcOut, - color: Provider.of(context).theme.portraitBackgroundColor(), + color: Provider.of(context).theme.portraitBackgroundColor, isAntiAlias: true, width: widget.diameter, height: widget.diameter, diff --git a/lib/widgets/profilerow.dart b/lib/widgets/profilerow.dart index 39bce219..a5d9e418 100644 --- a/lib/widgets/profilerow.dart +++ b/lib/widgets/profilerow.dart @@ -32,11 +32,11 @@ class _ProfileRowState extends State { padding: const EdgeInsets.all(6.0), //border size child: ProfileImage( badgeCount: 0, - badgeColor: Provider.of(context).theme.portraitProfileBadgeColor(), - badgeTextColor: Provider.of(context).theme.portraitProfileBadgeTextColor(), + badgeColor: Provider.of(context).theme.portraitProfileBadgeColor, + badgeTextColor: Provider.of(context).theme.portraitProfileBadgeTextColor, diameter: 64.0, imagePath: profile.imagePath, - border: profile.isOnline ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor())), + border: profile.isOnline ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor)), Expanded( child: Column( children: [ @@ -60,7 +60,7 @@ class _ProfileRowState extends State { IconButton( enableFeedback: true, tooltip: AppLocalizations.of(context)!.editProfile + " " + profile.nickname, - icon: Icon(Icons.create, color: Provider.of(context).current().mainTextColor()), + icon: Icon(Icons.create, color: Provider.of(context).current().mainTextColor), onPressed: () { _pushEditProfile(onion: profile.onion, displayName: profile.nickname, profileImage: profile.imagePath, encrypted: profile.isEncrypted); }, diff --git a/lib/widgets/quotedmessage.dart b/lib/widgets/quotedmessage.dart index 6d1854bc..78654f02 100644 --- a/lib/widgets/quotedmessage.dart +++ b/lib/widgets/quotedmessage.dart @@ -42,13 +42,13 @@ class QuotedMessageBubbleState extends State { } } var wdgSender = SelectableText(senderDisplayStr, - style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of(context).theme.messageFromMeTextColor() : Provider.of(context).theme.messageFromOtherTextColor())); + style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor)); var wdgMessage = SelectableText( widget.body + '\u202F', focusNode: _focus, style: TextStyle( - color: fromMe ? Provider.of(context).theme.messageFromMeTextColor() : Provider.of(context).theme.messageFromOtherTextColor(), + color: fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor, ), textAlign: TextAlign.left, textWidthBasis: TextWidthBasis.longestLine, @@ -61,11 +61,11 @@ class QuotedMessageBubbleState extends State { try { var qMessage = (snapshot.data! as Message); // Swap the background color for quoted tweets.. - var qTextColor = fromMe ? Provider.of(context).theme.messageFromOtherTextColor() : Provider.of(context).theme.messageFromMeTextColor(); + var qTextColor = fromMe ? Provider.of(context).theme.messageFromOtherTextColor : Provider.of(context).theme.messageFromMeTextColor; return Container( margin: EdgeInsets.all(5), padding: EdgeInsets.all(5), - color: fromMe ? Provider.of(context).theme.messageFromOtherBackgroundColor() : Provider.of(context).theme.messageFromMeBackgroundColor(), + color: fromMe ? Provider.of(context).theme.messageFromOtherBackgroundColor : Provider.of(context).theme.messageFromMeBackgroundColor, child: Wrap(runAlignment: WrapAlignment.spaceEvenly, alignment: WrapAlignment.spaceEvenly, runSpacing: 1.0, crossAxisAlignment: WrapCrossAlignment.center, children: [ Center(widthFactor: 1, child: Padding(padding: EdgeInsets.all(10.0), child: Icon(Icons.reply, size: 32, color: qTextColor))), Center(widthFactor: 1.0, child: DefaultTextStyle(child: qMessage.getPreviewWidget(context), style: TextStyle(color: qTextColor))) @@ -92,11 +92,11 @@ class QuotedMessageBubbleState extends State { decoration: BoxDecoration( color: error ? malformedColor - : (fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor() : Provider.of(context).theme.messageFromOtherBackgroundColor()), + : (fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor), border: Border.all( color: error ? malformedColor - : (fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor() : Provider.of(context).theme.messageFromOtherBackgroundColor()), + : (fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor), width: 1), borderRadius: BorderRadius.only( topLeft: Radius.circular(borderRadiousEh), diff --git a/lib/widgets/serverrow.dart b/lib/widgets/serverrow.dart index a4e8bb05..3acac630 100644 --- a/lib/widgets/serverrow.dart +++ b/lib/widgets/serverrow.dart @@ -29,7 +29,7 @@ class _ServerRowState extends State { Padding( padding: const EdgeInsets.all(6.0), //border size child: Icon(CwtchIcons.dns_24px, - color: server.running ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor(), size: 64)), + color: server.running ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor, size: 64)), Expanded( child: Column( children: [ @@ -38,7 +38,7 @@ class _ServerRowState extends State { semanticsLabel: server.description, style: Provider.of(context) .biggerFont - .apply(color: server.running ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor()), + .apply(color: server.running ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor), softWrap: true, overflow: TextOverflow.ellipsis, ), @@ -49,7 +49,7 @@ class _ServerRowState extends State { server.onion, softWrap: true, overflow: TextOverflow.ellipsis, - style: TextStyle(color: server.running ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor()), + style: TextStyle(color: server.running ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor), ))) ], )), @@ -58,7 +58,7 @@ class _ServerRowState extends State { IconButton( enableFeedback: true, tooltip: AppLocalizations.of(context)!.copyServerKeys, - icon: Icon(CwtchIcons.address_copy_2, color: Provider.of(context).current().mainTextColor()), + icon: Icon(CwtchIcons.address_copy_2, color: Provider.of(context).current().mainTextColor), onPressed: () { Clipboard.setData(new ClipboardData(text: server.serverBundle)); }, @@ -68,7 +68,7 @@ class _ServerRowState extends State { IconButton( enableFeedback: true, tooltip: AppLocalizations.of(context)!.editServerTitle, - icon: Icon(Icons.create, color: Provider.of(context).current().mainTextColor()), + icon: Icon(Icons.create, color: Provider.of(context).current().mainTextColor), onPressed: () { _pushEditServer(server); }, diff --git a/lib/widgets/textfield.dart b/lib/widgets/textfield.dart index f3803391..3dddd5ee 100644 --- a/lib/widgets/textfield.dart +++ b/lib/widgets/textfield.dart @@ -45,17 +45,17 @@ class _CwtchTextFieldState extends State { hintText: widget.hintText, floatingLabelBehavior: FloatingLabelBehavior.never, filled: true, - focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor(), width: 3.0)), - focusedErrorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor(), width: 3.0)), + focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor, width: 3.0)), + focusedErrorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor, width: 3.0)), - errorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor(), width: 3.0)), + errorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor, width: 3.0)), errorStyle: TextStyle( - color: theme.current().textfieldErrorColor(), + color: theme.current().textfieldErrorColor, fontWeight: FontWeight.bold, ), - fillColor: theme.current().textfieldBackgroundColor(), + fillColor: theme.current().textfieldBackgroundColor, contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0), - enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor(), width: 3.0))), + enabledBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor, width: 3.0))), ); }); } diff --git a/lib/widgets/tor_icon.dart b/lib/widgets/tor_icon.dart index 796e2a5f..5bdebfa8 100644 --- a/lib/widgets/tor_icon.dart +++ b/lib/widgets/tor_icon.dart @@ -19,7 +19,7 @@ class _TorIconState extends State { return RepaintBoundary( child: Icon( Provider.of(context).progress == 0 ? CwtchIcons.onion_off : (Provider.of(context).progress == 100 ? CwtchIcons.onion_on : CwtchIcons.onion_waiting), - color: Provider.of(context).theme.mainTextColor(), + color: Provider.of(context).theme.mainTextColor, semanticLabel: Provider.of(context).progress == 100 ? AppLocalizations.of(context)!.networkStatusOnline : (Provider.of(context).progress == 0 ? AppLocalizations.of(context)!.networkStatusDisconnected : AppLocalizations.of(context)!.networkStatusAttemptingTor), diff --git a/test/profileimage_test.dart b/test/profileimage_test.dart index cf582241..dc99213d 100644 --- a/test/profileimage_test.dart +++ b/test/profileimage_test.dart @@ -33,10 +33,10 @@ void main() { Widget testWidget = ProfileImage( imagePath: "profiles/001-centaur.png", - badgeTextColor: settingsEnglishDark.theme.portraitProfileBadgeTextColor(), - badgeColor: settingsEnglishDark.theme.portraitProfileBadgeColor(), + badgeTextColor: settingsEnglishDark.theme.portraitProfileBadgeTextColor, + badgeColor: settingsEnglishDark.theme.portraitProfileBadgeColor, maskOut: false, - border: settingsEnglishDark.theme.portraitOfflineBorderColor(), + border: settingsEnglishDark.theme.portraitOfflineBorderColor, diameter: 64.0, badgeCount: 10, ); From 089fee4c41dbbf30602126bb68a3a57f29d0b34f Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Fri, 10 Dec 2021 14:35:21 -0800 Subject: [PATCH 06/20] updates --- lib/settings.dart | 5 ----- lib/themes/cwtch.dart | 4 ++-- lib/themes/neon1.dart | 41 ++++++++++++++++++++--------------------- lib/themes/opaque.dart | 2 +- 4 files changed, 23 insertions(+), 29 deletions(-) diff --git a/lib/settings.dart b/lib/settings.dart index 30c6a59d..c0863991 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -65,11 +65,6 @@ class Settings extends ChangeNotifier { handleUpdate(dynamic settings) { // Set Theme and notify listeners this.setTheme(settings["Theme"], settings["ThemeMode"] ?? mode_dark); - /*if (settings["Theme"] == "light") { - this.setLight(); - } else { - this.setDark(); - }*/ // Set Locale and notify listeners switchLocale(Locale(settings["Locale"])); diff --git a/lib/themes/cwtch.dart b/lib/themes/cwtch.dart index 8d904c36..7b272962 100644 --- a/lib/themes/cwtch.dart +++ b/lib/themes/cwtch.dart @@ -56,7 +56,7 @@ class CwtchDark extends OpaqueThemeType { get sendHintTextColor => mauvePurple; get hilightElementColor => purple; get defaultButtonColor => accent; //hotPink; - get defaultButtonActiveColor => pink; + //get defaultButtonActiveColor => pink; get defaultButtonTextColor => whiteishPurple; get defaultButtonDisabledColor => lightGrey; get defaultButtonDisabledTextColor => darkGreyPurple; @@ -102,7 +102,7 @@ class CwtchLight extends OpaqueThemeType { get sendHintTextColor => purple; get hilightElementColor => purple; //darkPurple; // todo shouldn't be this, too dark, makes font unreadable get defaultButtonColor => accent; // hotPink; - get defaultButtonActiveColor => pink; // todo: lighten in light, darken in dark + //get defaultButtonActiveColor => pink; // todo: lighten in light, darken in dark get defaultButtonTextColor => whitePurple; // ? get defaultButtonDisabledColor => softGrey; get textfieldBackgroundColor => purple; diff --git a/lib/themes/neon1.dart b/lib/themes/neon1.dart index f3b2a505..58e85443 100644 --- a/lib/themes/neon1.dart +++ b/lib/themes/neon1.dart @@ -1,6 +1,7 @@ import 'dart:ui'; import 'dart:core'; +import 'package:cwtch/themes/cwtch.dart'; import 'package:flutter/material.dart'; import 'opaque.dart'; @@ -34,7 +35,7 @@ OpaqueThemeType GetNeon1Theme(String mode) { } } -class Neon1Dark extends OpaqueThemeType { +class Neon1Dark extends CwtchDark { static final Color background = Color(0xFF290826); static final Color header = Color(0xFF290826); static final Color userBubble = Color(0xFFD20070); @@ -49,19 +50,18 @@ class Neon1Dark extends OpaqueThemeType { get backgroundMainColor => background; // darkGreyPurple; get backgroundPaneColor => header; //darkGreyPurple; - get backgroundHilightElementColor => deepPurple; + //get backgroundHilightElementColor => deepPurple; get mainTextColor => font; //whiteishPurple; - get sendHintTextColor => mauvePurple; - get hilightElementColor => purple; + //get sendHintTextColor => mauvePurple; + //get hilightElementColor => purple; get defaultButtonColor => accent; //hotPink; - get defaultButtonActiveColor => pink; - get defaultButtonTextColor => whiteishPurple; + /*get defaultButtonTextColor => whiteishPurple; get defaultButtonDisabledColor => lightGrey; get defaultButtonDisabledTextColor => darkGreyPurple; get textfieldBackgroundColor => deepPurple; - get textfieldBorderColor => deepPurple; + get textfieldBorderColor => deepPurple;*/ get textfieldHintColor => mainTextColor; //TODO pick - get textfieldErrorColor => hotPink; + /* get textfieldErrorColor => hotPink; get scrollbarDefaultColor => purple; get portraitBackgroundColor => deepPurple; get portraitOnlineBorderColor => whiteishPurple; @@ -72,7 +72,7 @@ class Neon1Dark extends OpaqueThemeType { get portraitContactBadgeTextColor => whiteishPurple; get portraitProfileBadgeColor => mauvePurple; get portraitProfileBadgeTextColor => darkGreyPurple; - get dropShadowColor => mauvePurple; + get dropShadowColor => mauvePurple;*/ get toolbarIconColor => settings; //whiteishPurple; get messageFromMeBackgroundColor => userBubble; // mauvePurple; get messageFromMeTextColor => font; //whiteishPurple; @@ -80,7 +80,7 @@ class Neon1Dark extends OpaqueThemeType { get messageFromOtherTextColor => font; //whiteishPurple; } -class Neon1Light extends OpaqueThemeType { +class Neon1Light extends CwtchLight { static final Color background = Color(0xFFFFFDFF); static final Color header = Color(0xFFFF94C2); static final Color userBubble = Color(0xFFFF94C2); @@ -95,29 +95,28 @@ class Neon1Light extends OpaqueThemeType { get backgroundMainColor => background; //whitePurple; get backgroundPaneColor => header; //softPurple; - get backgroundHilightElementColor => softPurple; + //get backgroundHilightElementColor => softPurple; get mainTextColor => settings; - get sendHintTextColor => purple; - get hilightElementColor => purple; //darkPurple; // todo shouldn't be this, too dark, makes font unreadable + //get sendHintTextColor => purple; + //get hilightElementColor => purple; //darkPurple; // todo shouldn't be this, too dark, makes font unreadable get defaultButtonColor => accent; // hotPink; - get defaultButtonActiveColor => pink; // todo: lighten in light, darken in dark - get defaultButtonTextColor => whitePurple; // ? + /*get defaultButtonTextColor => whitePurple; // ? get defaultButtonDisabledColor => softGrey; get textfieldBackgroundColor => purple; - get textfieldBorderColor => purple; + get textfieldBorderColor => purple; */ get textfieldHintColor => font; //TODO pick - get textfieldErrorColor => hotPink; + //get textfieldErrorColor => hotPink; get scrollbarDefaultColor => accent; - get portraitBackgroundColor => softPurple; + /*get portraitBackgroundColor => softPurple; get portraitOnlineBorderColor => greyPurple; get portraitOfflineBorderColor => greyPurple; get portraitBlockedBorderColor => softGrey; - get portraitBlockedTextColor => softGrey; + get portraitBlockedTextColor => softGrey;*/ get portraitContactBadgeColor => accent; - get portraitContactBadgeTextColor => whitePurple; + /*get portraitContactBadgeTextColor => whitePurple; get portraitProfileBadgeColor => brightPurple; get portraitProfileBadgeTextColor => whitePurple; - get dropShadowColor => purple; + get dropShadowColor => purple;*/ get toolbarIconColor => settings; //darkPurple; get messageFromMeBackgroundColor => userBubble; //brightPurple; get messageFromMeTextColor => font; //mainTextColor; diff --git a/lib/themes/opaque.dart b/lib/themes/opaque.dart index bd037c08..f75a6ba4 100644 --- a/lib/themes/opaque.dart +++ b/lib/themes/opaque.dart @@ -68,7 +68,7 @@ abstract class OpaqueThemeType { get sendHintTextColor => red; get defaultButtonColor => red; - get defaultButtonActiveColor => mode == mode_light ? lighten(defaultButtonColor) : darken(defaultButtonColor); + get defaultButtonActiveColor => mode == mode_light ? darken(defaultButtonColor) : lighten(defaultButtonColor); get defaultButtonTextColor => red; get defaultButtonDisabledColor => red; get textfieldBackgroundColor => red; From dc550daaa1c94e01e7f3ee61699d9c365467f745 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Fri, 10 Dec 2021 21:07:47 -0800 Subject: [PATCH 07/20] migrate to new libcwtch changes; add vampire and witch; tweak switch button coloring --- lib/themes/neon1.dart | 79 +++++++++++++------------------ lib/themes/opaque.dart | 6 ++- lib/themes/vampire.dart | 70 +++++++++++++++++++++++++++ lib/themes/witch.dart | 70 +++++++++++++++++++++++++++ lib/views/addeditservers.dart | 4 +- lib/views/globalsettingsview.dart | 16 +++---- lib/views/peersettingsview.dart | 2 +- lib/widgets/contactrow.dart | 2 +- 8 files changed, 189 insertions(+), 60 deletions(-) create mode 100644 lib/themes/vampire.dart create mode 100644 lib/themes/witch.dart diff --git a/lib/themes/neon1.dart b/lib/themes/neon1.dart index 58e85443..2b4e396d 100644 --- a/lib/themes/neon1.dart +++ b/lib/themes/neon1.dart @@ -9,24 +9,6 @@ import 'opaque.dart'; final neon1_theme = "neon1"; final neon1_name = "Neon1"; //Todo translate -final Color darkGreyPurple = Color(0xFF281831); -final Color deepPurple = Color(0xFF422850); -final Color mauvePurple = Color(0xFF8E64A5); -final Color whiteishPurple = Color(0xFFE3DFE4); -final Color lightGrey = Color(0xFF9E9E9E); - -final Color whitePurple = Color(0xFFFFFDFF); -final Color softPurple = Color(0xFFFDF3FC); -final Color purple = Color(0xFFDFB9DE); -final Color brightPurple = Color(0xFFD1B0E0); // not in new: portrait badge color -final Color darkPurple = Color(0xFF350052); -final Color greyPurple = Color(0xFF775F84); // not in new: portrait borders -final Color pink = Color(0xFFE85DA1); // not in new: active button color -final Color hotPink = Color(0xFFD20070); // Color(0xFFD01972); -final Color softGrey = Color(0xFFB3B6B3); // not in new theme: blocked -//static final Color softGreen = Color(0xFFA0FFB0); -//static final Color softRed = Color(0xFFFFA0B0); - OpaqueThemeType GetNeon1Theme(String mode) { if (mode == mode_dark) { return Neon1Dark(); @@ -50,18 +32,24 @@ class Neon1Dark extends CwtchDark { get backgroundMainColor => background; // darkGreyPurple; get backgroundPaneColor => header; //darkGreyPurple; - //get backgroundHilightElementColor => deepPurple; get mainTextColor => font; //whiteishPurple; - //get sendHintTextColor => mauvePurple; - //get hilightElementColor => purple; get defaultButtonColor => accent; //hotPink; - /*get defaultButtonTextColor => whiteishPurple; + get textfieldHintColor => mainTextColor; //TODO pick + get toolbarIconColor => settings; //whiteishPurple; + get messageFromMeBackgroundColor => userBubble; // mauvePurple; + get messageFromMeTextColor => font; //whiteishPurple; + get messageFromOtherBackgroundColor => peerBubble; //deepPurple; + get messageFromOtherTextColor => font; //whiteishPurple; + + /*get backgroundHilightElementColor => deepPurple; + get sendHintTextColor => mauvePurple; + get hilightElementColor => purple; + get defaultButtonTextColor => whiteishPurple; get defaultButtonDisabledColor => lightGrey; get defaultButtonDisabledTextColor => darkGreyPurple; get textfieldBackgroundColor => deepPurple; - get textfieldBorderColor => deepPurple;*/ - get textfieldHintColor => mainTextColor; //TODO pick - /* get textfieldErrorColor => hotPink; + get textfieldBorderColor => deepPurple; + get textfieldErrorColor => hotPink; get scrollbarDefaultColor => purple; get portraitBackgroundColor => deepPurple; get portraitOnlineBorderColor => whiteishPurple; @@ -73,11 +61,7 @@ class Neon1Dark extends CwtchDark { get portraitProfileBadgeColor => mauvePurple; get portraitProfileBadgeTextColor => darkGreyPurple; get dropShadowColor => mauvePurple;*/ - get toolbarIconColor => settings; //whiteishPurple; - get messageFromMeBackgroundColor => userBubble; // mauvePurple; - get messageFromMeTextColor => font; //whiteishPurple; - get messageFromOtherBackgroundColor => peerBubble; //deepPurple; - get messageFromOtherTextColor => font; //whiteishPurple; + } class Neon1Light extends CwtchLight { @@ -95,31 +79,32 @@ class Neon1Light extends CwtchLight { get backgroundMainColor => background; //whitePurple; get backgroundPaneColor => header; //softPurple; - //get backgroundHilightElementColor => softPurple; get mainTextColor => settings; - //get sendHintTextColor => purple; - //get hilightElementColor => purple; //darkPurple; // todo shouldn't be this, too dark, makes font unreadable get defaultButtonColor => accent; // hotPink; - /*get defaultButtonTextColor => whitePurple; // ? - get defaultButtonDisabledColor => softGrey; - get textfieldBackgroundColor => purple; - get textfieldBorderColor => purple; */ get textfieldHintColor => font; //TODO pick - //get textfieldErrorColor => hotPink; get scrollbarDefaultColor => accent; - /*get portraitBackgroundColor => softPurple; - get portraitOnlineBorderColor => greyPurple; - get portraitOfflineBorderColor => greyPurple; - get portraitBlockedBorderColor => softGrey; - get portraitBlockedTextColor => softGrey;*/ get portraitContactBadgeColor => accent; - /*get portraitContactBadgeTextColor => whitePurple; - get portraitProfileBadgeColor => brightPurple; - get portraitProfileBadgeTextColor => whitePurple; - get dropShadowColor => purple;*/ get toolbarIconColor => settings; //darkPurple; get messageFromMeBackgroundColor => userBubble; //brightPurple; get messageFromMeTextColor => font; //mainTextColor; get messageFromOtherBackgroundColor => peerBubble; //purple; get messageFromOtherTextColor => font; //darkPurple; + + /*get backgroundHilightElementColor => softPurple; + get sendHintTextColor => purple; + get hilightElementColor => purple; //darkPurple; // todo shouldn't be this, too dark, makes font unreadable + get defaultButtonTextColor => whitePurple; // ? + get defaultButtonDisabledColor => softGrey; + get textfieldBackgroundColor => purple; + get textfieldBorderColor => purple; + get textfieldErrorColor => hotPink; + get portraitBackgroundColor => softPurple; + get portraitOnlineBorderColor => greyPurple; + get portraitOfflineBorderColor => greyPurple; + get portraitBlockedBorderColor => softGrey; + get portraitBlockedTextColor => softGrey; + get portraitContactBadgeTextColor => whitePurple; + get portraitProfileBadgeColor => brightPurple; + get portraitProfileBadgeTextColor => whitePurple; + get dropShadowColor => purple;*/ } \ No newline at end of file diff --git a/lib/themes/opaque.dart b/lib/themes/opaque.dart index f75a6ba4..7f63902e 100644 --- a/lib/themes/opaque.dart +++ b/lib/themes/opaque.dart @@ -3,6 +3,8 @@ import 'dart:core'; import 'package:cwtch/themes/cwtch.dart'; import 'package:cwtch/themes/neon1.dart'; +import 'package:cwtch/themes/vampire.dart'; +import 'package:cwtch/themes/witch.dart'; import 'package:flutter/material.dart'; import 'package:cwtch/settings.dart'; @@ -11,6 +13,8 @@ const mode_dark = "dark"; final themes = { cwtch_theme: {mode_light: CwtchLight(), mode_dark: CwtchDark()}, neon1_theme: {mode_light: Neon1Light(), mode_dark: Neon1Dark()}, + witch_theme: {mode_light: WitchLight(), mode_dark: WitchDark()}, + vampire_theme: {mode_light: VampireLight(), mode_dark: VampireDark()}, }; OpaqueThemeType getTheme(String themeId, String mode) { @@ -68,7 +72,7 @@ abstract class OpaqueThemeType { get sendHintTextColor => red; get defaultButtonColor => red; - get defaultButtonActiveColor => mode == mode_light ? darken(defaultButtonColor) : lighten(defaultButtonColor); + get defaultButtonActiveColor => /*mode == mode_light ? darken(defaultButtonColor) :*/ lighten(defaultButtonColor); get defaultButtonTextColor => red; get defaultButtonDisabledColor => red; get textfieldBackgroundColor => red; diff --git a/lib/themes/vampire.dart b/lib/themes/vampire.dart new file mode 100644 index 00000000..a0ba8191 --- /dev/null +++ b/lib/themes/vampire.dart @@ -0,0 +1,70 @@ +import 'dart:ui'; +import 'dart:core'; + +import 'package:cwtch/themes/cwtch.dart'; +import 'package:flutter/material.dart'; + +import 'opaque.dart'; + +final vampire_theme = "vampire"; +final vampire_name = "Vampire"; //Todo translate + +OpaqueThemeType GetVampireTheme(String mode) { + if (mode == mode_dark) { + return VampireDark(); + } else { + return VampireLight(); + } +} + +class VampireDark extends CwtchDark { + static final Color background = Color(0xFF281831); + static final Color header = Color(0xFF281831); + static final Color userBubble = Color(0xFF9A1218); + static final Color peerBubble = Color(0xFF422850); + static final Color font = Color(0xFFFFFFFF); + static final Color settings = Color(0xFFFDFFFD); + static final Color accent = Color(0xFF8E64A5); + + get name => vampire_name; + get theme => vampire_theme; + get mode => mode_dark; + + get backgroundMainColor => background; // darkGreyPurple; + get backgroundPaneColor => header; //darkGreyPurple; + get mainTextColor => font; //whiteishPurple; + get defaultButtonColor => accent; //hotPink; + get textfieldHintColor => mainTextColor; //TODO pick + get toolbarIconColor => settings; //whiteishPurple; + get messageFromMeBackgroundColor => userBubble; // mauvePurple; + get messageFromMeTextColor => font; //whiteishPurple; + get messageFromOtherBackgroundColor => peerBubble; //deepPurple; + get messageFromOtherTextColor => font; //whiteishPurple; +} + +class VampireLight extends CwtchLight { + static final Color background = Color(0xFFFFFDFD); + static final Color header = Color(0xFFD8C7E1); + static final Color userBubble = Color(0xFFD8C7E1); + static final Color peerBubble = Color(0xFFFFEBEE); + static final Color font = Color(0xFF281831); + static final Color settings = Color(0xFF281831); + static final Color accent = Color(0xFF8E64A5); + + get name => vampire_name; + get theme => vampire_theme; + get mode => mode_light; + + get backgroundMainColor => background; //whitePurple; + get backgroundPaneColor => header; //softPurple; + get mainTextColor => settings; + get defaultButtonColor => accent; // hotPink; + get textfieldHintColor => font; //TODO pick + get scrollbarDefaultColor => accent; + get portraitContactBadgeColor => accent; + get toolbarIconColor => settings; //darkPurple; + get messageFromMeBackgroundColor => userBubble; //brightPurple; + get messageFromMeTextColor => font; //mainTextColor; + get messageFromOtherBackgroundColor => peerBubble; //purple; + get messageFromOtherTextColor => font; //darkPurple; +} \ No newline at end of file diff --git a/lib/themes/witch.dart b/lib/themes/witch.dart new file mode 100644 index 00000000..069051ed --- /dev/null +++ b/lib/themes/witch.dart @@ -0,0 +1,70 @@ +import 'dart:ui'; +import 'dart:core'; + +import 'package:cwtch/themes/cwtch.dart'; +import 'package:flutter/material.dart'; + +import 'opaque.dart'; + +final witch_theme = "witch"; +final witch_name = "Witch"; //Todo translate + +OpaqueThemeType GetWitchTheme(String mode) { + if (mode == mode_dark) { + return WitchDark(); + } else { + return WitchLight(); + } +} + +class WitchDark extends CwtchDark { + static final Color background = Color(0xFF0E1E0E); + static final Color header = Color(0xFF0E1E0E); + static final Color userBubble = Color(0xFF1B5E20); + static final Color peerBubble = Color(0xFF003300); + static final Color font = Color(0xFFFFFFFF); + static final Color settings = Color(0xFFFDFFFD); + static final Color accent = Color(0xFFD20070); + + get name => witch_name; + get theme => witch_theme; + get mode => mode_dark; + + get backgroundMainColor => background; // darkGreyPurple; + get backgroundPaneColor => header; //darkGreyPurple; + get mainTextColor => font; //whiteishPurple; + get defaultButtonColor => accent; //hotPink; + get textfieldHintColor => mainTextColor; //TODO pick + get toolbarIconColor => settings; //whiteishPurple; + get messageFromMeBackgroundColor => userBubble; // mauvePurple; + get messageFromMeTextColor => font; //whiteishPurple; + get messageFromOtherBackgroundColor => peerBubble; //deepPurple; + get messageFromOtherTextColor => font; //whiteishPurple; +} + +class WitchLight extends CwtchLight { + static final Color background = Color(0xFFFDFFFD); + static final Color header = Color(0xFF80E27E); + static final Color userBubble = Color(0xFF80E27E); + static final Color peerBubble = Color(0xFFE8F5E9); + static final Color font = Color(0xFF0E1E0E); + static final Color settings = Color(0xFF0E1E0E); + static final Color accent = Color(0xFFD20070); + + get name => witch_name; + get theme => witch_theme; + get mode => mode_light; + + get backgroundMainColor => background; //whitePurple; + get backgroundPaneColor => header; //softPurple; + get mainTextColor => settings; + get defaultButtonColor => accent; // hotPink; + get textfieldHintColor => font; //TODO pick + get scrollbarDefaultColor => accent; + get portraitContactBadgeColor => accent; + get toolbarIconColor => settings; //darkPurple; + get messageFromMeBackgroundColor => userBubble; //brightPurple; + get messageFromMeTextColor => font; //mainTextColor; + get messageFromOtherBackgroundColor => peerBubble; //purple; + get messageFromOtherTextColor => font; //darkPurple; +} \ No newline at end of file diff --git a/lib/views/addeditservers.dart b/lib/views/addeditservers.dart index 415866b7..e73ec0e4 100644 --- a/lib/views/addeditservers.dart +++ b/lib/views/addeditservers.dart @@ -129,7 +129,7 @@ class _AddEditServerViewState extends State { Provider.of(context, listen: false).cwtch.StopServer(serverInfoState.onion); } }, - activeTrackColor: settings.theme.defaultButtonActiveColor, + activeTrackColor: settings.theme.defaultButtonColor, inactiveTrackColor: settings.theme.defaultButtonDisabledColor, secondary: Icon(CwtchIcons.negative_heart_24px, color: settings.current().mainTextColor), )), @@ -146,7 +146,7 @@ class _AddEditServerViewState extends State { Provider.of(context, listen: false).cwtch.SetServerAttribute(serverInfoState.onion, "autostart", value ? "true" : "false"); } }, - activeTrackColor: settings.theme.defaultButtonActiveColor, + activeTrackColor: settings.theme.defaultButtonColor, inactiveTrackColor: settings.theme.defaultButtonDisabledColor, secondary: Icon(CwtchIcons.favorite_24dp, color: settings.current().mainTextColor), ), diff --git a/lib/views/globalsettingsview.dart b/lib/views/globalsettingsview.dart index 66b14ec2..0156e32f 100644 --- a/lib/views/globalsettingsview.dart +++ b/lib/views/globalsettingsview.dart @@ -77,7 +77,7 @@ class _GlobalSettingsViewState extends State { // Save Settings... saveSettings(context); }, - activeTrackColor: settings.theme.defaultButtonActiveColor, + activeTrackColor: settings.theme.defaultButtonColor, inactiveTrackColor: settings.theme.defaultButtonDisabledColor, secondary: Icon(CwtchIcons.change_theme, color: settings.current().mainTextColor), ), @@ -153,7 +153,7 @@ class _GlobalSettingsViewState extends State { // Save Settings... saveSettings(context); }, - activeTrackColor: settings.theme.defaultButtonActiveColor, + activeTrackColor: settings.theme.defaultButtonColor, inactiveTrackColor: settings.theme.defaultButtonDisabledColor, secondary: Icon(CwtchIcons.block_unknown, color: settings.current().mainTextColor), ), @@ -166,7 +166,7 @@ class _GlobalSettingsViewState extends State { // Save Settings... saveSettings(context); }, - activeTrackColor: settings.theme.defaultButtonActiveColor, + activeTrackColor: settings.theme.defaultButtonColor, inactiveTrackColor: settings.theme.defaultButtonDisabledColor, secondary: Icon(CwtchIcons.streamer_bunnymask, color: settings.current().mainTextColor), ), @@ -183,7 +183,7 @@ class _GlobalSettingsViewState extends State { // Save Settings... saveSettings(context); }, - activeTrackColor: settings.theme.defaultButtonActiveColor, + activeTrackColor: settings.theme.defaultButtonColor, inactiveTrackColor: settings.theme.defaultButtonDisabledColor, secondary: Icon(CwtchIcons.enable_experiments, color: settings.current().mainTextColor), ), @@ -204,7 +204,7 @@ class _GlobalSettingsViewState extends State { // Save Settings... saveSettings(context); }, - activeTrackColor: settings.theme.defaultButtonActiveColor, + activeTrackColor: settings.theme.defaultButtonColor, inactiveTrackColor: settings.theme.defaultButtonDisabledColor, secondary: Icon(CwtchIcons.enable_groups, color: settings.current().mainTextColor), ), @@ -224,7 +224,7 @@ class _GlobalSettingsViewState extends State { // Save Settings... saveSettings(context); }, - activeTrackColor: settings.theme.defaultButtonActiveColor, + activeTrackColor: settings.theme.defaultButtonColor, inactiveTrackColor: settings.theme.defaultButtonDisabledColor, secondary: Icon(CwtchIcons.dns_24px, color: settings.current().mainTextColor), )), @@ -240,7 +240,7 @@ class _GlobalSettingsViewState extends State { } saveSettings(context); }, - activeTrackColor: settings.theme.defaultButtonActiveColor, + activeTrackColor: settings.theme.defaultButtonColor, inactiveTrackColor: settings.theme.defaultButtonDisabledColor, secondary: Icon(Icons.attach_file, color: settings.current().mainTextColor), ), @@ -256,7 +256,7 @@ class _GlobalSettingsViewState extends State { } saveSettings(context); }, - activeTrackColor: settings.theme.defaultButtonActiveColor, + activeTrackColor: settings.theme.defaultButtonColor, inactiveTrackColor: settings.theme.defaultButtonDisabledColor, secondary: Icon(Icons.link, color: settings.current().mainTextColor), ), diff --git a/lib/views/peersettingsview.dart b/lib/views/peersettingsview.dart index 0e02df17..57f42b40 100644 --- a/lib/views/peersettingsview.dart +++ b/lib/views/peersettingsview.dart @@ -137,7 +137,7 @@ class _PeerSettingsViewState extends State { Provider.of(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson); } }, - activeTrackColor: settings.theme.defaultButtonActiveColor, + activeTrackColor: settings.theme.defaultButtonColor, inactiveTrackColor: settings.theme.defaultButtonDisabledColor, secondary: Icon(CwtchIcons.block_peer, color: settings.current().mainTextColor), ), diff --git a/lib/widgets/contactrow.dart b/lib/widgets/contactrow.dart index ff1e963f..5872dddb 100644 --- a/lib/widgets/contactrow.dart +++ b/lib/widgets/contactrow.dart @@ -23,7 +23,7 @@ class _ContactRowState extends State { var contact = Provider.of(context); return Card( clipBehavior: Clip.antiAlias, - color: Provider.of(context).selectedConversation == contact.onion ? Provider.of(context).theme.backgroundHilightElementColor : null, + color: Provider.of(context).selectedConversation == contact.identifier ? Provider.of(context).theme.backgroundHilightElementColor : null, borderOnForeground: false, margin: EdgeInsets.all(0.0), child: InkWell( From e5997686434e6f50d4a3c3e0914191cde4a288fc Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Tue, 14 Dec 2021 13:29:13 -0600 Subject: [PATCH 08/20] update with new PRs rebase, update goldens for slight variance --- lib/main_test.dart | 2 +- lib/themes/opaque.dart | 2 +- lib/views/addeditservers.dart | 2 +- lib/views/globalsettingsview.dart | 2 +- lib/views/profileserversview.dart | 2 +- lib/views/remoteserverview.dart | 4 ++-- lib/widgets/buttontextfield.dart | 2 +- lib/widgets/remoteserverrow.dart | 6 +++--- test/buttontextfield_test.dart | 5 +++-- test/cwtchlabel_test.dart | 5 +++-- test/profileimage_test.dart | 5 +++-- test/textfield_basic.png | Bin 6274 -> 6275 bytes test/textfield_form_42.png | Bin 6263 -> 6263 bytes test/textfield_form_alpha.png | Bin 8157 -> 8123 bytes test/textfield_form_final.png | Bin 8003 -> 8060 bytes test/textfield_form_init.png | Bin 6206 -> 6235 bytes test/textfield_test.dart | 5 +++-- 17 files changed, 23 insertions(+), 19 deletions(-) diff --git a/lib/main_test.dart b/lib/main_test.dart index 07f02c72..6ba3edd8 100644 --- a/lib/main_test.dart +++ b/lib/main_test.dart @@ -14,7 +14,7 @@ import 'dart:typed_data'; import 'package:flutter_test/flutter_test.dart'; import 'package:glob/glob.dart'; -var globalSettings = Settings(Locale("en", ''), OpaqueDark()); +var globalSettings = Settings(Locale("en", ''), CwtchDark()); var globalErrorHandler = ErrorHandler(); void main() { diff --git a/lib/themes/opaque.dart b/lib/themes/opaque.dart index 7f63902e..8218934c 100644 --- a/lib/themes/opaque.dart +++ b/lib/themes/opaque.dart @@ -133,7 +133,7 @@ ThemeData mkThemeData(Settings opaque) { actionsIconTheme: IconThemeData( color: opaque.current().mainTextColor, )), - //bottomNavigationBarTheme: BottomNavigationBarThemeData(type: BottomNavigationBarType.fixed, backgroundColor: opaque.current().backgroundHilightElementColor()), // Can't determine current use + //bottomNavigationBarTheme: BottomNavigationBarThemeData(type: BottomNavigationBarType.fixed, backgroundColor: opaque.current().backgroundHilightElementColor), // Can't determine current use textButtonTheme: TextButtonThemeData( style: ButtonStyle( backgroundColor: MaterialStateProperty.all(opaque.current().defaultButtonColor), diff --git a/lib/views/addeditservers.dart b/lib/views/addeditservers.dart index e73ec0e4..1138dcdb 100644 --- a/lib/views/addeditservers.dart +++ b/lib/views/addeditservers.dart @@ -105,7 +105,7 @@ class _AddEditServerViewState extends State { ), CwtchTextField( controller: ctrlrDesc, - labelText: AppLocalizations.of(context)!.fieldDescriptionLabel, + hintText: AppLocalizations.of(context)!.fieldDescriptionLabel, autofocus: false, ) ]), diff --git a/lib/views/globalsettingsview.dart b/lib/views/globalsettingsview.dart index 0156e32f..3cdd04a5 100644 --- a/lib/views/globalsettingsview.dart +++ b/lib/views/globalsettingsview.dart @@ -245,7 +245,7 @@ class _GlobalSettingsViewState extends State { secondary: Icon(Icons.attach_file, color: settings.current().mainTextColor), ), SwitchListTile( - title: Text(AppLocalizations.of(context)!.enableExperimentClickableLinks, style: TextStyle(color: settings.current().mainTextColor())), + title: Text(AppLocalizations.of(context)!.enableExperimentClickableLinks, style: TextStyle(color: settings.current().mainTextColor)), subtitle: Text(AppLocalizations.of(context)!.experimentClickableLinksDescription), value: settings.isExperimentEnabled(ClickableLinksExperiment), onChanged: (bool value) { diff --git a/lib/views/profileserversview.dart b/lib/views/profileserversview.dart index 7ac06520..99040880 100644 --- a/lib/views/profileserversview.dart +++ b/lib/views/profileserversview.dart @@ -65,7 +65,7 @@ class _ProfileServersView extends State { final importCard = Card( child: ListTile( title: Text(AppLocalizations.of(context)!.importLocalServerLabel), - leading: Icon(CwtchIcons.add_circle_24px , color: Provider.of(context).current().mainTextColor()), + leading: Icon(CwtchIcons.add_circle_24px , color: Provider.of(context).current().mainTextColor), trailing: DropdownButton( onChanged: (String? importServer) { if (importServer!.isNotEmpty) { diff --git a/lib/views/remoteserverview.dart b/lib/views/remoteserverview.dart index bc940807..1245f7e8 100644 --- a/lib/views/remoteserverview.dart +++ b/lib/views/remoteserverview.dart @@ -130,7 +130,7 @@ class _RemoteServerViewState extends State { children: [ Text( group.nickname, - style: Provider.of(context).biggerFont.apply(color: Provider.of(context).theme.portraitOnlineBorderColor()), + style: Provider.of(context).biggerFont.apply(color: Provider.of(context).theme.portraitOnlineBorderColor), softWrap: true, overflow: TextOverflow.ellipsis, ), @@ -141,7 +141,7 @@ class _RemoteServerViewState extends State { group.onion, softWrap: true, overflow: TextOverflow.ellipsis, - style: TextStyle(color: Provider.of(context).theme.portraitOnlineBorderColor()), + style: TextStyle(color: Provider.of(context).theme.portraitOnlineBorderColor), ))) ]) ); diff --git a/lib/widgets/buttontextfield.dart b/lib/widgets/buttontextfield.dart index 4c3ad2d2..dddb7840 100644 --- a/lib/widgets/buttontextfield.dart +++ b/lib/widgets/buttontextfield.dart @@ -41,7 +41,7 @@ class _CwtchButtonTextFieldState extends State { enableIMEPersonalizedLearning: false, decoration: InputDecoration( labelText: widget.labelText, - labelStyle: TextStyle(color: theme.current().mainTextColor(), backgroundColor: theme.current().textfieldBackgroundColor()), + labelStyle: TextStyle(color: theme.current().mainTextColor, backgroundColor: theme.current().textfieldBackgroundColor), suffixIcon: IconButton( onPressed: widget.onPressed, icon: widget.icon, diff --git a/lib/widgets/remoteserverrow.dart b/lib/widgets/remoteserverrow.dart index 339a170d..bd4a8fb8 100644 --- a/lib/widgets/remoteserverrow.dart +++ b/lib/widgets/remoteserverrow.dart @@ -36,7 +36,7 @@ class _RemoteServerRowState extends State { Padding( padding: const EdgeInsets.all(6.0), //border size child: Icon(CwtchIcons.dns_24px, - color: running ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor(), + color: running ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor, size: 64) ), @@ -46,7 +46,7 @@ class _RemoteServerRowState extends State { Text( description, semanticsLabel: description, - style: Provider.of(context).biggerFont.apply(color: running ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor()), + style: Provider.of(context).biggerFont.apply(color: running ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor), softWrap: true, overflow: TextOverflow.ellipsis, ), @@ -57,7 +57,7 @@ class _RemoteServerRowState extends State { server.onion, softWrap: true, overflow: TextOverflow.ellipsis, - style: TextStyle(color: running ? Provider.of(context).theme.portraitOnlineBorderColor() : Provider.of(context).theme.portraitOfflineBorderColor()), + style: TextStyle(color: running ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor), ))) ], )), diff --git a/test/buttontextfield_test.dart b/test/buttontextfield_test.dart index 55361c2e..95c2d65a 100644 --- a/test/buttontextfield_test.dart +++ b/test/buttontextfield_test.dart @@ -5,6 +5,7 @@ // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. +import 'package:cwtch/themes/cwtch.dart'; import 'package:flutter/material.dart'; import 'package:cwtch/themes/opaque.dart'; import 'package:cwtch/settings.dart'; @@ -14,8 +15,8 @@ import 'package:provider/provider.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -var settingsEnglishDark = Settings(Locale("en", ''), OpaqueDark()); -var settingsEnglishLight = Settings(Locale("en", ''), OpaqueLight()); +var settingsEnglishDark = Settings(Locale("en", ''), CwtchDark()); +var settingsEnglishLight = Settings(Locale("en", ''), CwtchLight()); ChangeNotifierProvider getSettingsEnglishDark() => ChangeNotifierProvider.value(value: settingsEnglishDark); void main() { diff --git a/test/cwtchlabel_test.dart b/test/cwtchlabel_test.dart index 7ac0bd19..63ad75b7 100644 --- a/test/cwtchlabel_test.dart +++ b/test/cwtchlabel_test.dart @@ -5,6 +5,7 @@ // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. +import 'package:cwtch/themes/cwtch.dart'; import 'package:flutter/material.dart'; import 'package:cwtch/themes/opaque.dart'; import 'package:cwtch/settings.dart'; @@ -14,8 +15,8 @@ import 'package:provider/provider.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -var settingsEnglishDark = Settings(Locale("en", ''), OpaqueDark()); -var settingsEnglishLight = Settings(Locale("en", ''), OpaqueLight()); +var settingsEnglishDark = Settings(Locale("en", ''), CwtchDark()); +var settingsEnglishLight = Settings(Locale("en", ''), CwtchLight()); ChangeNotifierProvider getSettingsEnglishDark() => ChangeNotifierProvider.value(value: settingsEnglishDark); void main() { diff --git a/test/profileimage_test.dart b/test/profileimage_test.dart index dc99213d..239aa5aa 100644 --- a/test/profileimage_test.dart +++ b/test/profileimage_test.dart @@ -5,6 +5,7 @@ // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. +import 'package:cwtch/themes/cwtch.dart'; import 'package:flutter/material.dart'; import 'package:cwtch/themes/opaque.dart'; import 'package:cwtch/settings.dart'; @@ -14,8 +15,8 @@ import 'package:provider/provider.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -var settingsEnglishDark = Settings(Locale("en", ''), OpaqueDark()); -var settingsEnglishLight = Settings(Locale("en", ''), OpaqueLight()); +var settingsEnglishDark = Settings(Locale("en", ''), CwtchDark()); +var settingsEnglishLight = Settings(Locale("en", ''), CwtchLight()); ChangeNotifierProvider getSettingsEnglishDark() => ChangeNotifierProvider.value(value: settingsEnglishDark); String file(String slug) { diff --git a/test/textfield_basic.png b/test/textfield_basic.png index 693afb1c8287fb961caa6de2d49fd150179474e6..b17efd0799d2463672d6a97af1443a43aa3c5523 100644 GIT binary patch literal 6275 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 diff --git a/test/textfield_form_42.png b/test/textfield_form_42.png index 3d92569819c87f3ae6cd73e7074fd961d1cd749b..abb2c1375417a3f4228ab25b6976587b38af3b96 100644 GIT binary patch literal 6263 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 literal 6263 zcmeHLS6EY9)7~6Bf(0RpqM(F?018qBrAP^ejtB}Eq+2M5u7IHQqfsoBNEIPq0b@jn zfS`2LBRz1G-W38IO6UQS5b~|fx%-~yzxyx0+`!&z_N-Ym@65cj9-g-}5!xxf6M`Ti zGgCur2;!H5Aim>*+rb-c#h%mP4_}bA2@Wc3J3Iv*wgutLYz4tDLeT921RX?~8J@Ad zmBkneh@*#I8Ch)K@bKWxGqUG>ukBVpD0aBC@%c`~u_x`Seg+(=81akybp)TVA#?Ae z@o#nB>c16zQPz1zNz71pLn8!`7u|E);qDN?VqF?)7XXMa~RWa@Bb3 z%K-^Yc1Wm4=!AxL3AJY**lR-Dl{NRdYM#T{j7o(d6@;Xd13NPyBYV?aF+-B+lrWu& zpHbc%&pTVIHGNyU;TVEK*HvKFT+e zYh|n}w*71j1X+k6zTA-0halNF!C#vDq#$UYDdD=)4iPA3hYU_LVVfXSw=I(($oe_Y z9d=YO^W<)@9E}>+wTaucC-T%h&3(Q<|$kkNJoxPhcaLl3AZW){^D}{3jgk3ga$^$bDH$a;jM!F-eXHI?pdW8ZaD~WF^OH zEp33H!`B*gajTCKl@O|X)01^l=%G|yy$`Rl?=TlJ(a-32%{&q`4?vL2ryo=Fa%1T= z3oCL+E1Ld%-86|(US2ixr$FGZCOI1&UPRg>^rS?5lEfQ%Q5+`)=tkvm5tAj%%5biou<1eoo|_)j~wJvN7+6QH0xJZ zlon3aOAhOQm2I9xpN}4YQN@u)PP4dnN-oXP!cppz$jIZ$wqi@IUxo~_oLT)O1~%Q2 zO!BDA@W_8+?4uwNpWovukrrPc)=$FYHIzL4f@I>myXQWFBj!kY%zoY8*i%x?e&VLB z)21|-me-fLN6RSym{U%C$o!g2vw1lbZ9UBmDiHEKiZ1wElX(_{29Sfte7rHacd9z)(7v=0ZTraglt%1Qq#CpDI4#@kRcX<(_HZ&iI4OXs zhOgyYTEx_LL>8Y6w;8V5Sbg!%uruGL-0RoG@pe*EuwT8m08~eeQ^h6hMLNr!!iC7o z8@={Xv(K_`3yxHe@5c9&y6bAkI$Nh0sp%78YYWP^A=KSCfX$__ zu9soDhGowr_=n_Fu{Y)OC8!}|9JWwvQdU)$J-`f!lWJ(#Q?->(>jN znQvW4;=L5R4rbqA@h!*K-W~jhgrS&M5*~!zYI+rhjq!dXs$;g|3}Xkz#FK_hO1pXg3T6NZqieYSQoYsw~;GYRi?O9Es5@D7Pvf`2~c>%`%cqpAdU9;qYzgX zz~(SbN;7ZvyJvRAf$OeRQFWNoDio9J7!ou z)!g4DV)@0I+x+SLDc$Ob*C~}8TK8lSi0LRlblKvFEH1$yBKRS(`l5Vlmh&wekD0rb z&5Wq~l2Rp1R#rAvdzQ)vU2bGQB#wz9ozZU5%HKj+{;Pfd!R9yWS^SVi%@AU#gB(Si=INf^WQC3X`xCzqaf0MV^~EBE~l)h){4WNq@S&0s9w7_%ud z-YZr5GHqOIjRQfNQ-+OhZ|%s%H8*7#mK-5!JVw7wsp^=~3CU;*Xwaa{XT0`SE3YU8 z?IKUWwEA@Fw~Rc=SU%_{Mg)~icCan^e#xq`BW!5#2S2^_iz3B=3qhB~5URI9Dg<2m z{n#n}GCOQq_~GB6m}FyuMVdsxofL5?4SOK=6GFQccZP1gXbJKR+t37_$q>vq-1YKV zSA6PB``KMYu$x7X$G=M?utc(yb1a}?WVSa>m6sfoH)>Db20;kbL*89sg}#Nd$ByZP znru@-=441i5C(xte*Q+Zytw?C<>~QljT+7J{%15?|K#+?SA&&ae+Rbmd^p`-R;^U8%EYQvQ zrE&GZwN0tCt_@$tm$t8Wg^AkjRUMnc5VRctoecWRE(PrH?LQXymbx?N+HCzQ+9`Zc z-KH!GH_ZBoCBA$!(Z%D6$)Rx$47|&yjoCH>f$gRv8cT2N$ZW141g*GL*AN>f=gg&z zYL>^T6FlyshKX)oO>5Ta)F9q$M>%Jc6BzEJ7+OF=GE?qPtN8sL8e{u-@#uL7s_$qM zWKDSTZfCRSN6dqKd^$U(?Mq$SO=?!Y?L(kqz3$dneXf|9)h&zxI62SIIWj}xu}A8c zg5M>-m&;9}m!HM<0^7s&hoe@Vf7=GdyvQWzqLPs)5^#dE1`n5$4C49~fogCBUMLaE z0Vh4EAhoulr3kR4g9xkwR0onx5Y(z+3laMlUaKCG-0VLvGg-Wrs>x;dK>K|kx-3U~3_D@AUMh-~{$;hi1w z&Lio+eurW%^hM?nO?XU$Yd0Sb`xCMVXIJKo0QXYC8#dm8iB#MXglY|7TF^B!LYy4m zZ%|$DUeuTgEYb}`5U_|YLRAkI*>{EzCjg85C4y>zY1ZYJ4~S#uVA&gnjf*n+ps1Ll z>9_WRk1UQO0yhNV^YzE0bGv*K!W?unvEi~vZXyr0rn^pg_&{V!)xZ%{`zDKLPVP9w z{1Ark^k$7mFD1%dl`#Z*ucK$O`9sYkFnzp!wRfLt80`0b zMufODV9w9K5U5wu`oOtQ3>*J|H@7^Fu-1dOc_@o(hV9c_G&H>ppT&@n0{fxv6xwYa zex8-W-G{Z-DWTnN!7m151P|>2pF-gxsJk#ry^KV=y@yv0>l1b-fbC)=9}qu_NI}rw z(ulxdU+Me~fWX4+#hlF8`{j1&8fbAGp*~ZI@%F z%h*^7hzfj%#+Vg4Ri&6nZuqug*_T}2DA7lF^oJy6WUpA4WbI_okU#)7+$zTgd|dIY zi{kXQZE~W1yz0LyJU z<(|d1qC;W-UcR^oChvoKYGN)Z&V#0rG{8;70 z!NEg3%N3;P@isa+9v;Khu7oYG7MVRHb|Ja{G_zUDALqpW)$}LOq}@i+E?t@}nc*0j zj_@s&sm)vD{g`1GfQiQ?KAh0$;qmA$nl7RsH4lSd1yd`PMf}c&dc0NFeQyRt zG}J8-OQZX&=)&zJ&ZY}BR62JaDra^&s@mjeFKq)JxEpUks9OJPA8WKcNb91gGGna< z%xSOYAuZj|paULh2`A4$(DTp+EnLOo6M7wFwx>t{bg|50mB{AQ_h8Ae;RH@8g4YzW zI2hTJBP;`&<6znp+sRw~B|oH3Nw6VQt#HXp;{uzOfZs8%8SEl@=QRdLmhtR?fhK{6 z(eymIoMt<{1%;_x8_SrJ140~qkZ6X+hfvD8EZZnv0Jr+XKmq2Moc`%4H-GQXLOVdw zF*HV?hSvYdO%5TGa&sZGB+z*()H~WEz?t~u)nIEej1X;7a8k-aDMuO&(CIauD?sl; z^8+FYEEf2XUH!01$MlojD)iF5Pq2N2`Jp;9^;W^YBS>wlT66O~L@@O%cRbeJ!v`{| zMFs5^8iAp@a(km(uEu=OE@-{?+fA?ThoP5z1~A)E>Dyz| z4XZ^-{JBG3?jhcKM&IP&;vrxHDBI|maXzw1@HdQ^y2MOIj$YT;d61~@0jC4gBgU(A z_!Ij{+)@30Qpj5)Mdq|^;#XkD*KRAqtQZn7k(+ik{azTpB#cBn^SFg_o;77f69Zu9 z3m9D#I3VrFlcIq}pk16%(0Y!x1}~n!&xI$=KT0!u=5E)l%{T+Xl0Rf|fdUXSGzP+{ zf5=}H#VqgJsI29@(8ZRFQ0$z!+fAvHXPpzX!-rRf`9~sJ0FBP?4nHgolCZ`1n&O&E zq%3n5d4PnW;m7J0)iY;$kRvYnk@L^j#00F0qQ!b#%*iDqI3Zx%&Kc%C9lcOHae-X@ z{MdEPxEI?@D?8fS@vfpMP~vtU5k=9uH#vFHQ4D54qBFWI425;9mNEn_=7D%Y!AvbR)c@ps&vR*d?>5t(Hr@qC9Dpdh zxO8l7<@x57Xd=Q|qVAx<_doo`N2l*$n!tPwPsEA|j9`#zZa@V%(vj)m>8|ErNt*TC z{JY#J!j1Y-G46D|IbH(~X6M#(if|rLymeEXiyZ4fV!ZGP?eFvUpP24;08^$$Ro0x! zZZxhQtzQ8U-L3B0(m&y|mA0?-(!*}b1AxCZI`yseC_)afjS`U7;PS!pv{%_PuQCa* zGV#7YoD>x`{poKIs(8L)$I6b79js_#EdD-b^{)P=*SpaVb&v*UOLY~SEU=NSZAA5`)`*MBrOy8;}- z4dmd{yJ*802z1!ef1AVQpR12x$^z~F7XR;xL5VgFZn-M9+R|I120igx5-Fo+6%?Xj zz7g{S?kmqv!Wxgp!@HVG|L^txeDePTi0bW)i50>iM^WbhgE%M$UkO#`-<;2y%6B|{&o^N z6+N7gw<{+$$1!Kk0tbGO?4MOr5)%RRlifh+a=KJrb1_1uDNs3QW>Wr=@J*zXQzbEk zTsjgCa(_qH+=sv$VB9khW-y0`*!Fz(ZL1zDc^GgL1z$}u7jJ-8ytnE)E90HN(+IC9 ziSBo3L3YJSVqt7ZE?+`HJKYK7&Ay*sniE6nO^SyEbpu4HtE@;XIV}=hESWL0>95{X zq7o^e`Y2o+Q2Si(P>0($#>=Z#+3}OLnR=GB=4@dihJ{c1D0kZ`3Eb>0_t)oB4wQmh zQsEPaL959scvqVwri@Kz)_0L&k(NsjqZ+0?g&X~aWmqe1{Gc2i@JuUFsZQ~}Knp%c z1fBU)pKl?#%ikT`d*(}|2L!7vwac*vuhi?Ag909#ym6+`&q4s6b$?z#Td z=6y)m>85$PK8vMcjGD<|F!X9h;gcdzO<0S>P@R#M3wHV;oa;%Pl4`7*R#P>V|NPbW@&vw&$lYxa9(W21nHgCc7UC}7`47;j8LkW;Xsm1^iNr==)XogVkiO;=j-7oiD>wbLKdh>+8o_lanf~=-|IM?f(dQK|Y7PTI} z9!Dj8U4Ea_w`^F{LW^jQH_JDej+lxiE>$kSm_aWkZPD5_At*$Wt8}1gp`S!D|7yQ( zWQtocs%!kt-rnkiac7rLevDz;OG8ld{l7VLb6GmG3#8zeEdt-i*aiDcq^a2Xf|SYy zuK7ks&`OxGsjNN@5`jLRJuQJJ2nhrra)iW9Ks*u>g@AYSM4n&ij_QvT#lka>QheW53>gx^N_~88ui3p!-N*X7!BIKeb?tjNOz{oo4{MQlY zqEOZC&{YXTU-Z$v$_mGEtSPm2!6+@be%!NaoWSB@TTQLEjVgCS79xc+D<&t*^Gny) z``gGWFD|0htiuYhkH@c{BDQXCJyeW8s#@T9mcx-eII*+T+y-T|iN=a&nN$r+mUF^J zxBL3bx(=AK$9J#Xhg)q^A2#<)a}T(6vE}5-qBuRDs9s*BaNp2Fk7=%s#ad(iG4zlm zv7mzbL^J5M%PN5f;}3spSM$D0P&|)iY2|+p*wZ%4)J;IIuwYG_h0>fwTGHXR+W4iC z;*nQ>M|PCpf?~_U)U8i=dvrfH9f&P)rVJEJqf2#h#r>9^=1B-ru1CW0y)gfrJO$du zmr;89XdbJ*jQuHC3S&;`pR>XieEVn|X?<2Kx^gj`asbHq?aO#8I?>ff-#D)qVb=^n zWnGBd7?(+ZdUOV6$Yj_cD{R>mA0KbeapS`oDe%^~BN`g{CdQ|?j*=Z3;>zoGbW_|t zmL90lKbT`T-#sq!3Sx@ZUCTDbj8J{@T`gQE!a%DqSh-nLk6n|ibu7sL-@M{bqyE)b8{HLzhs`6S)RAty~{91`1pZFR%t zCpZ$Do-aT$zWDo=W0mqrC&KbVxbt2RWa9flrskrMjS2H{x;(3&sy3hZyVbatcb;{Z7TKe!207PHX1b1DU3nBAcQJ^2QCR&3omn&!ZNJ0W%g` zmu^NR(cGr=j~x|{Plp|kFsfU>QnQ>|Mn5{gzyE@!2#?OuCMLXljCg{o8v2_!av!Ec zO}F|{UR7bG?V(Ds#7o2-bsjJItu@zwJNbO@()p%A0+|l0Jv5@u zpGQzb^)1F9aENh3P77mIo|P4D^5n`4U%Y|cytP9@glWn_=(FVzRU!~63>}?8CvJ}( zOf`0MV+&o2I#Fa(J4-?&(JVSki(IJxj1tsW#RK&%63xi7SUB>kgP34=TeqZvqR=OB zXxELGjT=tTf*^etW0e=TzPqVgQbS{^jl=SqPCA*APq7y}HFT>k;2om2`s|k-{%9)y zU`Vky9woBQVdY0RvCeVn!@95GfjXIMw!Q=d+Xas$J*vJ(4tbH(M$S0Q;fASh+biza>nn%F5%ILvaS7CJ0#(U%!FNPaWgsGpzgiro-M(Roi?;E- zR4c-}j@|zU`O*G_u(+PK;Dett;=;^Mtd@8gF&YY&9#b9$H6gnq&uYR9^>q`}O(5uF z%h)K@LAiF?OoY z+tt^B*K?MmD|ZMvHCFM7`7M|8s@*JGI#aVmcCilwmJZ z)BkjOOP=_WRX2GmIO9Q=0I_6joXI{t;yjr`o4BzTRgR`t>FoL$bE?jpKa{28yL9uP zhIxhF{n4hug`&`t6p#BD%CAbj^}(rXHZWByduh(R2C8CuBd8e19E}eM>TFk`zG87=uZZ7I8lA{-@L7+{n9rtK7Prx!i9vo*lI(F4C&j)qOa6zED_jI# z%MAOX!IAvPYCNx~ebGWzaSPGBUp=B36(5q=cA*6M>O|Ia)vNloIF=4J!RlPddB|#dwCxVm!c6K3GXixhhD4q+opze zes`-UsH$0)usww0e0V^X&z`3&@D~bc-WixmXCfIsf*#<6=0fy~TuS9VZwAjl+B|_w zMn^LbPl!NO*5$IwctbN>=$eEz&XV=D8*aaHl=Tf>FufEv<89blrGZ*DA6uqQ<5eug zg2(vx7iT>@uA4cPursyek90-b8YJw2Aj01j67*e*)n(wxzz4I}-(Im#V)rsmSYlZ* z+g`vwnh?*h3+e`2iavAHD9QaCn*@y$%%K>^Cqs}sGopn$X*%HA@S9SXV2URYcZg}; z2fdbcoIlVr_DJ)@_NZ%55oys+cB-DL7~);v=p%?QC!88-Hx!rEi0EJi6r~T!K7W+6 zvGr!J;rPe~cdDOGYDKQk)ZatCLt2dMqmFTZ4@)F;2V7OpZ=5U6oADNi{Ru&lojp02 zNvmzcy0i{?^n9t)5d(o4 zU5amB2`Y5%)zC@!lq(G-ho1Y7e2NO$lqlLB{gueF$9?nN+ogFYInQIkF{Rv-dA(C& zxy|pDyjPtS6;5uO!U6CKRe=X*fA#586|Ie>e82F{KYqr$>1FUS-|2*jU+=sXg@fXf zf1u@A@m=&fHfxm+L5yhxGw;zT2;2Jzd4x@ z5j*)Y<7O8jSoXzxh~HFP8eVmqo(W>f(C7r6Wd&TCa0^2Tdlp|kz4_PKX0dS29e0e2 z=!;i45$*V)WoltYODMNViM|tho%Zw->|u+hE8MIAJ&nuctY(hqr8PC#OP2Q=_4FQi81P^$>J&*)(jQQk0JG}gOrk)#B2O6@m!2!bi&M|t75 zfiX)JM?et)sV=s)H8S1lGVD+#p{;S^IIO^fR5eSlOWXnMcrOP-nU`!KQf!MCo97#x zX>EqFu;JehrPM8W8JmuNYc#e}*D?`@KF6N!p1Pzp5{}#(+)znSr23UFI@MCI+KGfy zzKj=U2=7jgkWt3F*7j=ThW=Aqe%N9U&A>-+90Y01_AuXO2V_wVc<6fM1kUJ}J*Jh1 zZuaK>#44e8GU}NA6NaEe04gia;qqK5dgBHxFONN#Hy$W$f_K7Ibd9q;1ic4NhtB0| zC(%Q;bBAxdl0T$VY+x`H9@4#A0)i;ua+_KvyRxi~q;alSklb3Z&2Fk_4jxLe0+H`O za=JG~1p558PGR+DKCz)qufWl;sGY~wYIEqeEG7bl(M{XecXy?1IvIK-TxWaAwMzpZ zD400jC8)PA2Y@>^&vbA294vo!8ROA!Zjz^}wB8YVd~bgrY8~hQv=7)FV)@3ay=rQL%bw4Xs+@VZdL^3F)b)qUla2b*4xuA>?v<0L%aI&6Lx7@4LvbqsKt!0;hvYzU9QTl--oo+&jme;pN)*NCtgVO z0^;$Hm0y)Tvwo}qBJ;<}US-d_KUM&dE+jmEQT9v`5{zGz@%cYifKh+&VF2O>AJ1Qv z@jv)50P%y5r?G45psXyAu~2GZEGz#zGrted+?HghSb{zXVvN&ec>lV#=f<^-gSV9r zju8wtIcwMM=KLa5*UrmVQ#anFCm#0Q{CE44V}t+79+&!#dAFZ-0NviyQzmFwfNb*Q z7KZxkAqeuie)=3o;unCc&#AnC3EA&ID&uJKgOOe8Z#K!mo^SRlcgTRfzsNZL2EKr3 z03`~U`0bSG_W^7ns*2?&E3osm;VsPSFJR|&MHTqu&w#62ngm^VGj#AIGPREq73XHh zu$55(hoAh6wCXlh+H90?7ZozK1OBzPxs`tlqbKC>{vWo4b=y(PVT)u4vbekIn-DcV zDtM;?mlDcY_T~-m#{SdiW>)@BR?#qDDN3`t1yr1@XJl+iY~0Kkl-+L(R2cQ>d>SoP z_(Zq#M>0HqeoUCzHe*{=@>-Ws7|vdB=siM( z)zX}6QbF2yXUeyDmtuZ>NHtgi1YL-y=u%c}$MUIZYpt+2rk!U{K1QvWh*oc4E>D#DxE$d-@p2PsO!(c=)0H(={@z4iB06m!~}jip4WU+oLP@5 zEBFf-I}QGH6p!plX$nX@+LgH#5hQun@cSp%BIj$Xv$4n(=OazaHx1Z>o6-ng^@n>8 z&mSPFkRin8$Qo|rsGnY z)bhzt_;#a!Qmb>^I}(S@SKYX!0)cd;ta9kj7*L~%alv*z2Z0ZVF#fPqS4@a3F*0fn ztCI*cv>5k}vx}Q4H6LI5m@%C<;~tRsFL2Krj6E{p-?|@6ET$_}RLClWOeekCt^(Q& z7t`-wyI%<1NH%muLO5d3yMw8p6Akx6%+5^#*Ta+Pf>e1yAIHe_1#X!;N>3PzXU6}H zozs5I{H__lI$Fb{c@jnV4@j=?Z8Wn)+}!9G{zH##ssBz0;%($$!nQWe;g_SY_4cLa z9aJda;(IdJDeMu^g8ny;U_wcvQe4>uuv4XqCLTFId}5F1Vsx3)^XEgJ%qwW`$#uOkGv`NkWL(|)}o{pPPUxY7J@aeZ=5qt&C$PXMJDs+a?CZ4T3}hc^>d)9 z)-{QJ;=()U13>{<(Pz7R0LSV6D}^m2IR${wRL8RTPm4vR9L$a}f@OvA{!&3EJQ}S= zM)lMdvs;2&C8aRM6@2;b>)OFrWZ{OEU_7__v0K8>6>a-S7WP4JyLD}s6hMuh66k*d_t4%UC!@@{lgUb}Rk9ZU30@LxmLAj+PDUrayDLvD`lNXF? z&)CuJHF9N!9bS=hATZ`BG0xRTci?eLv@QLKknhV!!Wo*HjUdsPR=X5y^^=;l;+!II zARY3zE2wvOrF0%HJ+YeMtq3%zZ ztd6FkkZb6MONtJgOO46GO#U;y{yN{}=%q%JOm@ z8yY+#-M2dRJ~9bl{T2mDp=27HhT**aht2j={}Q&b>tC)kYl`w`xk)3jG{Z~8-sRY9 zZ63ox$-2Z6xA4L}6`!_yZi*-Q@p4-)*EC63V<$Hw_{&>aiXQ;8(CdDM2IhZX3ER`R zJY~#A^2#TYtPiGkI0ybck!y=v5OH4`LQZ*CZzqM(K%N(ML9_%5&huqZq)$*&{$ z1|PN*leLLuHmq^$TG$$BA~m-cpPBC6Uq=A6Pfy*flrhi||$Wt`q9#2_0zdnUx zM>21}2tKSIWKEnQk}V|{KYTdz6^WnArL~FfjXkyU45tDIof&Af)FFxn*Dg<38+Qg_SJaFc{!N+O?^J^;osVJWX>6$o_Veu-3Sb9GkKhYn zeIyud+$@B71hyUo?OlC~FhEV*$-$lJK2_A`?!vK#r|KHKc{Z}5GP9_tW63jNm&;`! zg|N}PU+r3MXokmI2!tPPAO(mHth`$X#; zfuCIaTEFjq&x&ZyffKRZhJ(s@GYec>=z`zYysOp_ub7ZIr4-+uFz)Yh z8)H{3a~ZZ(y~f~o6XSU?lJRK}1O=}FcQUKt5HC%tTB|p&hsTecn_?WhnL$Y|i=6Dc zyA+n+HW&iR*sH(loO_Wsm1vxGrEAlz2!v&QpOzbv0md0L`!?OM?9nmYtSBh*Uo)OM z@mZf!kg~ZAB^Oge=#YDTr3*PJo8)*4)DWZ5;_F7jQ#ytGo_QF^8uCylu(oUndh zeiS>jY~O$ofh_ixfELZ=K(Ft$3o&JpBni5{NKL;dQkqp)yPxxEdg86Q9O&CyDy8nR z^Tq60)bXNE>xP^=n9u`2nRlV zfvXVz#z%2JGCDP67BXZ2Be)JnBR~_KP?pq@oD!>}qEe?*H#>?dBO=Rc6p>zjeU{XlykFO;4ULRv_F zl&^9+83G9gOoW7(z=Dyd@MB9r>7)PfulLOO!RfazYn@%~M=ZdVZzVwHeR52A;h*<} zY<8*sSId#8I0!#xH>oqf{0p@)*lRNSA|_ljgD1LqiHPJH~EE@RVsYGi2# z@7xs06oO*s0sQ>hRg+Ri$fWhgTHV3+%AwGDrfW^p)@D`WPcLpXIIp4NBy_%E`3eNZ zw@bg%X6|t|wgNw&E=s@N`6lhJ?KXoqF)j@`os;dAof{--C~S+QKhUl;Ow)1$&%7)| z`xkx}s_3_~$q)pk{doO4@8;cp59>yKK=p+`F0Yg2g$QPu;tlF*?rYIo~89_e)D8WzzZ z{yI-Ot9DXr_s^hZtDpv@ROWLVALUA67>|>(vjdNWfJh2mDARA;M0b@B4!vFJ!h!(! zL-jEd?uU{r0(UUTF)PkQdGlIlv4!Qg{!*aE*|O;nr7x8gU1oPN#ig%bIgEjPr>qpC_={c-@a_9t*#x@tI{aNKCVu1p6 j#AFhj`G0;wE^jOCmn)WMp12Yq++=;m{&a<<-#`BgwP_a6 literal 8157 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 literal 8003 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 VPI3JjvZrAt>_wbWvEj}C{1+07y4e5# literal 6206 zcmeHLX*`tc-@m10TBK? zm`<{VnG*(sp|VW&tYgM7&vpBMp6BztdEPxQ|MO;MuIqPS*KhxRfA^zHHs(V6PVIvr zNC<6VVh2Hjk`N@IjMxoU^v?C`f-iv(J989NMHQO@e|CnT(Dn%MiAH!OLePmHXp>*; zBc9JO1Cz(YJw_L4yh+*?g}I!^_jvX9yRW6Dac4~mO$$ z*0KEkO>)K%RGf(L=-zt>iaR5Ndg`@fC*;2G(INRPNC0|jC!K(ng+&H5P1>3$8})(Z zvdolaR^SP#)&f`n)2f3S;SYGS8|M0PbJ_K@JUt?JwpLVneEomN zhP7=pdgbgzH+ZtqjC$VZ=j_Qp1XKOYc@w+&5TQ^3tU6>Hfe6Q-CJDf*&A`eFxJsJA4>G>b4zrTIrN|3dx?T8$k+EDMmrv2&C=JjVcs8gI; zoeSZ*8mpukCGiZR3jzufBbKMQl&g&QO-|VNho$>5u=UVkxc@5(A3ULUMQKuqwETdPR_aYc& zrAKqhy1aeD*Il4NDlApw?wTEkb$jAS(!%J>RlzKa3Zv9;d zCtu*;f-QNlEvI>?Mzfya8?3BySqKW6O_4!8KuQ=$kF&~6&+XT+%BiHK$(m$)JJv7; z2S|sPf(X^Jq`rRM?)8_W?+qiS>1Ojzr0~*;!@$DY$KhT+VLJ4Wn@9oZvx9fS0S&__ zlQzGrkEc@(F??@`P8+7*Zz+3u16y=Ls}_B+Him+aXI=Qfir(aYC2jVKK77yeytQTR zFi9&ubQ*#@ubL$!OT$OZ+Vnom!#{;hi!6wxw_-ww?CyF(bX7HHg(D)- zwp!szuSoe@2&*&-#~vzk5gZ&LL~{9{xq zL{%4Dc1`)IT2KU*zW4{8Z~x58QSN-MJF6dfEx%q4q}ID<$Dj{8PnjlUZu@2OY?kGu z=>9Wj>3O2ppY$@IVHo>9XAT=bTQPcLT#HK5wT$jf zatbh7ZRssv{WVPhGLF1B{g^Y)Bm1mv5*JrnfI9nc)5hc7)}!aKKkp6GU1{VQR;zj% z+P!k~NJ_5k(dSp!25OM|kx1Wt5)% zx6N^nlhb!uRF+P3ew=%8>NFIm#!yAc>%hU@qACyL3R9-`h@j*A-F*8Wgg|jVcWV(k z2N%E82CZ2et`Msy@0lB_pu(o^SgW3WalPVXd+EjJf{-lxdtjf{-@aq;18w*Sm&3Vp-oaxNP7l zgdfVD51j_dvR4*W-0u>jGLu_9&sl!Gs}1B-x?9bDD6U-&ReYt$4oxftJ#Mn(W{RA# zujx6Z<$1OM6x96)KV@HivF7z%xx4_@T_aJeIH0PGX|O)741!LcL#pSUA~IZ&<+sc+b#WC+&pDnG=hY;C|H>yvBs)S%u9VsDel7(;4cQ2t#w5%1)hOWKTr|B(!K7=4+xBo7{;mylPVly#JS@-(iWoS^8u4^rNKunVUJ>sY$1hw{15uBD1{;mA2g;8riKfmFgX=kD< zZ4c!q=Lk~jp-=oh+rQtlXE&?jc0nI3=Jds9rub{-txKUVGhQha62{G+;9e~keOnNS z>|oUGKLkN$0jJgytYZ^Gffv{#-2H+!fcYIXPq2Oqs`<7mE|z8W;+g;{_Ja>dgKv-U z?ec)&Jk^!XKi(XWjdeOGcd>E1%ZK?urlXNmVvz+qHI2j_k*1M1xeFUuY14K^rw$9Qh`CM4%=|p@xOzoapN_(kqo0W~o(ccyc zt3~+KIgRBzj2@@vw;OGx@uh_Imln$s4+-pmKJ*TWOVPF%e9O8aarPUoL$5DqB6iKT z@5;9G}As_Bad#%9#XC+Z)@TqW} zhQbTO2?!A(@F;{mB-Nw<9(9+H_Id~Jh#4mwfCCk0n27%d`{f@6BqkIn0_~PWrJBKq z#F?~xgT0`gkZWr3o*8Ug5eP%XuWlQ@Q%GrW*jId*c^jvdubdZ#g%hwy(b8=%5}XyZ zQ%`2xPl6lNxJrth34Iv@o1ra@MRB)vK$uv>!a5vygwS~k>mYSlY6B*|=e?x80%0A@ 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 diff --git a/test/textfield_test.dart b/test/textfield_test.dart index a133cb1e..27ea0f3e 100644 --- a/test/textfield_test.dart +++ b/test/textfield_test.dart @@ -7,6 +7,7 @@ import 'package:flutter/material.dart'; import 'package:cwtch/themes/opaque.dart'; +import 'package:cwtch/themes/cwtch.dart'; import 'package:cwtch/settings.dart'; import 'package:cwtch/widgets/textfield.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -14,8 +15,8 @@ import 'package:provider/provider.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -var settingsEnglishDark = Settings(Locale("en", ''), OpaqueDark()); -var settingsEnglishLight = Settings(Locale("en", ''), OpaqueLight()); +var settingsEnglishDark = Settings(Locale("en", ''), CwtchDark()); +var settingsEnglishLight = Settings(Locale("en", ''), CwtchLight()); ChangeNotifierProvider getSettingsEnglishDark() => ChangeNotifierProvider.value(value: settingsEnglishDark); String file(String slug) { From 8af4deaf95cbb2049f1128a37f200352e1de8c6a Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Wed, 15 Dec 2021 12:25:29 -0500 Subject: [PATCH 09/20] the rest of the themes --- lib/themes/ghost.dart | 70 ++++++++++++++++++++++++++++++++++++++++ lib/themes/mermaid.dart | 70 ++++++++++++++++++++++++++++++++++++++++ lib/themes/midnight.dart | 70 ++++++++++++++++++++++++++++++++++++++++ lib/themes/neon2.dart | 70 ++++++++++++++++++++++++++++++++++++++++ lib/themes/opaque.dart | 11 +++++++ lib/themes/pumpkin.dart | 70 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 361 insertions(+) create mode 100644 lib/themes/ghost.dart create mode 100644 lib/themes/mermaid.dart create mode 100644 lib/themes/midnight.dart create mode 100644 lib/themes/neon2.dart create mode 100644 lib/themes/pumpkin.dart diff --git a/lib/themes/ghost.dart b/lib/themes/ghost.dart new file mode 100644 index 00000000..6f870190 --- /dev/null +++ b/lib/themes/ghost.dart @@ -0,0 +1,70 @@ +import 'dart:ui'; +import 'dart:core'; + +import 'package:cwtch/themes/cwtch.dart'; +import 'package:flutter/material.dart'; + +import 'opaque.dart'; + +final ghost_theme = "ghost"; +final ghost_name = "Ghost"; //Todo translate + +OpaqueThemeType GetGhostTheme(String mode) { + if (mode == mode_dark) { + return GhostDark(); + } else { + return GhostLight(); + } +} + +class GhostDark extends CwtchDark { + static final Color background = Color(0xFF0D0D1F); + static final Color header = Color(0xFF0D0D1F); + static final Color userBubble = Color(0xFF1A237E); + static final Color peerBubble = Color(0xFF000051); + static final Color font = Color(0xFFFFFFFF); + static final Color settings = Color(0xFFFDFFFD); + static final Color accent = Color(0xFFD20070); + + get name => ghost_name; + get theme => ghost_theme; + get mode => mode_dark; + + get backgroundMainColor => background; // darkGreyPurple; + get backgroundPaneColor => header; //darkGreyPurple; + get mainTextColor => font; //whiteishPurple; + get defaultButtonColor => accent; //hotPink; + get textfieldHintColor => mainTextColor; //TODO pick + get toolbarIconColor => settings; //whiteishPurple; + get messageFromMeBackgroundColor => userBubble; // mauvePurple; + get messageFromMeTextColor => font; //whiteishPurple; + get messageFromOtherBackgroundColor => peerBubble; //deepPurple; + get messageFromOtherTextColor => font; //whiteishPurple; +} + +class GhostLight extends CwtchLight { + static final Color background = Color(0xFFFDFDFF); + static final Color header = Color(0xFFAAB6FE); + static final Color userBubble = Color(0xFFAAB6FE); + static final Color peerBubble = Color(0xFFE8EAF6); + static final Color font = Color(0xFF0D0D1F); + static final Color settings = Color(0xFF0D0D1F); + static final Color accent = Color(0xFFD20070); + + get name => ghost_name; + get theme => ghost_theme; + get mode => mode_light; + + get backgroundMainColor => background; //whitePurple; + get backgroundPaneColor => header; //softPurple; + get mainTextColor => settings; + get defaultButtonColor => accent; // hotPink; + get textfieldHintColor => font; //TODO pick + get scrollbarDefaultColor => accent; + get portraitContactBadgeColor => accent; + get toolbarIconColor => settings; //darkPurple; + get messageFromMeBackgroundColor => userBubble; //brightPurple; + get messageFromMeTextColor => font; //mainTextColor; + get messageFromOtherBackgroundColor => peerBubble; //purple; + get messageFromOtherTextColor => font; //darkPurple; +} \ No newline at end of file diff --git a/lib/themes/mermaid.dart b/lib/themes/mermaid.dart new file mode 100644 index 00000000..a8cde812 --- /dev/null +++ b/lib/themes/mermaid.dart @@ -0,0 +1,70 @@ +import 'dart:ui'; +import 'dart:core'; + +import 'package:cwtch/themes/cwtch.dart'; +import 'package:flutter/material.dart'; + +import 'opaque.dart'; + +final mermaid_theme = "mermaid"; +final mermaid_name = "Mermaid"; //Todo translate + +OpaqueThemeType GetMermaidTheme(String mode) { + if (mode == mode_dark) { + return MermaidDark(); + } else { + return MermaidLight(); + } +} + +class MermaidDark extends CwtchDark { + static final Color background = Color(0xFF102426); + static final Color header = Color(0xFF102426); + static final Color userBubble = Color(0xFF00838F); + static final Color peerBubble = Color(0xFF00363A); + static final Color font = Color(0xFFFFFFFF); + static final Color settings = Color(0xFFF7FCFD); + static final Color accent = Color(0xFF8E64A5); + + get name => mermaid_name; + get theme => mermaid_theme; + get mode => mode_dark; + + get backgroundMainColor => background; // darkGreyPurple; + get backgroundPaneColor => header; //darkGreyPurple; + get mainTextColor => font; //whiteishPurple; + get defaultButtonColor => accent; //hotPink; + get textfieldHintColor => mainTextColor; //TODO pick + get toolbarIconColor => settings; //whiteishPurple; + get messageFromMeBackgroundColor => userBubble; // mauvePurple; + get messageFromMeTextColor => font; //whiteishPurple; + get messageFromOtherBackgroundColor => peerBubble; //deepPurple; + get messageFromOtherTextColor => font; //whiteishPurple; +} + +class MermaidLight extends CwtchLight { + static final Color background = Color(0xFFF7FCFD); + static final Color header = Color(0xFF56C8D8); + static final Color userBubble = Color(0xFF56C8D8); + static final Color peerBubble = Color(0xFFB2EBF2); + static final Color font = Color(0xFF102426); + static final Color settings = Color(0xFF102426); + static final Color accent = Color(0xFF8E64A5); + + get name => mermaid_name; + get theme => mermaid_theme; + get mode => mode_light; + + get backgroundMainColor => background; //whitePurple; + get backgroundPaneColor => header; //softPurple; + get mainTextColor => settings; + get defaultButtonColor => accent; // hotPink; + get textfieldHintColor => font; //TODO pick + get scrollbarDefaultColor => accent; + get portraitContactBadgeColor => accent; + get toolbarIconColor => settings; //darkPurple; + get messageFromMeBackgroundColor => userBubble; //brightPurple; + get messageFromMeTextColor => font; //mainTextColor; + get messageFromOtherBackgroundColor => peerBubble; //purple; + get messageFromOtherTextColor => font; //darkPurple; +} \ No newline at end of file diff --git a/lib/themes/midnight.dart b/lib/themes/midnight.dart new file mode 100644 index 00000000..e6c4507f --- /dev/null +++ b/lib/themes/midnight.dart @@ -0,0 +1,70 @@ +import 'dart:ui'; +import 'dart:core'; + +import 'package:cwtch/themes/cwtch.dart'; +import 'package:flutter/material.dart'; + +import 'opaque.dart'; + +final midnight_theme = "midnight"; +final midnight_name = "Midnight"; //Todo translate + +OpaqueThemeType GetMidnightTheme(String mode) { + if (mode == mode_dark) { + return MidnightDark(); + } else { + return MidnightLight(); + } +} + +class MidnightDark extends CwtchDark { + static final Color background = Color(0xFF1B1B1B); + static final Color header = Color(0xFF1B1B1B); + static final Color userBubble = Color(0xFF373737); + static final Color peerBubble = Color(0xFF212121); + static final Color font = Color(0xFFFFFFFF); + static final Color settings = Color(0xFFFFFDFF); + static final Color accent = Color(0xFFD20070); + + get name => midnight_name; + get theme => midnight_theme; + get mode => mode_dark; + + get backgroundMainColor => background; // darkGreyPurple; + get backgroundPaneColor => header; //darkGreyPurple; + get mainTextColor => font; //whiteishPurple; + get defaultButtonColor => accent; //hotPink; + get textfieldHintColor => mainTextColor; //TODO pick + get toolbarIconColor => settings; //whiteishPurple; + get messageFromMeBackgroundColor => userBubble; // mauvePurple; + get messageFromMeTextColor => font; //whiteishPurple; + get messageFromOtherBackgroundColor => peerBubble; //deepPurple; + get messageFromOtherTextColor => font; //whiteishPurple; +} + +class MidnightLight extends CwtchLight { + static final Color background = Color(0xFFFFFDFF); + static final Color header = Color(0xFFE0E0E0); + static final Color userBubble = Color(0xFFE0E0E0); + static final Color peerBubble = Color(0xFFF3F3F3); + static final Color font = Color(0xFF1B1B1B); + static final Color settings = Color(0xFF1B1B1B); + static final Color accent = Color(0xFFD20070); + + get name => midnight_name; + get theme => midnight_theme; + get mode => mode_light; + + get backgroundMainColor => background; //whitePurple; + get backgroundPaneColor => header; //softPurple; + get mainTextColor => settings; + get defaultButtonColor => accent; // hotPink; + get textfieldHintColor => font; //TODO pick + get scrollbarDefaultColor => accent; + get portraitContactBadgeColor => accent; + get toolbarIconColor => settings; //darkPurple; + get messageFromMeBackgroundColor => userBubble; //brightPurple; + get messageFromMeTextColor => font; //mainTextColor; + get messageFromOtherBackgroundColor => peerBubble; //purple; + get messageFromOtherTextColor => font; //darkPurple; +} \ No newline at end of file diff --git a/lib/themes/neon2.dart b/lib/themes/neon2.dart new file mode 100644 index 00000000..ee90520f --- /dev/null +++ b/lib/themes/neon2.dart @@ -0,0 +1,70 @@ +import 'dart:ui'; +import 'dart:core'; + +import 'package:cwtch/themes/cwtch.dart'; +import 'package:flutter/material.dart'; + +import 'opaque.dart'; + +final neon2_theme = "neon2"; +final neon2_name = "Neon2"; //Todo translate + +OpaqueThemeType GetNeon2Theme(String mode) { + if (mode == mode_dark) { + return Neon2Dark(); + } else { + return Neon2Light(); + } +} + +class Neon2Dark extends CwtchDark { + static final Color background = Color(0xFF290826); + static final Color header = Color(0xFF290826); + static final Color userBubble = Color(0xFFA604FE); + static final Color peerBubble = Color(0xFF03AD00); + static final Color font = Color(0xFFFFFFFF); + static final Color settings = Color(0xFFFFFDFF); + static final Color accent = Color(0xFFA604FE); + + get name => neon2_name; + get theme => neon2_theme; + get mode => mode_dark; + + get backgroundMainColor => background; // darkGreyPurple; + get backgroundPaneColor => header; //darkGreyPurple; + get mainTextColor => font; //whiteishPurple; + get defaultButtonColor => accent; //hotPink; + get textfieldHintColor => mainTextColor; //TODO pick + get toolbarIconColor => settings; //whiteishPurple; + get messageFromMeBackgroundColor => userBubble; // mauvePurple; + get messageFromMeTextColor => font; //whiteishPurple; + get messageFromOtherBackgroundColor => peerBubble; //deepPurple; + get messageFromOtherTextColor => font; //whiteishPurple; +} + +class Neon2Light extends CwtchLight { + static final Color background = Color(0xFFFFFDFF); + static final Color header = Color(0xFFD8C7E1); + static final Color userBubble = Color(0xFFD8C7E1); + static final Color peerBubble = Color(0xFF80E27E); + static final Color font = Color(0xFF290826); + static final Color settings = Color(0xFF290826); + static final Color accent = Color(0xFFA604FE); + + get name => neon2_name; + get theme => neon2_theme; + get mode => mode_light; + + get backgroundMainColor => background; //whitePurple; + get backgroundPaneColor => header; //softPurple; + get mainTextColor => settings; + get defaultButtonColor => accent; // hotPink; + get textfieldHintColor => font; //TODO pick + get scrollbarDefaultColor => accent; + get portraitContactBadgeColor => accent; + get toolbarIconColor => settings; //darkPurple; + get messageFromMeBackgroundColor => userBubble; //brightPurple; + get messageFromMeTextColor => font; //mainTextColor; + get messageFromOtherBackgroundColor => peerBubble; //purple; + get messageFromOtherTextColor => font; //darkPurple; +} \ No newline at end of file diff --git a/lib/themes/opaque.dart b/lib/themes/opaque.dart index 8218934c..27eb5dec 100644 --- a/lib/themes/opaque.dart +++ b/lib/themes/opaque.dart @@ -2,17 +2,28 @@ import 'dart:ui'; import 'dart:core'; import 'package:cwtch/themes/cwtch.dart'; +import 'package:cwtch/themes/mermaid.dart'; import 'package:cwtch/themes/neon1.dart'; +import 'package:cwtch/themes/pumpkin.dart'; import 'package:cwtch/themes/vampire.dart'; import 'package:cwtch/themes/witch.dart'; import 'package:flutter/material.dart'; import 'package:cwtch/settings.dart'; +import 'ghost.dart'; +import 'midnight.dart'; +import 'neon2.dart'; + const mode_light = "light"; const mode_dark = "dark"; final themes = { cwtch_theme: {mode_light: CwtchLight(), mode_dark: CwtchDark()}, + ghost_theme: {mode_light: GhostLight(), mode_dark: GhostDark()}, + mermaid_theme: {mode_light: MermaidLight(), mode_dark: MermaidDark()}, + midnight_theme: {mode_light: MidnightLight(), mode_dark: MidnightDark()}, neon1_theme: {mode_light: Neon1Light(), mode_dark: Neon1Dark()}, + neon2_theme: {mode_light: Neon2Light(), mode_dark: Neon2Dark()}, + pumpkin_theme: {mode_light: PumpkinLight(), mode_dark: PumpkinDark()}, witch_theme: {mode_light: WitchLight(), mode_dark: WitchDark()}, vampire_theme: {mode_light: VampireLight(), mode_dark: VampireDark()}, }; diff --git a/lib/themes/pumpkin.dart b/lib/themes/pumpkin.dart new file mode 100644 index 00000000..da779341 --- /dev/null +++ b/lib/themes/pumpkin.dart @@ -0,0 +1,70 @@ +import 'dart:ui'; +import 'dart:core'; + +import 'package:cwtch/themes/cwtch.dart'; +import 'package:flutter/material.dart'; + +import 'opaque.dart'; + +final pumpkin_theme = "pumpkin"; +final pumpkin_name = "Pumpkin"; //Todo translate + +OpaqueThemeType GetPumpkinTheme(String mode) { + if (mode == mode_dark) { + return PumpkinDark(); + } else { + return PumpkinLight(); + } +} + +class PumpkinDark extends CwtchDark { + static final Color background = Color(0xFF281831); + static final Color header = Color(0xFF281831); + static final Color userBubble = Color(0xFFB53D00); + static final Color peerBubble = Color(0xFF422850); + static final Color font = Color(0xFFFFFFFF); + static final Color settings = Color(0xFFFFFBF6); + static final Color accent = Color(0xFF8E64A5); + + get name => pumpkin_name; + get theme => pumpkin_theme; + get mode => mode_dark; + + get backgroundMainColor => background; // darkGreyPurple; + get backgroundPaneColor => header; //darkGreyPurple; + get mainTextColor => font; //whiteishPurple; + get defaultButtonColor => accent; //hotPink; + get textfieldHintColor => mainTextColor; //TODO pick + get toolbarIconColor => settings; //whiteishPurple; + get messageFromMeBackgroundColor => userBubble; // mauvePurple; + get messageFromMeTextColor => font; //whiteishPurple; + get messageFromOtherBackgroundColor => peerBubble; //deepPurple; + get messageFromOtherTextColor => font; //whiteishPurple; +} + +class PumpkinLight extends CwtchLight { + static final Color background = Color(0xFFFFFBF6); + static final Color header = Color(0xFFFF9800); + static final Color userBubble = Color(0xFFFF9800); + static final Color peerBubble = Color(0xFFD8C7E1); + static final Color font = Color(0xFF281831); + static final Color settings = Color(0xFF281831); + static final Color accent = Color(0xFF8E64A5); + + get name => pumpkin_name; + get theme => pumpkin_theme; + get mode => mode_light; + + get backgroundMainColor => background; //whitePurple; + get backgroundPaneColor => header; //softPurple; + get mainTextColor => settings; + get defaultButtonColor => accent; // hotPink; + get textfieldHintColor => font; //TODO pick + get scrollbarDefaultColor => accent; + get portraitContactBadgeColor => accent; + get toolbarIconColor => settings; //darkPurple; + get messageFromMeBackgroundColor => userBubble; //brightPurple; + get messageFromMeTextColor => font; //mainTextColor; + get messageFromOtherBackgroundColor => peerBubble; //purple; + get messageFromOtherTextColor => font; //darkPurple; +} \ No newline at end of file From 124694447be48eecf510e45d21c5d32baba3c93c Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Wed, 15 Dec 2021 15:17:13 -0500 Subject: [PATCH 10/20] i10n theme names --- lib/l10n/intl_de.arb | 15 +++++++++++++- lib/l10n/intl_en.arb | 15 +++++++++++++- lib/l10n/intl_es.arb | 15 +++++++++++++- lib/l10n/intl_fr.arb | 15 +++++++++++++- lib/l10n/intl_it.arb | 15 +++++++++++++- lib/l10n/intl_pl.arb | 15 +++++++++++++- lib/l10n/intl_pt.arb | 15 +++++++++++++- lib/l10n/intl_ru.arb | 15 +++++++++++++- lib/themes/cwtch.dart | 5 +---- lib/themes/ghost.dart | 5 +---- lib/themes/mermaid.dart | 5 +---- lib/themes/midnight.dart | 5 +---- lib/themes/neon1.dart | 5 +---- lib/themes/neon2.dart | 5 +---- lib/themes/opaque.dart | 1 - lib/themes/pumpkin.dart | 5 +---- lib/themes/vampire.dart | 5 +---- lib/themes/witch.dart | 5 +---- lib/views/globalsettingsview.dart | 33 ++++++++++++++++++++++++++++--- 19 files changed, 151 insertions(+), 48 deletions(-) diff --git a/lib/l10n/intl_de.arb b/lib/l10n/intl_de.arb index 71936b39..3c7bdb25 100644 --- a/lib/l10n/intl_de.arb +++ b/lib/l10n/intl_de.arb @@ -1,6 +1,19 @@ { "@@locale": "de", - "@@last_modified": "2021-12-13T23:43:26+01:00", + "@@last_modified": "2021-12-15T20:46:48+01:00", + "themeColorLabel": "Color Theme", + "themeNameNeon2": "Neon2", + "themeNameNeon1": "Neon1", + "themeNameMidnight": "Midnight", + "themeNameMermaid": "Mermaid", + "themeNamePumpkin": "Pumpkin", + "themeNameGhost": "Ghost", + "themeNameVampire": "Vampire", + "themeNameWitch": "Witch", + "themeNameCwtch": "Cwtch", + "settingDownloadFolder": "Download Folder", + "settingImagePreviewsDescription": "Images will be downloaded and previewed automatically. Please note that image previews can often lead to security vulnerabilities, and you should not enable this Experiment if you use Cwtch with untrusted contacts. Profile pictures are planned for Cwtch 1.6.", + "settingImagePreviews": "Image Previews and Profile Pictures", "experimentClickableLinksDescription": "The clickable links experiment allows you to click on URLs shared in messages", "enableExperimentClickableLinks": "Enable Clickable Links", "serverConnectionsLabel": "Connection", diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index f1546402..42b7fca9 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -1,6 +1,19 @@ { "@@locale": "en", - "@@last_modified": "2021-12-13T23:43:26+01:00", + "@@last_modified": "2021-12-15T20:46:48+01:00", + "themeColorLabel": "Color Theme", + "themeNameNeon2": "Neon2", + "themeNameNeon1": "Neon1", + "themeNameMidnight": "Midnight", + "themeNameMermaid": "Mermaid", + "themeNamePumpkin": "Pumpkin", + "themeNameGhost": "Ghost", + "themeNameVampire": "Vampire", + "themeNameWitch": "Witch", + "themeNameCwtch": "Cwtch", + "settingDownloadFolder": "Download Folder", + "settingImagePreviewsDescription": "Images will be downloaded and previewed automatically. Please note that image previews can often lead to security vulnerabilities, and you should not enable this Experiment if you use Cwtch with untrusted contacts. Profile pictures are planned for Cwtch 1.6.", + "settingImagePreviews": "Image Previews and Profile Pictures", "experimentClickableLinksDescription": "The clickable links experiment allows you to click on URLs shared in messages", "enableExperimentClickableLinks": "Enable Clickable Links", "serverConnectionsLabel": "Connection", diff --git a/lib/l10n/intl_es.arb b/lib/l10n/intl_es.arb index ce52d391..809b2d91 100644 --- a/lib/l10n/intl_es.arb +++ b/lib/l10n/intl_es.arb @@ -1,6 +1,19 @@ { "@@locale": "es", - "@@last_modified": "2021-12-13T23:43:26+01:00", + "@@last_modified": "2021-12-15T20:46:48+01:00", + "themeColorLabel": "Color Theme", + "themeNameNeon2": "Neon2", + "themeNameNeon1": "Neon1", + "themeNameMidnight": "Midnight", + "themeNameMermaid": "Mermaid", + "themeNamePumpkin": "Pumpkin", + "themeNameGhost": "Ghost", + "themeNameVampire": "Vampire", + "themeNameWitch": "Witch", + "themeNameCwtch": "Cwtch", + "settingDownloadFolder": "Download Folder", + "settingImagePreviewsDescription": "Images will be downloaded and previewed automatically. Please note that image previews can often lead to security vulnerabilities, and you should not enable this Experiment if you use Cwtch with untrusted contacts. Profile pictures are planned for Cwtch 1.6.", + "settingImagePreviews": "Image Previews and Profile Pictures", "experimentClickableLinksDescription": "The clickable links experiment allows you to click on URLs shared in messages", "enableExperimentClickableLinks": "Enable Clickable Links", "serverConnectionsLabel": "Connection", diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index 5f4b6fc2..8140da2c 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -1,6 +1,19 @@ { "@@locale": "fr", - "@@last_modified": "2021-12-13T23:43:26+01:00", + "@@last_modified": "2021-12-15T20:46:48+01:00", + "themeColorLabel": "Color Theme", + "themeNameNeon2": "Neon2", + "themeNameNeon1": "Neon1", + "themeNameMidnight": "Midnight", + "themeNameMermaid": "Mermaid", + "themeNamePumpkin": "Pumpkin", + "themeNameGhost": "Ghost", + "themeNameVampire": "Vampire", + "themeNameWitch": "Witch", + "themeNameCwtch": "Cwtch", + "settingDownloadFolder": "Download Folder", + "settingImagePreviewsDescription": "Images will be downloaded and previewed automatically. Please note that image previews can often lead to security vulnerabilities, and you should not enable this Experiment if you use Cwtch with untrusted contacts. Profile pictures are planned for Cwtch 1.6.", + "settingImagePreviews": "Image Previews and Profile Pictures", "experimentClickableLinksDescription": "The clickable links experiment allows you to click on URLs shared in messages", "enableExperimentClickableLinks": "Enable Clickable Links", "serverMetricsLabel": "Métriques du serveur", diff --git a/lib/l10n/intl_it.arb b/lib/l10n/intl_it.arb index ece23e55..e30cfb70 100644 --- a/lib/l10n/intl_it.arb +++ b/lib/l10n/intl_it.arb @@ -1,6 +1,19 @@ { "@@locale": "it", - "@@last_modified": "2021-12-13T23:43:26+01:00", + "@@last_modified": "2021-12-15T20:46:48+01:00", + "themeColorLabel": "Color Theme", + "themeNameNeon2": "Neon2", + "themeNameNeon1": "Neon1", + "themeNameMidnight": "Midnight", + "themeNameMermaid": "Mermaid", + "themeNamePumpkin": "Pumpkin", + "themeNameGhost": "Ghost", + "themeNameVampire": "Vampire", + "themeNameWitch": "Witch", + "themeNameCwtch": "Cwtch", + "settingDownloadFolder": "Download Folder", + "settingImagePreviewsDescription": "Images will be downloaded and previewed automatically. Please note that image previews can often lead to security vulnerabilities, and you should not enable this Experiment if you use Cwtch with untrusted contacts. Profile pictures are planned for Cwtch 1.6.", + "settingImagePreviews": "Image Previews and Profile Pictures", "experimentClickableLinksDescription": "The clickable links experiment allows you to click on URLs shared in messages", "enableExperimentClickableLinks": "Enable Clickable Links", "serverConnectionsLabel": "Connection", diff --git a/lib/l10n/intl_pl.arb b/lib/l10n/intl_pl.arb index a5d18aa7..78708ee7 100644 --- a/lib/l10n/intl_pl.arb +++ b/lib/l10n/intl_pl.arb @@ -1,6 +1,19 @@ { "@@locale": "pl", - "@@last_modified": "2021-12-13T23:43:26+01:00", + "@@last_modified": "2021-12-15T20:46:48+01:00", + "themeColorLabel": "Color Theme", + "themeNameNeon2": "Neon2", + "themeNameNeon1": "Neon1", + "themeNameMidnight": "Midnight", + "themeNameMermaid": "Mermaid", + "themeNamePumpkin": "Pumpkin", + "themeNameGhost": "Ghost", + "themeNameVampire": "Vampire", + "themeNameWitch": "Witch", + "themeNameCwtch": "Cwtch", + "settingDownloadFolder": "Download Folder", + "settingImagePreviewsDescription": "Images will be downloaded and previewed automatically. Please note that image previews can often lead to security vulnerabilities, and you should not enable this Experiment if you use Cwtch with untrusted contacts. Profile pictures are planned for Cwtch 1.6.", + "settingImagePreviews": "Image Previews and Profile Pictures", "experimentClickableLinksDescription": "The clickable links experiment allows you to click on URLs shared in messages", "enableExperimentClickableLinks": "Enable Clickable Links", "serverConnectionsLabel": "Connection", diff --git a/lib/l10n/intl_pt.arb b/lib/l10n/intl_pt.arb index f41f5a06..a548ca3a 100644 --- a/lib/l10n/intl_pt.arb +++ b/lib/l10n/intl_pt.arb @@ -1,6 +1,19 @@ { "@@locale": "pt", - "@@last_modified": "2021-12-13T23:43:26+01:00", + "@@last_modified": "2021-12-15T20:46:48+01:00", + "themeColorLabel": "Color Theme", + "themeNameNeon2": "Neon2", + "themeNameNeon1": "Neon1", + "themeNameMidnight": "Midnight", + "themeNameMermaid": "Mermaid", + "themeNamePumpkin": "Pumpkin", + "themeNameGhost": "Ghost", + "themeNameVampire": "Vampire", + "themeNameWitch": "Witch", + "themeNameCwtch": "Cwtch", + "settingDownloadFolder": "Download Folder", + "settingImagePreviewsDescription": "Images will be downloaded and previewed automatically. Please note that image previews can often lead to security vulnerabilities, and you should not enable this Experiment if you use Cwtch with untrusted contacts. Profile pictures are planned for Cwtch 1.6.", + "settingImagePreviews": "Image Previews and Profile Pictures", "experimentClickableLinksDescription": "The clickable links experiment allows you to click on URLs shared in messages", "enableExperimentClickableLinks": "Enable Clickable Links", "serverConnectionsLabel": "Connection", diff --git a/lib/l10n/intl_ru.arb b/lib/l10n/intl_ru.arb index d4137344..8751074d 100644 --- a/lib/l10n/intl_ru.arb +++ b/lib/l10n/intl_ru.arb @@ -1,6 +1,19 @@ { "@@locale": "ru", - "@@last_modified": "2021-12-13T23:43:26+01:00", + "@@last_modified": "2021-12-15T20:46:48+01:00", + "themeColorLabel": "Color Theme", + "themeNameNeon2": "Neon2", + "themeNameNeon1": "Neon1", + "themeNameMidnight": "Midnight", + "themeNameMermaid": "Mermaid", + "themeNamePumpkin": "Pumpkin", + "themeNameGhost": "Ghost", + "themeNameVampire": "Vampire", + "themeNameWitch": "Witch", + "themeNameCwtch": "Cwtch", + "settingDownloadFolder": "Download Folder", + "settingImagePreviewsDescription": "Images will be downloaded and previewed automatically. Please note that image previews can often lead to security vulnerabilities, and you should not enable this Experiment if you use Cwtch with untrusted contacts. Profile pictures are planned for Cwtch 1.6.", + "settingImagePreviews": "Image Previews and Profile Pictures", "experimentClickableLinksDescription": "The clickable links experiment allows you to click on URLs shared in messages", "enableExperimentClickableLinks": "Enable Clickable Links", "serverConnectionsLabel": "Connection", diff --git a/lib/themes/cwtch.dart b/lib/themes/cwtch.dart index 7b272962..470ad617 100644 --- a/lib/themes/cwtch.dart +++ b/lib/themes/cwtch.dart @@ -5,8 +5,7 @@ import 'package:flutter/material.dart'; import 'opaque.dart'; -final cwtch_name = "Cwtch"; // todo translate -final cwtch_theme = "cwtch"; +const cwtch_theme = "cwtch"; final Color darkGreyPurple = Color(0xFF281831); final Color deepPurple = Color(0xFF422850); @@ -45,7 +44,6 @@ class CwtchDark extends OpaqueThemeType { static final Color settings = whiteishPurple; static final Color accent = hotPink; - get name => cwtch_name; get theme => cwtch_theme; get mode => mode_dark; @@ -91,7 +89,6 @@ class CwtchLight extends OpaqueThemeType { static final Color settings = darkPurple; static final Color accent = hotPink; - get name => cwtch_name; get theme => cwtch_theme; get mode => mode_light; diff --git a/lib/themes/ghost.dart b/lib/themes/ghost.dart index 6f870190..41fe3806 100644 --- a/lib/themes/ghost.dart +++ b/lib/themes/ghost.dart @@ -6,8 +6,7 @@ import 'package:flutter/material.dart'; import 'opaque.dart'; -final ghost_theme = "ghost"; -final ghost_name = "Ghost"; //Todo translate +const ghost_theme = "ghost"; OpaqueThemeType GetGhostTheme(String mode) { if (mode == mode_dark) { @@ -26,7 +25,6 @@ class GhostDark extends CwtchDark { static final Color settings = Color(0xFFFDFFFD); static final Color accent = Color(0xFFD20070); - get name => ghost_name; get theme => ghost_theme; get mode => mode_dark; @@ -51,7 +49,6 @@ class GhostLight extends CwtchLight { static final Color settings = Color(0xFF0D0D1F); static final Color accent = Color(0xFFD20070); - get name => ghost_name; get theme => ghost_theme; get mode => mode_light; diff --git a/lib/themes/mermaid.dart b/lib/themes/mermaid.dart index a8cde812..95937e85 100644 --- a/lib/themes/mermaid.dart +++ b/lib/themes/mermaid.dart @@ -6,8 +6,7 @@ import 'package:flutter/material.dart'; import 'opaque.dart'; -final mermaid_theme = "mermaid"; -final mermaid_name = "Mermaid"; //Todo translate +const mermaid_theme = "mermaid"; OpaqueThemeType GetMermaidTheme(String mode) { if (mode == mode_dark) { @@ -26,7 +25,6 @@ class MermaidDark extends CwtchDark { static final Color settings = Color(0xFFF7FCFD); static final Color accent = Color(0xFF8E64A5); - get name => mermaid_name; get theme => mermaid_theme; get mode => mode_dark; @@ -51,7 +49,6 @@ class MermaidLight extends CwtchLight { static final Color settings = Color(0xFF102426); static final Color accent = Color(0xFF8E64A5); - get name => mermaid_name; get theme => mermaid_theme; get mode => mode_light; diff --git a/lib/themes/midnight.dart b/lib/themes/midnight.dart index e6c4507f..4dd1b771 100644 --- a/lib/themes/midnight.dart +++ b/lib/themes/midnight.dart @@ -6,8 +6,7 @@ import 'package:flutter/material.dart'; import 'opaque.dart'; -final midnight_theme = "midnight"; -final midnight_name = "Midnight"; //Todo translate +const midnight_theme = "midnight"; OpaqueThemeType GetMidnightTheme(String mode) { if (mode == mode_dark) { @@ -26,7 +25,6 @@ class MidnightDark extends CwtchDark { static final Color settings = Color(0xFFFFFDFF); static final Color accent = Color(0xFFD20070); - get name => midnight_name; get theme => midnight_theme; get mode => mode_dark; @@ -51,7 +49,6 @@ class MidnightLight extends CwtchLight { static final Color settings = Color(0xFF1B1B1B); static final Color accent = Color(0xFFD20070); - get name => midnight_name; get theme => midnight_theme; get mode => mode_light; diff --git a/lib/themes/neon1.dart b/lib/themes/neon1.dart index 2b4e396d..196fcbf9 100644 --- a/lib/themes/neon1.dart +++ b/lib/themes/neon1.dart @@ -6,8 +6,7 @@ import 'package:flutter/material.dart'; import 'opaque.dart'; -final neon1_theme = "neon1"; -final neon1_name = "Neon1"; //Todo translate +const neon1_theme = "neon1"; OpaqueThemeType GetNeon1Theme(String mode) { if (mode == mode_dark) { @@ -26,7 +25,6 @@ class Neon1Dark extends CwtchDark { static final Color settings = Color(0xFFFFFDFF); static final Color accent = Color(0xFFA604FE); - get name => neon1_name; get theme => neon1_theme; get mode => mode_dark; @@ -73,7 +71,6 @@ class Neon1Light extends CwtchLight { static final Color settings = Color(0xFF290826); static final Color accent = Color(0xFFA604FE); - get name => neon1_name; get theme => neon1_theme; get mode => mode_light; diff --git a/lib/themes/neon2.dart b/lib/themes/neon2.dart index ee90520f..c2d551a0 100644 --- a/lib/themes/neon2.dart +++ b/lib/themes/neon2.dart @@ -6,8 +6,7 @@ import 'package:flutter/material.dart'; import 'opaque.dart'; -final neon2_theme = "neon2"; -final neon2_name = "Neon2"; //Todo translate +const neon2_theme = "neon2"; OpaqueThemeType GetNeon2Theme(String mode) { if (mode == mode_dark) { @@ -26,7 +25,6 @@ class Neon2Dark extends CwtchDark { static final Color settings = Color(0xFFFFFDFF); static final Color accent = Color(0xFFA604FE); - get name => neon2_name; get theme => neon2_theme; get mode => mode_dark; @@ -51,7 +49,6 @@ class Neon2Light extends CwtchLight { static final Color settings = Color(0xFF290826); static final Color accent = Color(0xFFA604FE); - get name => neon2_name; get theme => neon2_theme; get mode => mode_light; diff --git a/lib/themes/opaque.dart b/lib/themes/opaque.dart index 27eb5dec..d71df21f 100644 --- a/lib/themes/opaque.dart +++ b/lib/themes/opaque.dart @@ -62,7 +62,6 @@ Color darken(Color color, [double amount = 0.15]) { abstract class OpaqueThemeType { static final Color red = Color(0xFFFF0000); - get name => "Dummy"; get theme => "dummy"; get mode => mode_light; diff --git a/lib/themes/pumpkin.dart b/lib/themes/pumpkin.dart index da779341..943c73da 100644 --- a/lib/themes/pumpkin.dart +++ b/lib/themes/pumpkin.dart @@ -6,8 +6,7 @@ import 'package:flutter/material.dart'; import 'opaque.dart'; -final pumpkin_theme = "pumpkin"; -final pumpkin_name = "Pumpkin"; //Todo translate +const pumpkin_theme = "pumpkin"; OpaqueThemeType GetPumpkinTheme(String mode) { if (mode == mode_dark) { @@ -26,7 +25,6 @@ class PumpkinDark extends CwtchDark { static final Color settings = Color(0xFFFFFBF6); static final Color accent = Color(0xFF8E64A5); - get name => pumpkin_name; get theme => pumpkin_theme; get mode => mode_dark; @@ -51,7 +49,6 @@ class PumpkinLight extends CwtchLight { static final Color settings = Color(0xFF281831); static final Color accent = Color(0xFF8E64A5); - get name => pumpkin_name; get theme => pumpkin_theme; get mode => mode_light; diff --git a/lib/themes/vampire.dart b/lib/themes/vampire.dart index a0ba8191..459dfe7b 100644 --- a/lib/themes/vampire.dart +++ b/lib/themes/vampire.dart @@ -6,8 +6,7 @@ import 'package:flutter/material.dart'; import 'opaque.dart'; -final vampire_theme = "vampire"; -final vampire_name = "Vampire"; //Todo translate +const vampire_theme = "vampire"; OpaqueThemeType GetVampireTheme(String mode) { if (mode == mode_dark) { @@ -26,7 +25,6 @@ class VampireDark extends CwtchDark { static final Color settings = Color(0xFFFDFFFD); static final Color accent = Color(0xFF8E64A5); - get name => vampire_name; get theme => vampire_theme; get mode => mode_dark; @@ -51,7 +49,6 @@ class VampireLight extends CwtchLight { static final Color settings = Color(0xFF281831); static final Color accent = Color(0xFF8E64A5); - get name => vampire_name; get theme => vampire_theme; get mode => mode_light; diff --git a/lib/themes/witch.dart b/lib/themes/witch.dart index 069051ed..ebc7d17b 100644 --- a/lib/themes/witch.dart +++ b/lib/themes/witch.dart @@ -6,8 +6,7 @@ import 'package:flutter/material.dart'; import 'opaque.dart'; -final witch_theme = "witch"; -final witch_name = "Witch"; //Todo translate +const witch_theme = "witch"; OpaqueThemeType GetWitchTheme(String mode) { if (mode == mode_dark) { @@ -26,7 +25,6 @@ class WitchDark extends CwtchDark { static final Color settings = Color(0xFFFDFFFD); static final Color accent = Color(0xFFD20070); - get name => witch_name; get theme => witch_theme; get mode => mode_dark; @@ -51,7 +49,6 @@ class WitchLight extends CwtchLight { static final Color settings = Color(0xFF0E1E0E); static final Color accent = Color(0xFFD20070); - get name => witch_name; get theme => witch_theme; get mode => mode_light; diff --git a/lib/views/globalsettingsview.dart b/lib/views/globalsettingsview.dart index 3cdd04a5..d11847f6 100644 --- a/lib/views/globalsettingsview.dart +++ b/lib/views/globalsettingsview.dart @@ -2,7 +2,16 @@ import 'dart:convert'; import 'dart:io'; import 'package:cwtch/cwtch_icons_icons.dart'; import 'package:cwtch/models/servers.dart'; +import 'package:cwtch/themes/cwtch.dart'; +import 'package:cwtch/themes/ghost.dart'; +import 'package:cwtch/themes/mermaid.dart'; +import 'package:cwtch/themes/midnight.dart'; +import 'package:cwtch/themes/neon1.dart'; +import 'package:cwtch/themes/neon2.dart'; import 'package:cwtch/themes/opaque.dart'; +import 'package:cwtch/themes/pumpkin.dart'; +import 'package:cwtch/themes/vampire.dart'; +import 'package:cwtch/themes/witch.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:flutter/material.dart'; import 'package:cwtch/settings.dart'; @@ -82,7 +91,7 @@ class _GlobalSettingsViewState extends State { secondary: Icon(CwtchIcons.change_theme, color: settings.current().mainTextColor), ), ListTile( - title: Text("Colour Theme"), + title: Text(AppLocalizations.of(context)!.themeColorLabel), //AppLocalizations.of(context)!.settingTheme)), trailing: DropdownButton( value: Provider.of(context).theme.theme, @@ -95,9 +104,11 @@ class _GlobalSettingsViewState extends State { items: themes.keys.map>((String themeId) { return DropdownMenuItem( value: themeId, - child: Text(themes[themeId]?[mode_light]?.name ?? "Unknown"), //todo translate + child: Text(getThemeName(context, themeId)), ); - }).toList())), + }).toList()), + leading: Icon(CwtchIcons.change_theme, color: settings.current().mainTextColor), + ), ListTile( title: Text(AppLocalizations.of(context)!.settingUIColumnPortrait, style: TextStyle(color: settings.current().mainTextColor)), leading: Icon(Icons.table_chart, color: settings.current().mainTextColor), @@ -318,6 +329,22 @@ String getLanguageFull(context, String languageCode) { return languageCode; } +/// Since we don't seem to able to dynamically pull translations, this function maps themes to their names +String getThemeName(context, String theme) { + switch (theme) { + case cwtch_theme: return AppLocalizations.of(context)!.themeNameCwtch; + case ghost_theme: return AppLocalizations.of(context)!.themeNameGhost; + case mermaid_theme: return AppLocalizations.of(context)!.themeNameMermaid; + case midnight_theme: return AppLocalizations.of(context)!.themeNameMidnight; + case neon1_theme: return AppLocalizations.of(context)!.themeNameNeon1; + case neon2_theme: return AppLocalizations.of(context)!.themeNameNeon2; + case pumpkin_theme: return AppLocalizations.of(context)!.themeNamePumpkin; + case vampire_theme: return AppLocalizations.of(context)!.themeNameVampire; + case witch_theme: return AppLocalizations.of(context)!.themeNameWitch; + } + return theme; +} + /// Send an UpdateGlobalSettings to the Event Bus saveSettings(context) { var settings = Provider.of(context, listen: false); From b29bb1e4dcd742c855941888bcae6200de05fe34 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Wed, 15 Dec 2021 15:28:49 -0500 Subject: [PATCH 11/20] clean up comments, delete old code, pr comments --- lib/themes/cwtch.dart | 4 ---- lib/themes/neon1.dart | 40 ------------------------------- lib/views/addeditservers.dart | 2 -- lib/views/globalsettingsview.dart | 1 - 4 files changed, 47 deletions(-) diff --git a/lib/themes/cwtch.dart b/lib/themes/cwtch.dart index 470ad617..d0f0b64c 100644 --- a/lib/themes/cwtch.dart +++ b/lib/themes/cwtch.dart @@ -24,8 +24,6 @@ final Color greyPurple = Color(0xFF775F84); // not in new: portrait borders final Color pink = Color(0xFFE85DA1); // not in new: active button color final Color hotPink = Color(0xFFD20070); // Color(0xFFD01972); final Color softGrey = Color(0xFFB3B6B3); // not in new theme: blocked -//static final Color softGreen = Color(0xFFA0FFB0); -//static final Color softRed = Color(0xFFFFA0B0); OpaqueThemeType GetCwtchTheme(String mode) { if (mode == mode_dark) { @@ -54,7 +52,6 @@ class CwtchDark extends OpaqueThemeType { get sendHintTextColor => mauvePurple; get hilightElementColor => purple; get defaultButtonColor => accent; //hotPink; - //get defaultButtonActiveColor => pink; get defaultButtonTextColor => whiteishPurple; get defaultButtonDisabledColor => lightGrey; get defaultButtonDisabledTextColor => darkGreyPurple; @@ -99,7 +96,6 @@ class CwtchLight extends OpaqueThemeType { get sendHintTextColor => purple; get hilightElementColor => purple; //darkPurple; // todo shouldn't be this, too dark, makes font unreadable get defaultButtonColor => accent; // hotPink; - //get defaultButtonActiveColor => pink; // todo: lighten in light, darken in dark get defaultButtonTextColor => whitePurple; // ? get defaultButtonDisabledColor => softGrey; get textfieldBackgroundColor => purple; diff --git a/lib/themes/neon1.dart b/lib/themes/neon1.dart index 196fcbf9..cc8e6adc 100644 --- a/lib/themes/neon1.dart +++ b/lib/themes/neon1.dart @@ -38,28 +38,6 @@ class Neon1Dark extends CwtchDark { get messageFromMeTextColor => font; //whiteishPurple; get messageFromOtherBackgroundColor => peerBubble; //deepPurple; get messageFromOtherTextColor => font; //whiteishPurple; - - /*get backgroundHilightElementColor => deepPurple; - get sendHintTextColor => mauvePurple; - get hilightElementColor => purple; - get defaultButtonTextColor => whiteishPurple; - get defaultButtonDisabledColor => lightGrey; - get defaultButtonDisabledTextColor => darkGreyPurple; - get textfieldBackgroundColor => deepPurple; - get textfieldBorderColor => deepPurple; - get textfieldErrorColor => hotPink; - get scrollbarDefaultColor => purple; - get portraitBackgroundColor => deepPurple; - get portraitOnlineBorderColor => whiteishPurple; - get portraitOfflineBorderColor => purple; - get portraitBlockedBorderColor => lightGrey; - get portraitBlockedTextColor => lightGrey; - get portraitContactBadgeColor => hotPink; - get portraitContactBadgeTextColor => whiteishPurple; - get portraitProfileBadgeColor => mauvePurple; - get portraitProfileBadgeTextColor => darkGreyPurple; - get dropShadowColor => mauvePurple;*/ - } class Neon1Light extends CwtchLight { @@ -86,22 +64,4 @@ class Neon1Light extends CwtchLight { get messageFromMeTextColor => font; //mainTextColor; get messageFromOtherBackgroundColor => peerBubble; //purple; get messageFromOtherTextColor => font; //darkPurple; - - /*get backgroundHilightElementColor => softPurple; - get sendHintTextColor => purple; - get hilightElementColor => purple; //darkPurple; // todo shouldn't be this, too dark, makes font unreadable - get defaultButtonTextColor => whitePurple; // ? - get defaultButtonDisabledColor => softGrey; - get textfieldBackgroundColor => purple; - get textfieldBorderColor => purple; - get textfieldErrorColor => hotPink; - get portraitBackgroundColor => softPurple; - get portraitOnlineBorderColor => greyPurple; - get portraitOfflineBorderColor => greyPurple; - get portraitBlockedBorderColor => softGrey; - get portraitBlockedTextColor => softGrey; - get portraitContactBadgeTextColor => whitePurple; - get portraitProfileBadgeColor => brightPurple; - get portraitProfileBadgeTextColor => whitePurple; - get dropShadowColor => purple;*/ } \ No newline at end of file diff --git a/lib/views/addeditservers.dart b/lib/views/addeditservers.dart index 1138dcdb..d2d0af22 100644 --- a/lib/views/addeditservers.dart +++ b/lib/views/addeditservers.dart @@ -34,8 +34,6 @@ class _AddEditServerViewState extends State { late bool usePassword; - //late bool deleted; - @override void initState() { super.initState(); diff --git a/lib/views/globalsettingsview.dart b/lib/views/globalsettingsview.dart index d11847f6..000ed444 100644 --- a/lib/views/globalsettingsview.dart +++ b/lib/views/globalsettingsview.dart @@ -92,7 +92,6 @@ class _GlobalSettingsViewState extends State { ), ListTile( title: Text(AppLocalizations.of(context)!.themeColorLabel), - //AppLocalizations.of(context)!.settingTheme)), trailing: DropdownButton( value: Provider.of(context).theme.theme, onChanged: (String? newValue) { From abf4d79e80d797fb5c38e0281c38fee324a61f54 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Wed, 15 Dec 2021 17:29:27 -0500 Subject: [PATCH 12/20] flutter format --- lib/model.dart | 2 - lib/models/profileservers.dart | 4 +- lib/settings.dart | 2 - lib/themes/cwtch.dart | 4 +- lib/themes/ghost.dart | 2 +- lib/themes/mermaid.dart | 2 +- lib/themes/midnight.dart | 2 +- lib/themes/neon1.dart | 2 +- lib/themes/neon2.dart | 2 +- lib/themes/opaque.dart | 15 +-- lib/themes/pumpkin.dart | 2 +- lib/themes/vampire.dart | 2 +- lib/themes/witch.dart | 2 +- lib/views/addeditprofileview.dart | 2 +- lib/views/addeditservers.dart | 39 +++--- lib/views/contactsview.dart | 2 +- lib/views/globalsettingsview.dart | 57 +++++---- lib/views/messageview.dart | 3 +- lib/views/profileserversview.dart | 103 +++++++--------- lib/views/remoteserverview.dart | 139 +++++++++++----------- lib/views/splashView.dart | 3 +- lib/widgets/filebubble.dart | 3 +- lib/widgets/invitationbubble.dart | 3 +- lib/widgets/messagebubble.dart | 4 +- lib/widgets/messagebubbledecorations.dart | 3 +- lib/widgets/messagelist.dart | 116 +++++++++--------- lib/widgets/quotedmessage.dart | 4 +- lib/widgets/remoteserverrow.dart | 72 ++++++----- lib/widgets/serverrow.dart | 93 +++++++-------- lib/widgets/textfield.dart | 1 - 30 files changed, 322 insertions(+), 368 deletions(-) diff --git a/lib/model.dart b/lib/model.dart index 82246ee0..2106895b 100644 --- a/lib/model.dart +++ b/lib/model.dart @@ -282,8 +282,6 @@ class ProfileInfoState extends ChangeNotifier { this._contacts.updateLastMessageTime(this._contacts._contacts.first.identifier, this._contacts._contacts.first.lastMessageTime); } } - - } // Parse out the server list json into our server info state struct... diff --git a/lib/models/profileservers.dart b/lib/models/profileservers.dart index 5f422538..4b868b95 100644 --- a/lib/models/profileservers.dart +++ b/lib/models/profileservers.dart @@ -35,7 +35,7 @@ class ProfileServerListState extends ChangeNotifier { // online v offline if (a.status == "Synced" && b.status != "Synced") { return -1; - } else if (a.status != "Synced" && b.status == "Synced") { + } else if (a.status != "Synced" && b.status == "Synced") { return 1; } @@ -73,7 +73,7 @@ class RemoteServerInfoState extends ChangeNotifier { List _groups = []; RemoteServerInfoState({required this.onion, required this.identifier, required this.description, required this.status}); - + void updateDescription(String newDescription) { this.description = newDescription; notifyListeners(); diff --git a/lib/settings.dart b/lib/settings.dart index c0863991..f961af89 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -37,7 +37,6 @@ class Settings extends ChangeNotifier { bool blockUnknownConnections = false; bool streamerMode = false; - void setTheme(String themeId, String mode) { theme = getTheme(themeId, mode); notifyListeners(); @@ -220,7 +219,6 @@ class Settings extends ChangeNotifier { /// Convert this Settings object to a JSON representation for serialization on the /// event bus. dynamic asJson() { - return { "Locale": this.locale.languageCode, "Theme": theme.theme, diff --git a/lib/themes/cwtch.dart b/lib/themes/cwtch.dart index d0f0b64c..c5c65ae9 100644 --- a/lib/themes/cwtch.dart +++ b/lib/themes/cwtch.dart @@ -93,7 +93,7 @@ class CwtchLight extends OpaqueThemeType { get backgroundPaneColor => header; //softPurple; get backgroundHilightElementColor => softPurple; get mainTextColor => settings; - get sendHintTextColor => purple; + get sendHintTextColor => purple; get hilightElementColor => purple; //darkPurple; // todo shouldn't be this, too dark, makes font unreadable get defaultButtonColor => accent; // hotPink; get defaultButtonTextColor => whitePurple; // ? @@ -118,4 +118,4 @@ class CwtchLight extends OpaqueThemeType { get messageFromMeTextColor => font; //mainTextColor; get messageFromOtherBackgroundColor => peerBubble; //purple; get messageFromOtherTextColor => font; //darkPurple; -} \ No newline at end of file +} diff --git a/lib/themes/ghost.dart b/lib/themes/ghost.dart index 41fe3806..de2d3f2d 100644 --- a/lib/themes/ghost.dart +++ b/lib/themes/ghost.dart @@ -64,4 +64,4 @@ class GhostLight extends CwtchLight { get messageFromMeTextColor => font; //mainTextColor; get messageFromOtherBackgroundColor => peerBubble; //purple; get messageFromOtherTextColor => font; //darkPurple; -} \ No newline at end of file +} diff --git a/lib/themes/mermaid.dart b/lib/themes/mermaid.dart index 95937e85..c6e21122 100644 --- a/lib/themes/mermaid.dart +++ b/lib/themes/mermaid.dart @@ -64,4 +64,4 @@ class MermaidLight extends CwtchLight { get messageFromMeTextColor => font; //mainTextColor; get messageFromOtherBackgroundColor => peerBubble; //purple; get messageFromOtherTextColor => font; //darkPurple; -} \ No newline at end of file +} diff --git a/lib/themes/midnight.dart b/lib/themes/midnight.dart index 4dd1b771..da1f1bfd 100644 --- a/lib/themes/midnight.dart +++ b/lib/themes/midnight.dart @@ -64,4 +64,4 @@ class MidnightLight extends CwtchLight { get messageFromMeTextColor => font; //mainTextColor; get messageFromOtherBackgroundColor => peerBubble; //purple; get messageFromOtherTextColor => font; //darkPurple; -} \ No newline at end of file +} diff --git a/lib/themes/neon1.dart b/lib/themes/neon1.dart index cc8e6adc..fcb4f614 100644 --- a/lib/themes/neon1.dart +++ b/lib/themes/neon1.dart @@ -64,4 +64,4 @@ class Neon1Light extends CwtchLight { get messageFromMeTextColor => font; //mainTextColor; get messageFromOtherBackgroundColor => peerBubble; //purple; get messageFromOtherTextColor => font; //darkPurple; -} \ No newline at end of file +} diff --git a/lib/themes/neon2.dart b/lib/themes/neon2.dart index c2d551a0..bdfeaf73 100644 --- a/lib/themes/neon2.dart +++ b/lib/themes/neon2.dart @@ -64,4 +64,4 @@ class Neon2Light extends CwtchLight { get messageFromMeTextColor => font; //mainTextColor; get messageFromOtherBackgroundColor => peerBubble; //purple; get messageFromOtherTextColor => font; //darkPurple; -} \ No newline at end of file +} diff --git a/lib/themes/opaque.dart b/lib/themes/opaque.dart index d71df21f..9e601d32 100644 --- a/lib/themes/opaque.dart +++ b/lib/themes/opaque.dart @@ -17,7 +17,8 @@ import 'neon2.dart'; const mode_light = "light"; const mode_dark = "dark"; -final themes = { cwtch_theme: {mode_light: CwtchLight(), mode_dark: CwtchDark()}, +final themes = { + cwtch_theme: {mode_light: CwtchLight(), mode_dark: CwtchDark()}, ghost_theme: {mode_light: GhostLight(), mode_dark: GhostDark()}, mermaid_theme: {mode_light: MermaidLight(), mode_dark: MermaidDark()}, midnight_theme: {mode_light: MidnightLight(), mode_dark: MidnightDark()}, @@ -169,13 +170,10 @@ ThemeData mkThemeData(Settings opaque) { )), ), ), - scrollbarTheme: ScrollbarThemeData( - isAlwaysShown: false, thumbColor: MaterialStateProperty.all(opaque.current().scrollbarDefaultColor)), + scrollbarTheme: ScrollbarThemeData(isAlwaysShown: false, thumbColor: MaterialStateProperty.all(opaque.current().scrollbarDefaultColor)), tabBarTheme: TabBarTheme(indicator: UnderlineTabIndicator(borderSide: BorderSide(color: opaque.current().defaultButtonActiveColor))), dialogTheme: DialogTheme( - backgroundColor: opaque.current().backgroundPaneColor, - titleTextStyle: TextStyle(color: opaque.current().mainTextColor), - contentTextStyle: TextStyle(color: opaque.current().mainTextColor)), + 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), @@ -196,10 +194,7 @@ ThemeData mkThemeData(Settings opaque) { trackColor: MaterialStateProperty.all(opaque.current().dropShadowColor), ), floatingActionButtonTheme: FloatingActionButtonThemeData( - backgroundColor: opaque.current().defaultButtonColor, - hoverColor: opaque.current().defaultButtonActiveColor, - enableFeedback: true, - splashColor: opaque.current().defaultButtonActiveColor), + backgroundColor: opaque.current().defaultButtonColor, hoverColor: opaque.current().defaultButtonActiveColor, enableFeedback: true, splashColor: opaque.current().defaultButtonActiveColor), textSelectionTheme: TextSelectionThemeData( cursorColor: opaque.current().defaultButtonActiveColor, selectionColor: opaque.current().defaultButtonActiveColor, selectionHandleColor: opaque.current().defaultButtonActiveColor), ); diff --git a/lib/themes/pumpkin.dart b/lib/themes/pumpkin.dart index 943c73da..f1c2faef 100644 --- a/lib/themes/pumpkin.dart +++ b/lib/themes/pumpkin.dart @@ -64,4 +64,4 @@ class PumpkinLight extends CwtchLight { get messageFromMeTextColor => font; //mainTextColor; get messageFromOtherBackgroundColor => peerBubble; //purple; get messageFromOtherTextColor => font; //darkPurple; -} \ No newline at end of file +} diff --git a/lib/themes/vampire.dart b/lib/themes/vampire.dart index 459dfe7b..13bba5b2 100644 --- a/lib/themes/vampire.dart +++ b/lib/themes/vampire.dart @@ -64,4 +64,4 @@ class VampireLight extends CwtchLight { get messageFromMeTextColor => font; //mainTextColor; get messageFromOtherBackgroundColor => peerBubble; //purple; get messageFromOtherTextColor => font; //darkPurple; -} \ No newline at end of file +} diff --git a/lib/themes/witch.dart b/lib/themes/witch.dart index ebc7d17b..38ad6c8e 100644 --- a/lib/themes/witch.dart +++ b/lib/themes/witch.dart @@ -64,4 +64,4 @@ class WitchLight extends CwtchLight { get messageFromMeTextColor => font; //mainTextColor; get messageFromOtherBackgroundColor => peerBubble; //purple; get messageFromOtherTextColor => font; //darkPurple; -} \ No newline at end of file +} diff --git a/lib/views/addeditprofileview.dart b/lib/views/addeditprofileview.dart index f3dc72dc..95706b92 100644 --- a/lib/views/addeditprofileview.dart +++ b/lib/views/addeditprofileview.dart @@ -107,7 +107,7 @@ class _AddEditProfileViewState extends State { hintText: AppLocalizations.of(context)!.yourDisplayName, validator: (value) { if (value.isEmpty) { - return AppLocalizations.of(context)!.displayNameTooltip; + return AppLocalizations.of(context)!.displayNameTooltip; } return null; }, diff --git a/lib/views/addeditservers.dart b/lib/views/addeditservers.dart index d2d0af22..ede9911a 100644 --- a/lib/views/addeditservers.dart +++ b/lib/views/addeditservers.dart @@ -86,10 +86,10 @@ class _AddEditServerViewState extends State { // Onion Visibility( visible: serverInfoState.onion.isNotEmpty, - child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - CwtchLabel(label: AppLocalizations.of(context)!.serverAddress), - SelectableText(serverInfoState.onion) - ])), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [CwtchLabel(label: AppLocalizations.of(context)!.serverAddress), SelectableText(serverInfoState.onion)])), // Description Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -157,25 +157,18 @@ class _AddEditServerViewState extends State { height: 20, ), Text(AppLocalizations.of(context)!.serverMetricsLabel, style: Provider.of(context).biggerFont), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(AppLocalizations.of(context)!.serverTotalMessagesLabel), - ]), - Text(serverInfoState.totalMessages.toString()) - ]), - - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(AppLocalizations.of(context)!.serverConnectionsLabel), - ]), - Text(serverInfoState.connections.toString()) - ]), - - + Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + Row(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Text(AppLocalizations.of(context)!.serverTotalMessagesLabel), + ]), + Text(serverInfoState.totalMessages.toString()) + ]), + Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + Row(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Text(AppLocalizations.of(context)!.serverConnectionsLabel), + ]), + Text(serverInfoState.connections.toString()) + ]), ])), // ***** Password ***** diff --git a/lib/views/contactsview.dart b/lib/views/contactsview.dart index 0c59122e..cfb29b01 100644 --- a/lib/views/contactsview.dart +++ b/lib/views/contactsview.dart @@ -117,7 +117,7 @@ class _ContactsViewState extends State { if (Provider.of(context, listen: false).isExperimentEnabled(TapirGroupsExperiment) || Provider.of(context, listen: false).isExperimentEnabled(ServerManagementExperiment)) { actions.add(IconButton( icon: Icon(CwtchIcons.dns_24px), - tooltip: AppLocalizations.of(context)!.manageKnownServersButton, + tooltip: AppLocalizations.of(context)!.manageKnownServersButton, onPressed: () { _pushServers(); })); diff --git a/lib/views/globalsettingsview.dart b/lib/views/globalsettingsview.dart index 000ed444..e6887350 100644 --- a/lib/views/globalsettingsview.dart +++ b/lib/views/globalsettingsview.dart @@ -91,21 +91,21 @@ class _GlobalSettingsViewState extends State { secondary: Icon(CwtchIcons.change_theme, color: settings.current().mainTextColor), ), ListTile( - title: Text(AppLocalizations.of(context)!.themeColorLabel), - trailing: DropdownButton( - value: Provider.of(context).theme.theme, - onChanged: (String? newValue) { - setState(() { - settings.setTheme(newValue!, settings.theme.mode); - saveSettings(context); - }); - }, - items: themes.keys.map>((String themeId) { - return DropdownMenuItem( - value: themeId, - child: Text(getThemeName(context, themeId)), - ); - }).toList()), + title: Text(AppLocalizations.of(context)!.themeColorLabel), + trailing: DropdownButton( + value: Provider.of(context).theme.theme, + onChanged: (String? newValue) { + setState(() { + settings.setTheme(newValue!, settings.theme.mode); + saveSettings(context); + }); + }, + items: themes.keys.map>((String themeId) { + return DropdownMenuItem( + value: themeId, + child: Text(getThemeName(context, themeId)), + ); + }).toList()), leading: Icon(CwtchIcons.change_theme, color: settings.current().mainTextColor), ), ListTile( @@ -331,15 +331,24 @@ String getLanguageFull(context, String languageCode) { /// Since we don't seem to able to dynamically pull translations, this function maps themes to their names String getThemeName(context, String theme) { switch (theme) { - case cwtch_theme: return AppLocalizations.of(context)!.themeNameCwtch; - case ghost_theme: return AppLocalizations.of(context)!.themeNameGhost; - case mermaid_theme: return AppLocalizations.of(context)!.themeNameMermaid; - case midnight_theme: return AppLocalizations.of(context)!.themeNameMidnight; - case neon1_theme: return AppLocalizations.of(context)!.themeNameNeon1; - case neon2_theme: return AppLocalizations.of(context)!.themeNameNeon2; - case pumpkin_theme: return AppLocalizations.of(context)!.themeNamePumpkin; - case vampire_theme: return AppLocalizations.of(context)!.themeNameVampire; - case witch_theme: return AppLocalizations.of(context)!.themeNameWitch; + case cwtch_theme: + return AppLocalizations.of(context)!.themeNameCwtch; + case ghost_theme: + return AppLocalizations.of(context)!.themeNameGhost; + case mermaid_theme: + return AppLocalizations.of(context)!.themeNameMermaid; + case midnight_theme: + return AppLocalizations.of(context)!.themeNameMidnight; + case neon1_theme: + return AppLocalizations.of(context)!.themeNameNeon1; + case neon2_theme: + return AppLocalizations.of(context)!.themeNameNeon2; + case pumpkin_theme: + return AppLocalizations.of(context)!.themeNamePumpkin; + case vampire_theme: + return AppLocalizations.of(context)!.themeNameVampire; + case witch_theme: + return AppLocalizations.of(context)!.themeNameWitch; } return theme; } diff --git a/lib/views/messageview.dart b/lib/views/messageview.dart index 516aadd3..8b803daf 100644 --- a/lib/views/messageview.dart +++ b/lib/views/messageview.dart @@ -314,8 +314,7 @@ class _MessageViewState extends State { children = [composeBox]; } - return Container( - color: Provider.of(context).theme.backgroundMainColor, child: Column(mainAxisSize: MainAxisSize.min, children: children)); + return Container(color: Provider.of(context).theme.backgroundMainColor, child: Column(mainAxisSize: MainAxisSize.min, children: children)); } // Send the message if enter is pressed without the shift key... diff --git a/lib/views/profileserversview.dart b/lib/views/profileserversview.dart index 99040880..1fd029b4 100644 --- a/lib/views/profileserversview.dart +++ b/lib/views/profileserversview.dart @@ -10,14 +10,12 @@ import '../main.dart'; import '../model.dart'; import '../settings.dart'; - class ProfileServersView extends StatefulWidget { @override _ProfileServersView createState() => _ProfileServersView(); } class _ProfileServersView extends State { - @override void dispose() { super.dispose(); @@ -25,9 +23,10 @@ class _ProfileServersView extends State { @override Widget build(BuildContext context) { - - var knownServers = Provider.of(context).serverList.servers.map((RemoteServerInfoState remoteServer) { return remoteServer.onion + ".onion"; }).toSet(); - var importServerList = Provider.of(context).servers.where((server) => !knownServers.contains(server.onion) ).map>((ServerInfoState serverInfo) { + var knownServers = Provider.of(context).serverList.servers.map((RemoteServerInfoState remoteServer) { + return remoteServer.onion + ".onion"; + }).toSet(); + var importServerList = Provider.of(context).servers.where((server) => !knownServers.contains(server.onion)).map>((ServerInfoState serverInfo) { return DropdownMenuItem( value: serverInfo.onion, child: Text( @@ -37,25 +36,22 @@ class _ProfileServersView extends State { ); }).toList(); - importServerList.insert(0, DropdownMenuItem( - value: "", - child: Text(AppLocalizations.of(context)!.importLocalServerSelectText))); + importServerList.insert(0, DropdownMenuItem(value: "", child: Text(AppLocalizations.of(context)!.importLocalServerSelectText))); return Scaffold( appBar: AppBar( - title: Text(MediaQuery - .of(context) - .size - .width > 600 ? AppLocalizations.of(context)!.manageKnownServersLong : AppLocalizations.of(context)!.manageKnownServersShort), + title: Text(MediaQuery.of(context).size.width > 600 ? AppLocalizations.of(context)!.manageKnownServersLong : AppLocalizations.of(context)!.manageKnownServersShort), ), - body: Consumer(builder: (context, profile, child) { + body: Consumer( + builder: (context, profile, child) { ProfileServerListState servers = profile.serverList; - final tiles = servers.servers.map((RemoteServerInfoState server) { - return ChangeNotifierProvider.value( - value: server, - builder: (context, child) => RepaintBoundary(child: RemoteServerRow()), - ); - }, + final tiles = servers.servers.map( + (RemoteServerInfoState server) { + return ChangeNotifierProvider.value( + value: server, + builder: (context, child) => RepaintBoundary(child: RemoteServerRow()), + ); + }, ); final divided = ListTile.divideTiles( @@ -63,37 +59,31 @@ class _ProfileServersView extends State { tiles: tiles, ).toList(); - final importCard = Card( child: ListTile( - title: Text(AppLocalizations.of(context)!.importLocalServerLabel), - leading: Icon(CwtchIcons.add_circle_24px , color: Provider.of(context).current().mainTextColor), - trailing: DropdownButton( - onChanged: (String? importServer) { - if (importServer!.isNotEmpty) { - var server = Provider.of(context).getServer(importServer)!; - showImportConfirm(context, profile.onion, server.onion, server.description, server.serverBundle); - } - - }, - value: "", - items: importServerList, - - ))); + final importCard = Card( + child: ListTile( + title: Text(AppLocalizations.of(context)!.importLocalServerLabel), + leading: Icon(CwtchIcons.add_circle_24px, color: Provider.of(context).current().mainTextColor), + trailing: DropdownButton( + onChanged: (String? importServer) { + if (importServer!.isNotEmpty) { + var server = Provider.of(context).getServer(importServer)!; + showImportConfirm(context, profile.onion, server.onion, server.description, server.serverBundle); + } + }, + value: "", + items: importServerList, + ))); return LayoutBuilder(builder: (BuildContext context, BoxConstraints viewportConstraints) { - return Scrollbar( - isAlwaysShown: true, - child: SingleChildScrollView( - clipBehavior: Clip.antiAlias, - child: - Container( - margin: EdgeInsets.fromLTRB(5, 0, 5, 10), - padding: EdgeInsets.fromLTRB(5, 0, 5, 10), - child: Column(children: [ - - if (importServerList.length > 1) importCard, - - Column( children: divided ) - ]))));}); + return Scrollbar( + isAlwaysShown: true, + child: SingleChildScrollView( + clipBehavior: Clip.antiAlias, + child: Container( + margin: EdgeInsets.fromLTRB(5, 0, 5, 10), + padding: EdgeInsets.fromLTRB(5, 0, 5, 10), + child: Column(children: [if (importServerList.length > 1) importCard, Column(children: divided)])))); + }); return ListView(children: divided); }, @@ -102,7 +92,7 @@ class _ProfileServersView extends State { showImportConfirm(BuildContext context, String profileHandle, String serverHandle, String serverDesc, String bundle) { var serverLabel = serverDesc.isNotEmpty ? serverDesc : serverHandle; - serverHandle = serverHandle.substring(0, serverHandle.length-6 ); // remove '.onion' + serverHandle = serverHandle.substring(0, serverHandle.length - 6); // remove '.onion' // set up the buttons Widget cancelButton = ElevatedButton( child: Text(AppLocalizations.of(context)!.cancel), @@ -118,15 +108,9 @@ class _ProfileServersView extends State { Future.delayed(const Duration(milliseconds: 500), () { var profile = Provider.of(context); if (profile.serverList.getServer(serverHandle) != null) { - profile.serverList.getServer(serverHandle)?.updateDescription( - serverDesc); + profile.serverList.getServer(serverHandle)?.updateDescription(serverDesc); - Provider - .of(context, listen: false) - .cwtch - .SetConversationAttribute(profile.onion, profile.serverList - .getServer(serverHandle) - !.identifier, "server.description", serverDesc); + Provider.of(context, listen: false).cwtch.SetConversationAttribute(profile.onion, profile.serverList.getServer(serverHandle)!.identifier, "server.description", serverDesc); } }); Navigator.of(context).pop(); @@ -149,7 +133,4 @@ class _ProfileServersView extends State { }, ); } - - - -} \ No newline at end of file +} diff --git a/lib/views/remoteserverview.dart b/lib/views/remoteserverview.dart index 1245f7e8..18bcdd04 100644 --- a/lib/views/remoteserverview.dart +++ b/lib/views/remoteserverview.dart @@ -50,63 +50,62 @@ class _RemoteServerViewState extends State { Widget build(BuildContext context) { return Consumer3(builder: (context, profile, serverInfoState, settings, child) { return Scaffold( - appBar: AppBar( - title: Text(ctrlrDesc.text.isNotEmpty ? ctrlrDesc.text : serverInfoState.onion) - ), - body: Container( - margin: EdgeInsets.fromLTRB(30, 0, 30, 10), - padding: EdgeInsets.fromLTRB(20, 0, 20, 10), - child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox( - height: 20, - ), - CwtchLabel(label: AppLocalizations.of(context)!.serverAddress), - SizedBox( - height: 20, - ), - SelectableText( - serverInfoState.onion - ), + appBar: AppBar(title: Text(ctrlrDesc.text.isNotEmpty ? ctrlrDesc.text : serverInfoState.onion)), + body: Container( + margin: EdgeInsets.fromLTRB(30, 0, 30, 10), + padding: EdgeInsets.fromLTRB(20, 0, 20, 10), + child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ + SizedBox( + height: 20, + ), + CwtchLabel(label: AppLocalizations.of(context)!.serverAddress), + SizedBox( + height: 20, + ), + SelectableText(serverInfoState.onion), - // Description - SizedBox( - height: 20, - ), - CwtchLabel(label: AppLocalizations.of(context)!.serverDescriptionLabel), - Text(AppLocalizations.of(context)!.serverDescriptionDescription), - SizedBox( - height: 20, - ), - CwtchButtonTextField( - controller: ctrlrDesc, - readonly: false, - tooltip: AppLocalizations.of(context)!.saveBtn, - labelText: AppLocalizations.of(context)!.fieldDescriptionLabel, - icon: Icon(Icons.save), - onPressed: () { - Provider.of(context, listen: false).cwtch.SetConversationAttribute(profile.onion, serverInfoState.identifier, "server.description", ctrlrDesc.text); - serverInfoState.updateDescription(ctrlrDesc.text); - }, - ), + // Description + SizedBox( + height: 20, + ), + CwtchLabel(label: AppLocalizations.of(context)!.serverDescriptionLabel), + Text(AppLocalizations.of(context)!.serverDescriptionDescription), + SizedBox( + height: 20, + ), + CwtchButtonTextField( + controller: ctrlrDesc, + readonly: false, + tooltip: AppLocalizations.of(context)!.saveBtn, + labelText: AppLocalizations.of(context)!.fieldDescriptionLabel, + icon: Icon(Icons.save), + onPressed: () { + Provider.of(context, listen: false).cwtch.SetConversationAttribute(profile.onion, serverInfoState.identifier, "server.description", ctrlrDesc.text); + serverInfoState.updateDescription(ctrlrDesc.text); + }, + ), - SizedBox( - height: 20, - ), + SizedBox( + height: 20, + ), - Padding(padding: EdgeInsets.all(8), child: Text( AppLocalizations.of(context)!.groupsOnThisServerLabel),), - Expanded(child: _buildGroupsList(serverInfoState)) - ]))); - - }); + Padding( + padding: EdgeInsets.all(8), + child: Text(AppLocalizations.of(context)!.groupsOnThisServerLabel), + ), + Expanded(child: _buildGroupsList(serverInfoState)) + ]))); + }); } Widget _buildGroupsList(RemoteServerInfoState serverInfoState) { - final tiles = serverInfoState.groups.map((ContactInfoState group) { - return ChangeNotifierProvider.value( - value: group, - builder: (context, child) => RepaintBoundary(child: _buildGroupRow(group)), // ServerRow()), - ); - }, + final tiles = serverInfoState.groups.map( + (ContactInfoState group) { + return ChangeNotifierProvider.value( + value: group, + builder: (context, child) => RepaintBoundary(child: _buildGroupRow(group)), // ServerRow()), + ); + }, ); final divided = ListTile.divideTiles( @@ -126,26 +125,22 @@ class _RemoteServerViewState extends State { Widget _buildGroupRow(ContactInfoState group) { return Padding( padding: const EdgeInsets.all(6.0), //border size - child: Column( - children: [ - Text( - group.nickname, - style: Provider.of(context).biggerFont.apply(color: Provider.of(context).theme.portraitOnlineBorderColor), - softWrap: true, - overflow: TextOverflow.ellipsis, - ), - Visibility( - visible: !Provider.of(context).streamerMode, - child: ExcludeSemantics( - child: Text( - group.onion, - softWrap: true, - overflow: TextOverflow.ellipsis, - style: TextStyle(color: Provider.of(context).theme.portraitOnlineBorderColor), - ))) - ]) - ); + child: Column(children: [ + Text( + group.nickname, + style: Provider.of(context).biggerFont.apply(color: Provider.of(context).theme.portraitOnlineBorderColor), + softWrap: true, + overflow: TextOverflow.ellipsis, + ), + Visibility( + visible: !Provider.of(context).streamerMode, + child: ExcludeSemantics( + child: Text( + group.onion, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyle(color: Provider.of(context).theme.portraitOnlineBorderColor), + ))) + ])); } - } - diff --git a/lib/views/splashView.dart b/lib/views/splashView.dart index 4f495066..33eb9097 100644 --- a/lib/views/splashView.dart +++ b/lib/views/splashView.dart @@ -27,8 +27,7 @@ class SplashView extends StatelessWidget { Padding( padding: const EdgeInsets.all(20.0), child: Text(appState.appError == "" ? "Loading Cwtch..." : appState.appError, - style: TextStyle( - fontSize: 16.0, color: appState.appError == "" ? Provider.of(context).theme.mainTextColor : Provider.of(context).theme.textfieldErrorColor)), + style: TextStyle(fontSize: 16.0, color: appState.appError == "" ? Provider.of(context).theme.mainTextColor : Provider.of(context).theme.textfieldErrorColor)), ), Image(image: AssetImage("assets/Open_Privacy_Logo_lightoutline.png")), ])), diff --git a/lib/widgets/filebubble.dart b/lib/widgets/filebubble.dart index d9e0a44e..fd49e9fe 100644 --- a/lib/widgets/filebubble.dart +++ b/lib/widgets/filebubble.dart @@ -115,8 +115,7 @@ class FileBubbleState extends State { child: Container( decoration: BoxDecoration( color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor, - border: - Border.all(color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor, width: 1), + border: Border.all(color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor, width: 1), borderRadius: BorderRadius.only( topLeft: Radius.circular(borderRadiousEh), topRight: Radius.circular(borderRadiousEh), diff --git a/lib/widgets/invitationbubble.dart b/lib/widgets/invitationbubble.dart index e8ced225..2839b550 100644 --- a/lib/widgets/invitationbubble.dart +++ b/lib/widgets/invitationbubble.dart @@ -97,8 +97,7 @@ class InvitationBubbleState extends State { child: Container( decoration: BoxDecoration( color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor, - border: - Border.all(color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor, width: 1), + border: Border.all(color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor, width: 1), borderRadius: BorderRadius.only( topLeft: Radius.circular(borderRadiousEh), topRight: Radius.circular(borderRadiousEh), diff --git a/lib/widgets/messagebubble.dart b/lib/widgets/messagebubble.dart index ba4ecb95..469a1b5a 100644 --- a/lib/widgets/messagebubble.dart +++ b/lib/widgets/messagebubble.dart @@ -95,9 +95,7 @@ class MessageBubbleState extends State { child: Container( child: Container( decoration: BoxDecoration( - color: error - ? malformedColor - : (fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor), + color: error ? malformedColor : (fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor), border: Border.all( color: error ? malformedColor diff --git a/lib/widgets/messagebubbledecorations.dart b/lib/widgets/messagebubbledecorations.dart index 3c2ee679..6b740ea9 100644 --- a/lib/widgets/messagebubbledecorations.dart +++ b/lib/widgets/messagebubbledecorations.dart @@ -25,8 +25,7 @@ class _MessageBubbleDecoration extends State { mainAxisSize: MainAxisSize.min, children: [ Text(widget.prettyDate, - style: - TextStyle(fontSize: 9.0, color: widget.fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor), + style: TextStyle(fontSize: 9.0, color: widget.fromMe ? Provider.of(context).theme.messageFromMeTextColor : Provider.of(context).theme.messageFromOtherTextColor), textAlign: widget.fromMe ? TextAlign.right : TextAlign.left), !widget.fromMe ? SizedBox(width: 1, height: 1) diff --git a/lib/widgets/messagelist.dart b/lib/widgets/messagelist.dart index 32a81b73..57009768 100644 --- a/lib/widgets/messagelist.dart +++ b/lib/widgets/messagelist.dart @@ -37,64 +37,64 @@ class _MessageListState extends State { child: Container( color: Provider.of(context).theme.backgroundMainColor, child: Column(children: [ - Visibility( - visible: showMessageWarning, - child: Container( - padding: EdgeInsets.all(5.0), - color: Provider.of(context).theme.defaultButtonActiveColor, - child: DefaultTextStyle( - style: TextStyle(color: Provider.of(context).theme.defaultButtonTextColor), - child: showSyncing - ? Text(AppLocalizations.of(context)!.serverNotSynced, textAlign: TextAlign.center) - : showOfflineWarning - ? Text(Provider.of(context).isGroup ? AppLocalizations.of(context)!.serverConnectivityDisconnected : AppLocalizations.of(context)!.peerOfflineMessage, - textAlign: TextAlign.center) - // Only show the ephemeral status for peer conversations, not for groups... - : (showEphemeralWarning - ? Text(AppLocalizations.of(context)!.chatHistoryDefault, textAlign: TextAlign.center) - : - // We are not allowed to put null here, so put an empty text widget - Text("")), - ))), - Expanded( - child: Container( - // Only show broken heart is the contact is offline... - decoration: BoxDecoration( - image: Provider.of(outerContext).isOnline() - ? null - : DecorationImage( - fit: BoxFit.scaleDown, - alignment: Alignment.center, - image: AssetImage("assets/core/negative_heart_512px.png"), - colorFilter: ColorFilter.mode(Provider.of(context).theme.hilightElementColor, BlendMode.srcIn))), - // Don't load messages for syncing server... - child: loadMessages - ? ScrollablePositionedList.builder( - itemPositionsListener: widget.scrollListener, - itemScrollController: widget.scrollController, - initialScrollIndex: initi > 4 ? initi - 4 : 0, - itemCount: Provider.of(outerContext).totalMessages, - reverse: true, // NOTE: There seems to be a bug in flutter that corrects the mouse wheel scroll, but not the drag direction... - itemBuilder: (itemBuilderContext, index) { - var profileOnion = Provider.of(outerContext, listen: false).onion; - var contactHandle = Provider.of(outerContext, listen: false).identifier; - var messageIndex = index; + Visibility( + visible: showMessageWarning, + child: Container( + padding: EdgeInsets.all(5.0), + color: Provider.of(context).theme.defaultButtonActiveColor, + child: DefaultTextStyle( + style: TextStyle(color: Provider.of(context).theme.defaultButtonTextColor), + child: showSyncing + ? Text(AppLocalizations.of(context)!.serverNotSynced, textAlign: TextAlign.center) + : showOfflineWarning + ? Text(Provider.of(context).isGroup ? AppLocalizations.of(context)!.serverConnectivityDisconnected : AppLocalizations.of(context)!.peerOfflineMessage, + textAlign: TextAlign.center) + // Only show the ephemeral status for peer conversations, not for groups... + : (showEphemeralWarning + ? Text(AppLocalizations.of(context)!.chatHistoryDefault, textAlign: TextAlign.center) + : + // We are not allowed to put null here, so put an empty text widget + Text("")), + ))), + Expanded( + child: Container( + // Only show broken heart is the contact is offline... + decoration: BoxDecoration( + image: Provider.of(outerContext).isOnline() + ? null + : DecorationImage( + fit: BoxFit.scaleDown, + alignment: Alignment.center, + image: AssetImage("assets/core/negative_heart_512px.png"), + colorFilter: ColorFilter.mode(Provider.of(context).theme.hilightElementColor, BlendMode.srcIn))), + // Don't load messages for syncing server... + child: loadMessages + ? ScrollablePositionedList.builder( + itemPositionsListener: widget.scrollListener, + itemScrollController: widget.scrollController, + initialScrollIndex: initi > 4 ? initi - 4 : 0, + itemCount: Provider.of(outerContext).totalMessages, + reverse: true, // NOTE: There seems to be a bug in flutter that corrects the mouse wheel scroll, but not the drag direction... + itemBuilder: (itemBuilderContext, index) { + var profileOnion = Provider.of(outerContext, listen: false).onion; + var contactHandle = Provider.of(outerContext, listen: false).identifier; + var messageIndex = index; - return FutureBuilder( - future: messageHandler(outerContext, profileOnion, contactHandle, messageIndex), - builder: (context, snapshot) { - if (snapshot.hasData) { - var message = snapshot.data as Message; - var key = Provider.of(outerContext, listen: false).getMessageKey(contactHandle, message.getMetadata().messageID); - return message.getWidget(context, key); - } else { - return MessageLoadingBubble(); - } - }, - ); - }, - ) - : null)) - ]))); + return FutureBuilder( + future: messageHandler(outerContext, profileOnion, contactHandle, messageIndex), + builder: (context, snapshot) { + if (snapshot.hasData) { + var message = snapshot.data as Message; + var key = Provider.of(outerContext, listen: false).getMessageKey(contactHandle, message.getMetadata().messageID); + return message.getWidget(context, key); + } else { + return MessageLoadingBubble(); + } + }, + ); + }, + ) + : null)) + ]))); } } diff --git a/lib/widgets/quotedmessage.dart b/lib/widgets/quotedmessage.dart index 78654f02..e2af135e 100644 --- a/lib/widgets/quotedmessage.dart +++ b/lib/widgets/quotedmessage.dart @@ -90,9 +90,7 @@ class QuotedMessageBubbleState extends State { child: Container( child: Container( decoration: BoxDecoration( - color: error - ? malformedColor - : (fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor), + color: error ? malformedColor : (fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor : Provider.of(context).theme.messageFromOtherBackgroundColor), border: Border.all( color: error ? malformedColor diff --git a/lib/widgets/remoteserverrow.dart b/lib/widgets/remoteserverrow.dart index bd4a8fb8..e7b2417a 100644 --- a/lib/widgets/remoteserverrow.dart +++ b/lib/widgets/remoteserverrow.dart @@ -23,46 +23,42 @@ class _RemoteServerRowState extends State { @override Widget build(BuildContext context) { var server = Provider.of(context); - var description = server.description.isNotEmpty ? server.description : server.onion; + var description = server.description.isNotEmpty ? server.description : server.onion; var running = server.status == "Synced"; - return Consumer( - builder: (context, profile, child) { - return Card(clipBehavior: Clip.antiAlias, + return Consumer(builder: (context, profile, child) { + return Card( + clipBehavior: Clip.antiAlias, margin: EdgeInsets.all(0.0), child: InkWell( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + Padding( + padding: const EdgeInsets.all(6.0), //border size + child: Icon(CwtchIcons.dns_24px, + color: running ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor, size: 64)), + Expanded( + child: Column( children: [ - Padding( - padding: const EdgeInsets.all(6.0), //border size - child: Icon(CwtchIcons.dns_24px, - color: running ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor, - size: 64) - + Text( + description, + semanticsLabel: description, + style: Provider.of(context) + .biggerFont + .apply(color: running ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor), + softWrap: true, + overflow: TextOverflow.ellipsis, ), - Expanded( - child: Column( - children: [ - Text( - description, - semanticsLabel: description, - style: Provider.of(context).biggerFont.apply(color: running ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor), - softWrap: true, - overflow: TextOverflow.ellipsis, - ), - Visibility( - visible: !Provider.of(context).streamerMode, - child: ExcludeSemantics( - child: Text( - server.onion, - softWrap: true, - overflow: TextOverflow.ellipsis, - style: TextStyle(color: running ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor), - ))) - ], - )), - - ]), + Visibility( + visible: !Provider.of(context).streamerMode, + child: ExcludeSemantics( + child: Text( + server.onion, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyle(color: running ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor), + ))) + ], + )), + ]), onTap: () { Navigator.of(context).push(MaterialPageRoute( settings: RouteSettings(name: "remoteserverview"), @@ -72,7 +68,7 @@ class _RemoteServerRowState extends State { child: RemoteServerView(), ); })); - } - ));}); - } + })); + }); + } } diff --git a/lib/widgets/serverrow.dart b/lib/widgets/serverrow.dart index 3acac630..2c245b51 100644 --- a/lib/widgets/serverrow.dart +++ b/lib/widgets/serverrow.dart @@ -26,58 +26,57 @@ class _ServerRowState extends State { margin: EdgeInsets.all(0.0), child: InkWell( child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Padding( - padding: const EdgeInsets.all(6.0), //border size - child: Icon(CwtchIcons.dns_24px, - color: server.running ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor, size: 64)), - Expanded( - child: Column( - children: [ - Text( - server.description, - semanticsLabel: server.description, - style: Provider.of(context) - .biggerFont - .apply(color: server.running ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor), - softWrap: true, - overflow: TextOverflow.ellipsis, - ), - Visibility( - visible: !Provider.of(context).streamerMode, - child: ExcludeSemantics( - child: Text( - server.onion, + Padding( + padding: const EdgeInsets.all(6.0), //border size + child: Icon(CwtchIcons.dns_24px, + color: server.running ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor, size: 64)), + Expanded( + child: Column( + children: [ + Text( + server.description, + semanticsLabel: server.description, + style: Provider.of(context) + .biggerFont + .apply(color: server.running ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor), softWrap: true, overflow: TextOverflow.ellipsis, - style: TextStyle(color: server.running ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor), - ))) - ], - )), + ), + Visibility( + visible: !Provider.of(context).streamerMode, + child: ExcludeSemantics( + child: Text( + server.onion, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyle(color: server.running ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor), + ))) + ], + )), - // Copy server button - IconButton( - enableFeedback: true, - tooltip: AppLocalizations.of(context)!.copyServerKeys, - icon: Icon(CwtchIcons.address_copy_2, color: Provider.of(context).current().mainTextColor), - onPressed: () { - Clipboard.setData(new ClipboardData(text: server.serverBundle)); - }, - ), + // Copy server button + IconButton( + enableFeedback: true, + tooltip: AppLocalizations.of(context)!.copyServerKeys, + icon: Icon(CwtchIcons.address_copy_2, color: Provider.of(context).current().mainTextColor), + onPressed: () { + Clipboard.setData(new ClipboardData(text: server.serverBundle)); + }, + ), - // Edit button - IconButton( - enableFeedback: true, - tooltip: AppLocalizations.of(context)!.editServerTitle, - icon: Icon(Icons.create, color: Provider.of(context).current().mainTextColor), - onPressed: () { + // Edit button + IconButton( + enableFeedback: true, + tooltip: AppLocalizations.of(context)!.editServerTitle, + icon: Icon(Icons.create, color: Provider.of(context).current().mainTextColor), + onPressed: () { + _pushEditServer(server); + }, + ) + ]), + onTap: () { _pushEditServer(server); - }, - ) - ]), - onTap: () { - _pushEditServer(server); - } - )); + })); } void _pushEditServer(ServerInfoState server) { diff --git a/lib/widgets/textfield.dart b/lib/widgets/textfield.dart index 3dddd5ee..436bea19 100644 --- a/lib/widgets/textfield.dart +++ b/lib/widgets/textfield.dart @@ -47,7 +47,6 @@ class _CwtchTextFieldState extends State { filled: true, focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldBorderColor, width: 3.0)), focusedErrorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor, width: 3.0)), - errorBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(15.0), borderSide: BorderSide(color: theme.current().textfieldErrorColor, width: 3.0)), errorStyle: TextStyle( color: theme.current().textfieldErrorColor, From cde6962b8e6778f4ca0df0411650379af43baaf1 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Thu, 16 Dec 2021 13:36:14 -0500 Subject: [PATCH 13/20] group functionality fixes from storage engine; tor status include percent; crate group enhancement --- lib/cwtch/cwtchNotifier.dart | 19 ++++++++++--------- lib/torstatus.dart | 3 +++ lib/views/addcontactview.dart | 8 ++++++-- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/lib/cwtch/cwtchNotifier.dart b/lib/cwtch/cwtchNotifier.dart index 29ec9ce4..f3eaeb07 100644 --- a/lib/cwtch/cwtchNotifier.dart +++ b/lib/cwtch/cwtchNotifier.dart @@ -92,8 +92,8 @@ class CwtchNotifier { if (serverInfoState != null) { status = serverInfoState.status; } - if (profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(data["GroupID"]) == null) { - profileCN.getProfile(data["ProfileOnion"])?.contactList.add(ContactInfoState(data["ProfileOnion"], data["ConversationID"], data["GroupID"], + if (profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(int.parse(data["ConversationID"])) == null) { + profileCN.getProfile(data["ProfileOnion"])?.contactList.add(ContactInfoState(data["ProfileOnion"], int.parse(data["ConversationID"]), data["GroupID"], authorization: ContactAuthorization.approved, imagePath: data["PicturePath"], nickname: data["GroupName"], @@ -101,7 +101,7 @@ class CwtchNotifier { server: data["GroupServer"], isGroup: true, lastMessageTime: DateTime.now())); - profileCN.getProfile(data["ProfileOnion"])?.contactList.updateLastMessageTime(data["GroupID"], DateTime.now()); + profileCN.getProfile(data["ProfileOnion"])?.contactList.updateLastMessageTime(int.parse(data["ConversationID"]), DateTime.now()); } break; case "PeerDeleted": @@ -303,8 +303,8 @@ class CwtchNotifier { case "AcceptGroupInvite": EnvironmentConfig.debugLog("accept group invite"); - profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(data["GroupID"])!.authorization = ContactAuthorization.approved; - profileCN.getProfile(data["ProfileOnion"])?.contactList.updateLastMessageTime(data["GroupID"], DateTime.fromMillisecondsSinceEpoch(0)); + profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(int.parse(data["ConversationID"]))!.authorization = ContactAuthorization.approved; + profileCN.getProfile(data["ProfileOnion"])?.contactList.updateLastMessageTime(int.parse(data["ConversationID"]), DateTime.fromMillisecondsSinceEpoch(0)); break; case "ServerStateChange": // Update the Server Cache @@ -317,13 +317,14 @@ class CwtchNotifier { profileCN.getProfile(data["ProfileOnion"])?.contactList.resort(); break; case "SetGroupAttribute": + int identifier = int.parse(data["ConversationID"]); if (data["Key"] == "local.name") { - if (profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(data["GroupID"]) != null) { - profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(data["GroupID"])!.nickname = data["Data"]; + if (profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(identifier) != null) { + profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(identifier)!.nickname = data["Data"]; } } else if (data["Key"] == "local.archived") { - if (profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(data["GroupID"]) != null) { - profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(data["GroupID"])!.isArchived = data["Data"] == "true"; + if (profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(identifier) != null) { + profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(identifier)!.isArchived = data["Data"] == "true"; } } else { EnvironmentConfig.debugLog("unhandled set group attribute event: ${data['Key']}"); diff --git a/lib/torstatus.dart b/lib/torstatus.dart index a6910b58..af94b78d 100644 --- a/lib/torstatus.dart +++ b/lib/torstatus.dart @@ -18,6 +18,9 @@ class TorStatus extends ChangeNotifier { progress = new_progress; status = new_status; + if (new_progress != 100) { + status = "$new_progress% - $new_status"; + } notifyListeners(); } diff --git a/lib/views/addcontactview.dart b/lib/views/addcontactview.dart index c073f0f5..4e984595 100644 --- a/lib/views/addcontactview.dart +++ b/lib/views/addcontactview.dart @@ -197,11 +197,15 @@ class _AddContactViewState extends State { }, isExpanded: true, // magic property value: server, - items: Provider.of(context).serverList.servers.map>((RemoteServerInfoState serverInfo) { + items: Provider.of(context) + .serverList + .servers + .where((serverInfo) => serverInfo.status == "Synced") + .map>((RemoteServerInfoState serverInfo) { return DropdownMenuItem( value: serverInfo.onion, child: Text( - serverInfo.onion, + serverInfo.description, overflow: TextOverflow.ellipsis, ), ); From aff7a5f4b210d7026c07ee2c0c587a830c7e44d2 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Thu, 16 Dec 2021 19:50:43 -0500 Subject: [PATCH 14/20] deleting removed event event handlers --- lib/cwtch/cwtchNotifier.dart | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/lib/cwtch/cwtchNotifier.dart b/lib/cwtch/cwtchNotifier.dart index f3eaeb07..b7adfb19 100644 --- a/lib/cwtch/cwtchNotifier.dart +++ b/lib/cwtch/cwtchNotifier.dart @@ -300,12 +300,6 @@ class CwtchNotifier { } } break; - case "AcceptGroupInvite": - EnvironmentConfig.debugLog("accept group invite"); - - profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(int.parse(data["ConversationID"]))!.authorization = ContactAuthorization.approved; - profileCN.getProfile(data["ProfileOnion"])?.contactList.updateLastMessageTime(int.parse(data["ConversationID"]), DateTime.fromMillisecondsSinceEpoch(0)); - break; case "ServerStateChange": // Update the Server Cache profileCN.getProfile(data["ProfileOnion"])?.updateServerStatusCache(data["GroupServer"], data["ConnectionState"]); @@ -316,20 +310,6 @@ class CwtchNotifier { }); profileCN.getProfile(data["ProfileOnion"])?.contactList.resort(); break; - case "SetGroupAttribute": - int identifier = int.parse(data["ConversationID"]); - if (data["Key"] == "local.name") { - if (profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(identifier) != null) { - profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(identifier)!.nickname = data["Data"]; - } - } else if (data["Key"] == "local.archived") { - if (profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(identifier) != null) { - profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(identifier)!.isArchived = data["Data"] == "true"; - } - } else { - EnvironmentConfig.debugLog("unhandled set group attribute event: ${data['Key']}"); - } - break; case "SetPeerAttribute": if (data["Key"] == "local.name") { if (profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(data["RemotePeer"]) != null) { From eb38f48c67bbb0fbcf4b912537c49d01fd0ca5e2 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Thu, 16 Dec 2021 19:52:15 -0500 Subject: [PATCH 15/20] first pass at uninstaller --- windows/nsis/cwtch-installer.nsi | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/windows/nsis/cwtch-installer.nsi b/windows/nsis/cwtch-installer.nsi index 75a59515..20c39414 100644 --- a/windows/nsis/cwtch-installer.nsi +++ b/windows/nsis/cwtch-installer.nsi @@ -65,6 +65,11 @@ ShowInstDetails show !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_FINISH +!insertmacro MUI_UNPAGE_WELCOME +!insertmacro MUI_UNPAGE_CONFIRM +!insertmacro MUI_UNPAGE_INSTFILES +!insertmacro MUI_UNPAGE_FINISH + ; Languages -------------------------------- !insertmacro MUI_LANGUAGE "English" @@ -81,12 +86,18 @@ Section FILE /r "..\..\build\windows\runner\Release\" #FILESLISTEND + CreateDirectory "$SMPROGRAMS\Cwtch" # create a shortcut in the start menu programs directory - CreateDirectory "$SMPROGRAMS\Cwtch" CreateShortcut "$SMPROGRAMS\Cwtch\Cwtch.lnk" "$INSTDIR\cwtch.exe" "" "$INSTDIR\cwtch.ico" ;Store installation folder WriteRegStr HKCU "Software\Cwtch" "installLocation" $INSTDIR SectionEnd + +Section "Uninstall" + RMDir "$INSTDIR" /r /REBOOTOK + + DeleteRegKey /ifempty HKCU "Software\Cwtch\installLocation" +SectionEnd \ No newline at end of file From 6ba447f9417e23a27f4212cb52b5d25fc18e5e21 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Fri, 17 Dec 2021 17:13:09 -0500 Subject: [PATCH 16/20] appState support modal message --- lib/main.dart | 2 +- lib/model.dart | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/main.dart b/lib/main.dart index 3c3f27bd..9a8ba5b5 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -110,7 +110,7 @@ class FlwtchState extends State { supportedLocales: AppLocalizations.supportedLocales, title: 'Cwtch', theme: mkThemeData(settings), - home: appState.cwtchInit == true ? ShiftRightFixer(child: ProfileMgrView()) : SplashView(), + home: (!appState.cwtchInit || appState.modalState != ModalState.none) ? SplashView() : ShiftRightFixer(child: ProfileMgrView()), ), ); }, diff --git a/lib/model.dart b/lib/model.dart index 2106895b..e0953b12 100644 --- a/lib/model.dart +++ b/lib/model.dart @@ -26,8 +26,14 @@ class ChatMessage { }; } +enum ModalState { + none, + storageMigration +} + class AppState extends ChangeNotifier { bool cwtchInit = false; + ModalState modalState = ModalState.none; bool cwtchIsClosing = false; String appError = ""; String? _selectedProfile; From 75acfe8dd092b15332996d45d4f300fe924c9c0a Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Fri, 17 Dec 2021 17:34:56 -0500 Subject: [PATCH 17/20] contact list sort more often and float unauthed contacts to top --- lib/model.dart | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/model.dart b/lib/model.dart index 2106895b..083b63e4 100644 --- a/lib/model.dart +++ b/lib/model.dart @@ -149,6 +149,7 @@ class ContactListState extends ChangeNotifier { servers?.addGroup(contact); } }); + resort(); notifyListeners(); } @@ -157,6 +158,7 @@ class ContactListState extends ChangeNotifier { if (newContact.isGroup) { servers?.addGroup(newContact); } + resort(); notifyListeners(); } @@ -164,12 +166,18 @@ class ContactListState extends ChangeNotifier { _contacts.sort((ContactInfoState a, ContactInfoState b) { // return -1 = a first in list // return 1 = b first in list + // blocked contacts last if (a.isBlocked == true && b.isBlocked != true) return 1; if (a.isBlocked != true && b.isBlocked == true) return -1; // archive is next... if (!a.isArchived && b.isArchived) return -1; if (a.isArchived && !b.isArchived) return 1; + + // unapproved top + if (a.isInvitation && !b.isInvitation) return -1; + if (!a.isInvitation && b.isInvitation) return 1; + // special sorting for contacts with no messages in either history if (a.lastMessageTime.millisecondsSinceEpoch == 0 && b.lastMessageTime.millisecondsSinceEpoch == 0) { // online contacts first From 6adea075e7e175e9afbb90d2369c2acd9a19f934 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Fri, 17 Dec 2021 18:23:18 -0500 Subject: [PATCH 18/20] Make splash scren stateful; add translations; add message and progress bar for storage migration --- lib/cwtch/cwtchNotifier.dart | 6 ++++ lib/l10n/intl_de.arb | 4 ++- lib/l10n/intl_en.arb | 4 ++- lib/l10n/intl_es.arb | 4 ++- lib/l10n/intl_fr.arb | 32 +++++++++--------- lib/l10n/intl_it.arb | 4 ++- lib/l10n/intl_pl.arb | 4 ++- lib/l10n/intl_pt.arb | 4 ++- lib/l10n/intl_ru.arb | 64 +++++++++++++++++++----------------- lib/model.dart | 5 +++ lib/views/splashView.dart | 30 ++++++++++++++--- 11 files changed, 104 insertions(+), 57 deletions(-) diff --git a/lib/cwtch/cwtchNotifier.dart b/lib/cwtch/cwtchNotifier.dart index 29ec9ce4..07e70622 100644 --- a/lib/cwtch/cwtchNotifier.dart +++ b/lib/cwtch/cwtchNotifier.dart @@ -374,6 +374,12 @@ class CwtchNotifier { break; case "ImportingProfileEvent": break; + case "StartingStorageMigration": + appState.SetModalState(ModalState.storageMigration); + break; + case "DoneStorageMigration": + appState.SetModalState(ModalState.none); + break; default: EnvironmentConfig.debugLog("unhandled event: $type"); } diff --git a/lib/l10n/intl_de.arb b/lib/l10n/intl_de.arb index 3c7bdb25..3809c10d 100644 --- a/lib/l10n/intl_de.arb +++ b/lib/l10n/intl_de.arb @@ -1,6 +1,8 @@ { "@@locale": "de", - "@@last_modified": "2021-12-15T20:46:48+01:00", + "@@last_modified": "2021-12-17T23:48:01+01:00", + "storageMigrationModalMessage": "Migrating profiles to new storage format. This could take a few minutes...", + "loadingCwtch": "Loading Cwtch...", "themeColorLabel": "Color Theme", "themeNameNeon2": "Neon2", "themeNameNeon1": "Neon1", diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 42b7fca9..467c586b 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -1,6 +1,8 @@ { "@@locale": "en", - "@@last_modified": "2021-12-15T20:46:48+01:00", + "@@last_modified": "2021-12-17T23:48:01+01:00", + "storageMigrationModalMessage": "Migrating profiles to new storage format. This could take a few minutes...", + "loadingCwtch": "Loading Cwtch...", "themeColorLabel": "Color Theme", "themeNameNeon2": "Neon2", "themeNameNeon1": "Neon1", diff --git a/lib/l10n/intl_es.arb b/lib/l10n/intl_es.arb index 809b2d91..6a055fbb 100644 --- a/lib/l10n/intl_es.arb +++ b/lib/l10n/intl_es.arb @@ -1,6 +1,8 @@ { "@@locale": "es", - "@@last_modified": "2021-12-15T20:46:48+01:00", + "@@last_modified": "2021-12-17T23:48:01+01:00", + "storageMigrationModalMessage": "Migrating profiles to new storage format. This could take a few minutes...", + "loadingCwtch": "Loading Cwtch...", "themeColorLabel": "Color Theme", "themeNameNeon2": "Neon2", "themeNameNeon1": "Neon1", diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index 8140da2c..3d928173 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -1,21 +1,23 @@ { "@@locale": "fr", - "@@last_modified": "2021-12-15T20:46:48+01:00", - "themeColorLabel": "Color Theme", - "themeNameNeon2": "Neon2", - "themeNameNeon1": "Neon1", - "themeNameMidnight": "Midnight", - "themeNameMermaid": "Mermaid", - "themeNamePumpkin": "Pumpkin", - "themeNameGhost": "Ghost", + "@@last_modified": "2021-12-17T23:48:01+01:00", + "storageMigrationModalMessage": "Migrating profiles to new storage format. This could take a few minutes...", + "loadingCwtch": "Loading Cwtch...", + "experimentClickableLinksDescription": "L'expérience des liens cliquables vous permet de cliquer sur les URLs partagés dans les messages", + "themeNameWitch": "Sorcière", "themeNameVampire": "Vampire", - "themeNameWitch": "Witch", + "themeNamePumpkin": "Citrouille", + "themeNameNeon2": "Néon2", + "themeNameNeon1": "Néon1", + "themeNameMidnight": "Minuit", + "themeNameMermaid": "Sirène", + "themeNameGhost": "Fantôme", "themeNameCwtch": "Cwtch", - "settingDownloadFolder": "Download Folder", - "settingImagePreviewsDescription": "Images will be downloaded and previewed automatically. Please note that image previews can often lead to security vulnerabilities, and you should not enable this Experiment if you use Cwtch with untrusted contacts. Profile pictures are planned for Cwtch 1.6.", - "settingImagePreviews": "Image Previews and Profile Pictures", - "experimentClickableLinksDescription": "The clickable links experiment allows you to click on URLs shared in messages", - "enableExperimentClickableLinks": "Enable Clickable Links", + "themeColorLabel": "Thème de couleur", + "settingImagePreviewsDescription": "Les images seront téléchargées et prévisualisées automatiquement. Veuillez noter que la prévisualisation des images peut souvent conduire à des failles de sécurité, et vous ne devriez pas activer cette expérience si vous utilisez Cwtch avec des contacts non fiables. Les images de profil sont prévues pour Cwtch 1.6.", + "settingImagePreviews": "Aperçu des images et photos de profil", + "settingDownloadFolder": "Dossier de téléchargement", + "enableExperimentClickableLinks": "Activer les liens cliquables", "serverMetricsLabel": "Métriques du serveur", "serverTotalMessagesLabel": "Nombre total de messages", "serverConnectionsLabel": "Connexion", @@ -279,4 +281,4 @@ "newBulletinLabel": "Nouveau bulletin", "createGroupBtn": "Créer", "createGroupTitle": "Créer un groupe" -} +} \ No newline at end of file diff --git a/lib/l10n/intl_it.arb b/lib/l10n/intl_it.arb index e30cfb70..621ece9b 100644 --- a/lib/l10n/intl_it.arb +++ b/lib/l10n/intl_it.arb @@ -1,6 +1,8 @@ { "@@locale": "it", - "@@last_modified": "2021-12-15T20:46:48+01:00", + "@@last_modified": "2021-12-17T23:48:01+01:00", + "storageMigrationModalMessage": "Migrating profiles to new storage format. This could take a few minutes...", + "loadingCwtch": "Loading Cwtch...", "themeColorLabel": "Color Theme", "themeNameNeon2": "Neon2", "themeNameNeon1": "Neon1", diff --git a/lib/l10n/intl_pl.arb b/lib/l10n/intl_pl.arb index 78708ee7..6bed7cd6 100644 --- a/lib/l10n/intl_pl.arb +++ b/lib/l10n/intl_pl.arb @@ -1,6 +1,8 @@ { "@@locale": "pl", - "@@last_modified": "2021-12-15T20:46:48+01:00", + "@@last_modified": "2021-12-17T23:48:01+01:00", + "storageMigrationModalMessage": "Migrating profiles to new storage format. This could take a few minutes...", + "loadingCwtch": "Loading Cwtch...", "themeColorLabel": "Color Theme", "themeNameNeon2": "Neon2", "themeNameNeon1": "Neon1", diff --git a/lib/l10n/intl_pt.arb b/lib/l10n/intl_pt.arb index a548ca3a..b77121d2 100644 --- a/lib/l10n/intl_pt.arb +++ b/lib/l10n/intl_pt.arb @@ -1,6 +1,8 @@ { "@@locale": "pt", - "@@last_modified": "2021-12-15T20:46:48+01:00", + "@@last_modified": "2021-12-17T23:48:01+01:00", + "storageMigrationModalMessage": "Migrating profiles to new storage format. This could take a few minutes...", + "loadingCwtch": "Loading Cwtch...", "themeColorLabel": "Color Theme", "themeNameNeon2": "Neon2", "themeNameNeon1": "Neon1", diff --git a/lib/l10n/intl_ru.arb b/lib/l10n/intl_ru.arb index 8751074d..6c1fb55a 100644 --- a/lib/l10n/intl_ru.arb +++ b/lib/l10n/intl_ru.arb @@ -1,36 +1,40 @@ { "@@locale": "ru", - "@@last_modified": "2021-12-15T20:46:48+01:00", - "themeColorLabel": "Color Theme", - "themeNameNeon2": "Neon2", - "themeNameNeon1": "Neon1", - "themeNameMidnight": "Midnight", - "themeNameMermaid": "Mermaid", - "themeNamePumpkin": "Pumpkin", - "themeNameGhost": "Ghost", - "themeNameVampire": "Vampire", - "themeNameWitch": "Witch", + "@@last_modified": "2021-12-17T23:48:01+01:00", + "storageMigrationModalMessage": "Migrating profiles to new storage format. This could take a few minutes...", + "loadingCwtch": "Loading Cwtch...", + "themeColorLabel": "Тема", + "themeNameNeon2": "Неон2", + "themeNameNeon1": "Неон1", + "themeNameMidnight": "Полночь", + "themeNameMermaid": "Русалка", + "themeNamePumpkin": "Тыква", + "themeNameGhost": "Призрак", + "themeNameVampire": "Вампир", + "themeNameWitch": "Ведьма", "themeNameCwtch": "Cwtch", - "settingDownloadFolder": "Download Folder", - "settingImagePreviewsDescription": "Images will be downloaded and previewed automatically. Please note that image previews can often lead to security vulnerabilities, and you should not enable this Experiment if you use Cwtch with untrusted contacts. Profile pictures are planned for Cwtch 1.6.", - "settingImagePreviews": "Image Previews and Profile Pictures", - "experimentClickableLinksDescription": "The clickable links experiment allows you to click on URLs shared in messages", - "enableExperimentClickableLinks": "Enable Clickable Links", - "serverConnectionsLabel": "Connection", - "serverTotalMessagesLabel": "Total Messages", - "serverMetricsLabel": "Server Metrics", - "saveBtn": "Сохранить", + "settingDownloadFolder": "Скачать папку", + "settingImagePreviewsDescription": "Автоматическая загрузка изображений. Обратите внимание, что предварительный просмотр изображений часто может использоваться для взлома или деаномизации. Не используйте данную функцию если Вы контактируете с ненадежными контактами. Аватары профиля запланированы для версии Cwtch 1.6.", + "settingImagePreviews": "Предпросмотр изображений и фотографий профиля", + "experimentClickableLinksDescription": "Экспериментальная функция которая позволяет нажимать на URL адреса в сообщениях", + "enableExperimentClickableLinks": "Включить кликабельные ссылки", + "serverConnectionsLabel": "Соединение", + "serverTotalMessagesLabel": "Всего сообщений", + "serverMetricsLabel": "Показатели сервера", + "manageKnownServersShort": "Серверы", + "manageKnownServersLong": "Управление серверами", + "displayNameTooltip": "Введите отображаемое имя", + "manageKnownServersButton": "Управление серверами", + "fieldDescriptionLabel": "Описание", + "groupsOnThisServerLabel": "Группы, в которых я нахожусь, размещены на этом сервере", + "importLocalServerButton": "Импорт %1", + "importLocalServerSelectText": "Выбрать локальный сервер", + "importLocalServerLabel": "Импортировать локальный сервер", + "newMessagesLabel": "Новое сообщение", + "localeRU": "Русский", "profileOnionLabel": "Send this address to contacts you want to connect with", - "manageKnownServersShort": "Servers", - "manageKnownServersLong": "Manage Known Servers", - "displayNameTooltip": "Please enter a display name", - "manageKnownServersButton": "Manage Known Servers", - "fieldDescriptionLabel": "Description", - "groupsOnThisServerLabel": "Groups I am in hosted on this server", - "importLocalServerButton": "Import %1", - "importLocalServerSelectText": "Select Local Server", - "importLocalServerLabel": "Import a locally hosted server", - "newMessagesLabel": "New Messages", + "savePeerHistory": "Хранить историю", + "saveBtn": "Сохранить", "networkStatusOnline": "В сети", "copiedToClipboardNotification": "Скопировано в буфер обмена", "defaultProfileName": "Алиса", @@ -39,7 +43,6 @@ "groupNameLabel": "Имя группы", "serverLabel": "Сервер", "copyBtn": "Копировать", - "localeRU": "Russian", "copyServerKeys": "Копировать ключи", "verfiyResumeButton": "Проверить\/продолжить", "fileCheckingStatus": "Проверка статуса загрузки", @@ -220,7 +223,6 @@ "unblockBtn": "Разблокировать контакт", "dontSavePeerHistory": "Удалить историю", "savePeerHistoryDescription": "Определяет политуку хранения или удаления переписки с данным контактом.", - "savePeerHistory": "Хранить исторую", "blockBtn": "Заблокировать контакт", "displayNameLabel": "Отображаемое имя", "addressLabel": "Адрес", diff --git a/lib/model.dart b/lib/model.dart index e0953b12..86ddbe4c 100644 --- a/lib/model.dart +++ b/lib/model.dart @@ -53,6 +53,11 @@ class AppState extends ChangeNotifier { notifyListeners(); } + void SetModalState(ModalState newState) { + modalState = newState; + notifyListeners(); + } + String? get selectedProfile => _selectedProfile; set selectedProfile(String? newVal) { this._selectedProfile = newVal; diff --git a/lib/views/splashView.dart b/lib/views/splashView.dart index 33eb9097..9e68b2f8 100644 --- a/lib/views/splashView.dart +++ b/lib/views/splashView.dart @@ -1,11 +1,17 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import '../model.dart'; import '../settings.dart'; -class SplashView extends StatelessWidget { +class SplashView extends StatefulWidget { + @override + _SplashViewState createState() => _SplashViewState(); +} + +class _SplashViewState extends State { @override Widget build(BuildContext context) { return Consumer( @@ -25,10 +31,24 @@ class SplashView extends StatelessWidget { isAntiAlias: true, ), Padding( - padding: const EdgeInsets.all(20.0), - child: Text(appState.appError == "" ? "Loading Cwtch..." : appState.appError, - style: TextStyle(fontSize: 16.0, color: appState.appError == "" ? Provider.of(context).theme.mainTextColor : Provider.of(context).theme.textfieldErrorColor)), - ), + padding: const EdgeInsets.all(20.0), + child: Column(children: [ + Padding( + padding: EdgeInsets.all(6.0), + child: Text( + appState.appError != "" + ? appState.appError + : appState.modalState == ModalState.none + ? AppLocalizations.of(context)!.loadingCwtch + : AppLocalizations.of(context)!.storageMigrationModalMessage, + style: TextStyle( + fontSize: 16.0, color: appState.appError == "" ? Provider.of(context).theme.mainTextColor : Provider.of(context).theme.textfieldErrorColor))), + Visibility( + visible: appState.modalState == ModalState.storageMigration, + child: LinearProgressIndicator( + color: Provider.of(context).theme.defaultButtonActiveColor, + )) + ])), Image(image: AssetImage("assets/Open_Privacy_Logo_lightoutline.png")), ])), )); From 4946b6c51a829d8632dec78c2e92afead97464fa Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Sat, 18 Dec 2021 11:51:44 -0500 Subject: [PATCH 19/20] fix nsis syntax; write uninstaller --- windows/nsis/cwtch-installer.nsi | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/windows/nsis/cwtch-installer.nsi b/windows/nsis/cwtch-installer.nsi index 20c39414..a63ee737 100644 --- a/windows/nsis/cwtch-installer.nsi +++ b/windows/nsis/cwtch-installer.nsi @@ -94,10 +94,12 @@ Section ;Store installation folder WriteRegStr HKCU "Software\Cwtch" "installLocation" $INSTDIR + WriteUninstaller "$INSTDIR\uninstall.exe" + SectionEnd Section "Uninstall" - RMDir "$INSTDIR" /r /REBOOTOK + RMDir /r /REBOOTOK "$INSTDIR" DeleteRegKey /ifempty HKCU "Software\Cwtch\installLocation" SectionEnd \ No newline at end of file From 8e489131fa1dd39ff853c840a992eb52933ab9a4 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Sat, 18 Dec 2021 13:51:52 -0500 Subject: [PATCH 20/20] fix bg color of servers pane --- lib/views/serversview.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/views/serversview.dart b/lib/views/serversview.dart index 5e943b43..d413f2b2 100644 --- a/lib/views/serversview.dart +++ b/lib/views/serversview.dart @@ -30,6 +30,7 @@ class _ServersView extends State { @override Widget build(BuildContext context) { return Scaffold( + backgroundColor: Provider.of(context, listen: false).theme.backgroundMainColor, appBar: AppBar( title: Text(MediaQuery.of(context).size.width > 600 ? AppLocalizations.of(context)!.serversManagerTitleLong : AppLocalizations.of(context)!.serversManagerTitleShort), actions: getActions(),