From 28ed360e1c4a6b71e4b1228ba9e19d796fff0631 Mon Sep 17 00:00:00 2001 From: ereio Date: Fri, 18 Mar 2022 11:51:22 -0400 Subject: [PATCH 01/22] refactor: remove old 0.2.9 message session conversion code --- analysis_options.yaml | 25 +++--- ...ue-batch-names.md => issue-batch-names.md} | 0 lib/cache/codec.dart | 3 +- lib/cache/serializer.dart | 9 +- lib/global/https.dart | 11 ++- lib/global/libs/matrix/encryption.dart | 1 - lib/global/libs/matrix/notifications.dart | 1 - lib/store/alerts/actions.dart | 8 +- lib/store/crypto/state.dart | 73 +--------------- .../settings/theme-settings/selectors.dart | 85 +++++++------------ 10 files changed, 64 insertions(+), 152 deletions(-) rename docs/{various-issue-batch-names.md => issue-batch-names.md} (100%) diff --git a/analysis_options.yaml b/analysis_options.yaml index e86c8d07b..b176da65b 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -7,6 +7,17 @@ analyzer: linter: rules: + # TODO: convert to true + prefer_const_constructors: false + lines_longer_than_80_chars: false + avoid_redundant_argument_values: false + prefer_typing_uninitialized_variables: false + empty_catches: false + avoid_dynamic_calls: false + # sort_constructors_first: true + # always_put_required_named_parameters_first: true + # always_specify_types: true + # Disabled file_names: false type_annotate_public_apis: false @@ -18,21 +29,9 @@ linter: prefer_conditional_assignment: false sized_box_for_whitespace: false always_use_package_imports: false + require_trailing_commas: false use_build_context_synchronously: false # powers most of the navigation... # Enabled prefer_single_quotes: true - - # sort_constructors_first: true - # prefer_double_quotes: true - # public_member_api_docs: true - # always_specify_types: true - # always_put_required_named_parameters_first: false - - # TODO: - prefer_const_constructors: false - lines_longer_than_80_chars: false - avoid_redundant_argument_values: false - prefer_typing_uninitialized_variables: false - empty_catches: false diff --git a/docs/various-issue-batch-names.md b/docs/issue-batch-names.md similarity index 100% rename from docs/various-issue-batch-names.md rename to docs/issue-batch-names.md diff --git a/lib/cache/codec.dart b/lib/cache/codec.dart index a3586d9f6..3a6460f09 100644 --- a/lib/cache/codec.dart +++ b/lib/cache/codec.dart @@ -48,6 +48,7 @@ class _EncryptDecoder extends Converter { final iv = base64.decode(input.substring(0, IV_LENGTH_BASE_64.round())); // Extract the real input + // ignore: parameter_assignments input = input.substring(IV_LENGTH_BASE_64.round()); // Decode the input @@ -61,7 +62,7 @@ class EncryptCodec extends Codec { late _EncryptDecoder _decoder; EncryptCodec(Key passwordBytes) { - var aes = AES(passwordBytes, mode: AESMode.ctr, padding: null); + final aes = AES(passwordBytes, mode: AESMode.ctr, padding: null); _encoder = _EncryptEncoder(aes); _decoder = _EncryptDecoder(aes); diff --git a/lib/cache/serializer.dart b/lib/cache/serializer.dart index d3a92f897..cc4c83d52 100644 --- a/lib/cache/serializer.dart +++ b/lib/cache/serializer.dart @@ -138,7 +138,6 @@ class CacheSerializer implements StateSerializer { } }); - // TODO: move down after 0.2.9 release final cryptoState = cryptoStore ?? preloaded[StorageKeys.CRYPTO] as CryptoStore? ?? CryptoStore(); @@ -149,10 +148,10 @@ class CacheSerializer implements StateSerializer { loading: false, authStore: authStore ?? preloaded[StorageKeys.AUTH] ?? AuthStore(), cryptoStore: messageSessionsLoaded.isEmpty - ? cryptoState.upgradeSessions_temp() - : cryptoState.upgradeSessions_temp().copyWith( - messageSessionsInbound: preloaded[StorageKeys.MESSAGE_SESSIONS], - ), + ? cryptoState + : cryptoState.copyWith( + messageSessionsInbound: messageSessionsLoaded, + ), settingsStore: preloaded[StorageKeys.SETTINGS] ?? settingsStore ?? SettingsStore(), syncStore: syncStore ?? SyncStore(), mediaStore: mediaStore ?? MediaStore().copyWith(mediaCache: preloaded[StorageKeys.MEDIA]), diff --git a/lib/global/https.dart b/lib/global/https.dart index f1b133441..a08e6c947 100644 --- a/lib/global/https.dart +++ b/lib/global/https.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:http/http.dart' as http; import 'package:http/io_client.dart'; +import 'package:syphon/global/print.dart'; import 'package:syphon/store/settings/proxy-settings/model.dart'; /// This is LetsEncrypt's self-signed trusted root certificate authority @@ -59,9 +60,9 @@ HttpClient customHttpClient({String? cert}) { } } on TlsException catch (e) { if (e.osError?.message != null && e.osError!.message.contains('CERT_ALREADY_IN_HASH_TABLE')) { - print('createHttpClient() - cert already trusted! Skipping.'); + log.info('[customHttpClient] - cert already trusted! Skipping.'); } else { - print('createHttpClient().setTrustedCertificateBytes EXCEPTION: $e'); + log.error('[customHttpClient] setTrustedCertificateBytes EXCEPTION: $e'); rethrow; } } finally {} @@ -82,13 +83,11 @@ http.Client createClient({ProxySettings? proxySettings}) { proxySettings.host, int.parse(proxySettings.port), // port input allows numbers only, so no try/catch 'Basic', // Basic authentication - HttpClientBasicCredentials(proxySettings.username, proxySettings.password) - ); + HttpClientBasicCredentials(proxySettings.username, proxySettings.password)); } return 'PROXY ${proxySettings.host}:${proxySettings.port};'; - } - else { + } else { return 'DIRECT'; } }; diff --git a/lib/global/libs/matrix/encryption.dart b/lib/global/libs/matrix/encryption.dart index 3e7d45ba1..ea933af12 100644 --- a/lib/global/libs/matrix/encryption.dart +++ b/lib/global/libs/matrix/encryption.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'dart:convert'; -import 'package:http/http.dart' as http; import 'package:syphon/global/https.dart'; import 'package:syphon/global/libs/matrix/constants.dart'; import 'package:syphon/global/libs/matrix/index.dart'; diff --git a/lib/global/libs/matrix/notifications.dart b/lib/global/libs/matrix/notifications.dart index 82227a155..4f85f6487 100644 --- a/lib/global/libs/matrix/notifications.dart +++ b/lib/global/libs/matrix/notifications.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'dart:convert'; -import 'package:http/http.dart' as http; import 'package:syphon/global/https.dart'; import 'package:syphon/global/values.dart'; diff --git a/lib/store/alerts/actions.dart b/lib/store/alerts/actions.dart index e900d5b9d..27326c774 100644 --- a/lib/store/alerts/actions.dart +++ b/lib/store/alerts/actions.dart @@ -41,9 +41,11 @@ ThunkAction startAlertsObserver() { throw 'Cannot call startAlertsObserver with an existing instance'; } - store.dispatch(SetAlertsObserver( - alertsObserver: StreamController.broadcast(), - )); + store.dispatch( + SetAlertsObserver( + alertsObserver: StreamController.broadcast(), + ), + ); }; } diff --git a/lib/store/crypto/state.dart b/lib/store/crypto/state.dart index 79e4d9dd5..41c9ed779 100644 --- a/lib/store/crypto/state.dart +++ b/lib/store/crypto/state.dart @@ -1,7 +1,6 @@ import 'package:equatable/equatable.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:olm/olm.dart'; -import 'package:syphon/global/print.dart'; import 'package:syphon/store/crypto/keys/models.dart'; import 'package:syphon/store/crypto/sessions/model.dart'; @@ -21,24 +20,17 @@ class CryptoStore extends Equatable { final bool deviceKeyVerified; final bool oneTimeKeysStable; - // Map + // Map final Map> keySessions; // both olm inbound and outbound key sessions // Map // megolm - messages final Map outboundMessageSessions; // Map // megolm - messages per chat + // NOTE: backed up to sqlite db storage, JsonKey ignore to not cache @JsonKey(ignore: true) final Map>> messageSessionsInbound; - // Map // megolm - index per chat - @Deprecated('switch to using "index" inside MessageSession within inboundMessageSessionsAll') - final Map> messageSessionIndex; - - // Map // megolm - messages per chat - @Deprecated('switch to inboundMessageSessionsAll to include old session for a device') - final Map> inboundMessageSessions; - /// Map deviceKeys final Map> deviceKeys; @@ -57,11 +49,9 @@ class CryptoStore extends Equatable { this.deviceKeysExist = false, this.deviceKeyVerified = false, this.oneTimeKeysStable = true, - this.inboundMessageSessions = const {}, // Megolm Sessions this.messageSessionsInbound = const {}, // Megolm Sessions this.outboundMessageSessions = const {}, // Megolm Sessions this.keySessions = const {}, // Olm sessions - this.messageSessionIndex = const {}, this.deviceKeys = const {}, this.deviceKeysOwned = const {}, this.oneTimeKeysClaimed = const {}, @@ -90,10 +80,8 @@ class CryptoStore extends Equatable { bool? deviceKeysExist, bool? deviceKeyVerified, bool? oneTimeKeysStable, - @Deprecated('only for converting') Map>? messageSessionIndex, - @Deprecated('only for converting') Map>? inboundMessageSessions, - Map>>? messageSessionsInbound, Map? outboundMessageSessions, + Map>>? messageSessionsInbound, Map>? keySessions, Map? deviceKeysOwned, Map>? deviceKeys, @@ -103,8 +91,6 @@ class CryptoStore extends Equatable { CryptoStore( olmAccount: olmAccount ?? this.olmAccount, olmAccountKey: olmAccountKey ?? this.olmAccountKey, - messageSessionIndex: messageSessionIndex ?? this.messageSessionIndex, - inboundMessageSessions: inboundMessageSessions ?? this.inboundMessageSessions, messageSessionsInbound: messageSessionsInbound ?? this.messageSessionsInbound, outboundMessageSessions: outboundMessageSessions ?? this.outboundMessageSessions, keySessions: keySessions ?? this.keySessions, @@ -117,59 +103,6 @@ class CryptoStore extends Equatable { oneTimeKeysCounts: oneTimeKeysCounts ?? this.oneTimeKeysCounts, ); - // TODO: remove after 0.2.9 release - // @Deprecated('only use to migrate keys from < 0.2.8 to 0.2.9') - CryptoStore upgradeSessions_temp() { - if (inboundMessageSessions.isEmpty) { - return this; - } - - log.warn('[upgradeSessions_temp] UPGRADING PREVIOUS KEY SESSIONS'); - - final messageSessionsUpdated = Map>>.from( - messageSessionsInbound, - ); - - for (final roomSessions in inboundMessageSessions.entries) { - final roomId = roomSessions.key; - final sessions = roomSessions.value; - - for (final messsageSessions in sessions.entries) { - final senderKey = messsageSessions.key; - final messageIndex = ((messageSessionIndex[roomId] ?? {})[senderKey]) ?? 0; - final sessionsSerialized = messsageSessions.value; - - final messageSessionNew = MessageSession( - index: messageIndex, - serialized: sessionsSerialized, // already pickled - createdAt: DateTime.now().millisecondsSinceEpoch, - ); - - // new message session updates - messageSessionsUpdated.update( - roomId, - (identitySessions) => identitySessions - ..update( - senderKey, - (sessions) => sessions..insert(0, messageSessionNew), - ifAbsent: () => [messageSessionNew], - ), - ifAbsent: () => { - senderKey: [messageSessionNew], - }, - ); - } - } - - log.warn('[upgradeSessions_temp] COMPLETED, WIPING PREVIOUS KEY SESSIONS'); - - return copyWith( - messageSessionIndex: const {}, - inboundMessageSessions: const {}, - messageSessionsInbound: messageSessionsUpdated, - ); - } - Map toJson() => _$CryptoStoreToJson(this); factory CryptoStore.fromJson(Map json) => _$CryptoStoreFromJson(json); } diff --git a/lib/store/settings/theme-settings/selectors.dart b/lib/store/settings/theme-settings/selectors.dart index 3847143fb..49b8e0424 100644 --- a/lib/store/settings/theme-settings/selectors.dart +++ b/lib/store/settings/theme-settings/selectors.dart @@ -19,6 +19,15 @@ ThemeType themeTypeFromSystem() { return ThemeType.Light; } +ThemeType resolveThemeOverride(ThemeType themeType) { + var themeTypeOverride = themeType; + if (themeTypeOverride == ThemeType.System) { + themeTypeOverride = themeTypeFromSystem(); + } + + return themeTypeOverride; +} + String selectMainFabType(ThemeSettings themeSettings) { return enumToString(themeSettings.mainFabType); } @@ -50,10 +59,6 @@ SystemUiOverlayStyle computeSystemUIColor(BuildContext context, {double ratio = } int selectRowHighlightColor(ThemeType themeType) { - if (themeType == ThemeType.System) { - themeType = themeTypeFromSystem(); - } - switch (themeType) { case ThemeType.Light: return Colours.greyLightest; @@ -64,10 +69,8 @@ int selectRowHighlightColor(ThemeType themeType) { } } -int selectSystemUiColor(ThemeType themeType) { - if (themeType == ThemeType.System) { - themeType = themeTypeFromSystem(); - } +int selectSystemUiColor(ThemeType themeTypeNew) { + final themeType = resolveThemeOverride(themeTypeNew); switch (themeType) { case ThemeType.Light: @@ -79,10 +82,8 @@ int selectSystemUiColor(ThemeType themeType) { } } -Brightness selectSystemUiIconColor(ThemeType themeType) { - if (themeType == ThemeType.System) { - themeType = themeTypeFromSystem(); - } +Brightness selectSystemUiIconColor(ThemeType themeTypeNew) { + final themeType = resolveThemeOverride(themeTypeNew); switch (themeType) { case ThemeType.Light: @@ -92,10 +93,8 @@ Brightness selectSystemUiIconColor(ThemeType themeType) { } } -Color selectIconBackground(ThemeType themeType) { - if (themeType == ThemeType.System) { - themeType = themeTypeFromSystem(); - } +Color selectIconBackground(ThemeType themeTypeNew) { + final themeType = resolveThemeOverride(themeTypeNew); switch (themeType) { case ThemeType.Light: @@ -107,10 +106,8 @@ Color selectIconBackground(ThemeType themeType) { } } -Color selectAvatarBackground(ThemeType themeType) { - if (themeType == ThemeType.System) { - themeType = themeTypeFromSystem(); - } +Color selectAvatarBackground(ThemeType themeTypeNew) { + final themeType = resolveThemeOverride(themeTypeNew); switch (themeType) { case ThemeType.Light: @@ -122,10 +119,8 @@ Color selectAvatarBackground(ThemeType themeType) { } } -Brightness selectThemeBrightness(ThemeType themeType) { - if (themeType == ThemeType.System) { - themeType = themeTypeFromSystem(); - } +Brightness selectThemeBrightness(ThemeType themeTypeNew) { + final themeType = resolveThemeOverride(themeTypeNew); switch (themeType) { case ThemeType.Light: @@ -135,10 +130,8 @@ Brightness selectThemeBrightness(ThemeType themeType) { } } -Color selectIconColor(ThemeType themeType) { - if (themeType == ThemeType.System) { - themeType = themeTypeFromSystem(); - } +Color selectIconColor(ThemeType themeTypeNew) { + final themeType = resolveThemeOverride(themeTypeNew); switch (themeType) { case ThemeType.Light: @@ -148,10 +141,8 @@ Color selectIconColor(ThemeType themeType) { } } -Color? selectModalColor(ThemeType themeType) { - if (themeType == ThemeType.System) { - themeType = themeTypeFromSystem(); - } +Color? selectModalColor(ThemeType themeTypeNew) { + final themeType = resolveThemeOverride(themeTypeNew); switch (themeType) { case ThemeType.Night: @@ -161,10 +152,8 @@ Color? selectModalColor(ThemeType themeType) { } } -int? selectScaffoldBackgroundColor(ThemeType themeType) { - if (themeType == ThemeType.System) { - themeType = themeTypeFromSystem(); - } +int? selectScaffoldBackgroundColor(ThemeType themeTypeNew) { + final themeType = resolveThemeOverride(themeTypeNew); switch (themeType) { case ThemeType.Light: @@ -178,10 +167,8 @@ int? selectScaffoldBackgroundColor(ThemeType themeType) { } } -Color selectInputTextColor(ThemeType themeType) { - if (themeType == ThemeType.System) { - themeType = themeTypeFromSystem(); - } +Color selectInputTextColor(ThemeType themeTypeNew) { + final themeType = resolveThemeOverride(themeTypeNew); switch (themeType) { case ThemeType.Light: @@ -191,10 +178,8 @@ Color selectInputTextColor(ThemeType themeType) { } } -Color selectCursorColor(ThemeType themeType) { - if (themeType == ThemeType.System) { - themeType = themeTypeFromSystem(); - } +Color selectCursorColor(ThemeType themeTypeNew) { + final themeType = resolveThemeOverride(themeTypeNew); switch (themeType) { case ThemeType.Light: @@ -204,10 +189,8 @@ Color selectCursorColor(ThemeType themeType) { } } -Color selectInputBackgroundColor(ThemeType themeType) { - if (themeType == ThemeType.System) { - themeType = themeTypeFromSystem(); - } +Color selectInputBackgroundColor(ThemeType themeTypeNew) { + final themeType = resolveThemeOverride(themeTypeNew); switch (themeType) { case ThemeType.Light: @@ -219,10 +202,8 @@ Color selectInputBackgroundColor(ThemeType themeType) { } } -double? selectAppBarElevation(ThemeType themeType) { - if (themeType == ThemeType.System) { - themeType = themeTypeFromSystem(); - } +double? selectAppBarElevation(ThemeType themeTypeNew) { + final themeType = resolveThemeOverride(themeTypeNew); switch (themeType) { case ThemeType.Darker: From 7715d95700ae00d42d92f06470b133af4dfbc51d Mon Sep 17 00:00:00 2001 From: ereio Date: Fri, 18 Mar 2022 14:02:29 -0400 Subject: [PATCH 02/22] fix: extending simplepads dm fix to other places --- ios/Runner.xcodeproj/project.pbxproj | 12 +- lib/store/rooms/selectors.dart | 25 +++- lib/store/rooms/state.dart | 5 +- .../home/search/search-users-screen.dart | 130 ++++++++++++------ .../widgets/modals/modal-user-details.dart | 88 ++++++------ 5 files changed, 160 insertions(+), 100 deletions(-) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 202277476..7a52d7929 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -355,7 +355,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 2100; + CURRENT_PROJECT_VERSION = 2111; DEVELOPMENT_TEAM = W98LUTKH5G; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -371,7 +371,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - MARKETING_VERSION = 0.2.10; + MARKETING_VERSION = 0.2.11; PRODUCT_BUNDLE_IDENTIFIER = org.tether.tether; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -496,7 +496,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 2100; + CURRENT_PROJECT_VERSION = 2111; DEVELOPMENT_TEAM = W98LUTKH5G; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -512,7 +512,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - MARKETING_VERSION = 0.2.10; + MARKETING_VERSION = 0.2.11; PRODUCT_BUNDLE_IDENTIFIER = org.tether.tether; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -529,7 +529,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 2100; + CURRENT_PROJECT_VERSION = 2111; DEVELOPMENT_TEAM = W98LUTKH5G; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -545,7 +545,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - MARKETING_VERSION = 0.2.10; + MARKETING_VERSION = 0.2.11; PRODUCT_BUNDLE_IDENTIFIER = org.tether.tether; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; diff --git a/lib/store/rooms/selectors.dart b/lib/store/rooms/selectors.dart index c716238c9..286fb656f 100644 --- a/lib/store/rooms/selectors.dart +++ b/lib/store/rooms/selectors.dart @@ -1,20 +1,35 @@ import 'package:syphon/store/events/messages/model.dart'; import 'package:syphon/store/index.dart'; +import 'package:syphon/store/user/model.dart'; import './room/model.dart'; Room selectRoom({required AppState state, String? id}) { return state.roomStore.rooms[id] ?? Room(id: id ?? ''); } +String selectDirectChatIdExisting({required AppState state, User? user}) { + if (user == null) return ''; + + for (final room in state.roomStore.roomList) { + if (room.direct && room.userIds.contains(user.userId)) { + return room.id; + } + } + + return ''; +} + List filterBlockedRooms(List rooms, List blocked) { final List roomList = rooms; return roomList - ..removeWhere((room) => - room.userIds.length == 2 && - room.userIds.any( - (userId) => blocked.contains(userId), - )) + ..removeWhere( + (room) => + room.userIds.length == 2 && + room.userIds.any( + (userId) => blocked.contains(userId), + ), + ) ..toList(); } diff --git a/lib/store/rooms/state.dart b/lib/store/rooms/state.dart index a3335a645..3dc975343 100644 --- a/lib/store/rooms/state.dart +++ b/lib/store/rooms/state.dart @@ -1,5 +1,3 @@ -import 'dart:async'; - import 'package:equatable/equatable.dart'; import 'package:json_annotation/json_annotation.dart'; @@ -37,6 +35,5 @@ class RoomStore extends Equatable { ); Map toJson() => _$RoomStoreToJson(this); - factory RoomStore.fromJson(Map json) => - _$RoomStoreFromJson(json); + factory RoomStore.fromJson(Map json) => _$RoomStoreFromJson(json); } diff --git a/lib/views/home/search/search-users-screen.dart b/lib/views/home/search/search-users-screen.dart index 6f36391b4..69163af73 100644 --- a/lib/views/home/search/search-users-screen.dart +++ b/lib/views/home/search/search-users-screen.dart @@ -7,6 +7,7 @@ import 'package:syphon/global/formatters.dart'; import 'package:syphon/global/strings.dart'; import 'package:syphon/store/index.dart'; import 'package:syphon/store/rooms/actions.dart'; +import 'package:syphon/store/rooms/selectors.dart'; import 'package:syphon/store/search/actions.dart'; import 'package:syphon/store/settings/theme-settings/model.dart'; import 'package:syphon/store/user/model.dart'; @@ -73,12 +74,31 @@ class SearchUserState extends State { } @protected - onCreateChat({required BuildContext context, _Props? props, User? user}) async { + onCreateChat({required BuildContext context, required User user, _Props? props}) async { + final store = StoreProvider.of(context); + + final existingChatId = selectDirectChatIdExisting( + state: store.state, + user: user, + ); + + // Navigate to existing DM if one already exists + if (existingChatId.isNotEmpty) { + return Navigator.popAndPushNamed( + context, + Routes.chat, + arguments: ChatScreenArguments( + roomId: existingChatId, + title: user.displayName, + ), + ); + } + return showDialog( context: context, builder: (BuildContext dialogContext) => DialogStartChat( user: user, - title: 'Chat with ${formatUsername(user!)}', + title: 'Chat with ${formatUsername(user)}', content: Strings.confirmStartChat, onStartChat: () async { setState(() { @@ -108,7 +128,26 @@ class SearchUserState extends State { /// attempt chating with a user by the name searched /// @protected - onAttemptChat({required User user, required BuildContext context, _Props? props}) async { + onAttemptChat({required BuildContext context, required User user, _Props? props}) async { + final store = StoreProvider.of(context); + + final existingChatId = selectDirectChatIdExisting( + state: store.state, + user: user, + ); + + // Navigate to existing DM if one already exists + if (existingChatId.isNotEmpty) { + return Navigator.popAndPushNamed( + context, + Routes.chat, + arguments: ChatScreenArguments( + roomId: existingChatId, + title: user.displayName, + ), + ); + } + return showDialog( context: context, builder: (BuildContext dialogContext) => DialogStartChat( @@ -292,45 +331,46 @@ class SearchUserState extends State { @override Widget build(BuildContext context) => StoreConnector( - distinct: true, - converter: (Store store) => _Props.mapStateToProps(store), - builder: (context, props) { - return Scaffold( - appBar: AppBarSearch( - title: Strings.titleSearchUsers, - label: 'Search for a user...', - tooltip: 'Search users', - forceFocus: true, - focusNode: searchInputFocusNode, - onChange: (text) => setState(() { - searchable = text; - }), - onSearch: (text) { - setState(() { + distinct: true, + converter: (Store store) => _Props.mapStateToProps(store), + builder: (context, props) { + return Scaffold( + appBar: AppBarSearch( + title: Strings.titleSearchUsers, + label: 'Search for a user...', + tooltip: 'Search users', + forceFocus: true, + focusNode: searchInputFocusNode, + onChange: (text) => setState(() { searchable = text; - }); - props.onSearch(text); - }, - ), - body: Stack( - children: [ - Visibility( - visible: searchable.isEmpty, - child: buildPreviewList(context, props), - ), - Visibility( - visible: searchable.isNotEmpty, - child: buildSearchList(context, props), - ), - Positioned( - child: Loader( - loading: props.loading, + }), + onSearch: (text) { + setState(() { + searchable = text; + }); + props.onSearch(text); + }, + ), + body: Stack( + children: [ + Visibility( + visible: searchable.isEmpty, + child: buildPreviewList(context, props), ), - ), - ], - ), - ); - }); + Visibility( + visible: searchable.isNotEmpty, + child: buildSearchList(context, props), + ), + Positioned( + child: Loader( + loading: props.loading, + ), + ), + ], + ), + ); + }, + ); } class _Props extends Equatable { @@ -382,10 +422,12 @@ class _Props extends Equatable { store.dispatch(searchUsers(searchText: text)); }, onCreateChatDirect: ({required User user}) async { - return store.dispatch(createRoom( - isDirect: true, - invites: [user], - )); + return store.dispatch( + createRoom( + isDirect: true, + invites: [user], + ), + ); }, ); } diff --git a/lib/views/widgets/modals/modal-user-details.dart b/lib/views/widgets/modals/modal-user-details.dart index fa19255dc..8482784ec 100644 --- a/lib/views/widgets/modals/modal-user-details.dart +++ b/lib/views/widgets/modals/modal-user-details.dart @@ -10,6 +10,7 @@ import 'package:syphon/global/dimensions.dart'; import 'package:syphon/global/strings.dart'; import 'package:syphon/store/index.dart'; import 'package:syphon/store/rooms/actions.dart'; +import 'package:syphon/store/rooms/selectors.dart'; import 'package:syphon/store/user/actions.dart'; import 'package:syphon/store/user/model.dart'; import 'package:syphon/views/home/chat/chat-screen.dart'; @@ -53,43 +54,52 @@ class ModalUserDetails extends StatelessWidget { onMessageUser({required BuildContext context, required _Props props}) async { final user = props.user; - String directChatId = props.directChatId; + final existingChatId = props.existingChatId; - // Asking the user to create new DM if there isn't one already - if (directChatId.isEmpty) { - await showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext dialogContext) => DialogStartChat( - user: user, - title: Strings.listItemUserDetailsStartChat(user.displayName), - content: Strings.confirmStartChat, - onStartChat: () async { - directChatId = await props.onCreateChatDirect(user: user) ?? ''; - Navigator.pop(dialogContext); - - if (nested != null && nested!) { - Navigator.pop(dialogContext); - } - }, - onCancel: () async { - Navigator.pop(dialogContext); - }, - ), - ); - } - - if (directChatId.isNotEmpty) { - Navigator.popAndPushNamed( + // Navigate to existing DM if one already exists + if (existingChatId.isNotEmpty) { + return Navigator.popAndPushNamed( context, Routes.chat, arguments: ChatScreenArguments( - roomId: directChatId, + roomId: existingChatId, title: user.displayName, ), ); } - + + // Asking the user to create new DM if there isn't one already + await showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext dialogContext) => DialogStartChat( + user: user, + title: Strings.listItemUserDetailsStartChat(user.displayName), + content: Strings.confirmStartChat, + onStartChat: () async { + final roomIdNew = await props.onCreateChatDirect(user: user) ?? ''; + Navigator.pop(dialogContext); + + if (nested != null && nested!) { + Navigator.pop(dialogContext); + } + + if (roomIdNew) { + Navigator.popAndPushNamed( + context, + Routes.chat, + arguments: ChatScreenArguments( + roomId: existingChatId, + title: user.displayName, + ), + ); + } + }, + onCancel: () async { + Navigator.pop(dialogContext); + }, + ), + ); } @override @@ -260,19 +270,19 @@ class ModalUserDetails extends StatelessWidget { class _Props extends Equatable { final User user; - final Map users; - final String directChatId; final bool blocked; final bool loading; + final String existingChatId; + final Map users; final Function onBlockUser; final Function onCreateChatDirect; const _Props({ required this.user, required this.users, - required this.directChatId, required this.loading, required this.blocked, + required this.existingChatId, required this.onCreateChatDirect, required this.onBlockUser, }); @@ -281,7 +291,7 @@ class _Props extends Equatable { List get props => [ user, users, - directChatId, + existingChatId, loading, blocked, ]; @@ -306,14 +316,10 @@ class _Props extends Equatable { return users[userId] ?? User(); }(), users: store.state.userStore.users, - directChatId: () { - for (final room in store.state.roomStore.roomList) { - if (room.direct && user != null && room.userIds.contains(user.userId)) { - return room.id; - } - } - return ''; - }(), + existingChatId: selectDirectChatIdExisting( + state: store.state, + user: user ?? User(userId: userId), + ), loading: store.state.userStore.loading, blocked: store.state.userStore.blocked.contains(userId ?? user!.userId), onBlockUser: (User user) async { From 9f6731943f5dacb96030292f9593f5a7a4620268 Mon Sep 17 00:00:00 2001 From: ereio Date: Fri, 18 Mar 2022 16:46:20 -0400 Subject: [PATCH 03/22] chore: read by -> seen by --- assets/translations/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/translations/en.json b/assets/translations/en.json index 4284d987a..41ef5afdd 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -175,7 +175,7 @@ "list-item-received": "Received", "list-item-via": "Platform", "list-item-from": "From", - "list-item-read-by": "Read By", + "list-item-read-by": "Seen By", "alert-restart-app-effect": "You'll need to close and restart the app for this to take effect", "alert-invite-user-unknown": "This user doesn't appear to exist within matrix, but you can attempt to invite them anyway.\n\nMake sure you have the correct name before trying.", "alert-feature-in-progress": "🛠 This feature is coming soon", From 640a45884ab8ec1b759fc1cea983535330506d2a Mon Sep 17 00:00:00 2001 From: ereio Date: Fri, 18 Mar 2022 18:25:56 -0400 Subject: [PATCH 04/22] fix: load image hitbox issue --- lib/cache/middleware.dart | 2 +- lib/main.dart | 6 +++- lib/store/rooms/actions.dart | 2 +- lib/store/sync/actions.dart | 24 ++++++++-------- lib/views/widgets/image-matrix.dart | 37 ++++++++++++------------- lib/views/widgets/messages/message.dart | 1 - 6 files changed, 36 insertions(+), 36 deletions(-) diff --git a/lib/cache/middleware.dart b/lib/cache/middleware.dart index 4451b86c2..f1067d594 100644 --- a/lib/cache/middleware.dart +++ b/lib/cache/middleware.dart @@ -32,7 +32,7 @@ bool cacheMiddleware(Store store, dynamic action) { printInfo('[initStore] persistor saving from ${action.runtimeType}'); return true; case SetSynced: - return (action as SetSynced).synced ?? false; + return ((action as SetSynced).synced ?? false) && !store.state.syncStore.synced; default: return false; } diff --git a/lib/main.dart b/lib/main.dart index a8d75b16d..5ddb5a824 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; - +import 'package:flutter/rendering.dart'; import 'package:syphon/context/storage.dart'; import 'package:syphon/global/platform.dart'; +import 'package:syphon/global/values.dart'; import 'package:syphon/views/prelock.dart'; // ignore: avoid_void_async @@ -14,6 +15,9 @@ void main() async { // pull current context / nullable final context = await loadContextCurrent(); + if (DEBUG_MODE) { + debugPaintSizeEnabled = true; + } // init app runApp(Prelock( appContext: context, diff --git a/lib/store/rooms/actions.dart b/lib/store/rooms/actions.dart index 79ae50f21..7c29e00e8 100644 --- a/lib/store/rooms/actions.dart +++ b/lib/store/rooms/actions.dart @@ -166,7 +166,7 @@ ThunkAction fetchRoom( ThunkAction fetchRooms({bool syncState = false}) { return (Store store) async { try { - printInfo('[fetchSync] *** starting fetch all rooms *** '); + printInfo('[fetchRooms] *** starting fetch all rooms *** '); final data = await MatrixApi.fetchRoomIds( protocol: store.state.authStore.protocol, homeserver: store.state.authStore.user.homeserver, diff --git a/lib/store/sync/actions.dart b/lib/store/sync/actions.dart index c60061b33..4ad90b929 100644 --- a/lib/store/sync/actions.dart +++ b/lib/store/sync/actions.dart @@ -260,6 +260,7 @@ ThunkAction fetchSync({String? since, bool forceFull = false}) { final Map toDeviceJson = data['to_device'] ?? {}; final Map oneTimeKeyCount = data['device_one_time_keys_count'] ?? {}; + // Parse and save room / message updates if (roomJson.isNotEmpty) { final Map joinedJson = roomJson['join'] ?? {}; final Map invitesJson = roomJson['invite'] ?? {}; @@ -273,26 +274,23 @@ ThunkAction fetchSync({String? since, bool forceFull = false}) { await store.dispatch(syncRooms(invitesJson)); } } + + // Updates for device specific data (mostly room encryption) if (toDeviceJson.isNotEmpty) { - // Updates for device specific data (mostly room encryption) await store.dispatch(syncDevice(toDeviceJson)); } // Update encryption one time key count - store.dispatch( - updateOneTimeKeyCounts( - Map.from(oneTimeKeyCount), - ), - ); + store.dispatch(updateOneTimeKeyCounts( + Map.from(oneTimeKeyCount), + )); // Update synced to indicate init sync and next batch id (lastSince) - store.dispatch( - SetSynced( - synced: true, - syncing: false, - lastSince: nextBatch, - ), - ); + store.dispatch(SetSynced( + synced: true, + syncing: false, + lastSince: nextBatch, + )); if (isFullSync) { printInfo('[fetchSync] *** full sync completed ***'); diff --git a/lib/views/widgets/image-matrix.dart b/lib/views/widgets/image-matrix.dart index d9e9ef53e..61bb430a4 100644 --- a/lib/views/widgets/image-matrix.dart +++ b/lib/views/widgets/image-matrix.dart @@ -114,31 +114,30 @@ class MatrixImageState extends State with Lifecycle { // allows user option to manually load images on tap if (!widget.autodownload && !props.exists && !localLoading) { return TouchableOpacity( + behavior: HitTestBehavior.translucent, onTap: () => onManualLoad(), child: Container( + padding: EdgeInsets.all(widget.loadingPadding), width: widget.size ?? widget.width, height: widget.size ?? widget.height, - child: Padding( - padding: EdgeInsets.all(widget.loadingPadding), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.photo, - size: Dimensions.avatarSizeLarge, - color: Colors.white, - ), - Padding( - padding: EdgeInsets.only(top: 8), - child: Text( - Strings.labelDownloadImage, - style: TextStyle( - color: Colors.white, - ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.photo, + size: Dimensions.avatarSizeLarge, + color: Colors.white, + ), + Padding( + padding: EdgeInsets.only(top: 8), + child: Text( + Strings.labelDownloadImage, + style: TextStyle( + color: Colors.white, ), ), - ], - ), + ), + ], ), ), ); diff --git a/lib/views/widgets/messages/message.dart b/lib/views/widgets/messages/message.dart index 711d18c4f..bcb963a3b 100644 --- a/lib/views/widgets/messages/message.dart +++ b/lib/views/widgets/messages/message.dart @@ -3,7 +3,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:flutter_redux/flutter_redux.dart'; -import 'package:photo_view/photo_view.dart'; import 'package:swipeable/swipeable.dart'; import 'package:syphon/global/colours.dart'; import 'package:syphon/global/dimensions.dart'; From 74c085c37257edb2687c8f04260fc77d0e0b97ba Mon Sep 17 00:00:00 2001 From: ereio Date: Fri, 18 Mar 2022 18:27:08 -0400 Subject: [PATCH 05/22] fix: remove border layer unless specified --- lib/global/values.dart | 1 + lib/main.dart | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/global/values.dart b/lib/global/values.dart index ff7f06eda..66fd0a2bb 100644 --- a/lib/global/values.dart +++ b/lib/global/values.dart @@ -63,6 +63,7 @@ class Values { // ignore: non_constant_identifier_names const bool DEBUG_MODE = !kReleaseMode; +const bool SHOW_BORDERS = false; class SupportedLanguages { static const defaultLang = 'en'; diff --git a/lib/main.dart b/lib/main.dart index 5ddb5a824..addb27951 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -15,9 +15,10 @@ void main() async { // pull current context / nullable final context = await loadContextCurrent(); - if (DEBUG_MODE) { - debugPaintSizeEnabled = true; + if (SHOW_BORDERS && DEBUG_MODE) { + debugPaintSizeEnabled = SHOW_BORDERS; } + // init app runApp(Prelock( appContext: context, From 5e7e63af1c9b580d186389d0f8804bd81bce1c1c Mon Sep 17 00:00:00 2001 From: ereio Date: Fri, 18 Mar 2022 19:27:26 -0400 Subject: [PATCH 06/22] feature: resend failed sent messages, message actions needs refactoring soon --- lib/global/noop.dart | 1 + lib/store/events/messages/actions.dart | 76 +++++++++++++++++-- lib/store/events/messages/formatters.dart | 1 - lib/views/home/chat/chat-screen.dart | 10 ++- lib/views/home/chat/widgets/message-list.dart | 16 +++- lib/views/widgets/containers/media-card.dart | 6 +- .../widgets/lists/list-local-images.dart | 1 - lib/views/widgets/messages/message.dart | 12 +-- 8 files changed, 100 insertions(+), 23 deletions(-) create mode 100644 lib/global/noop.dart diff --git a/lib/global/noop.dart b/lib/global/noop.dart new file mode 100644 index 000000000..ab3f4c0d4 --- /dev/null +++ b/lib/global/noop.dart @@ -0,0 +1 @@ +noop() {} diff --git a/lib/store/events/messages/actions.dart b/lib/store/events/messages/actions.dart index 88aa2cdcd..49f32a114 100644 --- a/lib/store/events/messages/actions.dart +++ b/lib/store/events/messages/actions.dart @@ -158,6 +158,42 @@ ThunkAction mutateMessagesAll() { }; } +// TODO: need to rework to remove old outbox message +ThunkAction sendMessageExisting({ + required String roomId, + required Message message, + Message? related, + bool edit = false, +}) { + return (Store store) async { + final room = store.state.roomStore.rooms[roomId]!; + + store.dispatch(DeleteOutboxMessage( + message: message, + )); + + if (room.encryptionEnabled) { + return store.dispatch( + sendMessageEncrypted( + roomId: room.id, + message: message, + related: related, + edit: edit, + ), + ); + } + + return store.dispatch( + sendMessage( + roomId: room.id, + message: message, + related: related, + edit: edit, + ), + ); + }; +} + /// Send Message ThunkAction sendMessage({ required String roomId, @@ -169,16 +205,20 @@ ThunkAction sendMessage({ return (Store store) async { final room = store.state.roomStore.rooms[roomId]!; + // if you're incredibly unlucky, and fast, you could have a problem here + final tempId = Random.secure().nextInt(1 << 32).toString(); + + int? sent; + Message? pending; + try { store.dispatch(UpdateRoom(id: room.id, sending: true)); final reply = store.state.roomStore.rooms[room.id]!.reply; final userId = store.state.authStore.user.userId!; - // if you're incredibly unlucky, and fast, you could have a problem here - final tempId = Random.secure().nextInt(1 << 32).toString(); // pending outbox message - Message pending = await formatMessageContent( + pending = await formatMessageContent( tempId: tempId, userId: userId, message: message, @@ -210,6 +250,7 @@ ThunkAction sendMessage({ ); if (data['errcode'] != null) { + // edits will not have outbox messages if (!edit) { store.dispatch(SaveOutboxMessage( tempId: tempId, @@ -225,6 +266,9 @@ ThunkAction sendMessage({ throw data['error']; } + // mark a successfully sent + sent = DateTime.now().millisecondsSinceEpoch; + // Update sent message with event id but needs // to be syncing to remove from outbox if (!edit) { @@ -240,11 +284,27 @@ ThunkAction sendMessage({ return true; } catch (error) { - store.dispatch(addAlert( - error: error, - message: error.toString(), - origin: 'sendMessage', - )); + // dont show error notifications for common networking issues + if (error is! SocketException) { + store.dispatch(addAlert( + error: error, + message: error.toString(), + origin: 'sendMessage', + )); + } + + // if the message has not been successfully sent + if (pending != null && sent == null) { + store.dispatch(SaveOutboxMessage( + tempId: tempId, + pendingMessage: pending.copyWith( + timestamp: DateTime.now().millisecondsSinceEpoch, + pending: false, + syncing: false, + failed: true, + ), + )); + } return false; } finally { store.dispatch(UpdateRoom( diff --git a/lib/store/events/messages/formatters.dart b/lib/store/events/messages/formatters.dart index 8ea555648..54add392c 100644 --- a/lib/store/events/messages/formatters.dart +++ b/lib/store/events/messages/formatters.dart @@ -4,7 +4,6 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:mime/mime.dart'; import 'package:syphon/global/libs/matrix/constants.dart'; -import 'package:syphon/global/print.dart'; import 'package:syphon/store/events/messages/model.dart'; import 'package:syphon/store/media/converters.dart'; import 'package:syphon/store/media/encryption.dart'; diff --git a/lib/views/home/chat/chat-screen.dart b/lib/views/home/chat/chat-screen.dart index 8052d29f6..a0a9eafb0 100644 --- a/lib/views/home/chat/chat-screen.dart +++ b/lib/views/home/chat/chat-screen.dart @@ -665,9 +665,9 @@ class ChatScreenState extends State { child: Stack( children: [ MessageList( + roomId: props.room.id, editing: editing, editorController: editorController, - roomId: props.room.id, showAvatars: props.showAvatars, selectedMessage: selectedMessage, scrollController: messagesController, @@ -862,8 +862,12 @@ class _Props extends Equatable { ), ); }, - onSendMessage: ( - {required String body, String? type, bool edit = false, Message? related}) async { + onSendMessage: ({ + required String body, + String? type, + bool edit = false, + Message? related, + }) async { if (roomId == null || body.isEmpty) return; final room = store.state.roomStore.rooms[roomId]!; diff --git a/lib/views/home/chat/widgets/message-list.dart b/lib/views/home/chat/widgets/message-list.dart index 01cd7d665..e16d5f4e9 100644 --- a/lib/views/home/chat/widgets/message-list.dart +++ b/lib/views/home/chat/widgets/message-list.dart @@ -6,6 +6,7 @@ import 'package:redux/redux.dart'; import 'package:syphon/global/colours.dart'; import 'package:syphon/global/print.dart'; import 'package:syphon/store/events/actions.dart'; +import 'package:syphon/store/events/messages/actions.dart'; import 'package:syphon/store/events/messages/model.dart'; import 'package:syphon/store/events/messages/selectors.dart'; import 'package:syphon/store/events/reactions/actions.dart'; @@ -23,7 +24,7 @@ import 'package:syphon/views/widgets/messages/message.dart'; import 'package:syphon/views/widgets/messages/typing-indicator.dart'; class MessageList extends StatefulWidget { - final String? roomId; + final String roomId; final bool editing; final bool showAvatars; @@ -87,6 +88,18 @@ class MessageListState extends State with Lifecycle { } } + onResendMessage(Message message) { + final store = StoreProvider.of(context); + + final roomId = widget.roomId; + + try { + store.dispatch(sendMessageExisting(roomId: roomId, message: message)); + } catch (error) { + printError(error.toString()); + } + } + onToggleReaction({Message? message, String? emoji}) { final store = StoreProvider.of(context); final roomId = widget.roomId; @@ -219,6 +232,7 @@ class MessageListState extends State with Lifecycle { timeFormat: props.timeFormat, onSendEdit: widget.onSendEdit, onSwipe: onSelectReply, + onResend: onResendMessage, onPressAvatar: () => widget.onViewUserDetails!( message: message, user: user, diff --git a/lib/views/widgets/containers/media-card.dart b/lib/views/widgets/containers/media-card.dart index 360915ca1..8fbac7682 100644 --- a/lib/views/widgets/containers/media-card.dart +++ b/lib/views/widgets/containers/media-card.dart @@ -1,16 +1,14 @@ import 'package:flutter/material.dart'; import 'package:syphon/global/colours.dart'; -import 'package:syphon/global/dimensions.dart'; - -_empty() {} +import 'package:syphon/global/noop.dart'; class MediaCard extends StatelessWidget { const MediaCard({ Key? key, this.text, this.icon = Icons.photo, - this.onPress = _empty, + this.onPress = noop, this.disabled = false, }) : super(key: key); diff --git a/lib/views/widgets/lists/list-local-images.dart b/lib/views/widgets/lists/list-local-images.dart index fd3528264..7156aaf45 100644 --- a/lib/views/widgets/lists/list-local-images.dart +++ b/lib/views/widgets/lists/list-local-images.dart @@ -8,7 +8,6 @@ import 'package:path/path.dart' as path; import 'package:path_provider/path_provider.dart'; import 'package:syphon/global/colours.dart'; import 'package:syphon/global/dimensions.dart'; -import 'package:syphon/global/print.dart'; import 'package:syphon/global/strings.dart'; import 'package:syphon/views/widgets/lifecycle.dart'; diff --git a/lib/views/widgets/messages/message.dart b/lib/views/widgets/messages/message.dart index bcb963a3b..d5596cae5 100644 --- a/lib/views/widgets/messages/message.dart +++ b/lib/views/widgets/messages/message.dart @@ -8,6 +8,7 @@ import 'package:syphon/global/colours.dart'; import 'package:syphon/global/dimensions.dart'; import 'package:syphon/global/formatters.dart'; import 'package:syphon/global/libs/matrix/constants.dart'; +import 'package:syphon/global/noop.dart'; import 'package:syphon/global/strings.dart'; import 'package:syphon/global/weburl.dart'; import 'package:syphon/store/events/messages/model.dart'; @@ -46,12 +47,13 @@ class MessageWidget extends StatelessWidget { this.timeFormat = TimeFormat.hr12, this.color, this.luminance = 0.0, + this.onSwipe = noop, + this.onResend = noop, this.onSendEdit, this.onLongPress, this.onPressAvatar, this.onInputReaction, this.onToggleReaction, - this.onSwipe, }) : super(key: key); final bool messageOnly; @@ -75,7 +77,8 @@ class MessageWidget extends StatelessWidget { final ThemeType themeType; final TextEditingController? editorController; - final Function? onSwipe; + final Function onSwipe; + final Function onResend; final Function? onSendEdit; final Function? onPressAvatar; final Function? onInputReaction; @@ -202,9 +205,7 @@ class MessageWidget extends StatelessWidget { } onSwipeMessage(Message message) { - if (onSwipe != null) { - onSwipe!(message); - } + onSwipe(message); } onConfirmLink(BuildContext context, String? url) { @@ -414,6 +415,7 @@ class MessageWidget extends StatelessWidget { ), ), child: GestureDetector( + onTap: message.failed ? onResend(message) : null, onLongPress: () { if (onLongPress != null) { HapticFeedback.lightImpact(); From d5d485ea29e37ef36913c74fb6f3c9c555854b4b Mon Sep 17 00:00:00 2001 From: Ed Geraghty Date: Sun, 20 Mar 2022 13:58:50 +0000 Subject: [PATCH 07/22] chore: FAQ --- docs/faq-en.md | 18 ++++++++++++++++++ docs/images/info.png | Bin 0 -> 2577 bytes docs/images/people.png | Bin 0 -> 2820 bytes docs/images/syphon_not_trusted.png | Bin 0 -> 2921 bytes docs/images/verify.png | Bin 0 -> 22925 bytes 5 files changed, 18 insertions(+) create mode 100644 docs/faq-en.md create mode 100644 docs/images/info.png create mode 100644 docs/images/people.png create mode 100644 docs/images/syphon_not_trusted.png create mode 100644 docs/images/verify.png diff --git a/docs/faq-en.md b/docs/faq-en.md new file mode 100644 index 000000000..0b614269a --- /dev/null +++ b/docs/faq-en.md @@ -0,0 +1,18 @@ +# Syphon FAQ + +## How do I... + +### ...Verify my session? + +The option to manually/non-interactively verify sessions has been "hidden" in recent Element client releases. + +In order to cross-sign/verify your Syphon session, with the Element client: + +1. Open any chat you're in - though to make your life easier the smaller the better +1. Click the ![](images/info.png) button in the top-right to show room information +1. Click ![](images/people.png) +1. Click on your name (if you're in a large room, you may have to search) +1. Click on the untrusted session ![](images/syphon_not_trusted.png) +1. Click "Manually Verify By Text" ![](images/verify.png) + +n.b. Interactive cross-signing is roadmapped as part of the `0.3.0` release \ No newline at end of file diff --git a/docs/images/info.png b/docs/images/info.png new file mode 100644 index 0000000000000000000000000000000000000000..e419908db9a673eeb2bcffce012f530da14b8ace GIT binary patch literal 2577 zcmV+s3hwoZP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D38qOzK~#8N?VJm6 z71bHX|M!(Qh{R}+Aa4tzL5h;_kP$^DT4B z`R{kW@0{J((t2IxheemiuKcy=;#fkkU@Re6FqRN37)uBij3opM#u9=BW6dLU25dIK z<$&Mm0371kw2L$yBmAO!d}8zZVDoqZx7g@dl+hG|-R?kKoC|h`Q`F1eTDPtSwY%T% zgU{-16cxx z)1ay9f>0Y#TNy(50R9y5n<#W#DXPf*up@%^nQ@pmg{%QsK+!$;a$f)v#5a zhP~{F*pBisDHK`MH7W^Xga{!iIYlTuie^iTpw5@k5u&guLh$P>*XQ%$TtmH*QYV~a z=*#R2&z)KDr=}=J)Ulnehx6TCED9+m9Z1{KHS1dMxOiD1-&m{(G`3#!c1k43>J+YQ zI^9rTtE5z*A%U!c1ka2tcyAu2r1as~QqF>q!B)XwXc_YO(@h)gB%_$gza#4uuIzAC z<9PxJW<)@ECk*4?%FrrPhUz#Vzj-L8xN3a0!Mw*i6|jc|_sXc%o5VkGQA* z#vAR+AiqM2M%ilU5`yU`LPEQaru^HKp{9js)?&iVuf{=(wRb-NDTalcn`p_1R ztWh`MlJ4E{!qVl)nU;$NaSt(rRuR?6NL6;!AptZ$Gn2P)AticC@{*M;AtZb(TDnNt z6O~bHvs!1-xsr|Rc|T`rOUKX1osOq||2RJQ@FP6-Eo#FTOS@DGBrD{tV-98V8TZjZGz+@!Hxq_+0VIWvDrG1}>KiLx=nTJ9q8Ir#p9J z&b{~GveZ;;dcOp#U-=VX8%%J0UZOl|YTy+i)b+!!!=b~Kc>T|B;+mmDxK4dCdgJS= zWB6=ODgN;Evlu^aEb@Oc8|hbEj*9;t;%oQrE93lvk@+t5b?V`xzlXZDX)3y3*;B{0 z@I9VLqDdw96L%;_<-|YSzC8$Ajee1vwg_5~2$n1=z)j=Epz7E$4Cvnv%a$x`wHAvP zJ%{^$n#WHg&0GBD*N1~$A3E?Cxsxt`R0E@d>$6Z(W75u+LRw*Nnrto zTs;^^M0$)EI#w=Q%tJ^=Lt?mCL?ndn-Mew8E?-)RM}PS+yrNU-DVsiR3ewUpLs9V> z{Nll1;g1Un;Bk9!`_##poHGfdZXAg%Teo3W-hG&HPagIkC>Np`i|njXoNsMy9p?Y; zNfazvj5FfN{`Y?>Fem>3EH7FGx7Uk4eKPnuEo#r!;=xBA#msy2v8Qw|TY;LhXR)vB z0GgVbuvu8HmtR|psZ(e&QsHwdGuk|3O25TXZr#sljNK9WjdUQ!V@v zaxw#9 zn@YHoX`bPM`|`14$1V}FtzdKg@~dmnLs*1&{<03Mie3~?Un5>zQ5+J=1sXioqIhZb zE7&Qb5^`RtuH;y5*!Vuys6-})p%+ahxZaU38WHZfx56`dM9VfoeJWZr4~??bPz@iW z)!_7mWoO-p@-GkK`0*2bEVyIIGpEikJMe{aL{2P35KMad6&QBSP!XfEUX34TehYU1bSXf;YBEo^#?}y1T-AP?;o}CdOT=UTbTNe z5;8Odpc^E$Tc|^A^L-Klp=uEVSpO)a1+v63`9~R@2u&eabRATO28*tTB?Jq`*8l2j nt)bz2jIMPMf#oAu2!Q_s4u$LGA#0$j00000NkvXXu0mjfK3vYI literal 0 HcmV?d00001 diff --git a/docs/images/people.png b/docs/images/people.png new file mode 100644 index 0000000000000000000000000000000000000000..4cb51752fc3876c5cd01523b479f49110ddf689a GIT binary patch literal 2820 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 TIO61UWqWYnOuth1QRM#s-l=yn literal 0 HcmV?d00001 diff --git a/docs/images/syphon_not_trusted.png b/docs/images/syphon_not_trusted.png new file mode 100644 index 0000000000000000000000000000000000000000..2333bfd1f128be03828dc6918284fa0e833a40c5 GIT binary patch literal 2921 zcmV-v3zqbWP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D3jRq%K~#8N?VSr) zRAm~+|1jXdfG`7sJ0@0{}u&vSnB|IQh| z;}RU&c|?hG^Pu%;>*h#PFe*GW8WC?Aomz1sFKsHq3c#CVoy$#RCsL zrpoReISet;lTcJ#j28ZWRgQoB#7W$B=N*_9I~86A1KwS*2rEDP0`JUw1O58;fyH8` z_HIbnxeI@r5UuvN@SS<+(>oGoiv_>@k`AlYiVfdv!uhN$OrA6z8#l#cLi7~XRuF`y zkHbXBczJn|TzVrl^^_7&LkS9MiS7~MIDY)Z6}Mv%&Yb=-R;~F`iIiax+GLxNo{56O zLL5AFSk=`BA2;IGFeDu~i1hRft+ax$Ze5jB!G$)YQ|6+ptl+3W6Y9ElnyB3W6Xs z22Cmv3W6Xs1|mX15S$(np&$rOkBCqZ1gA$tCAij}dc7V7g8}YtZd!>TI43Nz zv8`HQps}j-xZLv!qF}msd0<|L*6^yM?I2@w%p|EgnrqpwJ4w{fU3W#%>5Tq?)3o>3 z#C-uqw9#J{Af9>#=n)C*OVkR0vt{M@Pgb6`R+YYedQl>b!lEThv3A{8IC3-vS=l)x zMhl9IOE8Uu7}m85w(s~}wdcuJS)69G8P7ib6xsy`K8f@-d*L7KB2n z>{Mwvo(gJ#V|1KS>m`-)?AL>uxnb-LEil607u=DbOUi29Z@$Gs>v}v#{ke-qn)zm{ z>ZgrPlmaJET?BoO3-lSoXdiJo7f^Po?)haLmI$wv+?)zQ-ZyHbnjM!>-q02z=z8}fd_rNbm-7dP3T%$T87CnuVCRnm*Dj|^I`P$#i)_P z)pn(&rTAdkN2+egvgN9*TemLiRS=pYoQala?0hUZmxaAlS09`P%_Ph% zc^7ev#P?vzDXhuPtFd41$K%wWxoPKB|F}i9}F_X4jl~!D%_d}JWusSQPbEVS zy&myfzg64u@c86UKdJZ3k0(yRh2&`RGphAV^ar+T!+>&XYfH%f{(dwR&QLOCSjIff zzsY1$>)ejpGkLjrC@U*d=}{1xGMuXBkSs^sBr8uEX*H|kni~&o4Ya@7u01j=R0C}v?4eitkMi+W*9IBBp)viY zAoZS;;W`=y2Wh`PvEMJtjsq3n;NkSjaC&^cRRD_V09?m?=C)it#N>0upUyB26JZ(+ z8)u}ZYimRbNr)E>uDf8a`+H^izgA-Bu05Fe!t*$CAQ5|aZYL4;#fpD_hNR>Js?8Qk zfN5vXs=L7n36~%7$#5!M{l!WoCVY#~&=4&CU|Hpmw=Uj$e=()ZgZTTD$vBd{2Y-F+ z&)BeWGd@}Isn$Xeu3w5NoXj|tj%*Sj!@`+)Is=1AjC&$FVkZqd`KL1PpUYPDCyL9I zC^ysaHOjZW#waOXj>fa*$KCLdsZGhwWLhlVdi7* z3h#(V0!`}LB2#_8+@Cfyq~A^LxNS5g$8GrqO4M8z;I32qNuWBmVR~8B8#}e(@Mo6r z|0angv-fUZaV>2(eF*+z*EcM-haa&S*`vEkd$m1E^YfL;2{IP?W;%QB9H!5jT}6V-rY-T>%M1+DMI6WdlK@glC5uqRmPLGIC5Co@3L?{S?(<34j1i|SM5ekCfICV%^Npx z4sYDJNpl+?_ypqD?hE|8>8>gN@4xt z^{i1Sz1nHI_kiB4neqDiR=j!-_UTl7(Jf`|R6a!iD)mbCus&AI1%iL@>iU|D82Geh zqFZn}c-KX^Gwr7dZookn{-JG(cS!Jt|6fI*&8N!qJD&ANA|HH`@Q;01?=6xLTlI;P z1DA$SNTMHu!D_$z75ow(8#7q;4lMI`#c7BTJleo#q>@>L2eZ!jhkt$gdw%#aN;QA{ z0fx+b23-Dk{TX(=!mMBA)mSy@bKWzg>$N z=xsKWR=XaH<;Px+ch@Zbxlw3hPyDL^lYf}B{%u^uKR=ASm#24K*|$eOwVU2f{+za~ zRNfBoT}Enl9-Wb5NqVQ^^N&QX`%a#*6e^h;Xv~vz6{~#{+^Sw%#cA@&;C?Ufc0Z_z z#DfdT6i-T@=qs<*egA+8#@pdk>y@O#or*rdy}Dp)pYv5y%{-)%dl^Y17&GnC{Mv1; zm&N9HX2LGyR3nkw(5yM_408-ouzw4)ZoY#`_dQs_GIZ&~x{*5=bPl-Dfn}5~mAi%) zXo!Y=hg?Pk(drW|T)(O|VO}HYDJuT=0So8I!TDceZZBCGM7a*4AE{}fFTT{yLB(9) z+FA05j_#1}QgON_{#qcm(Tmlz zm0v0ReD26CW=_iYU00_iRrZr@ew0lvEm#@+y8&%}3C%gxT*K}0AMq98Eu>05dU_4c zpzD$RMFw8|R5yG1%NOq`B~do|#wCo^)6zD%}s^T?_INiv*zpj|4WRd5td zoQU(*us#aB=5#jSOupaSCz~U4;fEBXVo1CNbl1u|qY=e=L}TRKtVrF}oLvOJDZ=zx zUOs%lK5hUqtFzi;A<^U08Ah2Pk3AXFIo;aHIFVD#y2M?SXgS??Xdb?iubL4j96~JR zk`8ORl$*PrW#2}ptKHM^*IV(9yq>}R*Ss7QxTthK`nZ&6!nnD`$KD& zYbjqhsp;UAF~w^<_uK)9VieS(yKj`<{L|;<2~34w-IVYjV{o zHnNH&XBaka@Z4rJZuCf0Qc9=@HhG~;G*Z>aBw;vFD>$?JmCKy#>^j~56X&- z>)%2!3x+DRtxIVz$t2@xq26TDxoE0)jL9=CzRh4Rg$oTL20M6KO*BJT-Viewx+5Lv#2=q)ae7}C7r5C zklo%Pef(;~aY{Vw5R-SwV&2a6GJ@b3BU@U0dPA2W{fy1#HDJ3+^yDCT_GqLjrY7 zNK8C-GF9VjNBjhs4T}1jGGLus2SUrkvd4GV`Sp|?BO)%2{YAXa>sm^6s(;kf5quAv zLk*t=N71M=x)4(0F2hLuHud%EY|D{}WUr7gU0wQ(IbA7!7ZeWli}gYu-`%SVZ}m*D z^Ow~ICV5Hz$3Oey*`l{*>Xq`&MO3uhqUa^;o703&X27~LV_%jKYTbXlQAwD{(wGqJ zVG_4t?Z&%b2T{{535t}Q_{IzvQbys61MdYp+?*lF0vd%4>NznF7%Jjd6e zzH#j;XPUdVuWBPue>YF1p3kb-##$cKY+w@To?NK*pfsQUd5(hJK6C7jnt~b)DqmfDF zalL*P)zcUdz2Bcp%Mr`ch6*R6@bYnVf{6QSPhP*_q2O1wgDl9UV5!v6htGEum*gT3 zeZ9)OcO}mb4|q#-HZIk$6Op6&CUPUau_n)fEMe}~f(*$iYx5&}-lJ$xj;&dD*z^Q;MU5s-~g76lqE_@?fGv?3x1wu-0 z%?`g+INoPPT3{LveO657&w7?G$!TREEw!saCbLt)0yF}dDefep#Bf`2Ti`BUobc>~ z$WW#!S=Bd+z}tkbZ{DA;U72%Za^*3qs!MJx%|+t;r?>2eF!sK7>kfSWzm59iYa2Ci z4n6qS_ih>pwN@BjnC&#(a+OL<7;SG!5!(M_c0uIpwx(LO>+2|X{f10gJaHYp2sinw zKSPWa-=A{2U>JH7Txslr(oZzLBRXceLQVAB+Fl;{ex3C{?oO$+ITG2gDbg+aF@URG zY9zulC~ttcyqLVgSH>GyKO=Z)R9g4QgVrymeyhTr{aL6CnUve8ZT%TitU4*JOU2MW zQ_Q*J^I~V%n-SL5-Sy;5Zbn8Umtd70vpHq|7yDmOb2mQUp^UQ+b!0j`ZZ~nhp7#&m z+&ZY)A{(`_mzJ^~fS~mm|Fmna^kNx$&NUq?M(S?V>EA09e$U-bcyV;1e72Sq2(+=v zu-cw{m(?KWy~pODiI)5P#E?aW$0Q#(Q(ezCdATP8;g?W7=(L=|Z*y3GJO;5!^Ffd0 zd-Jk`_3hAOBBvVpb8HbwKgApMuxeQ? z`Lq#5MnuW^HpT^h`I0_xi`;j;^{VG&E`X&!?d)K8NKxG3w^7N{3Gqz5!`y;_@CV$C zAG3VE2#-@ieWfOl}{9I%Se6j6O(UJ zP8r_sSc>jZlFf`~O%jg6wiYH7>GU-cLY{5z>Q^plzI%tugJXkN;51!>G}9-%=$e+Q zy7ifeGA>onUSYDrYI(ifq5{%h|9CQ(RuvI&Za1@b4!IVy@Lat}q*{~M+T5ht@IlsPsn#1qK<&LM1H2qjFp1+p7TI8f7oqpHRxQhUjEIsbT z=RQ9rzL_JN4GK7RlfCX@%4y$;46q+Zgb!HOD3h+c%AzCt#@Xmb*>HgLXamgeXdV-O zaYh9~RJXC^&3(sRsTK~l`=Qu|3^;tpf4K%)X}OZP4~zDbrs`#F%ED^;`* zQXU-b!;2DK;Du;EfG_$n#?pgtWYO*~suTYN@_t&$==&^C%3dz@XIAfvXiub0%TTsy z&u$=W%8G&9G4T+*{M?~{K~mUsK7MK!JYV&k81IVTW}rIwdW#jwD)K3;*kc-2)@0TF z)C8*hCcyjlCrw=4nS8Vo{Ak*0U^2&jy7Jzz5{DsN+3#?D=xd-arO2jjtK4`J6~>`t zgSdGJ%B8Pa<2;-A1A^Z6tY|#GdwkFey|q6-U1LY*-R@jAQd3Ln$7ayzeBqnG1*`|g zd=Z*Zf5m~LsU)kL&D%Aaow>RxahjZ<^EAd--mBH9K&$;$_gS)gKm*B*w`BfAQxztPewcBO}dHW-zEFeT)_2VDgJqAJt>9!Y(C{`GJ8_UvDX z*YywZYyJPDlGWd7@Od({Z*bjlYEh1LP7=kkJ}I9sIsY6s0e>)fF6fLH$;LJI(I zR)6@_dfW#jomxJYCVmcoz=oxZA3{8ewgYlnHJgF?^woX%Grp$JEmq;HeEYKt!)ps6 z#ZMq~Qy^XoxkzZ^PLpv|)(dCieji=Xn2vKpd8MyMd9Y<%;^iY^2>MFi*6=Ve+GRz%TR3pyu&G-EOYJLfdeWnv{Nx<7bj9OrKh=*#(Agz0hVk zx<|`%qVqaJ_G;_a#I{@zbOX4oBzpt5wZ9LDb_4K7oGwjAHG)tcp{2lc9iIB-dv;^T zG~mdKMF0f%ewu?M-NfbRnOA)=R~!?I(Dm!y>5~UYo#~kCSBD1uRZV!j*s|~KVaFQtPsz1VuwVB*SIC&$LD^i z5n0yr^Y4cnvr5+IXCYDi$9)4;lrzDKeM+oBCIW$p#fH_&EtvBqpIzDA5c(K+zFKIS zyq;~r(eJZoYFtd0=DyFb2{j=@ytmWPsr{eOZb{mZ3Odpq)jdF5wHJv8Oej?ID`W*>1#Dq|75El8_Qub*ysiq5m;5fiHiYv(1q7SyqfW=i%T zoMLxVYPQ;_)-9#?Wh8Tv7ks6Z<0x;9QXz4K-*~YG6RKjKS93PT`lC~b@AUq1PYL!O zlA!N>;*xYvg0>>U-0h&+%y8);;f!#Z%Y~#_(@tf~44*0eZsfx}#Ly;X_{z{Fc!`?| z&1VFxv34*2f%rjpIm8Ta>^Y~1+wvEYjgwga zoff4#De<<|_S!4MO1xvPt~hirzQR{)E{{&Q*bN)1234SewA{gTNZGLz3Fa6-0 z-t-S`6)%rC4PPlS!(o2=;diD4XXV=OYoOF)2!qGjKK?SZ?lkSKpsXCRb+*PZS>ahk zqE;9|@v`@KyxLvpNd7>#n$#5sPm&V8grxLN-Sz{Ah|@A|gKEbo~^rT(Q~Zd2Tra^XlmS;y*inUK!#ig|58 zVem86-sJ6%6|Kig&LEtv5FhC_&ko5b)9s7}mksRoocf)-J^K}6Tz|eVhiQ0yu&N0& zp{uV@aiC)$6(2|wh8541Jwa8NHZn-My;aSS%-y}U`paUjz2%b?*W0qMO|~^RHHYS3 zMt3f+I*38eKM6Rw)f)wF*FOlrt9-3oUt(0v+PVGt%+q#Gl|!fCaiz^bLgZ>4kr5A9 z`z4rQ+3_v3rPh6oN8~;=yXWR;Tw>l`r(~Nmx0OSa)KPkOcCZWc{TE;^wfX(+vo#Q% z%}=I_s)|!Mc4urHNOxL$t4y5b0?$K5&N84jS$;2h8n-mh?6+$D7(07leZ(1-jf8p5 z^%p!FBY{De#*NO+9?j+MscyJP!ydQPxRe~IoQumQH4ep zlVurlDTBRThe+_`-#gp?r>dpWLz zk=&o~J^0DzIMbxhIS7ipkdup|DZ%1!SdKRaNw53*nQ)#ATC7*E zIO2XIaJ?6vAOUpx7BHf{M@ zq>niuH{H_^OJh2(r(3|-PT;Ych^Ml8P*8zm3g3RKKhxp+G!5DIm$?AAkQrcNK}2N{ zJs|t!V{TDxCG^ma-2zXf(t05F6727Ar+wZg6N+<-C^=}*_Ser3tv)5{;GOF|!25Bg92E7F-+O0fxJ(9IXjog5F6wEJ z2-7PZA^o&3ZM6q%#UuA0R0XMFEW%28k#r^BOe&jWq@vCiT}qAWb6$lic}&(gPUdkp zX|bw|a#EC+KljrnM3Zf`eAs*M2>OFH&+Dul0S%_wb!d2puf?E<7 ziJO2(KnRc;q%YXzIZKC+2mYOueHhF!-j2mx8rdwi(;k_F756 z*sP;W*zy=OvS{$eDcL)ju*r2pOnr3n6c+!{?o-I;jW_f+N$G9(W*fa>_|6;8qlpp{ z`5;#rwJWuRODjl2=fpVH7=uc$j7L%r&b2>FcZO4q_}=Gu`>ZtLPj?1e(ltBVBniVe zx*Zm?`e8I9dHrFEfNur9wl;?@@_~O2+vBH7w{HqK*JX-Z{YbosS<6a*+b9oJJ)D&! zU$CZA>`3!gR<815(EBP4@!gzUTmDQHVsDk>F#dag$=gDZmoAIg3sf<__w)S~kd@lL zd631s-mCl40a-j^wL4SzUB}t_cWOz=Ath(x_ya5$d(sCAWTS)T$r&8SSGA3$03JPL6WjPX`7hPw?-=tG$2HEhF zPGa+d(#NDJIiTZ@%+ouV$nW3!2{285J(B>~KWw^^DV$rsvoYclgt~3JCNcfYrK;?S z6f)RuyqG#biFuglo%z*bQTg!krq>>QwA5bJd82n$DFIHIG$p4_S*BH!Y3~a%gO5Y@ zqJ4PMM>IkSUK!3%LW;mzl#0aRO~}^zbFH39ZxiZj_<~%D&;>7@%idyc9IuOHhVcH? z5SGB8DON37Ab#0E`eb{SS51;%FIC8e$+%(mTS7FwH>z|c5OZj!U+;J1d(d)C5q$`9 zih2Ofxv5>Guhw$DNvk5W;ahtZ{M+=HrFbb@Hg+w+b?k@s(XI~KBzQCx{w}+a^t9?V zHTu&$os1;M3(DT4@vy{M#ei(SO+Dpbhw#hc6*eRCr~maWh* zza}EU`_+t!PpAy(!+5p}8Y+)$mO(li4j>E;jSKyvWxu;VWI5XHT`f#;USf-rYW#O(zGG)V zz{-Y{CoF-9ow+Xqg8?xGNA&G={ONwXk znu|EWpU;dje;uw5dxi2jvYMr$Fu4FSRmC@n1c%QYPsJ*x@K||Up6MO$pz@6Op2W~% zdeIn3=X=v-X7Tv_>vu?R&iyuSJZkO;__OeEvc|Kq>9SX;!XL|;v4iBEUi2Fy6gWM5 zG8NvZ?PTas%ENPXB{IukgokU#*d7co+8~Q(J?FaGnPMfCdXB7T|Aw29gn4{gyHPjBfr-; z!kl^5pgTtL(C4ckIVpHs&chPz4CdYYlw;`V=$w$PfuC_??3Nc4M10o2qWoi^p?MXd zSbBA2o$%v_8?IdVVsmht-$+#QAX;g@M#b6RxB$2x=6g;0Y6+r^!-XlI~6r1uy&?=%rMv2{^VFZnE z8Dxy&AtHTEuXw^R+S;(tOQ6X(7?!H8xcmLebvcwtO~UL3{jV0w%5iduN@gJjHicb_ z=iHi8fL4NZIWHI)EgZ2N)Y=OydMr46;QtY5W%a$wvbQyN)+^hDLEzF0t!N+boSKR3 z74kybv|7gmVAdE~kjKVndp|l<_mD-9Oj+E6unX7IJ8QP>5;HRPD&AeEkj~r%5Oxyg zXj9SFw%~X!3i*>Nq$M?vcJ<3stPK5S5icpZcY&c?^x3PCVjeuWFz~ya{}M%IpKgL{ z>i!nzzYGWeYbyBn@&6tkNq0}v3XF7bkghL*LnYG7FRyv96=r#+le9qNODcR^4AEdW z)PiD9QShL)EFuj6cYqKbTXVTW|baJ&k!C&Eykbxs$l}2^}cyHn6C+<=pGl8kr2_Mt=y*f zdR_pqWZ%-;GlTQ6H1HEWcqC*fB?=`VbT{Z879{rj~w3(ap$ zwtzzfnJ=pOTTQRX@DEhSCs-;vMy*ctVb`XO^yMw;j=_|4*+7I-Z8yJ~#1lXVfUd7U zBqSw`AF=t}?Y|ox7yDh#(84%bgg+lWr{e@0f>STll0`$SGvh1!_v>@u(NqOMRo%XP z5+N;`ongbZ1MNWK!47OVjFd%4Xb}wkI8E3k7VC%N2K)q^~7x zlGuft;Lfm>T+{bB6#*+8e~~oPmLJYyzjt+KjaaXvuPFt9eBm*9HG)kTt97|v?z9h&RchDV(#yUTawxjv}c zo50N!8$#08rIO}xigcQ`#DD_(fV4K(Yun&j*mX0#3aqf*y9W-Ow}@7l74@{-s-06B za-10Z%O|Y{J95!>de2+oxCrq zQyZlKQAq{si$2orSUczelC=)>QE$m?Y zOJrUPZeljeHrvaq1hh=w0&l5nczNh=`E_fyR&8^`89~b)ZtNBBj+eT{poiHS)j%?}AgOG_E&+^G#7=f37DwQ8VXVcAY8xw{PF9 zMpoUQOfbaf_X6Q4$1PV8Nye`#&^7sO;JM075K+P7>jd6}vTOumI<_fz&zj?o;1Au} z;4hEFATxff2HAf)x)f1OzE=ENrS4D#t=5@7r0?~@yvbKRNqy6A7ZR=bv8&&5(ItL4 zEKel|+dq5QoKm@}0MHP2(|OebPQ!Yt8KT_oYXjpaKbMZWW0~YjbRmG~nsECd1$v*? zL>VFWZeGga%iKbH$m;+};t4IcHt`z1f`R8cu7*IU`DOAQh2{IA-UB=QSj`=kfQ4_JZh%W-w7|8L zh5m<5$&bKV=h+{DTKkfXBEOzX9+!Jwd#l`n??$ViY)vu&d0Y};f{8>w$CsFxflPC| zVGcLy(oEGd#aWaRx#9s&Zo#p*Jd4ChrXT^`SxjT=w8N9`^px3u`QjP?a_We~K^H4A=u)Bi4giDAb-OB&Z& z5kt#`;^lOslH`?T#PUFvnp~5Z=ISqrB%OnkU-~o?-^ai+YD*>AkRgqsioiL@+46Ud z3cFeR`fLmTv$Ju+eN?vw@?nqvKl#D_&x?~@)a>*!u<>`7e@85LCV_^0@f~t_Us*qY z=ur&n=ec5mRsGeBICl7bhjwBZ&`~Im;BBas5oXs?&v1!(ZVFHzj@C;qXFU>7_mg-B zk2pKkI`eFMRS1kHmvMuUfBBmdz@ZbDr@}K%YfoVqY&y$o;w$#W_vg$e zX4leph|;N2`89sHb@nHcRv1bv>J`)A>ChMSUabSY!20ZK;8IC#Nwz+$f*ldO7;nF- z(I?L9bg6k<-j28H&_Bm*9g<~{$#6)@dcAQ}IZ_WYWnGLVg?tek<^GNcU}T6ooA5)B zo}HY``9}v}&XV?j`!khf1Gw|XPc15jfT2!pf3=56 zDT#Z0L1Z>JSFuM>7sOKUz7}_ZCDoI4k9yD#i+PVrA4|ce+MOwJr6*e%(sA4#F7u!D zkEp#OtLw$Gxcmk^+aY2nbukB)$emUZ?pua38*4ZxIVf2G~DAWQ=WOh)=oCW+)hMM3 zB+Vr*t>0T0t;1dNB!yt*0C2_~igB0FZ_k~4$OrtPzkyx%;#;Q@ivZW#RKdnJn#GWK z+wD|AtED^@z9m=+FzAsq7v)fxk*pu;>T8Q!xY?`H+bI&>nTLLLS;~McPBIW$>NqWG z@+WqL7;^cV-MF;kvfugMP6$Ucw>dT3@7K*zs&}(0c>-*qUa^4dU|eZi=A z!JK`l2ZBl@`nRX9@Y$>$TK3__(J~ygy9O_9k0pU3IP;|+vXx-%{CJAMcaH%9Y3;M? zGag9`_}s~YNnXUkhWCv`+Iu?`?Az1qP9K+#cXI?>kjnY-6G9=&QEQ*#3?TvVNcy8p zNdhQgUdXNbX(6GK(cO9p*_G7bJEuLhQjI{^M6uC(zKhEm9 zL6WqTEZ7se7*ATE?xr)ML*~eIV`bcD7Y?NjnyTsIPk_7&X;!l>=A~E|$Fih)IC!z@ z?AA%CVl{VpvBu3rKW+rh4LCSj!_X%Vna~>o^2t!V5b7hK#VCdxZ&$s3cf3_!;W}bX zN58&@pdS)ojz)af<@rOE^qYYA(brv<$p&o_1`&>Y)vUN9YYANUSXe_vNxFo;&Lze_ z@jl>9Gzox|@$fRIJ7234%#ys<;kgBr9UwxHQ=MpS4PN8cd(5c|LoU3>m%4x+`prWo z&3ZS{E-n1iRaHE+$mh9EUrd)v#z8}SEmy8hjx%*{YS#dhW(-bSIQ8r_5|&9bZufz zcBc*J)NZ3q0R5@%0`D2|-H>IZ*n*du9SX1(CN=#zuZ&~!cAh24&d%N+{CI-CblPPj zG+xJ`02}H4LbrF0Z7gGh%Ofd>5kAQ}uk5eO*yK-3yVJF5oLmKWagSvl*}OoNk?sP% z#Sj8TG$a+(7Y5E#-JTj=%Qm@&2>ku7A=|=>+rl21dZqtKQZjbFJ;SCcdi*5UDQ4y} zBl*LvJKeLZrxW&x1PG?C!0ESqTZ+<(2=}khM5(D_u_%B4Kzmeip^oLd&$pgE+VyXu zzh<>3)q(+EkXyT-kWxnQQ-iG4&dk~HN}i#>(c;h6D~}h-DVY2K?Cgo#>M!caI^Rn1%Z`x> z$H_Y>VlMAj*St3;WDpLhtviI#x5ov(ekyy^r&Bz*QlaLkk|vP2USOL7H_fhLOyo4w zkqbO5Mi>ubNllW8 z0eqeUkdiK8(_{(B=Vu3i9{pb>lcvknXDQ;H@bi_vgm~?|dwWEkY9q00MfWLGoaR=vvCLo2kn_a^7UF zMTNd`Miq>jGn@kAj_WklO_t-`jvNHWYirO1G<~o&amK2(VElC4*x%Dgn&$RNbGjs0 zjvjnY=s@k?Jt~#&VD(VuN$(8=byO{^3&O-CA6X;mt7>qprLb%D`5iy_?VoMmZ|7|< z+Xd9<`vfP&zbUU+?!{R(%n;u4-(ssJ{xA!7GPA}m>a_~hu7xNranCm10*g;;8bG+H zIPmHigY3o&bo$>q)@<02O^g>A>N2+VpR9gkLEaDj^0cuB8Uz7=faO7A3C-Zrr}v5T zfb#-z3t4SHHVC)vya2rE7~6@jna7Vl#D{H9>@6WH=YOS$>6(ADSmd~OO+jx+Dc~yp z`tUh?N!9T-Jzz`z&L&nBr2XTqjB2K+UE;uM4bs*nmB!Hr=b*!N2i9P&y1_y`Zb&QE{$ayw4A1K>hiE_EXLJI z6LNbZl*!_t+=exFeJg-HTablKNJy@w`a>MFX5pAlY`G&e{yKr~xkg!|d2a%hhdgiL zF{z{(@c_o}VI6Xk@~RtUq0o;^oad8QsXWAJk+@2Y;i+iQw|tTCjy|MY!!BRxX|r*0Sn zvqiw$53Uv>9Gyas2yQnyyoEUvziG@l9*HnOKGkBMv*dUz1Z6m`{kgBCT84nQVU5bL zwZsR8HRm&;w|?_ZEKMd3?=RUu;b3?X?0SS(7*pV}Al6{^5u;h_>?Gp3S;Yk^AI1m( z#{+~@?hUpB(0e&fDa^q^1P6_aCGEI{e4+pS^$)-5AAXvxxFS1%nj^#(x7^sKM1td* z-tAgX!`;22q8@yhm4ow~YasB7ZuEQ|Sz>5U7TGrvWYzJ;X}iG_L-Wp;-j2YI_&&u; zE5yn@72?|-Tc^+YXL4Iz4NM#A_%teBh1TtNGO@B6;D+Pe+BdXd-7U1qil;Jp^g{+% z?HMbG-7b4o@w}{Ip;tf00QX7?Ae7YjkosQgpZRy)SCP3{mEI!k1~uuqwv_;^NY=`Q zHwt-zV`g$YorGn5^?s|CK_43n@CNL!(Pk3)2J8E8-+qS;;Ms)M4<1#o=@+QC`b9zpt1KU#-bV*9l z{Ul~*w3R{cd*={Iv3FWL8ILdg81u}|-?Pytx)yaj7n7<}xAEY;?>JA!(a|AwAbPID z)VIt?PtvFYLAZVLCjO{-d)ixZi1Bmvt-jzyzL|%07JzW>tlC0|TOC7|gumGO@(1xS zL5vz*!OPG4Ze7Z>Z0M>}fTB>zmoW)w+iwO0kB^cXOfk|$qQj4Wj1{wiAV-mTiib^& z^6Jy?=1>>=%lsd6?GA*7bEmlttR(=G)7(cG0>U|7gJwRW5sbAPvFY|4H)hIkS+{LQ zhXgp`nFF+YMewPiJ#S+%bX6_?H8al78+rpVG43I9Zs-h}iCPl6u+f!H0jFw*vEg2I za~==y^8pL_=pK_wQsx;R!0tT+Jpdt-A;)~IGXzD~NIiBWLxay=KbGej(}PL8`XFUk zB}D|J?87A7NkNUMiIMyTe3X8mmFsE|$l*b#fYih<{)F#7-_(_iQH%B$(}C$1Eddn5 zG1Ts+gn{i)??=@0w)Qpw80vU@j=y?kvz1_HJd=uSD}v^%)X|_;)BOuCo^!+NuTk`` z$R4R=2+jJjx$2dc4XWFXG~{MJ9P+ybm_R6_5u7K7bxKL(q+GCRI>v)l?q_W9ZNJHe zNlKN&t|@#scH#s-pvSOUtn7KRq(I)dcsjtgV2B z*&*zPL9^>XThnAt#ong?u+eKOe7Wadq217H|V#3~Uu&_!Xy;rwHQX%{2 z^Z7@DdHfDtZ&O47X&CgfTNoihdVD&eJ6N(*I_s|~4!Nh;54l5KUhM2HZt)PM^yB>H zj5F~&iumF3thmvwIiW|ifHTE-Tx#K5(_fsR^1MiS<%S)o?njOFwjUkf(!_UCmj2!` zY}M!S5Q4@3jz95xzfKlE)4?Oey zaG%pa8FG5e>AQDkW7VJP=|?Rt7)%@}@BhVj?{jN~_leMUDH$6w8`k6;X_mNmB9$ZE zigWEE4)x+qN&dNUS?N#|u($EB`K}b^yIS${xDW;s%)4KR21uY<79;I=DU@Wpbo}zN zJW_Kim?7YWL2Y1G2t(ZLwD89HUf;Jm_IoAoEdVnPzz*h*7&q9K)))ZeM)YYk$gF*C z?A)aIDv{VB=i+F*_e3gc1R7j*3fL1S0V(R3;{(qF^3km-KN&^4W-W9{t$cFDX?HP5 z1pwD%B~2=TFXcEaE*Zc!zubGXMg&f=-s3_Us=yRF>Oyru$T;2wY<-;2u@wp2ThWbE z)>TqA0QM3+ogCQKTrEiQ%obW`TAD~JT9cI3Uv8hoF#J;|bvM-C|2PJ)K4zR)D6`XH z+28bEI$?L`WmJkV+euj-=YF2(Zni8ixiEb65wH&7HQg?=)_JaqiLgIwJKvSx%@GZ+ z#aSDgTc6{`?ww#iK+8XMAk+3_T?g%TT$SpS@ER% zhq008(>%hSY97>Emu(bzH*(n0pE)24vW+h%g{N`}l&M;oIk;Q%rkJ6_LW(;V%d62y zr7BTIPqyTW*L^mvA8w6!g5Ie5ZKo-mmBG$$G*|*$LfR2QYFwkn{>yPH?#eovcTe}# zYEeGg2YFIwhwe^i^1_iH>HXjOKiqU3xY)x1H@tg)^Mcle1x&$lP5Lqeho}Ts zSSx3}(ES*P5Ze{{z28{mV9u<+8fkqaBE!$ux1*6gS`BJ2K|1s@!k@6l#e|nBxH-E} zo|hOL*&2W^?eJn);ZG7U;`zNp+>mR(Su`6`TpaU7ko140+W&Vt_&;xn!sYobW-cz}tdNip{(nZ{p0{nma(~hQ-qFH6 zI=cRUyx?zCGsM{?VQMc`O#kE1F*7Tx9AKs5u=$;i9RJr=o}-@K7ANLSkEZSGM3!3_@j?z(%7mJ->d<`_9m->j6cb4vU@NuAXR+L-cOB4kZ?#G` zkY{=hcVGDxl=(EibH+c{2c1N5QYE-(Qm}aRwE(Ef#`I#K)1bF$s;# zTL&gn)x4Qlw?hU+Ab?tlUP}$VHi~6q z-U?5-tGK>siW8EY>C~w!0RIFRX{CAih@SUV%KXcyp(nGQhI#9qbibyR)fp<-G}}TV zD)B9gKizB=bGiH=TfFuP`hIYDU6hvFEbB5iY4Z!u9cz#`Y~l%OGbywd;_GBZiXTn& zO*szvSBngn`0x*E)N4=o<-Y6=w=J49%+e&g{>~J!yOf|Bdi-S>d2OStj6?o6@ff-8YVi;I$~~N;->a;Xw;BsSnJ) zZ6(4VzRyXmo+_YEUcNj&{O$ksQORzdhfObz)jfA_hrqx!YpjLT&&zpBr#ndr(~8Il ze-B;_*&l1%_RUJIi?x!m?ehq!ZzgcrZ^3ii<>Tpdf{8HY=b`j|X|I}{P`gtdG^s~r zTzbx2QXPj4I)PS$x?J!Ul0;s$Pp_mVUw?aE(z}Pn98q#U9^##Gq_=KJN{;uY@k!OC z7@*W%#E>5w8@w{d_u^|W3WF`OSmWmK)Y76ujv^rE`0n>w{@l@-IToH4E|)jx6?g(# zXj-iQ;gxupn~vJrZ@YZJwQVt7EY18LF|ul zw@6im%FZeGHTp?hqtzTdp|@20de2!;6cFYKCFM_9fGC&VyRx74$F0+)u#HOGpw5kB zynN(dg>M%AF-ml$I2(epPYQ#no49U^Fqbylp;=hYKeFH3o6ud%tbGIW@1x>hNs*s% z7gBsRH^6N98tIk4jsaF%OA4nM=y%-UUihouufjR^b3Q?Y2c)(_&hjFD>sjOz?M5Q}8ka;oGg?Z};^jcNkp{N1oM(CO$&PmRD!MxB8;V1Xp#KA-? zW;SX>H`axS2)RaB-`0BYlmbfJdwZGzd-FIX-Lz*9ynk_dv_IX-?e-W09qrXM3f68k zDCIV2rTG}Q^!NE05pt`TiL_M3^?~pbT`K$}Px2~kptWeyCr7Err5ExSyD8F=$2F^r zXBRiY-8Hz2Ce2D&{+tQWiADp(Ejr*m)E3vNz79nPUAf!t?RhvCx4Jndby+td7dZ{z zzO31y(tTTO5*OWETY^vZg!W|9Ccr98aZAGK(57_Ttf#--5SD)0OGS0k#=VHyP4+Q( zO9c?rEBfe8hfIW5z0umPsLzZPgp!}z$e`;`dMdj^@lQ zG+#v}w%{S*r1#rEo>_MlV`EfI#?=O27i#9M6m7-sm%1qIN7wTy(=8`%f$GPWA=CpO z&X%g3Png&`r-z|Sq5SuRyrL#at`xgVWiOBTR~}4%kL*BADh6iGdj9zo6|EzQ_od)& zup@Rrnb&}K7F{E-@)hm2wBlEdi;abu6INzUkeU~>)IDo`L`3b{^mX{-jiHeq_L+t>YcAngfhlM#y*Va`gr$ea!q*o)>7$WL)v0pYU#pk(4Rbl~xN>S{o|Q~E>)M`$Y>7X8UMoZeiX2`fA{89r_{M$MQqie(l#x9r zm7o;nKTFRIPsWxGkH0YaBe7CnYLc2qg;}$Ay{guUmIo*Aw?3!Y#j*tQgl^2C0@xBq zoWh-`9ab5p$9@g0?2}gJXZ#T(!iJw^zUw^Ye3nT<+%a7hwnH!xRW1z5wkkz{MG21| zs_@n({a{&fr-D+)imfaVYb~!`3H4C<>nioN<>p$W%r&2KB}Isp$sn4!7~%M5F51lo z_)v!*8=}~6YP~y^mrlnj89c-Jjuz~XQk8Z#Mqe7-=in9_cog5PaS7&G5ZGMf zHA9J!pFsTHz;?@W(j`8wRJ#vPyi{A(E0tZ%vBeQqbD-cdKvdOk=B_dusvBJ;e-#YM ze=QgaX-V^ONP9euHzG;lBTu^iG_$7q5bRRF_+L6X&u})}caK*~NfpHptv!mO_DGGy zD4J4HqtqU;N2yUYTD#N=MeUtZd&L%7#0qMUidmzob`mA6ob+73|9Nw+^X9yK-rUzS zuIIX+=kvYq@4BlC)JNzedg!vSKqs4QVJhjGT8-4vtVrclOOYVfs5=B(m$sEsHDwSK zf#bc`RH!uxgLc*k2;GB@M;Bp?jV)u6+&?9zit`>Go3v_1-T<0U^kSL*K&V5zL?jk- zYy}7eRwmH*H!pXiE(u*t=f!&2LKDncolteJ!OR;kb^kfmU+E-dhYhR9Qh4(nAuG5u zW+N|M34hz-K(72)RdLGwzC5?<+*vvquChA6XmLI_nmY|D#e%k?YHw_0`Sdb$^4`%A zPjj4(Z^_hwi*)x2qfP(FyyXr_Eu|~c;tA(Heg;!M^G$hpWmbALp>K6^UXBa2j7zN!fZ)H_0;s8-Qgn7^57V z7b^cfR)>D!cDw%LM32rPp7mIz6F306rC6ZX9U#2$yznpmna@? z5dkb<$57{@cMb&I>g)EQfnV>I_|LF7M(q4}LfiNUuRNb-2lbs~77yk8D&*W*Zz$kp z;QF)>u{8s)3`oUVH@x2nh>2hPSvmJlb)l=$3$fSfDq0BZF5Qi{$D<=BJ%)pnguS>Y zlb65+X9=Lh#SuB5=qR14FJenN#u;#OYQxZ`O}gIu`%I6~z_hpzgkH#{%Aj$5yYlMt z<^*izdRcTKnnrwW?SB8mUzOdEd1@m(Wi+!Zr>_jatX+?v`y9f5H4#tx6su@Plz8Yp zsju<)1aet|=Nn?D+FVE9f#wBL@C)T7KKIk7u)N4Zki#f9*O$oDoTAOg_iCFFMIPf7 zvCMMjy8_%K9sc}3P>oQVn!wZiH=B4_Q6-a}n2WoNC@|BhN2pjbT{X#WWel$h++~$s z)diTLEHq5^zEY^D@6QUH;=Wv-SmCAa(q~Q9RzMrKr)L`wJlSLnwGL7FJtjrKVl5SXA zX$`dPMyu3e?FvYHwNcGVB;gCACdqvH^!uE&kkCd^LMBi&IuppwIcfMTGn5mN)d@7S zbh`M(*=19wXGqMm^W6jAZaWVtUgRF=sJ$~>6qH>SQ+dsxhtlYr3c|b-al|a>wT+d zbgQHQvsa$=E8ahnEgOGYl*^J}S+5*gnp;($wuj?I8W-C&92&~6r{&^nR2m&ia|wNr zo!HBh72a8`uB*PkLcT>84B-a348f-AZA}h(?$^fp!tw{pRluXW+FsNURrSa4LRMiq zWvT(z29J(>&GF$k%Vd$?rAT<hWvVOkWW$?zS)kXxm`(#ZRG zd^*EeZ8bj3(&C@d^EE>yDE1zsFxr1Lv$gsB3cp_YygwxJs?CrFQ$ug3Lin5J;cPWp z^_$C6YCV*CXF5x$W?UPmk{{_cYpLk!g$0h^R1iY-M5`Y4?*zW5VY* z=`%C~LquJ4LTt)z@6Stzm$$?LwD({G74u(DKGm}<)uJRiw!Y;!K6+`Shpv>yc znJt5aQ=P6?yGpd!A~uz;kpF)>7jVx5Yvhyd#7Y6zJZlc9nSZ zL^Ce6d}IFf)CDcLDir+3TE>yZ>sChgfvnMf5Y;xnsl1l~Kzd;89gOJktsLTsE(q|0 zYX*W0$0#=xkUzf2P$={MQf225Y+EWal#crBEy`XZoq~Zq3>rTGNV! z>kc*zySS;-yb-L2xQHW9u&5@C3x@ad9V8O{`J9rV<14BY`E1mzX>B8Cc%~n4OL5Sp zO;hk%IhZe456$b{KJ@wbW$5|6p%VUeOo4?36^c&OWlYIjcj~UXmx=^)W>l55up+a^ zjyto%_ZdoNHC}3)M+;VRlkK%-k4ph%@vmfmjCMTYU0Dd_p^9iLDI*(f!MT;4x?GkL zm0wiFRgbdVyqm+zN)a^ZL_$#NAgQor($s{^HCg2$)WKaf7YR`C8av^bB&Un0XHZ?VgWxoQ+(s!_a~zl z->If-%R4&ze~!U%+SG?!@M7HXemVa5vNhug902*QxJhniq``GJe*xG7&fd2eN zXOk85`^kyg(HFCAJ!(o8kxeTCsK~D(`lyUb-+qz~H(4HkPAgcv;(UG!OJt&E5q&hr zsX8wd#vu*k-YaCm*)9wuwVZ#r_$F0n&*4dU*jUh}aG)H(*{Nyah{&KMt-7NJWoZw8y@V;nQQBltJO5aNMyi39aU~T|nfvXxg^c<+Gnw zai-}~%pWCHyKI{C!Tc!`7k@rz_OMCVaW3e z2u)w>U>(X)W_=1%Wd55)r>tSnUl!)fsJls+&Q@fO*hoQ3d_G6JH8)!VHI;Cuk#p1f z4Nzeu>48lGa5Y<8!Ac1`$qYlsbw=<#0A;j_~&ml5ZdA~gBy zw|;qlBwp%#heOcqDZ?IqLu0Mqf-WfeN+OYUd_D8J%~}Z46ftPj3?6vMuIKs*bmK)K z0#vY?AN$o2>CEbBr`HSMWMS6}kWyFLDp_3b7h=NCS~1Cvhu)WZW~qIPS6skj#Ba}u zL9zWSM( zdt=H;5z$Bi(+vR1Rgo~eb#4{jo&63sXYO8=yIaA(*>rHWX^NFhWnZoU*3~EnK3>M| zFd#`vow`Z=`RQV`8L3D3cGpn+lCE)vOTh!LLb`rLq{U`tmiC-(#n5;5z0LA#qZ^f9 zfrA6`%EMtk3)=w}lMxi4l->nl8_#Os=T{muO83jE{;|>gc+qNrlLekliI4pH+|&A< zm63(oGEO`BTYi_){_O(plS{e3n~n<=n}lK^>Vx?ZR1u>kH5{$W_sN^GGGhNQsF~b1 zZcv)Jb=I+M^OCd#@t>^udC0lQ8~ysgia0^H>N>$QAiWur7FDND0<+!8YG)MX`qr=rqbXfNAQMz_XA^0J0r5qo{_S43lzWi4dg8-|>hYnV6=ke+wSmglomjdw{zU8w<$=6lxH zJ;d||Xhu}^?`Qo`c;NOxhFFjkIeiUbMLG86J^dm-I*@Yk1<{^q5|uuqZ?%pKr z;#4Xz(=WEPpb7NlYR~V-5?uPF+YfhDj-!Yc6V!gw@9lr{>IdaRp0CgH3gtxvBI_Qg z&gog4Co@-Zlbnn!}Q#V5%oNuIDAzTCK5q ziC76{`e$8*YAT@8lsqzWExsG`UfF9DgQODmJ03g}&6oQ(6p0JH?{@PUswm!mJJLwgB5z&yzB~V*?+$lb*q5?y;gpn2pZjT4;}P+! zR>kpI)-yEgZhvug6(deMTjM~Lt)uF{v2NC-SGP(|uN24MN(#3<$8V8?$wz>-jh?TJ zqwk0f$54O_gw#|A^4)j8Z$2uHf46Y@{QCT>*TR2cJS${WS_zg2nMMcqhBQ2Cb2)R6 zd2PYu7?CVa#LqEL#9y93(-6T)6r8joYvjOZhQSH#86L351verBjU+y&*#-S2*bjTa zB#RKOlik{?hRqZSb|;$wF#HwIfLh&OJpK;JT~boE11Cy zVO#kSjW#VVB*S;{N=I!EtY&W_m}=>N63{iW%%Ib6+$r&r*%kW$>gt!Js45As;Z28PxJrewzq%zq@S8-u|p>!ZL|=NbQJi<<9oA3*W- z@63x&|NJXg{eO&-3@m4DRR5PKpwY<<$CG`8{?=DF_Sv5%Kh;n8pK)fU%kF|AU;Tu0 qbs4#|o?N7xht|xi&tK5IV4#`_?!C0uqC>V&zVuKFs#&998}VPCORkv! literal 0 HcmV?d00001 From 983cc98463a6b1e7b36ca5d282e268e291411906 Mon Sep 17 00:00:00 2001 From: Ed Geraghty Date: Sun, 20 Mar 2022 14:11:58 +0000 Subject: [PATCH 08/22] chore: notifications FAQ --- docs/faq-en.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/faq-en.md b/docs/faq-en.md index 0b614269a..ae6b02477 100644 --- a/docs/faq-en.md +++ b/docs/faq-en.md @@ -15,4 +15,10 @@ In order to cross-sign/verify your Syphon session, with the Element client: 1. Click on the untrusted session ![](images/syphon_not_trusted.png) 1. Click "Manually Verify By Text" ![](images/verify.png) -n.b. Interactive cross-signing is roadmapped as part of the `0.3.0` release \ No newline at end of file +n.b. Interactive cross-signing is roadmapped as part of the `0.3.0` release + +### ...Get Notifications? + +Notifications are currently **Android-Only**. + +Like most features in Syphon, notifications are disabled by default. \ No newline at end of file From 94f9ee632673585526a01ebb550414184edf3f29 Mon Sep 17 00:00:00 2001 From: Ed Geraghty Date: Sun, 20 Mar 2022 14:13:44 +0000 Subject: [PATCH 09/22] chore: RR FAQ --- docs/faq-en.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/faq-en.md b/docs/faq-en.md index ae6b02477..994bc3f81 100644 --- a/docs/faq-en.md +++ b/docs/faq-en.md @@ -21,4 +21,8 @@ n.b. Interactive cross-signing is roadmapped as part of the `0.3.0` release Notifications are currently **Android-Only**. -Like most features in Syphon, notifications are disabled by default. \ No newline at end of file +Like most features in Syphon, notifications are disabled by default. + +### ...Send Read Receipts? + +Like most features in Syphon, Read Receipts are disabled by default and must be enabled in the Settings. \ No newline at end of file From f48a7f14d3248170d5ec3264f4e642897ea624ca Mon Sep 17 00:00:00 2001 From: Ed Geraghty Date: Sun, 20 Mar 2022 14:33:09 +0000 Subject: [PATCH 10/22] chore: immediate remediation --- docs/faq-en.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/faq-en.md b/docs/faq-en.md index 994bc3f81..3890d8436 100644 --- a/docs/faq-en.md +++ b/docs/faq-en.md @@ -1,5 +1,13 @@ # Syphon FAQ +## [X] feature is acting strange/my settings aren't saved + +Syphon is currently in open alpha, meaning development is currently rapid meaning each release consists of quite a "jump" in features. + +In the first instance, if you've updated your client and are experiencing "weird" behaviour, please **uninstall** your local version and **clean install** the app with its latest version to ensure any local settings files are recreated at their latest settings. + +If you're still encountering errors or weird behaviour, you've probably encountered a bug so please ask for help! + ## How do I... ### ...Verify my session? From afcb5231cbf42ad366dc31525e23df47b53d603b Mon Sep 17 00:00:00 2001 From: Ed Geraghty Date: Sun, 20 Mar 2022 14:44:43 +0000 Subject: [PATCH 11/22] chore: missing features FAQ --- docs/faq-en.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/faq-en.md b/docs/faq-en.md index 3890d8436..09920eced 100644 --- a/docs/faq-en.md +++ b/docs/faq-en.md @@ -1,5 +1,13 @@ # Syphon FAQ +## Where is [X] feature? + +Syphon is currently in early development. Whilst we believe the code to of a standard where we can share with a wider userbase, Syphon does not rely on public Matrix libraries, instead coding against [the Matrix specification](https://spec.matrix.org/latest/). + +This means that Syphon is currently missing features found in other Matrix chat clients as the development team work to implement them. + + + ## [X] feature is acting strange/my settings aren't saved Syphon is currently in open alpha, meaning development is currently rapid meaning each release consists of quite a "jump" in features. From 9b9078e0e8ceb1fd0897b9ed17cd463ba25ff9db Mon Sep 17 00:00:00 2001 From: Ed Geraghty Date: Sun, 20 Mar 2022 14:47:42 +0000 Subject: [PATCH 12/22] chore: that is the question answered. It is, indeed, to be. --- docs/faq-en.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/faq-en.md b/docs/faq-en.md index 09920eced..d358a432c 100644 --- a/docs/faq-en.md +++ b/docs/faq-en.md @@ -2,11 +2,11 @@ ## Where is [X] feature? -Syphon is currently in early development. Whilst we believe the code to of a standard where we can share with a wider userbase, Syphon does not rely on public Matrix libraries, instead coding against [the Matrix specification](https://spec.matrix.org/latest/). +Syphon is currently in early development. Whilst we believe the code to be of a standard where we can share with a wider userbase, Syphon does not rely on public Matrix libraries, instead coding against [the Matrix specification](https://spec.matrix.org/latest/). This means that Syphon is currently missing features found in other Matrix chat clients as the development team work to implement them. - +[Syphon's feature roadmap can be found here](https://syphon.org/roadmap). ## [X] feature is acting strange/my settings aren't saved From 47fde031adf32319065e6c86d632585372b1104b Mon Sep 17 00:00:00 2001 From: Ed Geraghty Date: Mon, 21 Mar 2022 15:46:49 +0000 Subject: [PATCH 13/22] chore: make that sentence scan better --- docs/faq-en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/faq-en.md b/docs/faq-en.md index d358a432c..90a5e357f 100644 --- a/docs/faq-en.md +++ b/docs/faq-en.md @@ -10,7 +10,7 @@ This means that Syphon is currently missing features found in other Matrix chat ## [X] feature is acting strange/my settings aren't saved -Syphon is currently in open alpha, meaning development is currently rapid meaning each release consists of quite a "jump" in features. +Syphon is currently in open alpha, meaning development is currently rapid so each release consists of quite a "jump" in features. In the first instance, if you've updated your client and are experiencing "weird" behaviour, please **uninstall** your local version and **clean install** the app with its latest version to ensure any local settings files are recreated at their latest settings. From e8964e0db1607a37ad9fdbd47a69c77dde78fc4a Mon Sep 17 00:00:00 2001 From: Ed Geraghty Date: Mon, 21 Mar 2022 15:51:37 +0000 Subject: [PATCH 14/22] chore: add another link to the roadmap, since I mentioned it --- docs/faq-en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/faq-en.md b/docs/faq-en.md index 90a5e357f..9e52b51c6 100644 --- a/docs/faq-en.md +++ b/docs/faq-en.md @@ -31,7 +31,7 @@ In order to cross-sign/verify your Syphon session, with the Element client: 1. Click on the untrusted session ![](images/syphon_not_trusted.png) 1. Click "Manually Verify By Text" ![](images/verify.png) -n.b. Interactive cross-signing is roadmapped as part of the `0.3.0` release +n.b. Interactive cross-signing is [roadmapped](https://syphon.org/roadmap) as part of the `0.3.0` release. ### ...Get Notifications? From 3e5b4d76c6ecfe2fc8db23862a3c0e065cc60004 Mon Sep 17 00:00:00 2001 From: Linerly Date: Sat, 19 Mar 2022 00:28:29 +0000 Subject: [PATCH 15/22] Translated using Weblate (Indonesian) Currently translated at 100.0% (338 of 338 strings) Translation: Syphon/Translations Translate-URL: https://hosted.weblate.org/projects/syphon/syphon/id/ --- assets/translations/id.json | 69 ++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/assets/translations/id.json b/assets/translations/id.json index 43df187d8..5c4ce437b 100644 --- a/assets/translations/id.json +++ b/assets/translations/id.json @@ -269,5 +269,72 @@ "list-item-chat-detail-vibrate": "Getaran", "content-notification-style-type-latest": "Tampilkan satu notifikasi dengan pesan terbaru", "label-show-attachment-options": "Buka opsi lampiran", - "content-support-dialog": "Komunitas Syphon ada untuk membantu Anda sebanyak yang kami bisa.\n\nSilakan bergabung ke obrolan Dukungam kami atau kirim kami sebuah email. Diingat bahwa email dapat membutuhkan 1-5+ hari kerja untuk sebuah balasan!" + "content-support-dialog": "Komunitas Syphon ada untuk membantu Anda sebanyak yang kami bisa.\n\nSilakan bergabung ke obrolan Dukungam kami atau kirim kami sebuah email. Diingat bahwa email dapat membutuhkan 1-5+ hari kerja untuk sebuah balasan!", + "label-syncing": "Menyinkron", + "header-ordering": "Urutan", + "header-media-auto-download": "Pengunduhan media otomatis", + "title-dialog-sync-interval": "Atur Interval Penyinkronan", + "title-dialog-chat-with-user": "Obrol dengan {}", + "title-dialog-attempt-chat-with-user": "Coba mengobrol dengan {}", + "title-import-session-keys": "Impor Kunci Sesi", + "title-export-session-keys": "Ekspor Kunci Sesi", + "title-dialog-confirm-deactivate-account": "Konfirmasi Penonaktifan Akun", + "title-dialog-backup-session-keys": "Cadangkan Kunci Sesi", + "title-dialog-enter-screen-lock-pin": "Masukkan pin kunci layar Anda saat ini", + "subtitle-settings-enter-sends": "Menekan tombol enter akan mengirimkan sebuah pesan", + "subtitle-settings-dismiss-keyboard": "Abaikan keyboard setelah mengirimkan sebuah pesan", + "subtitle-settings-view-uploaded-media": "Lihat semua data yang terunggah, bahkan yang tidak dapat diakses dari pesan", + "subtitle-manual-sync": "Lakukan sebuah penyinkronan matrix secara paksa berdasarkan stempel waktu penyinkronan terakhir", + "subtitle-force-full-sync": "Lakukan penyinkronan penuh secara paksa untuk semua data dan pesan-pesan pengguna", + "label-timestamp": "Stempel Waktu", + "label-none": "Tidak Ada", + "label-stopped": "Diberhentikan", + "label-version": "Versi", + "label-search-for-user": "Cari pengguna...", + "label-new-password": "Kata Sandi Baru", + "label-confirm-new-password": "Konfirmasi Kata Sandi Baru", + "list-item-settings-dismiss-keyboard": "Abaikan Keyboard", + "list-item-settings-sort-by": "Urut Berdasarkan", + "list-item-settings-group-by": "Kelompok Berdasarkan", + "list-item-settings-view-uploaded-media": "Lihat semua Media yang terunggah", + "list-item-settings-auto-download": "Pengunduhan Otomatis", + "list-item-settings-when-using-mobile-data": "Ketika menggunakan jaringan seluler", + "list-item-settings-when-using-wi-fi": "Ketika menggunakan Wi-Fi", + "list-item-settings-when-roaming": "Ketika Roaming", + "list-item-settings-force-full-sync": "Paksa Sinkron Penuh", + "title-dialog-logout": "Keluar", + "header-general": "Umum", + "header-media": "Media", + "header-update-password": "Perbarui Kata Sandi", + "title-dialog-remove-screen-lock": "Hilangkan Kunci Layar", + "title-blocked-users": "Pengguna Yang Diblokir", + "title-dialog-confirm-deactivate-account-final": "Konfirmasi Terakhir Penonaktifan Akun", + "button-text-remove": "Hapus", + "title-dialog-verify-new-screen-lock-pin": "Masukkan ulang pin Anda untuk memverifikasi", + "button-text-import": "impor", + "alert-storage-access-required-for-keys": "Masukkan kata sandi untuk pengimporan kunci sesi ini.", + "title-dialog-enter-new-screen-lock-pin": "Masukkan pin kunci layar Anda yang baru", + "subtitle-images-audio-video-files": "Gambar, Audio, Video, File", + "label-current-password": "Kata Sandi Saat Ini", + "list-item-settings-language": "Bahasa", + "list-item-settings-24h-format": "Format Waktu 24 Jam", + "alert-wait-for-full-sync-before-switching": "Tunggu untuk penyinkronan untuk selesai sebelum beralih ke akun lain", + "subtitle-settings-show-membership-events": "Tampilkan perubahan keanggotaan dalam obrolan", + "subtitle-settings-24h-format": "Tampilkan stempel waktu pesan menggunakan format 24 jam", + "subtitle-theme-settings": "Tema {}, Font {}", + "subtitle-privacy-settings": "Layar Kunci {}, Kunci Pendaftaran {}", + "label-seconds": "detik", + "button-text-confirm-delete-keys": "Hapus Kunci", + "list-item-settings-show-membership-events": "Tampilkan Peristiwa Keanggotaan", + "list-item-settings-enter-sends": "Tombol Enter Mengirim", + "list-item-settings-manual-sync": "Penyinkronan Manual", + "content-logout-multiaccount-confirm": "\n\nAnda memiliki beberapa akun lain, mengeluarkan dari akun Anda saat ini akan mengalihkan Anda ke sesi akun yang lain.", + "alert-log-out-enable-multiaccount": "Anda harus mengeluarkan\\nsesi Anda saat ini untuk mengaktifkan multiakun", + "content-import-session-keys-enter-password": "Masukkan kata sandi untuk pengimporan kunci sesi ini.", + "content-export-session-keys": "Masukkan sebuah kata sandi untuk cadangan kunci sesi ini.\n\nDiingat bahwa pengeksporan mungkin membutuhkan beberapa waktu untuk selesai.", + "content-export-session-keys-enter-password": "Masukkan sebuah kata sandi untuk mengenkripsikan kunci sesi.", + "content-import-session-keys": "Masukkan sebuah kata sandi untuk pengimporan kunci sesi ini.\n\nDiingat bahwa pengimporan mungkin membutuhkan beberapa waktu untuk selesai.", + "content-logout-confirm": "Apakah Anda yakin untuk keluar dari akun Anda?", + "content-remove-screen-lock": "Apakah Anda yakin untuk menghapus kunci layar? Ini juga akan menghapus lindungan pin cache", + "semantics-image-password-update": "Pengguna memikirkan sebuah kata sandi dalam putaran angin" } From 1d8967911f5db7a7d808228571d7aa0626916f57 Mon Sep 17 00:00:00 2001 From: Ihor Hordiichuk Date: Fri, 18 Mar 2022 20:15:25 +0000 Subject: [PATCH 16/22] Translated using Weblate (Ukrainian) Currently translated at 100.0% (338 of 338 strings) Translation: Syphon/Translations Translate-URL: https://hosted.weblate.org/projects/syphon/syphon/uk/ --- assets/translations/uk.json | 69 ++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/assets/translations/uk.json b/assets/translations/uk.json index d99e5b0a6..0097c7130 100644 --- a/assets/translations/uk.json +++ b/assets/translations/uk.json @@ -269,5 +269,72 @@ "semantics-image-signup-username": "Людина, що спирається ліктем на ID-картку", "semantics-image-password-reset": "Людина, що поклала розслаблену руку на лист із прапорцем всередині", "label-show-attachment-options": "Відкрити параметри вкладення", - "content-support-dialog": "Спільнота Syphon тут, щоб допомогти вам.\n\nНе соромтеся приєднатися до нашого чату підтримки або надіслати нам електронний лист. Будь ласка, майте на увазі, що відповідь електронною поштою буде надіслано впродовж 1-5+ робочих днів для відповіді!" + "content-support-dialog": "Спільнота Syphon тут, щоб допомогти вам.\n\nНе соромтеся приєднатися до нашого чату підтримки або надіслати нам електронний лист. Будь ласка, майте на увазі, що відповідь електронною поштою буде надіслано впродовж 1-5+ робочих днів для відповіді!", + "content-export-session-keys-enter-password": "Введіть пароль для шифрування ключів сеансу.", + "content-import-session-keys": "Введіть пароль для імпорту ключа цього сеансу.\n\nЗауважте, що імпорт може тривати деякий час.", + "content-logout-confirm": "Ви впевнені, що хочете вийти?", + "title-dialog-remove-screen-lock": "Вилучити блокування екрана", + "button-text-remove": "Вилучити", + "list-item-settings-language": "Мова", + "title-dialog-enter-screen-lock-pin": "Введіть поточний PIN-код блокування екрана", + "title-dialog-verify-new-screen-lock-pin": "Введіть PIN-код ще раз, щоб підтвердити", + "label-version": "Версія", + "subtitle-settings-dismiss-keyboard": "Ховати клавіатуру після надсилання повідомлення", + "list-item-settings-when-roaming": "У роумінгу", + "subtitle-force-full-sync": "Примусова повна синхронізація всіх даних користувачів та повідомлень", + "label-syncing": "Синхронізація", + "label-stopped": "Зупинено", + "label-seconds": "секунд", + "label-search-for-user": "Шукати користувача...", + "label-current-password": "Поточний пароль", + "button-text-confirm-delete-keys": "Видалити ключі", + "list-item-settings-show-membership-events": "Показувати події участі", + "list-item-settings-auto-download": "Автозавантаження", + "header-ordering": "Упорядкування", + "header-update-password": "Оновити пароль", + "title-dialog-confirm-deactivate-account": "Підтвердити деактивацію облікового запису", + "title-dialog-confirm-deactivate-account-final": "Підтвердити остаточну деактивацію облікового запису", + "title-dialog-backup-session-keys": "Резервні ключі сеансу", + "subtitle-settings-show-membership-events": "Показувати зміни участі у бесіді", + "subtitle-settings-enter-sends": "Натискання клавіші enter надішле повідомлення", + "subtitle-settings-24h-format": "Показувати часові позначки повідомлення у 24-годинному форматі", + "subtitle-settings-view-uploaded-media": "Перегляд усіх вивантажених даних, навіть тих, які неможливо отримати з повідомлень", + "subtitle-images-audio-video-files": "Зображення, аудіо, відео, файли", + "subtitle-theme-settings": "Тема {}, шрифт {}", + "subtitle-privacy-settings": "Блокування екрана {}, блокування реєстрації {}", + "label-none": "Немає", + "label-new-password": "Новий пароль", + "list-item-settings-enter-sends": "Надсилання кнопкою Enter", + "list-item-settings-dismiss-keyboard": "Сховати клавіатуру", + "list-item-settings-sort-by": "Сортувати за", + "list-item-settings-group-by": "Групувати за", + "list-item-settings-when-using-mobile-data": "За використання мобільних даних", + "list-item-settings-when-using-wi-fi": "За використання Wi-Fi", + "list-item-settings-manual-sync": "Синхронізація вручну", + "alert-log-out-enable-multiaccount": "Щоб увімкнути кілька облікових записів, потрібно вийти з\\nпоточного сеансу", + "content-remove-screen-lock": "Ви впевнені, що хочете вилучити блокування екрана? Це також вилучить PIN-захист кешу", + "alert-storage-access-required-for-keys": "Введіть пароль для імпорту ключа сеансу.", + "content-import-session-keys-enter-password": "Введіть пароль для імпорту ключа сеансу.", + "header-media": "Медіа", + "title-dialog-logout": "Вийти", + "header-general": "Загальні", + "header-media-auto-download": "Автоматичне завантаження медіафайлів", + "title-dialog-sync-interval": "Змінити інтервал синхронізації", + "title-import-session-keys": "Імпорт ключів сеансу", + "title-export-session-keys": "Експорт ключів сеансу", + "title-dialog-chat-with-user": "Поспілкуватися з {}", + "title-dialog-attempt-chat-with-user": "Спробувати поспілкуватися з {}", + "title-blocked-users": "Заблоковані користувачі", + "label-timestamp": "Позначка часу", + "label-confirm-new-password": "Підтвердити новий пароль", + "button-text-import": "імпорт", + "list-item-settings-24h-format": "24-годинний формат часу", + "list-item-settings-view-uploaded-media": "Переглянути всі вивантажені медіафайли", + "list-item-settings-force-full-sync": "Примусова повна синхронізація", + "title-dialog-enter-new-screen-lock-pin": "Введіть новий PIN-код блокування екрана", + "subtitle-manual-sync": "Примусова matrix-синхронізація на основі позначки часу останньої синхронізації", + "alert-wait-for-full-sync-before-switching": "Дочекайтеся завершення повної синхронізації перед перемиканням облікових записів", + "content-export-session-keys": "Введіть пароль для резервного копіювання ключа цього сеансу.\n\nЗауважте, що експорт може тривати деякий час.", + "content-logout-multiaccount-confirm": "\n\nОскільки у вас є інші облікові записи, після виходу ви перейдете до іншого сеансу облікового запису.", + "semantics-image-password-update": "Користувач вигадує пароль у вирі вітру" } From 9130bd170ac9b938be5902ff4a3e31e2ce47e36a Mon Sep 17 00:00:00 2001 From: albanobattistella Date: Sun, 20 Mar 2022 15:07:11 +0000 Subject: [PATCH 17/22] Translated using Weblate (Italian) Currently translated at 91.1% (308 of 338 strings) Translation: Syphon/Translations Translate-URL: https://hosted.weblate.org/projects/syphon/syphon/it/ --- assets/translations/it.json | 39 ++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/assets/translations/it.json b/assets/translations/it.json index a7e37125e..8a3b0a52a 100644 --- a/assets/translations/it.json +++ b/assets/translations/it.json @@ -269,5 +269,42 @@ "list-item-chat-detail-vibrate": "Vibrazione", "content-notification-style-type-inbox": "Raggruppa i nuovi messaggi in una notifica", "label-show-attachment-options": "Apri le opzioni degli allegati", - "content-support-dialog": "La comunità di Syphon è qui per aiutarti come può.\n\nSentiti libero/a di unirti alla nostra chat di supporto o inviarci un'e-mail. Tieni presente che l'e-mail può richiedere da 1 a 5 giorni lavorativi per una risposta!" + "content-support-dialog": "La comunità di Syphon è qui per aiutarti come può.\n\nSentiti libero/a di unirti alla nostra chat di supporto o inviarci un'e-mail. Tieni presente che l'e-mail può richiedere da 1 a 5 giorni lavorativi per una risposta!", + "header-general": "Generale", + "header-ordering": "Ordinamento", + "header-media": "Media", + "header-update-password": "Aggiorna password", + "title-dialog-sync-interval": "Modifica intervallo di sincronizzazione", + "title-dialog-chat-with-user": "Chatta con {}", + "title-dialog-attempt-chat-with-user": "Prova a chattare con {}", + "title-blocked-users": "Utenti bloccati", + "title-import-session-keys": "Importa chiavi di sessione", + "title-export-session-keys": "Esporta chiavi di sessione", + "title-dialog-confirm-deactivate-account": "Conferma Disattivazione Account", + "title-dialog-backup-session-keys": "Chiavi di sessione di backup", + "title-dialog-remove-screen-lock": "Rimuovi Blocco schermo", + "title-dialog-enter-screen-lock-pin": "Inserisci il PIN di blocco dello schermo corrente", + "title-dialog-enter-new-screen-lock-pin": "Inserisci il tuo nuovo pin di blocco dello schermo", + "title-dialog-verify-new-screen-lock-pin": "Inserisci di nuovo il tuo PIN per verificare", + "subtitle-settings-enter-sends": "Premendo il tasto Invio verrà inviato un messaggio", + "subtitle-settings-view-uploaded-media": "Visualizza tutti i dati caricati, anche quelli non accessibili dai messaggi", + "subtitle-theme-settings": "Tema {}, Font {}", + "label-version": "Versione", + "label-seconds": "secondi", + "label-search-for-user": "Cerca un utente...", + "label-current-password": "Password attuale", + "label-new-password": "Nuova password", + "label-confirm-new-password": "Conferma nuova password", + "button-text-import": "importa", + "button-text-remove": "Rimuovi", + "list-item-settings-language": "Lingua", + "label-syncing": "Sincronizzazione", + "subtitle-settings-24h-format": "Mostra i timestamp dei messaggi utilizzando il formato 24 ore", + "header-media-auto-download": "Download automatico dei media", + "title-dialog-logout": "Logout", + "title-dialog-confirm-deactivate-account-final": "Conferma Finale Disattivazione Account", + "subtitle-settings-show-membership-events": "Mostra le modifiche all'interno della chat", + "subtitle-settings-dismiss-keyboard": "Chiudi la tastiera dopo aver inviato un messaggio", + "subtitle-images-audio-video-files": "Immagini, audio, video, file", + "list-item-settings-sort-by": "Ordina per" } From 34fa3d932dde8bd08c45a0d78fdf22a7ce106c81 Mon Sep 17 00:00:00 2001 From: "J. Lavoie" Date: Mon, 21 Mar 2022 20:37:45 +0000 Subject: [PATCH 18/22] Translated using Weblate (French) Currently translated at 100.0% (338 of 338 strings) Translation: Syphon/Translations Translate-URL: https://hosted.weblate.org/projects/syphon/syphon/fr/ --- assets/translations/fr.json | 69 ++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/assets/translations/fr.json b/assets/translations/fr.json index 3a02b80b3..7b5de94a8 100644 --- a/assets/translations/fr.json +++ b/assets/translations/fr.json @@ -269,5 +269,72 @@ "content-notification-style-type-latest": "Afficher une notification avec le message le plus récent", "content-notification-style-type-itemized": "Une nouvelle notification apparaîtra pour chaque nouveau message", "label-show-attachment-options": "Ouvrir les options de pièce jointe", - "content-support-dialog": "La communauté Syphon est là pour vous aider dans la mesure de ses possibilités.\n\nN'hésitez pas à rejoindre notre discussion d'assistance ou à nous envoyer un courriel. Veuillez noter que la réponse à un courriel peut prendre de 1 à 5 jours ouvrables !" + "content-support-dialog": "La communauté Syphon est là pour vous aider dans la mesure de ses possibilités.\n\nN'hésitez pas à rejoindre notre discussion d'assistance ou à nous envoyer un courriel. Veuillez noter que la réponse à un courriel peut prendre de 1 à 5 jours ouvrables !", + "header-ordering": "Classement", + "header-update-password": "Mettre à jour le mot de passe", + "title-dialog-sync-interval": "Modifier l'intervalle de synchronisation", + "title-dialog-attempt-chat-with-user": "Essayer de discuter avec {}", + "title-blocked-users": "Utilisateurs bloqués", + "title-export-session-keys": "Exporter les clés de session", + "title-dialog-confirm-deactivate-account": "Confirmer la désactivation du compte", + "title-dialog-confirm-deactivate-account-final": "Confirmer la désactivation finale du compte", + "title-dialog-remove-screen-lock": "Supprimer le verrouillage de l'écran", + "title-dialog-enter-screen-lock-pin": "Saisissez votre code de verrouillage actuel", + "title-dialog-verify-new-screen-lock-pin": "Entrez à nouveau votre code pour confirmer", + "subtitle-settings-show-membership-events": "Afficher les changements de membres dans la discussion", + "subtitle-settings-enter-sends": "En appuyant sur la touche Entrée, vous enverrez un message", + "subtitle-settings-dismiss-keyboard": "Désactiver le clavier après avoir envoyé un message", + "subtitle-settings-view-uploaded-media": "Voir toutes les données téléversées, même celles qui ne sont pas accessibles à partir des messages", + "subtitle-theme-settings": "Thème {}, police {}", + "subtitle-privacy-settings": "Verrouillage de l'écran {}, verrouillage de l'enregistrement {}", + "label-seconds": "secondes", + "label-new-password": "Nouveau mot de passe", + "button-text-remove": "Retirer", + "list-item-settings-show-membership-events": "Afficher les évènements d'adhésion", + "list-item-settings-enter-sends": "La touche Entrée envoie", + "list-item-settings-24h-format": "Format de l'heure en 24 heures", + "list-item-settings-dismiss-keyboard": "Désactiver le clavier", + "list-item-settings-group-by": "Regrouper par", + "list-item-settings-view-uploaded-media": "Voir tous les médias téléversés", + "list-item-settings-auto-download": "Téléchargement automatique", + "list-item-settings-when-using-wi-fi": "En Wi-Fi", + "list-item-settings-when-roaming": "En itinérance", + "list-item-settings-manual-sync": "Synchronisation manuelle", + "list-item-settings-force-full-sync": "Forcer la synchronisation complète", + "content-logout-confirm": "Voulez-vous vraiment vous déconnecter ?", + "content-logout-multiaccount-confirm": "\n\nComme vous avez d'autres comptes, la déconnexion vous fera passer à une autre session de compte.", + "content-remove-screen-lock": "Voulez-vous vraiment supprimer le verrouillage de l'écran ? Ceci supprimera également la protection par NIP du cache", + "title-dialog-logout": "Se déconnecter", + "header-media": "Média", + "subtitle-settings-24h-format": "Afficher l'horodatage des messages au format 24 heures", + "header-general": "Général", + "header-media-auto-download": "Téléchargement automatique des médias", + "title-dialog-chat-with-user": "Discuter avec {}", + "title-import-session-keys": "Importer les clés de session", + "title-dialog-backup-session-keys": "Clés de session de sauvegarde", + "title-dialog-enter-new-screen-lock-pin": "Saisissez votre nouveau code de verrouillage", + "label-timestamp": "Horodatage", + "label-current-password": "Mot de passe actuel", + "list-item-settings-language": "Langue", + "subtitle-images-audio-video-files": "Images, audio, vidéo, fichiers", + "subtitle-force-full-sync": "Effectuer une synchronisation complète forcée de toutes les données et de tous les messages de l'utilisateur", + "label-none": "Aucun", + "label-version": "Version", + "label-search-for-user": "Rechercher un utilisateur…", + "button-text-import": "importer", + "subtitle-manual-sync": "Effectuer une synchronisation forcée de Matrix en fonction de l'horodatage de la dernière synchronisation", + "label-stopped": "Arrêté", + "list-item-settings-sort-by": "Trier par", + "label-syncing": "Synchronisation", + "button-text-confirm-delete-keys": "Supprimer les clés", + "label-confirm-new-password": "Confirmer le nouveau mot de passe", + "list-item-settings-when-using-mobile-data": "En utilisant les données mobiles", + "alert-storage-access-required-for-keys": "Saisissez le mot de passe pour cette importation de clé de session.", + "alert-wait-for-full-sync-before-switching": "Attendez la fin de la synchronisation complète avant de changer de compte", + "content-export-session-keys": "Saisissez un mot de passe pour cette sauvegarde de clé de session.\n\nVeuillez noter que l'exportation peut prendre un certain temps.", + "alert-log-out-enable-multiaccount": "Vous devez vous déconnecter de votre\\nsession actuelle pour activer le multicompte", + "content-import-session-keys-enter-password": "Saisissez le mot de passe pour cette importation de clé de session.", + "content-export-session-keys-enter-password": "Saisissez un mot de passe pour crypter vos clés de session.", + "content-import-session-keys": "Saisissez le mot de passe pour cette importation de clé de session.\n\nVeuillez noter que l'importation peut prendre un certain temps.", + "semantics-image-password-update": "Utilisateur imaginant un mot de passe dans un tourbillon de vent" } From 7772790d362d0e41ea2f233ca8d028cab8172d7d Mon Sep 17 00:00:00 2001 From: "J. Lavoie" Date: Mon, 21 Mar 2022 22:52:27 +0000 Subject: [PATCH 19/22] Translated using Weblate (Italian) Currently translated at 94.0% (318 of 338 strings) Translation: Syphon/Translations Translate-URL: https://hosted.weblate.org/projects/syphon/syphon/it/ --- assets/translations/it.json | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/assets/translations/it.json b/assets/translations/it.json index 8a3b0a52a..c8908aa9c 100644 --- a/assets/translations/it.json +++ b/assets/translations/it.json @@ -280,7 +280,7 @@ "title-blocked-users": "Utenti bloccati", "title-import-session-keys": "Importa chiavi di sessione", "title-export-session-keys": "Esporta chiavi di sessione", - "title-dialog-confirm-deactivate-account": "Conferma Disattivazione Account", + "title-dialog-confirm-deactivate-account": "Conferma la disattivazione dell'account", "title-dialog-backup-session-keys": "Chiavi di sessione di backup", "title-dialog-remove-screen-lock": "Rimuovi Blocco schermo", "title-dialog-enter-screen-lock-pin": "Inserisci il PIN di blocco dello schermo corrente", @@ -300,11 +300,21 @@ "list-item-settings-language": "Lingua", "label-syncing": "Sincronizzazione", "subtitle-settings-24h-format": "Mostra i timestamp dei messaggi utilizzando il formato 24 ore", - "header-media-auto-download": "Download automatico dei media", - "title-dialog-logout": "Logout", - "title-dialog-confirm-deactivate-account-final": "Conferma Finale Disattivazione Account", + "header-media-auto-download": "Scaricamento automatico dei media", + "title-dialog-logout": "Esci", + "title-dialog-confirm-deactivate-account-final": "Conferma finale disattivazione account", "subtitle-settings-show-membership-events": "Mostra le modifiche all'interno della chat", "subtitle-settings-dismiss-keyboard": "Chiudi la tastiera dopo aver inviato un messaggio", "subtitle-images-audio-video-files": "Immagini, audio, video, file", - "list-item-settings-sort-by": "Ordina per" + "list-item-settings-sort-by": "Ordina per", + "subtitle-privacy-settings": "Blocco schermo {}, Blocco registrazione {}", + "subtitle-manual-sync": "Esegui una sincronizzazione forzata della matrice in base alla marca temporale dell'ultima sincronizzazione", + "subtitle-force-full-sync": "Esegui una sincronizzazione completa forzata di tutti i dati e messaggi dell'utente", + "label-timestamp": "Marca temporale", + "label-none": "Nessuna", + "label-stopped": "Fermato", + "list-item-settings-group-by": "Raggruppa per", + "list-item-settings-auto-download": "Scaricamento automatico", + "list-item-settings-view-uploaded-media": "Visualizza tutti i media caricati", + "list-item-settings-when-using-mobile-data": "Quando si usano i dati mobili" } From 9bcb46b2e950462068bb3d582577bbc7eea4e9d8 Mon Sep 17 00:00:00 2001 From: Eshagh Shahedany Date: Tue, 22 Mar 2022 06:49:43 +0100 Subject: [PATCH 20/22] Added translation using Weblate (Persian) --- assets/translations/fa.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 assets/translations/fa.json diff --git a/assets/translations/fa.json b/assets/translations/fa.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/assets/translations/fa.json @@ -0,0 +1 @@ +{} From 01142e34ea6e8dbfa6afec34b7039a0c962a04eb Mon Sep 17 00:00:00 2001 From: ereio Date: Tue, 22 Mar 2022 18:42:18 -0400 Subject: [PATCH 21/22] fix: string mapping issues, remove ipad support for release --- assets/translations/ar.json | 2 +- assets/translations/cs.json | 2 +- assets/translations/de.json | 2 +- assets/translations/en-Shaw.json | 2 +- assets/translations/en.json | 2 +- assets/translations/eu.json | 2 +- assets/translations/fr.json | 2 +- assets/translations/hu.json | 2 +- assets/translations/id.json | 2 +- assets/translations/it.json | 2 +- assets/translations/ru.json | 2 +- assets/translations/uk.json | 2 +- ios/Runner.xcodeproj/project.pbxproj | 12 ++++++------ pubspec.yaml | 2 +- 14 files changed, 19 insertions(+), 19 deletions(-) diff --git a/assets/translations/ar.json b/assets/translations/ar.json index ff661862b..1817c01db 100644 --- a/assets/translations/ar.json +++ b/assets/translations/ar.json @@ -224,7 +224,7 @@ "title-dialog-draft-preview": "معاينة المسودة", "label-color": "اللون", "button-text-go-back": "الرجوع للخلف", - "list-item-user-details-confirm-start-chat": "الدردشة مع {}", + "list-item-user-details-start-chat": "الدردشة مع {}", "label-search-unencrypted": "البحث غير مشفر", "label-chat-settings": "إعدادات الدردشة", "button-gallery": "المعرض", diff --git a/assets/translations/cs.json b/assets/translations/cs.json index 93ea446d2..b69f113f9 100644 --- a/assets/translations/cs.json +++ b/assets/translations/cs.json @@ -248,7 +248,7 @@ "list-item-settings-proxy-password": "Proxy heslo", "list-item-settings-sync-interval": "Interval synchronizace", "list-item-user-details-invite-to-room": "Pozvat do místnosti", - "list-item-user-details-confirm-start-chat": "Psát si s {}", + "list-item-user-details-start-chat": "Psát si s {}", "list-item-user-details-send-message": "Poslat správu", "list-item-advanced-settings-start-background": "Spustit službu na pozadí", "list-item-advanced-settings-test-sync-loop": "Test synchronizace na pozadí", diff --git a/assets/translations/de.json b/assets/translations/de.json index d111994a1..ca5c370e1 100644 --- a/assets/translations/de.json +++ b/assets/translations/de.json @@ -202,7 +202,7 @@ "list-item-chat-detail-view-key": "Schlüssel anzeigen", "list-item-settings-sync-toggle": "Synchronisation an/aus", "list-item-user-details-invite-to-room": "In Raum einladen", - "list-item-user-details-confirm-start-chat": "Reden mit {}", + "list-item-user-details-start-chat": "Reden mit {}", "list-item-user-details-unblock-user": "Benutzer entsperren", "list-item-user-details-block-user": "Benutzer sperren", "list-item-image-options-photo-select-method": "Fotoauswahlverfahren", diff --git a/assets/translations/en-Shaw.json b/assets/translations/en-Shaw.json index 4738153be..d3da72fb9 100644 --- a/assets/translations/en-Shaw.json +++ b/assets/translations/en-Shaw.json @@ -153,7 +153,7 @@ "list-item-settings-sync-interval": "𐑕𐑦𐑙𐑒 𐑦𐑯𐑑𐑼𐑝𐑩𐑤", "list-item-settings-sync-toggle": "𐑑𐑪𐑜𐑩𐑤 𐑕𐑦𐑙𐑒𐑦𐑙", "list-item-user-details-invite-to-room": "𐑦𐑯𐑝𐑲𐑑 𐑑 𐑮𐑵𐑥", - "list-item-user-details-confirm-start-chat": "𐑗𐑨𐑑 𐑢𐑦𐑞 {}", + "list-item-user-details-start-chat": "𐑗𐑨𐑑 𐑢𐑦𐑞 {}", "list-item-user-details-send-message": "𐑕𐑧𐑯𐑛 𐑩 𐑥𐑧𐑕𐑦𐑡", "list-item-user-details-view-profile": "𐑝𐑿 𐑐𐑮𐑴𐑓𐑲𐑤", "list-item-user-details-unblock-user": "𐑳𐑯𐑚𐑤𐑪𐑒 𐑿𐑟𐑼", diff --git a/assets/translations/en.json b/assets/translations/en.json index bfe33ff4e..47d268c21 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -209,7 +209,7 @@ "list-item-settings-manual-sync": "Manual Sync", "list-item-settings-force-full-sync": "Force Full Sync", "list-item-user-details-invite-to-room": "Invite to Room", - "list-item-user-details-confirm-start-chat": "Chat with {}", + "list-item-user-details-start-chat": "Chat with {}", "list-item-user-details-send-message": "Send A Message", "list-item-user-details-view-profile": "View Profile", "list-item-user-details-unblock-user": "Unblock User", diff --git a/assets/translations/eu.json b/assets/translations/eu.json index 098f7ca8c..53d60f4f9 100644 --- a/assets/translations/eu.json +++ b/assets/translations/eu.json @@ -99,7 +99,7 @@ "list-item-settings-sync-interval": "Sinkronizazio denbora-tartea", "list-item-settings-sync-toggle": "Piztu edo itzali sinkronizazioa", "list-item-user-details-invite-to-room": "Gonbidatu gelara", - "list-item-user-details-confirm-start-chat": "Txateatu {}(r)ekin", + "list-item-user-details-start-chat": "Txateatu {}(r)ekin", "list-item-user-details-send-message": "Bidali mezua", "list-item-user-details-view-profile": "Ikusi profila", "list-item-user-details-unblock-user": "Desblokeatu erabiltzailea", diff --git a/assets/translations/fr.json b/assets/translations/fr.json index 3a02b80b3..8964ffb79 100644 --- a/assets/translations/fr.json +++ b/assets/translations/fr.json @@ -192,7 +192,7 @@ "list-item-settings-sync-interval": "Intervalle de synchronisation", "list-item-settings-sync-toggle": "Activer/Désactiver la synchronisation", "list-item-user-details-invite-to-room": "Inviter dans le groupe", - "list-item-user-details-confirm-start-chat": "Discuter avec {}", + "list-item-user-details-start-chat": "Discuter avec {}", "list-item-user-details-view-profile": "Voir le profil", "list-item-user-details-unblock-user": "Débloquer l'utilisateur", "list-item-user-details-block-user": "Bloquer l'utilisateur", diff --git a/assets/translations/hu.json b/assets/translations/hu.json index 835b7e873..bb4b6a78b 100644 --- a/assets/translations/hu.json +++ b/assets/translations/hu.json @@ -210,7 +210,7 @@ "list-item-chat-detail-notification-setting": "Értesítési beállítások", "button-chat-details": "beszélgetés részletei", "list-item-chat-detail-vibrate": "Rezgés", - "list-item-user-details-confirm-start-chat": "Beszélgetés {} felhasználóval", + "list-item-user-details-start-chat": "Beszélgetés {} felhasználóval", "list-item-image-options-remove-photo": "Kép eltávolítása", "list-item-advanced-settings-stop-background": "Összes Service megállítása", "content-notification-style-type-itemized": "Új értesítés mutatása minden egyes új üzenethez", diff --git a/assets/translations/id.json b/assets/translations/id.json index 43df187d8..95a4629b7 100644 --- a/assets/translations/id.json +++ b/assets/translations/id.json @@ -208,7 +208,7 @@ "list-item-settings-sync-interval": "Interval Sinkronisasi", "list-item-settings-sync-toggle": "Alih Sinkronisasi", "list-item-user-details-invite-to-room": "Undang ke Ruangan", - "list-item-user-details-confirm-start-chat": "Obrol dengan {}", + "list-item-user-details-start-chat": "Obrol dengan {}", "list-item-user-details-send-message": "Kirim Sebuah Pesan", "list-item-user-details-view-profile": "Tampilkan Profil", "list-item-user-details-unblock-user": "Hilangkan Pemblokiran Pengguna", diff --git a/assets/translations/it.json b/assets/translations/it.json index a7e37125e..109695b53 100644 --- a/assets/translations/it.json +++ b/assets/translations/it.json @@ -249,7 +249,7 @@ "tooltip-profile-settings": "Profilo e impostazioni", "tooltip-search-chats": "Cerca discussioni", "tooltip-cancel-reply": "Annulla la risposta", - "list-item-user-details-confirm-start-chat": "Parla con {}", + "list-item-user-details-start-chat": "Parla con {}", "subtitle-proxy-use-basic-authentication": "Fornisci nome utente e password per autenticarsi con un proxy", "content-proxy-password": "La password per l'autenticazione con il tuo proxy", "title-proxy-password": "Modifica la password del proxy", diff --git a/assets/translations/ru.json b/assets/translations/ru.json index f1502b2a4..219d18a70 100644 --- a/assets/translations/ru.json +++ b/assets/translations/ru.json @@ -162,7 +162,7 @@ "list-item-user-details-send-message": "Отправить Сообщение", "list-item-user-details-block-user": "Заблокировать Пользователя", "list-item-chat-detail-notification-setting": "Настройки Уведомлений", - "list-item-user-details-confirm-start-chat": "Чат с {}", + "list-item-user-details-start-chat": "Чат с {}", "list-item-user-details-unblock-user": "Разблокировать Пользователя", "list-item-chat-detail-notifications": "Уведомления", "list-item-chat-detail-vibrate": "Вибрация", diff --git a/assets/translations/uk.json b/assets/translations/uk.json index d99e5b0a6..8a76fea1e 100644 --- a/assets/translations/uk.json +++ b/assets/translations/uk.json @@ -194,7 +194,7 @@ "label-default-room-notification": "Типовий (Argon)", "label-search-unencrypted": "Шукати незашифровано", "alert-invite-user-unknown": "Цього користувача немає у matrix, але ви можете спробувати запросити їх.\n\nПерш ніж спробувати, переконайтеся, що у вас є правильне ім'я.", - "list-item-user-details-confirm-start-chat": "Спілкуватися з {}", + "list-item-user-details-start-chat": "Спілкуватися з {}", "list-item-advanced-settings-force-function": "Примусова функція", "alert-restart-app-effect": "Щоб зміни набрати чинності, потрібно закрити та перезапустити застосунок", "alert-feature-in-progress": "🛠 Ця функція з'явиться незабаром", diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 7a52d7929..ac1fac21b 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -355,7 +355,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 2111; + CURRENT_PROJECT_VERSION = 2120; DEVELOPMENT_TEAM = W98LUTKH5G; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -371,7 +371,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - MARKETING_VERSION = 0.2.11; + MARKETING_VERSION = 0.2.12; PRODUCT_BUNDLE_IDENTIFIER = org.tether.tether; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -496,7 +496,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 2111; + CURRENT_PROJECT_VERSION = 2120; DEVELOPMENT_TEAM = W98LUTKH5G; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -512,7 +512,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - MARKETING_VERSION = 0.2.11; + MARKETING_VERSION = 0.2.12; PRODUCT_BUNDLE_IDENTIFIER = org.tether.tether; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -529,7 +529,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 2111; + CURRENT_PROJECT_VERSION = 2120; DEVELOPMENT_TEAM = W98LUTKH5G; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -545,7 +545,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - MARKETING_VERSION = 0.2.11; + MARKETING_VERSION = 0.2.12; PRODUCT_BUNDLE_IDENTIFIER = org.tether.tether; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; diff --git a/pubspec.yaml b/pubspec.yaml index 565f778e6..001e62a22 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: syphon description: a privacy focused matrix client -version: 0.2.11+2111 +version: 0.2.12+2122 environment: sdk: ">=2.12.0 <3.0.0" From 449610d5e6f05e2cbbf3664c28bdd5c8a68cfd26 Mon Sep 17 00:00:00 2001 From: ereio Date: Tue, 22 Mar 2022 21:19:10 -0400 Subject: [PATCH 22/22] fix: invite dialog dismiss --- lib/views/home/chat/chat-screen.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/views/home/chat/chat-screen.dart b/lib/views/home/chat/chat-screen.dart index a0a9eafb0..508fef824 100644 --- a/lib/views/home/chat/chat-screen.dart +++ b/lib/views/home/chat/chat-screen.dart @@ -93,14 +93,16 @@ class ChatScreenState extends State { showDialog( context: context, barrierDismissible: false, - builder: (_) => DialogInvite( + builder: (dialogContext) => DialogInvite( onAccept: props.onAcceptInvite, onReject: () { props.onRejectInvite(); Navigator.popUntil(context, (route) => route.isFirst); + Navigator.pop(dialogContext); }, onCancel: () { Navigator.popUntil(context, (route) => route.isFirst); + Navigator.pop(dialogContext); }, ), );