From a4ce168aecc7b387f221bbfa3bf3564fa09e3c5d Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Wed, 26 Jan 2022 20:03:48 -0500 Subject: [PATCH 1/7] calculate server progress based on last message, nowtime, and message flow; display progress on group contact and remote server --- lib/cwtch/cwtchNotifier.dart | 6 +++- lib/models/contact.dart | 8 +++++ lib/models/profile.dart | 3 +- lib/models/profileservers.dart | 35 ++++---------------- lib/models/remoteserver.dart | 54 +++++++++++++++++++++++++++++++ lib/views/addcontactview.dart | 1 + lib/views/profileserversview.dart | 1 + lib/views/remoteserverview.dart | 1 + lib/widgets/contactrow.dart | 2 ++ lib/widgets/remoteserverrow.dart | 9 +++++- 10 files changed, 89 insertions(+), 31 deletions(-) create mode 100644 lib/models/remoteserver.dart diff --git a/lib/cwtch/cwtchNotifier.dart b/lib/cwtch/cwtchNotifier.dart index f8ac337c..0367c7ee 100644 --- a/lib/cwtch/cwtchNotifier.dart +++ b/lib/cwtch/cwtchNotifier.dart @@ -5,6 +5,7 @@ import 'package:cwtch/models/contact.dart'; import 'package:cwtch/models/message.dart'; import 'package:cwtch/models/profilelist.dart'; import 'package:cwtch/models/profileservers.dart'; +import 'package:cwtch/models/remoteserver.dart'; import 'package:cwtch/models/servers.dart'; import 'package:cwtch/notification_manager.dart'; import 'package:provider/provider.dart'; @@ -193,7 +194,8 @@ class CwtchNotifier { var senderHandle = data['RemotePeer']; var senderImage = data['Picture']; var timestampSent = DateTime.tryParse(data['TimestampSent'])!; - var currentTotal = profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(identifier)!.totalMessages; + var contact = profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(identifier); + var currentTotal = contact!.totalMessages; var isAuto = data['Auto'] == "true"; String? contenthash = data['ContentHash']; var selectedConversation = appState.selectedProfile == data["ProfileOnion"] && appState.selectedConversation == identifier; @@ -214,6 +216,8 @@ class CwtchNotifier { notificationManager.notify("New Message From Group!"); } + RemoteServerInfoState? server = profileCN.getProfile(data["ProfileOnion"])?.serverList.getServer(contact.server); + server?.updateSyncProgressFor(timestampSent); } else { // This is dealt with by IndexedAcknowledgment EnvironmentConfig.debugLog("new message from group from yourself - this should not happen"); diff --git a/lib/models/contact.dart b/lib/models/contact.dart index d39aa193..064950c6 100644 --- a/lib/models/contact.dart +++ b/lib/models/contact.dart @@ -26,6 +26,7 @@ class ContactInfoState extends ChangeNotifier { // todo: a nicer way to model contacts, groups and other "entities" late bool _isGroup; String? _server; + double _serverSyncProgress = 0.0; late bool _archived; String? _acnCircuit; @@ -176,6 +177,12 @@ class ContactInfoState extends ChangeNotifier { // we only allow callers to fetch the server get server => this._server; + double get serverSyncProgress => this._serverSyncProgress; + set serverSyncProgress(double newProgress) { + _serverSyncProgress = newProgress; + notifyListeners(); + } + bool isOnline() { if (this.isGroup == true) { // We now have an out of sync warning so we will mark these as online... @@ -211,6 +218,7 @@ class ContactInfoState extends ChangeNotifier { newMarker++; } + this._lastMessageTime = timestamp; this.messageCache.addNew(profileOnion, identifier, messageID, timestamp, senderHandle, senderImage, isAuto, data, contenthash); this.totalMessages += 1; diff --git a/lib/models/profile.dart b/lib/models/profile.dart index d79617ef..268eeb78 100644 --- a/lib/models/profile.dart +++ b/lib/models/profile.dart @@ -1,5 +1,6 @@ import 'dart:convert'; +import 'package:cwtch/models/remoteserver.dart'; import 'package:flutter/widgets.dart'; import 'contact.dart'; @@ -72,7 +73,7 @@ class ProfileInfoState extends ChangeNotifier { List servers = jsonDecode(serversJson); this._servers.replace(servers.map((server) { // TODO Keys... - return RemoteServerInfoState(onion: server["onion"], identifier: server["identifier"], description: server["description"], status: server["status"]); + return RemoteServerInfoState(server["onion"], server["identifier"], server["description"], server["status"]); })); this._contacts.contacts.forEach((contact) { diff --git a/lib/models/profileservers.dart b/lib/models/profileservers.dart index 9dd7af49..fbc02203 100644 --- a/lib/models/profileservers.dart +++ b/lib/models/profileservers.dart @@ -1,3 +1,4 @@ +import 'package:cwtch/models/remoteserver.dart'; import 'package:flutter/material.dart'; import 'contact.dart'; @@ -33,12 +34,17 @@ class ProfileServerListState extends ChangeNotifier { // return -1 = a first in list // return 1 = b first in list - // online v offline + // online v syncing v offline if (a.status == "Synced" && b.status != "Synced") { return -1; } else if (a.status != "Synced" && b.status == "Synced") { return 1; } + if (a.status == "Authenticated" && b.status != "Authenticated") { + return -1; + } else if (a.status != "Authenticated" && b.status == "Authenticated") { + return 1; + } // num of groups if (a.groups.length > b.groups.length) { @@ -65,30 +71,3 @@ class ProfileServerListState extends ChangeNotifier { List get servers => _servers.sublist(0); //todo: copy?? dont want caller able to bypass changenotifier } - -class RemoteServerInfoState extends ChangeNotifier { - final String onion; - final int identifier; - String status; - String description; - List _groups = []; - - RemoteServerInfoState({required this.onion, required this.identifier, required this.description, required this.status}); - - void updateDescription(String newDescription) { - this.description = newDescription; - notifyListeners(); - } - - void clearGroups() { - _groups = []; - } - - void addGroup(ContactInfoState group) { - _groups.add(group); - notifyListeners(); - } - - List get groups => _groups.sublist(0); //todo: copy?? dont want caller able to bypass changenotifier - -} diff --git a/lib/models/remoteserver.dart b/lib/models/remoteserver.dart new file mode 100644 index 00000000..b83a8844 --- /dev/null +++ b/lib/models/remoteserver.dart @@ -0,0 +1,54 @@ +import 'package:flutter/cupertino.dart'; + +import 'contact.dart'; + +class RemoteServerInfoState extends ChangeNotifier { + final String onion; + final int identifier; + String _status; + String description; + List _groups = []; + + double syncProgress = 0; + DateTime lastPreSyncMessagTime = new DateTime(2020); + + RemoteServerInfoState(this.onion, this.identifier, this.description, this._status); + + void updateDescription(String newDescription) { + this.description = newDescription; + notifyListeners(); + } + + void clearGroups() { + _groups = []; + } + + void addGroup(ContactInfoState group) { + _groups.add(group); + notifyListeners(); + } + + String get status => _status; + set status(String newStatus) { + _status = newStatus; + if (status == "Authenticated") { + // syncing, set lastPreSyncMessageTime + _groups.forEach((g) { + if(g.lastMessageTime.isAfter(lastPreSyncMessagTime)) { + lastPreSyncMessagTime = g.lastMessageTime; + } + }); + } + notifyListeners(); + } + + void updateSyncProgressFor(DateTime point) { + var range = lastPreSyncMessagTime.difference(DateTime.now()); + var pointFromStart = lastPreSyncMessagTime.difference(point); + syncProgress = pointFromStart.inSeconds / range.inSeconds * 100; + groups.forEach((g) { g.serverSyncProgress = syncProgress;}); + notifyListeners(); + } + + List get groups => _groups.sublist(0); //todo: copy?? dont want caller able to bypass changenotifier +} \ No newline at end of file diff --git a/lib/views/addcontactview.dart b/lib/views/addcontactview.dart index 2d58c43f..3cee78c1 100644 --- a/lib/views/addcontactview.dart +++ b/lib/views/addcontactview.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'package:cwtch/cwtch_icons_icons.dart'; import 'package:cwtch/models/profile.dart'; +import 'package:cwtch/models/remoteserver.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:cwtch/errorHandler.dart'; diff --git a/lib/views/profileserversview.dart b/lib/views/profileserversview.dart index 6a4d3ebd..2c4e8aab 100644 --- a/lib/views/profileserversview.dart +++ b/lib/views/profileserversview.dart @@ -1,5 +1,6 @@ import 'package:cwtch/models/profile.dart'; import 'package:cwtch/models/profileservers.dart'; +import 'package:cwtch/models/remoteserver.dart'; import 'package:cwtch/models/servers.dart'; import 'package:cwtch/widgets/remoteserverrow.dart'; import 'package:flutter/material.dart'; diff --git a/lib/views/remoteserverview.dart b/lib/views/remoteserverview.dart index 46ac8567..22e0a6f2 100644 --- a/lib/views/remoteserverview.dart +++ b/lib/views/remoteserverview.dart @@ -4,6 +4,7 @@ import 'package:cwtch/cwtch_icons_icons.dart'; import 'package:cwtch/models/contact.dart'; import 'package:cwtch/models/profile.dart'; import 'package:cwtch/models/profileservers.dart'; +import 'package:cwtch/models/remoteserver.dart'; import 'package:cwtch/models/servers.dart'; import 'package:cwtch/widgets/buttontextfield.dart'; import 'package:cwtch/widgets/contactrow.dart'; diff --git a/lib/widgets/contactrow.dart b/lib/widgets/contactrow.dart index 53dfe32c..ef53d95a 100644 --- a/lib/widgets/contactrow.dart +++ b/lib/widgets/contactrow.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:cwtch/models/appstate.dart'; import 'package:cwtch/models/contact.dart'; import 'package:cwtch/models/profile.dart'; +import 'package:cwtch/models/profileservers.dart'; import 'package:cwtch/views/contactsview.dart'; import 'package:flutter/material.dart'; import 'package:flutter/painting.dart'; @@ -66,6 +67,7 @@ class _ContactRowState extends State { visible: contact.isGroup && contact.status == "Authenticated", child: LinearProgressIndicator( color: Provider.of(context).theme.defaultButtonActiveColor, + value: contact.serverSyncProgress, )), Visibility( visible: !Provider.of(context).streamerMode, diff --git a/lib/widgets/remoteserverrow.dart b/lib/widgets/remoteserverrow.dart index c35b0e9a..fab0076f 100644 --- a/lib/widgets/remoteserverrow.dart +++ b/lib/widgets/remoteserverrow.dart @@ -1,6 +1,7 @@ import 'package:cwtch/main.dart'; import 'package:cwtch/models/profile.dart'; import 'package:cwtch/models/profileservers.dart'; +import 'package:cwtch/models/remoteserver.dart'; import 'package:cwtch/models/servers.dart'; import 'package:cwtch/views/addeditservers.dart'; import 'package:cwtch/views/remoteserverview.dart'; @@ -55,7 +56,13 @@ class _RemoteServerRowState extends State { softWrap: true, overflow: TextOverflow.ellipsis, style: TextStyle(color: running ? Provider.of(context).theme.portraitOnlineBorderColor : Provider.of(context).theme.portraitOfflineBorderColor), - ))) + ))), + Visibility( + visible: server.status == "Authenticated", + child: LinearProgressIndicator( + color: Provider.of(context).theme.defaultButtonActiveColor, + value: server.syncProgress, + )), ], )), ]), From d84850af490582d2ff77b9e5b4a7685d39f3c5df Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Thu, 27 Jan 2022 12:58:16 -0800 Subject: [PATCH 2/7] Fixup Length Display so it counts Bytes not Chars --- lib/notification_manager.dart | 2 +- lib/views/messageview.dart | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/notification_manager.dart b/lib/notification_manager.dart index 1a0200fe..91f1cb52 100644 --- a/lib/notification_manager.dart +++ b/lib/notification_manager.dart @@ -54,7 +54,7 @@ class WindowsNotificationManager implements NotificationsManager { } // clicked if (event is ToastActivated) { - active = false; + active = false; } // if a supplied action was clicked if (event is ToastInteracted) { diff --git a/lib/views/messageview.dart b/lib/views/messageview.dart index 9437dda8..89fa5b29 100644 --- a/lib/views/messageview.dart +++ b/lib/views/messageview.dart @@ -179,13 +179,14 @@ class _MessageViewState extends State { // size because of the additional wrapping end encoding // hybrid groups should allow these numbers to be the same. static const P2PMessageLengthMax = 7000; - static const GroupMessageLengthMax = 1800; + static const GroupMessageLengthMax = 1600; void _sendMessage([String? ignoredParam]) { var isGroup = Provider.of(context).contactList.getContact(Provider.of(context, listen: false).selectedConversation!)!.isGroup; // peers and groups currently have different length constraints (servers can store less)... - var lengthOk = (isGroup && ctrlrCompose.value.text.length < GroupMessageLengthMax) || ctrlrCompose.value.text.length <= P2PMessageLengthMax; + var actualMessageLength = ctrlrCompose.value.text.length; + var lengthOk = (isGroup && actualMessageLength < GroupMessageLengthMax) || actualMessageLength <= P2PMessageLengthMax; if (ctrlrCompose.value.text.isNotEmpty && lengthOk) { if (Provider.of(context, listen: false).selectedConversation != null && Provider.of(context, listen: false).selectedIndex != null) { @@ -250,6 +251,10 @@ class _MessageViewState extends State { bool isOffline = Provider.of(context).isOnline() == false; bool isGroup = Provider.of(context).isGroup; + var charLength = ctrlrCompose.value.text.characters.length; + var expectedLength = ctrlrCompose.value.text.length; + var numberOfBytesMoreThanChar = (expectedLength - charLength); + var composeBox = Container( color: Provider.of(context).theme.backgroundMainColor, padding: EdgeInsets.all(2), @@ -274,11 +279,16 @@ class _MessageViewState extends State { keyboardType: TextInputType.multiline, enableIMEPersonalizedLearning: false, minLines: 1, - maxLength: isGroup ? GroupMessageLengthMax : P2PMessageLengthMax, + maxLength: (isGroup ? GroupMessageLengthMax : P2PMessageLengthMax) - numberOfBytesMoreThanChar, maxLengthEnforcement: MaxLengthEnforcement.enforced, maxLines: null, onFieldSubmitted: _sendMessage, enabled: !isOffline, + onChanged: (String x) { + setState(() { + // we need to force a rerender here to update the max length count + }); + }, decoration: InputDecoration( hintText: isOffline ? "" : AppLocalizations.of(context)!.placeholderEnterMessage, hintStyle: TextStyle(color: Provider.of(context).theme.sendHintTextColor), From f818d4f2f8bd401f767975fd52e3c7630e242c6e Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Thu, 27 Jan 2022 18:40:45 -0500 Subject: [PATCH 3/7] remove syncProgress from contact and wire contact row to search server's list --- lib/models/contact.dart | 7 ------- lib/models/remoteserver.dart | 5 +++-- lib/views/contactsview.dart | 10 +++++++++- lib/widgets/contactrow.dart | 2 +- lib/widgets/profilerow.dart | 2 +- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/models/contact.dart b/lib/models/contact.dart index 064950c6..5ac0edd4 100644 --- a/lib/models/contact.dart +++ b/lib/models/contact.dart @@ -26,7 +26,6 @@ class ContactInfoState extends ChangeNotifier { // todo: a nicer way to model contacts, groups and other "entities" late bool _isGroup; String? _server; - double _serverSyncProgress = 0.0; late bool _archived; String? _acnCircuit; @@ -177,12 +176,6 @@ class ContactInfoState extends ChangeNotifier { // we only allow callers to fetch the server get server => this._server; - double get serverSyncProgress => this._serverSyncProgress; - set serverSyncProgress(double newProgress) { - _serverSyncProgress = newProgress; - notifyListeners(); - } - bool isOnline() { if (this.isGroup == true) { // We now have an out of sync warning so we will mark these as online... diff --git a/lib/models/remoteserver.dart b/lib/models/remoteserver.dart index b83a8844..f9e658dd 100644 --- a/lib/models/remoteserver.dart +++ b/lib/models/remoteserver.dart @@ -42,11 +42,12 @@ class RemoteServerInfoState extends ChangeNotifier { notifyListeners(); } + // updateSyncProgressFor point takes a message's time, and updates the server sync progress, + // based on that point in time between the precalculated lastPreSyncMessagTime and Now void updateSyncProgressFor(DateTime point) { var range = lastPreSyncMessagTime.difference(DateTime.now()); var pointFromStart = lastPreSyncMessagTime.difference(point); - syncProgress = pointFromStart.inSeconds / range.inSeconds * 100; - groups.forEach((g) { g.serverSyncProgress = syncProgress;}); + syncProgress = pointFromStart.inSeconds / range.inSeconds; notifyListeners(); } diff --git a/lib/views/contactsview.dart b/lib/views/contactsview.dart index 4e7b6ade..7f6b2236 100644 --- a/lib/views/contactsview.dart +++ b/lib/views/contactsview.dart @@ -3,6 +3,7 @@ import 'package:cwtch/models/appstate.dart'; import 'package:cwtch/models/contact.dart'; import 'package:cwtch/models/contactlist.dart'; import 'package:cwtch/models/profile.dart'; +import 'package:cwtch/models/profilelist.dart'; import 'package:cwtch/views/profileserversview.dart'; import 'package:flutter/material.dart'; import 'package:cwtch/widgets/contactrow.dart'; @@ -154,8 +155,15 @@ class _ContactsViewState extends State { Widget _buildContactList() { final tiles = Provider.of(context).filteredList().map((ContactInfoState contact) { - return ChangeNotifierProvider.value(key: ValueKey(contact.profileOnion + "" + contact.onion), value: contact, builder: (_, __) => RepaintBoundary(child: ContactRow())); + return MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: contact), + ChangeNotifierProvider.value(value: Provider.of(context).serverList), + ], + builder: (context, child) => RepaintBoundary(child: ContactRow()), + ); }); + final divided = ListTile.divideTiles( context: context, tiles: tiles, diff --git a/lib/widgets/contactrow.dart b/lib/widgets/contactrow.dart index ef53d95a..b61b8ffa 100644 --- a/lib/widgets/contactrow.dart +++ b/lib/widgets/contactrow.dart @@ -67,7 +67,7 @@ class _ContactRowState extends State { visible: contact.isGroup && contact.status == "Authenticated", child: LinearProgressIndicator( color: Provider.of(context).theme.defaultButtonActiveColor, - value: contact.serverSyncProgress, + value: Provider.of(context).serverList.getServer(contact.server)?.syncProgress, )), Visibility( visible: !Provider.of(context).streamerMode, diff --git a/lib/widgets/profilerow.dart b/lib/widgets/profilerow.dart index 6d2c8e8e..acbdce0a 100644 --- a/lib/widgets/profilerow.dart +++ b/lib/widgets/profilerow.dart @@ -91,7 +91,7 @@ class _ProfileRowState extends State { return MultiProvider( providers: [ ChangeNotifierProvider.value(value: profile), - ChangeNotifierProvider.value(value: profile.contactList), + ChangeNotifierProvider.value(value: profile.contactList) ], builder: (innercontext, widget) { var appState = Provider.of(context); From 247f4073b8cb1dc606155e988017ca8c14e552b6 Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Wed, 2 Feb 2022 10:45:58 -0800 Subject: [PATCH 4/7] Update Url Launcher --- lib/main.dart | 5 ++--- linux/my_application.cc | 7 ++++--- pubspec.yaml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 63aed68d..21b1a01f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -51,13 +51,14 @@ class Flwtch extends StatefulWidget { } } -class FlwtchState extends State with WindowListener, WidgetsBindingObserver { +class FlwtchState extends State with WindowListener { final TextStyle biggerFont = const TextStyle(fontSize: 18); late Cwtch cwtch; late ProfileListState profs; final MethodChannel notificationClickChannel = MethodChannel('im.cwtch.flwtch/notificationClickHandler'); final MethodChannel shutdownMethodChannel = MethodChannel('im.cwtch.flwtch/shutdownClickHandler'); final MethodChannel shutdownLinuxMethodChannel = MethodChannel('im.cwtch.linux.shutdown'); + final GlobalKey navKey = GlobalKey(); Future shutdownDirect(MethodCall call) { @@ -186,7 +187,6 @@ class FlwtchState extends State with WindowListener, WidgetsBindingObser // coder beware: args["RemotePeer"] is actually a handle, and could be eg a groupID Future _externalNotificationClicked(MethodCall call) async { var args = jsonDecode(call.arguments); - var profile = profs.getProfile(args["ProfileOnion"])!; var convo = profile.contactList.getContact(args["Handle"])!; Provider.of(navKey.currentContext!, listen: false).initialScrollIndex = convo.unreadMessages; @@ -231,7 +231,6 @@ class FlwtchState extends State with WindowListener, WidgetsBindingObser globalAppState.focus = false; } - @override void dispose() { cwtch.Shutdown(); diff --git a/linux/my_application.cc b/linux/my_application.cc index 07ad9a37..86d95331 100644 --- a/linux/my_application.cc +++ b/linux/my_application.cc @@ -132,14 +132,15 @@ static void my_application_activate(GApplication* application) { gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + // Create a specific channel for shutting down cwtch when the close button is triggered // We have registered the "destroy" handle above for this reason FlEngine *engine = fl_view_get_engine(view); g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); g_autoptr(FlBinaryMessenger) messenger = fl_engine_get_binary_messenger(engine); - channel = - fl_method_channel_new(messenger, - "im.cwtch.linux.shutdown", FL_METHOD_CODEC(codec)); + channel = fl_method_channel_new(messenger, "im.cwtch.linux.shutdown", FL_METHOD_CODEC(codec)); + gtk_widget_grab_focus(GTK_WIDGET(view)); diff --git a/pubspec.yaml b/pubspec.yaml index 9c74a0b6..ee0dc128 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -41,7 +41,7 @@ dependencies: scrollable_positioned_list: ^0.2.0-nullsafety.0 file_picker: ^4.3.2 file_picker_desktop: ^1.1.0 - url_launcher: ^6.0.12 + url_launcher: ^6.0.18 desktoasts: ^0.0.2 window_manager: ^0.1.4 From 3f5908e03ae4f330630956a4a14d87e7d95cec0b Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Wed, 2 Feb 2022 14:10:04 -0800 Subject: [PATCH 5/7] Load / Rename / Delete Profile Tests --- .../02_global_settings/05_streamer.feature | 4 -- .../04_profile_mgmt/01_create_delete.feature | 56 +++++++++++++++++-- .../gherkin_suite_test.editable.dart | 2 + .../steps/cwtch_profile_steps.dart | 0 integration_test/steps/overrides.dart | 38 ++++++++++++- lib/l10n/intl_de.arb | 2 +- lib/l10n/intl_en.arb | 4 +- lib/l10n/intl_es.arb | 2 +- lib/l10n/intl_fr.arb | 38 ++++++------- lib/l10n/intl_it.arb | 2 +- lib/l10n/intl_pl.arb | 2 +- lib/l10n/intl_pt.arb | 4 +- lib/l10n/intl_ru.arb | 2 +- lib/themes/opaque.dart | 4 +- lib/views/addeditprofileview.dart | 4 +- lib/views/profilemgrview.dart | 1 + pubspec.yaml | 3 + 17 files changed, 126 insertions(+), 42 deletions(-) delete mode 100644 integration_test/steps/cwtch_profile_steps.dart diff --git a/integration_test/features/02_global_settings/05_streamer.feature b/integration_test/features/02_global_settings/05_streamer.feature index 83bc153f..e69de29b 100644 --- a/integration_test/features/02_global_settings/05_streamer.feature +++ b/integration_test/features/02_global_settings/05_streamer.feature @@ -1,4 +0,0 @@ -@env:aliceandbob1 -Feature: Streamer mode setting hides onions - Scenario: Turning on streamer mode - Given \ No newline at end of file diff --git a/integration_test/features/04_profile_mgmt/01_create_delete.feature b/integration_test/features/04_profile_mgmt/01_create_delete.feature index c9825ed9..b085848f 100644 --- a/integration_test/features/04_profile_mgmt/01_create_delete.feature +++ b/integration_test/features/04_profile_mgmt/01_create_delete.feature @@ -1,3 +1,4 @@ +@env:persist Feature: Basic Profile Management Scenario: Error on Creating a Profile without a Display Name Given I wait until the widget with type 'ProfileMgrView' is present @@ -18,14 +19,18 @@ Feature: Basic Profile Management Then I tap the "passwordCheckBox" widget And I expect the text 'New Password' to be absent And I take a screenshot - Then I fill the "displayNameFormElement" field with "Alice (

hello

)" + Then I fill the "displayNameFormElement" field with "Alice (Unencrypted)" Then I tap the "button" widget with label "Add new profile" - And I expect a "ProfileRow" widget with text "Alice (

hello

)" + And I expect a "ProfileRow" widget with text "Alice (Unencrypted)" And I take a screenshot - Then I tap the "ProfileRow" widget with label "Alice (

hello

)" - And I expect the text 'Alice (

hello

) » Conversations' to be present + Then I tap the "ProfileRow" widget with label "Alice (Unencrypted)" + And I expect the text "Alice (Unencrypted) » Conversations" to be present And I take a screenshot + Scenario: Load Unencrypted Profile + Given I wait until the widget with type 'ProfileMgrView' is present + Then I expect a "ProfileRow" widget with text "Alice (Unencrypted)" + Scenario: Create Encrypted Profile Given I wait until the widget with type 'ProfileMgrView' is present And I tap the button with tooltip "Add new profile" @@ -41,4 +46,45 @@ Feature: Basic Profile Management And I take a screenshot Then I tap the "ProfileRow" widget with label "Alice (Encrypted)" And I expect the text 'Alice (Encrypted) » Conversations' to be present - And I take a screenshot \ No newline at end of file + And I take a screenshot + + Scenario: Load an Encrypted Profile by Unlocking it with a Password + Given I wait until the widget with type 'ProfileMgrView' is present + Then I expect the text 'Enter a password to view your profiles' to be absent + And I tap the button with tooltip "Unlock encrypted profiles by entering their password." + Then I expect the text 'Enter a password to view your profiles' to be present + When I fill the "unlockPasswordProfileElement" field with "password1" + And I tap the "button" widget with label "Unlock" + Then I expect a "ProfileRow" widget with text "Alice (Encrypted)" + + Scenario: Load an Encrypted Profile by Unlocking it with a Password and Change the Name + Given I wait until the widget with type 'ProfileMgrView' is present + Then I expect the text 'Enter a password to view your profiles' to be absent + And I tap the button with tooltip "Unlock encrypted profiles by entering their password." + Then I expect the text 'Enter a password to view your profiles' to be present + When I fill the "unlockPasswordProfileElement" field with "password1" + And I tap the "button" widget with label "Unlock" + Then I expect a "ProfileRow" widget with text "Alice (Encrypted)" + When I tap the "IconButton" widget with tooltip "Edit Profile Alice (Encrypted)" + Then I expect the text 'Display Name' to be present + Then I fill the "displayNameFormElement" field with "Carol (Encrypted)" + And I tap the "button" widget with label "Save Profile" + And I wait until the widget with type 'ProfileMgrView' is present + Then I expect a "ProfileRow" widget with text "Carol (Encrypted)" + + Scenario: Delete an Encrypted Profile + Given I wait until the widget with type 'ProfileMgrView' is present + Then I expect the text 'Enter a password to view your profiles' to be absent + And I tap the button with tooltip "Unlock encrypted profiles by entering their password." + Then I expect the text 'Enter a password to view your profiles' to be present + When I fill the "unlockPasswordProfileElement" field with "password1" + And I tap the "button" widget with label "Unlock" + Then I expect a "ProfileRow" widget with text "Carol (Encrypted)" + And I take a screenshot + When I tap the "IconButton" widget with tooltip "Edit Profile Carol (Encrypted)" + Then I expect the text 'Display Name' to be present + When I tap the button that contains the text "Delete" + Then I expect the text "Really Delete Profile" to be present + When I tap the "button" widget with label "Really Delete Profile" + And I wait until the widget with type 'ProfileMgrView' is present + Then I expect a "ProfileRow" widget with text "Carol (Encrypted)" to be absent diff --git a/integration_test/gherkin_suite_test.editable.dart b/integration_test/gherkin_suite_test.editable.dart index 6e38f100..6b235f95 100644 --- a/integration_test/gherkin_suite_test.editable.dart +++ b/integration_test/gherkin_suite_test.editable.dart @@ -38,7 +38,9 @@ void main() { // overrides TapWidgetWithType(), TapWidgetWithLabel(), + TapWidgetWithTooltip(), ExpectWidgetWithText(), + AbsentWidgetWithText(), WaitUntilTypeExists(), ExpectTextToBePresent(), ExpectWidgetWithTextWithin(), diff --git a/integration_test/steps/cwtch_profile_steps.dart b/integration_test/steps/cwtch_profile_steps.dart deleted file mode 100644 index e69de29b..00000000 diff --git a/integration_test/steps/overrides.dart b/integration_test/steps/overrides.dart index a9d647f4..48ce16f3 100644 --- a/integration_test/steps/overrides.dart +++ b/integration_test/steps/overrides.dart @@ -37,6 +37,22 @@ StepDefinitionGeneric TapWidgetWithLabel() { firstMatchOnly: true); //Text wdg = await context.world.appDriver.widget(finder, ExpectedWidgetResultType.first); //print(wdg.debugDescribeChildren().first.) + await context.world.appDriver.scrollIntoView(finder); + await context.world.appDriver.tap(finder); + await context.world.appDriver.waitForAppToSettle(); + }, + ); +} + +StepDefinitionGeneric TapWidgetWithTooltip() { + return given2( + RegExp(r'I tap the {string} widget with tooltip {string}$'), + (ofType, text, context) async { + final finder = context.world.appDriver.findByDescendant( + context.world.appDriver.findBy(widgetTypeByName(ofType), FindType.type), + context.world.appDriver.findBy(text, FindType.tooltip), + firstMatchOnly: true); + await context.world.appDriver.scrollIntoView(finder); await context.world.appDriver.tap(finder); await context.world.appDriver.waitForAppToSettle(); }, @@ -59,6 +75,23 @@ StepDefinitionGeneric ExpectWidgetWithText() { ); } +StepDefinitionGeneric AbsentWidgetWithText() { + return given2( + RegExp(r'I expect a {string} widget with text {string} to be absent$'), + (ofType, text, context) async { + final finder = context.world.appDriver.findByDescendant( + context.world.appDriver.findBy(widgetTypeByName(ofType), FindType.type), + context.world.appDriver.findBy(text, FindType.text), + firstMatchOnly: true); + //Text wdg = await context.world.appDriver.widget(finder, ExpectedWidgetResultType.first); + //print(wdg.debugDescribeChildren().first.) + await context.world.appDriver.isAbsent(finder); + await context.world.appDriver.waitForAppToSettle(); + }, + ); +} + + StepDefinitionGeneric TapButtonWithText() { return given1( RegExp(r'I tap the {string} (?:button|element|label|icon|field|text|widget)$'), @@ -67,8 +100,7 @@ StepDefinitionGeneric TapButtonWithText() { context.world.appDriver.findBy(Flwtch, FindType.type), context.world.appDriver.findBy(input1, FindType.key), firstMatchOnly: true); - //Text wdg = await context.world.appDriver.widget(finder, ExpectedWidgetResultType.first); - //print(wdg.debugDescribeChildren().first.) + await context.world.appDriver.scrollIntoView(finder); await context.world.appDriver.tap(finder); await context.world.appDriver.waitForAppToSettle(); }, @@ -229,6 +261,8 @@ Type widgetTypeByName(String input1) { return TorIcon; case "button": return ElevatedButton; + case "IconButton": + return IconButton; case "ProfileRow": return ProfileRow; default: diff --git a/lib/l10n/intl_de.arb b/lib/l10n/intl_de.arb index ff53b0ac..5ac7c7d8 100644 --- a/lib/l10n/intl_de.arb +++ b/lib/l10n/intl_de.arb @@ -1,6 +1,6 @@ { "@@locale": "de", - "@@last_modified": "2022-01-18T00:38:14+01:00", + "@@last_modified": "2022-01-28T19:57:41+01:00", "torSettingsEnabledCacheDescription": "Cache the current downloaded Tor consensus to reuse next time Cwtch is opened. This will allow Tor to start faster. When disabled, Cwtch will purge cached data on start up.", "torSettingsEnableCache": "Cache Tor Consensus", "labelTorNetwork": "Tor Network", diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 0e1cb975..df6497f1 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -1,6 +1,7 @@ { "@@locale": "en", - "@@last_modified": "2022-01-18T00:38:14+01:00", + "@@last_modified": "2022-01-28T19:57:41+01:00", + "editProfile": "Edit Profile", "torSettingsEnabledCacheDescription": "Cache the current downloaded Tor consensus to reuse next time Cwtch is opened. This will allow Tor to start faster. When disabled, Cwtch will purge cached data on start up.", "torSettingsEnableCache": "Cache Tor Consensus", "labelTorNetwork": "Tor Network", @@ -239,7 +240,6 @@ "radioNoPassword": "Unencrypted (No password)", "radioUsePassword": "Password", "copiedToClipboardNotification": "Copied to Clipboard", - "editProfile": "Edit Profille", "newProfile": "New Profile", "defaultProfileName": "Alice", "profileName": "Display name", diff --git a/lib/l10n/intl_es.arb b/lib/l10n/intl_es.arb index 81fd56f3..5f418b75 100644 --- a/lib/l10n/intl_es.arb +++ b/lib/l10n/intl_es.arb @@ -1,6 +1,6 @@ { "@@locale": "es", - "@@last_modified": "2022-01-18T00:38:14+01:00", + "@@last_modified": "2022-01-28T19:57:41+01:00", "torSettingsEnabledCacheDescription": "Cache the current downloaded Tor consensus to reuse next time Cwtch is opened. This will allow Tor to start faster. When disabled, Cwtch will purge cached data on start up.", "torSettingsEnableCache": "Cache Tor Consensus", "labelTorNetwork": "Tor Network", diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index 82f8c123..dd2c0544 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -1,22 +1,24 @@ { "@@locale": "fr", - "@@last_modified": "2022-01-18T00:38:14+01:00", - "torSettingsEnabledCacheDescription": "Cache the current downloaded Tor consensus to reuse next time Cwtch is opened. This will allow Tor to start faster. When disabled, Cwtch will purge cached data on start up.", - "torSettingsEnableCache": "Cache Tor Consensus", - "labelTorNetwork": "Tor Network", - "descriptionACNCircuitInfo": "In depth information about the path that the anonymous communication network is using to connect to this conversation.", - "labelACNCircuitInfo": "ACN Circuit Info", - "fileSharingSettingsDownloadFolderTooltip": "Browse to select a different default folder for downloaded files.", - "fileSharingSettingsDownloadFolderDescription": "When files are downloaded automatically (e.g. image files, when image previews are enabled) a default location to download the files to is needed.", - "torSettingsErrorSettingPort": "Port Number must be between 1 and 65535", - "torSettingsUseCustomTorServiceConfigurastionDescription": "Override the default tor configuration. Warning: This could be dangerous. Only turn this on if you know what you are doing.", - "torSettingsUseCustomTorServiceConfiguration": "Use a Custom Tor Service Configuration (torrc)", - "torSettingsCustomControlPortDescription": "Use a custom port for control connections to the Tor proxy", - "torSettingsCustomControlPort": "Custom Control Port", - "torSettingsCustomSocksPortDescription": "Use a custom port for data connections to the Tor proxy", - "torSettingsCustomSocksPort": "Custom SOCKS Port", - "torSettingsEnabledAdvancedDescription": "Use an existing Tor service on your system, or change the parameters of the Cwtch Tor Service", - "torSettingsEnabledAdvanced": "Enable Advanced Tor Configuration", + "@@last_modified": "2022-01-28T19:57:41+01:00", + "editProfile": "Modifier le profil", + "settingTheme": "Utilisez des thèmes clairs", + "torSettingsUseCustomTorServiceConfiguration": "Utiliser une configuration personnalisée du service Tor (torrc)", + "torSettingsUseCustomTorServiceConfigurastionDescription": "Remplacer la configuration par défaut de tor. Avertissement : Cela peut être dangereux. Ne l'activez que si vous savez ce que vous faites.", + "torSettingsErrorSettingPort": "Le numéro de port doit être compris entre 1 et 65535.", + "torSettingsEnableCache": "Cache du Consensus Tor", + "torSettingsEnabledCacheDescription": "Mettre en cache le consensus Tor actuellement téléchargé pour le réutiliser la prochaine fois que Cwtch est ouvert. Cela permettra à Tor de démarrer plus rapidement. Lorsqu'il est désactivé, Cwtch purgera les données mises en cache au démarrage.", + "torSettingsEnabledAdvancedDescription": "Utilisez un service Tor existant sur votre système ou modifiez les paramètres du service Tor de Cwtch.", + "torSettingsEnabledAdvanced": "Activer la configuration avancée de Tor", + "torSettingsCustomSocksPortDescription": "Utiliser un port personnalisé pour les connexions de données au proxy Tor", + "torSettingsCustomSocksPort": "Port SOCKS personnalisé", + "torSettingsCustomControlPortDescription": "Utiliser un port personnalisé pour contrôler les connexions au proxy Tor", + "torSettingsCustomControlPort": "Port de contrôle personnalisé", + "labelTorNetwork": "Réseau Tor", + "labelACNCircuitInfo": "Informations sur le circuit ACN", + "fileSharingSettingsDownloadFolderTooltip": "Parcourir pour sélectionner un autre dossier par défaut pour les fichiers téléchargés.", + "fileSharingSettingsDownloadFolderDescription": "Lorsque les fichiers sont téléchargés automatiquement (par exemple, les fichiers image, lorsque les aperçus d'image sont activés), un emplacement par défaut pour télécharger les fichiers est nécessaire.", + "descriptionACNCircuitInfo": "Informations détaillées sur le chemin que le réseau de communication anonyme utilise pour se connecter à cette conversation.", "msgConfirmSend": "Êtes-vous sûr de vouloir envoyer", "acceptGroupInviteLabel": "Voulez-vous accepter l'invitation au groupe de", "msgFileTooBig": "La taille du fichier ne peut pas dépasser 10 Go", @@ -187,7 +189,6 @@ "deleteConfirmLabel": "Tapez SUPPRIMER pour confirmer", "addNewProfileBtn": "Ajouter un nouveau profil", "enterProfilePassword": "Entrez un mot de passe pour consulter vos profils", - "editProfile": "Modifier le profil", "radioUsePassword": "Mot de passe", "radioNoPassword": "Non chiffré (pas de mot de passe)", "saveProfileBtn": "Sauvegarder le profil", @@ -205,7 +206,6 @@ "localePt": "Portugais", "localeDe": "Allemand", "settingInterfaceZoom": "Niveau de zoom", - "settingTheme": "Thème", "themeLight": "Clair", "themeDark": "Sombre", "experimentsEnabled": "Activer les expériences", diff --git a/lib/l10n/intl_it.arb b/lib/l10n/intl_it.arb index 2a69d62d..b94f3e24 100644 --- a/lib/l10n/intl_it.arb +++ b/lib/l10n/intl_it.arb @@ -1,6 +1,6 @@ { "@@locale": "it", - "@@last_modified": "2022-01-18T00:38:14+01:00", + "@@last_modified": "2022-01-28T19:57:41+01:00", "torSettingsEnabledCacheDescription": "Cache the current downloaded Tor consensus to reuse next time Cwtch is opened. This will allow Tor to start faster. When disabled, Cwtch will purge cached data on start up.", "torSettingsEnableCache": "Cache Tor Consensus", "labelTorNetwork": "Tor Network", diff --git a/lib/l10n/intl_pl.arb b/lib/l10n/intl_pl.arb index 882e91de..3866a59b 100644 --- a/lib/l10n/intl_pl.arb +++ b/lib/l10n/intl_pl.arb @@ -1,6 +1,6 @@ { "@@locale": "pl", - "@@last_modified": "2022-01-18T00:38:14+01:00", + "@@last_modified": "2022-01-28T19:57:41+01:00", "torSettingsEnabledCacheDescription": "Cache the current downloaded Tor consensus to reuse next time Cwtch is opened. This will allow Tor to start faster. When disabled, Cwtch will purge cached data on start up.", "torSettingsEnableCache": "Cache Tor Consensus", "labelTorNetwork": "Tor Network", diff --git a/lib/l10n/intl_pt.arb b/lib/l10n/intl_pt.arb index fa60f581..41142267 100644 --- a/lib/l10n/intl_pt.arb +++ b/lib/l10n/intl_pt.arb @@ -1,6 +1,6 @@ { "@@locale": "pt", - "@@last_modified": "2022-01-18T00:38:14+01:00", + "@@last_modified": "2022-01-28T19:57:41+01:00", "torSettingsEnabledCacheDescription": "Cache the current downloaded Tor consensus to reuse next time Cwtch is opened. This will allow Tor to start faster. When disabled, Cwtch will purge cached data on start up.", "torSettingsEnableCache": "Cache Tor Consensus", "labelTorNetwork": "Tor Network", @@ -227,7 +227,7 @@ "radioNoPassword": "Unencrypted (No password)", "radioUsePassword": "Password", "copiedToClipboardNotification": "Copiado", - "editProfile": "Edit Profille", + "editProfile": "Edit Profile", "newProfile": "New Profile", "defaultProfileName": "Alice", "profileName": "Display name", diff --git a/lib/l10n/intl_ru.arb b/lib/l10n/intl_ru.arb index 4ea0b04e..5357f2cb 100644 --- a/lib/l10n/intl_ru.arb +++ b/lib/l10n/intl_ru.arb @@ -1,6 +1,6 @@ { "@@locale": "ru", - "@@last_modified": "2022-01-18T00:38:14+01:00", + "@@last_modified": "2022-01-28T19:57:41+01:00", "torSettingsEnabledCacheDescription": "Cache the current downloaded Tor consensus to reuse next time Cwtch is opened. This will allow Tor to start faster. When disabled, Cwtch will purge cached data on start up.", "torSettingsEnableCache": "Cache Tor Consensus", "labelTorNetwork": "Tor Network", diff --git a/lib/themes/opaque.dart b/lib/themes/opaque.dart index ea219674..e54ad510 100644 --- a/lib/themes/opaque.dart +++ b/lib/themes/opaque.dart @@ -123,6 +123,7 @@ abstract class OpaqueThemeType { ThemeData mkThemeData(Settings opaque) { return ThemeData( + fontFamily: "OpenSans", visualDensity: VisualDensity.adaptivePlatformDensity, primarySwatch: Colors.red, primaryIconTheme: IconThemeData( @@ -149,6 +150,7 @@ ThemeData mkThemeData(Settings opaque) { color: opaque.current().mainTextColor, ), titleTextStyle: TextStyle( + fontFamily: "OpenSans", color: opaque.current().mainTextColor, ), actionsIconTheme: IconThemeData( @@ -183,7 +185,7 @@ ThemeData mkThemeData(Settings opaque) { 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( fontFamily: "OpenSans", color: opaque.current().mainTextColor), contentTextStyle: TextStyle(color: opaque.current().mainTextColor, fontFamily: "OpenSans",)), textTheme: TextTheme( headline1: TextStyle(color: opaque.current().mainTextColor), headline2: TextStyle(color: opaque.current().mainTextColor), diff --git a/lib/views/addeditprofileview.dart b/lib/views/addeditprofileview.dart index 01f3b2c0..9841712b 100644 --- a/lib/views/addeditprofileview.dart +++ b/lib/views/addeditprofileview.dart @@ -186,13 +186,13 @@ class _AddEditProfileViewState extends State { autoFillHints: [AutofillHints.newPassword], validator: (value) { // Password field can be empty when just updating the profile, not on creation - if (Provider.of(context).isEncrypted && + if (Provider.of(context, listen: false).isEncrypted && Provider.of(context, listen: false).onion.isEmpty && value.isEmpty && usePassword) { return AppLocalizations.of(context)!.passwordErrorEmpty; } - if (Provider.of(context).deleteProfileError == true) { + if (Provider.of(context, listen: false).deleteProfileError == true) { return AppLocalizations.of(context)!.enterCurrentPasswordForDelete; } return null; diff --git a/lib/views/profilemgrview.dart b/lib/views/profilemgrview.dart index 1782459c..69657178 100644 --- a/lib/views/profilemgrview.dart +++ b/lib/views/profilemgrview.dart @@ -191,6 +191,7 @@ class _ProfileMgrViewState extends State { height: 20, ), CwtchPasswordField( + key: Key("unlockPasswordProfileElement"), autofocus: true, controller: ctrlrPassword, action: unlock, diff --git a/pubspec.yaml b/pubspec.yaml index ee0dc128..3e80f667 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -95,6 +95,9 @@ flutter: - family: CwtchIcons fonts: - asset: assets/fonts/CwtchIcons.ttf + - family: OpenSans + fonts: + - asset: assets/fonts/OpenSans-Regular.ttf # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a From f00b78be761522dd081da749725e695404968b9a Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Wed, 2 Feb 2022 14:12:12 -0800 Subject: [PATCH 6/7] Remove OpenSans --- lib/themes/opaque.dart | 4 +--- pubspec.yaml | 3 --- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/themes/opaque.dart b/lib/themes/opaque.dart index e54ad510..f0e578aa 100644 --- a/lib/themes/opaque.dart +++ b/lib/themes/opaque.dart @@ -123,7 +123,6 @@ abstract class OpaqueThemeType { ThemeData mkThemeData(Settings opaque) { return ThemeData( - fontFamily: "OpenSans", visualDensity: VisualDensity.adaptivePlatformDensity, primarySwatch: Colors.red, primaryIconTheme: IconThemeData( @@ -150,7 +149,6 @@ ThemeData mkThemeData(Settings opaque) { color: opaque.current().mainTextColor, ), titleTextStyle: TextStyle( - fontFamily: "OpenSans", color: opaque.current().mainTextColor, ), actionsIconTheme: IconThemeData( @@ -185,7 +183,7 @@ ThemeData mkThemeData(Settings opaque) { 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( fontFamily: "OpenSans", color: opaque.current().mainTextColor), contentTextStyle: TextStyle(color: opaque.current().mainTextColor, fontFamily: "OpenSans",)), + 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), diff --git a/pubspec.yaml b/pubspec.yaml index 3e80f667..ee0dc128 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -95,9 +95,6 @@ flutter: - family: CwtchIcons fonts: - asset: assets/fonts/CwtchIcons.ttf - - family: OpenSans - fonts: - - asset: assets/fonts/OpenSans-Regular.ttf # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a From 812bfaac4e69cc8696a25200b8abde83532f6d63 Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Wed, 2 Feb 2022 14:12:58 -0800 Subject: [PATCH 7/7] Formatting --- lib/main.dart | 2 +- lib/models/remoteserver.dart | 4 ++-- lib/themes/opaque.dart | 6 +++++- lib/views/contactsview.dart | 2 +- lib/views/globalsettingsview.dart | 2 +- lib/views/profilemgrview.dart | 7 ++++++- lib/widgets/buttontextfield.dart | 11 ++++++++++- lib/widgets/messagerow.dart | 2 +- lib/widgets/profilerow.dart | 5 +---- 9 files changed, 28 insertions(+), 13 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 21b1a01f..f6174247 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -37,7 +37,7 @@ Future main() async { WidgetsFlutterBinding.ensureInitialized(); print("runApp()"); runApp(Flwtch()); - sleep(Duration(seconds:1)); + sleep(Duration(seconds: 1)); } class Flwtch extends StatefulWidget { diff --git a/lib/models/remoteserver.dart b/lib/models/remoteserver.dart index f9e658dd..2af03cd4 100644 --- a/lib/models/remoteserver.dart +++ b/lib/models/remoteserver.dart @@ -34,7 +34,7 @@ class RemoteServerInfoState extends ChangeNotifier { if (status == "Authenticated") { // syncing, set lastPreSyncMessageTime _groups.forEach((g) { - if(g.lastMessageTime.isAfter(lastPreSyncMessagTime)) { + if (g.lastMessageTime.isAfter(lastPreSyncMessagTime)) { lastPreSyncMessagTime = g.lastMessageTime; } }); @@ -52,4 +52,4 @@ class RemoteServerInfoState extends ChangeNotifier { } List get groups => _groups.sublist(0); //todo: copy?? dont want caller able to bypass changenotifier -} \ No newline at end of file +} diff --git a/lib/themes/opaque.dart b/lib/themes/opaque.dart index f0e578aa..b71f655e 100644 --- a/lib/themes/opaque.dart +++ b/lib/themes/opaque.dart @@ -183,7 +183,11 @@ ThemeData mkThemeData(Settings opaque) { 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), diff --git a/lib/views/contactsview.dart b/lib/views/contactsview.dart index 7f6b2236..9bc2f28d 100644 --- a/lib/views/contactsview.dart +++ b/lib/views/contactsview.dart @@ -163,7 +163,7 @@ class _ContactsViewState extends State { builder: (context, child) => RepaintBoundary(child: ContactRow()), ); }); - + final divided = ListTile.divideTiles( context: context, tiles: tiles, diff --git a/lib/views/globalsettingsview.dart b/lib/views/globalsettingsview.dart index f4cec611..5b733587 100644 --- a/lib/views/globalsettingsview.dart +++ b/lib/views/globalsettingsview.dart @@ -107,7 +107,7 @@ class _GlobalSettingsViewState extends State { items: themes.keys.map>((String themeId) { return DropdownMenuItem( value: themeId, - child: Text("ddi_$themeId",key: Key("ddi_$themeId")),//getThemeName(context, themeId)), + child: Text("ddi_$themeId", key: Key("ddi_$themeId")), //getThemeName(context, themeId)), ); }).toList()), leading: Icon(CwtchIcons.change_theme, color: settings.current().mainTextColor), diff --git a/lib/views/profilemgrview.dart b/lib/views/profilemgrview.dart index 69657178..f22de587 100644 --- a/lib/views/profilemgrview.dart +++ b/lib/views/profilemgrview.dart @@ -108,7 +108,12 @@ class _ProfileMgrViewState extends State { } // Global Settings - actions.add(IconButton(key: Key("OpenSettingsView"), icon: Icon(Icons.settings), tooltip: AppLocalizations.of(context)!.tooltipOpenSettings, splashRadius: Material.defaultSplashRadius / 2, onPressed: _pushGlobalSettings)); + actions.add(IconButton( + key: Key("OpenSettingsView"), + icon: Icon(Icons.settings), + tooltip: AppLocalizations.of(context)!.tooltipOpenSettings, + splashRadius: Material.defaultSplashRadius / 2, + onPressed: _pushGlobalSettings)); // shutdown cwtch actions.add(IconButton(icon: Icon(Icons.close), tooltip: AppLocalizations.of(context)!.shutdownCwtchTooltip, splashRadius: Material.defaultSplashRadius / 2, onPressed: _modalShutdown)); diff --git a/lib/widgets/buttontextfield.dart b/lib/widgets/buttontextfield.dart index ecd2631f..dd695de2 100644 --- a/lib/widgets/buttontextfield.dart +++ b/lib/widgets/buttontextfield.dart @@ -5,7 +5,16 @@ import 'package:provider/provider.dart'; // Provides a styled Text Field for use in Form Widgets. // Callers must provide a text controller, label helper text and a validator. class CwtchButtonTextField extends StatefulWidget { - CwtchButtonTextField({required this.controller, required this.onPressed, required this.icon, required this.tooltip, this.readonly = true, this.labelText, this.testKey, this.onChanged,}); + CwtchButtonTextField({ + required this.controller, + required this.onPressed, + required this.icon, + required this.tooltip, + this.readonly = true, + this.labelText, + this.testKey, + this.onChanged, + }); final TextEditingController controller; final Function()? onPressed; final Function(String)? onChanged; diff --git a/lib/widgets/messagerow.dart b/lib/widgets/messagerow.dart index 4b109d12..354bb46a 100644 --- a/lib/widgets/messagerow.dart +++ b/lib/widgets/messagerow.dart @@ -80,7 +80,7 @@ class MessageRowState extends State with SingleTickerProviderStateMi Widget wdgIcons = Platform.isAndroid ? SizedBox.shrink() : Visibility( - visible: true,//Provider.of(context).hoveredIndex == Provider.of(context).messageID, + visible: true, //Provider.of(context).hoveredIndex == Provider.of(context).messageID, maintainSize: true, maintainAnimation: true, maintainState: true, diff --git a/lib/widgets/profilerow.dart b/lib/widgets/profilerow.dart index acbdce0a..1ab6e273 100644 --- a/lib/widgets/profilerow.dart +++ b/lib/widgets/profilerow.dart @@ -89,10 +89,7 @@ class _ProfileRowState extends State { builder: (BuildContext buildcontext) { return OrientationBuilder(builder: (orientationBuilderContext, orientation) { return MultiProvider( - providers: [ - ChangeNotifierProvider.value(value: profile), - ChangeNotifierProvider.value(value: profile.contactList) - ], + providers: [ChangeNotifierProvider.value(value: profile), ChangeNotifierProvider.value(value: profile.contactList)], builder: (innercontext, widget) { var appState = Provider.of(context); var settings = Provider.of(context);