From f84ac1d1216e3ceb5209a3cf0389490e4ad3bca8 Mon Sep 17 00:00:00 2001 From: Christian Pauly Date: Sun, 4 Oct 2020 09:16:46 +0200 Subject: [PATCH 01/17] fix: Minor user status bugs --- lib/components/matrix.dart | 58 ++++++++++++++++++++------------------ lib/views/status_view.dart | 2 ++ pubspec.lock | 52 +++++++++++++++++----------------- 3 files changed, 58 insertions(+), 54 deletions(-) diff --git a/lib/components/matrix.dart b/lib/components/matrix.dart index 2306404..cf25467 100644 --- a/lib/components/matrix.dart +++ b/lib/components/matrix.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:convert'; import 'dart:io'; import 'package:famedlysdk/encryption.dart'; @@ -55,6 +54,8 @@ class MatrixState extends State { @override BuildContext context; + static const String userStatusesType = 'chat.fluffy.user_statuses'; + Map get shareContent => _shareContent; set shareContent(Map content) { _shareContent = content; @@ -90,6 +91,7 @@ class MatrixState extends State { widget.clientName, ); } + _cleanUpUserStatus(userStatuses); } Map getAuthByPassword(String password, [String session]) => { @@ -195,16 +197,6 @@ class MatrixState extends State { @override void initState() { store = widget.store ?? Store(); - store.getItem('fluffychat.user_statuses').then( - (json) { - userStatuses = json == null - ? [] - : (jsonDecode(json)['user_statuses'] as List) - .map((j) => UserStatus.fromJson(j)) - .toList(); - _cleanUpUserStatus(); - }, - ); if (widget.client == null) { debugPrint('[Matrix] Init matrix client'); final Set verificationMethods = { @@ -303,9 +295,18 @@ class MatrixState extends State { super.initState(); } - List userStatuses = []; + List get userStatuses { + try { + return (client.accountData[userStatusesType].content['user_statuses'] + as List) + .map((json) => UserStatus.fromJson(json)) + .toList(); + } catch (_) {} + return []; + } void _storeUserStatus(Presence presence) { + final tmpUserStatuses = List.from(userStatuses); final currentStatusIndex = userStatuses.indexWhere((u) => u.userId == presence.senderId); final newUserStatus = UserStatus() @@ -313,36 +314,37 @@ class MatrixState extends State { ..statusMsg = presence.presence.statusMsg ..userId = presence.senderId; if (currentStatusIndex == -1) { - userStatuses.add(newUserStatus); - } else if (userStatuses[currentStatusIndex].statusMsg != + tmpUserStatuses.add(newUserStatus); + } else if (tmpUserStatuses[currentStatusIndex].statusMsg != presence.presence.statusMsg) { if (presence.presence.statusMsg.trim().isEmpty) { - userStatuses.removeAt(currentStatusIndex); + tmpUserStatuses.removeAt(currentStatusIndex); } else { - userStatuses[currentStatusIndex] = newUserStatus; + tmpUserStatuses[currentStatusIndex] = newUserStatus; } } else { return; } - _cleanUpUserStatus(); + _cleanUpUserStatus(tmpUserStatuses); } - void _cleanUpUserStatus() { + void _cleanUpUserStatus(List tmpUserStatuses) { final now = DateTime.now().millisecondsSinceEpoch; - userStatuses + tmpUserStatuses .removeWhere((u) => (now - u.receivedAt) > (1000 * 60 * 60 * 24)); - userStatuses.sort((a, b) => b.receivedAt.compareTo(a.receivedAt)); - if (userStatuses.length > 40) { - userStatuses.removeRange(40, userStatuses.length); + tmpUserStatuses.sort((a, b) => b.receivedAt.compareTo(a.receivedAt)); + if (tmpUserStatuses.length > 40) { + tmpUserStatuses.removeRange(40, tmpUserStatuses.length); } - store.setItem( - 'fluffychat.user_statuses', - jsonEncode( + if (tmpUserStatuses != userStatuses) { + client.setAccountData( + client.userID, + userStatusesType, { - 'user_statuses': userStatuses.map((i) => i.toJson()).toList(), + 'user_statuses': tmpUserStatuses.map((i) => i.toJson()).toList(), }, - ), - ); + ); + } } @override diff --git a/lib/views/status_view.dart b/lib/views/status_view.dart index d2b0bea..0ea3ba2 100644 --- a/lib/views/status_view.dart +++ b/lib/views/status_view.dart @@ -81,6 +81,7 @@ class StatusView extends StatelessWidget { backgroundColor: displayname.color, extendBody: true, appBar: AppBar( + titleSpacing: 0.0, brightness: Brightness.dark, leading: IconButton( icon: Icon( @@ -100,6 +101,7 @@ class StatusView extends StatelessWidget { ), subtitle: Text( status?.userId ?? Matrix.of(context).client.userID, + maxLines: 1, style: TextStyle(color: Colors.white), ), ), diff --git a/pubspec.lock b/pubspec.lock index ae41de7..2d4e578 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -49,7 +49,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.4.2" + version: "2.5.0-nullsafety.1" base58check: dependency: transitive description: @@ -63,7 +63,7 @@ packages: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0-nullsafety.1" bot_toast: dependency: "direct main" description: @@ -91,14 +91,14 @@ packages: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.1.0-nullsafety.3" charcode: dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.1.3" + version: "1.2.0-nullsafety.1" cli_util: dependency: transitive description: @@ -112,14 +112,14 @@ packages: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "1.1.0-nullsafety.1" collection: dependency: transitive description: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.14.13" + version: "1.15.0-nullsafety.3" convert: dependency: transitive description: @@ -175,7 +175,7 @@ packages: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.2.0-nullsafety.1" famedlysdk: dependency: "direct main" description: @@ -456,7 +456,7 @@ packages: name: js url: "https://pub.dartlang.org" source: hosted - version: "0.6.2" + version: "0.6.3-nullsafety.1" localstorage: dependency: "direct main" description: @@ -484,7 +484,7 @@ packages: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.8" + version: "0.12.10-nullsafety.1" matrix_file_e2ee: dependency: transitive description: @@ -512,7 +512,7 @@ packages: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.1.8" + version: "1.3.0-nullsafety.3" mime: dependency: transitive description: @@ -605,7 +605,7 @@ packages: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "1.8.0-nullsafety.1" path_provider: dependency: "direct main" description: @@ -647,7 +647,7 @@ packages: name: pedantic url: "https://pub.dartlang.org" source: hosted - version: "1.9.0" + version: "1.10.0-nullsafety.1" petitparser: dependency: transitive description: @@ -689,7 +689,7 @@ packages: name: pool url: "https://pub.dartlang.org" source: hosted - version: "1.4.0" + version: "1.5.0-nullsafety.1" process: dependency: transitive description: @@ -792,21 +792,21 @@ packages: name: source_map_stack_trace url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0-nullsafety.2" source_maps: dependency: transitive description: name: source_maps url: "https://pub.dartlang.org" source: hosted - version: "0.10.9" + version: "0.10.10-nullsafety.1" source_span: dependency: transitive description: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "1.8.0-nullsafety.2" sqflite: dependency: "direct main" description: @@ -841,21 +841,21 @@ packages: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.9.5" + version: "1.10.0-nullsafety.1" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0-nullsafety.1" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.0.5" + version: "1.1.0-nullsafety.1" synchronized: dependency: transitive description: @@ -869,35 +869,35 @@ packages: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.2.0-nullsafety.1" test: dependency: transitive description: name: test url: "https://pub.dartlang.org" source: hosted - version: "1.15.2" + version: "1.16.0-nullsafety.5" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.17" + version: "0.2.19-nullsafety.2" test_core: dependency: transitive description: name: test_core url: "https://pub.dartlang.org" source: hosted - version: "0.3.10" + version: "0.3.12-nullsafety.5" typed_data: dependency: transitive description: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.0-nullsafety.3" universal_html: dependency: "direct main" description: @@ -981,7 +981,7 @@ packages: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.0.8" + version: "2.1.0-nullsafety.3" vm_service: dependency: transitive description: @@ -1053,5 +1053,5 @@ packages: source: hosted version: "0.1.2" sdks: - dart: ">=2.9.0 <3.0.0" + dart: ">=2.10.0-110 <2.11.0" flutter: ">=1.20.0 <2.0.0" From 6ffbf16cffca01285a2933140a5301eb339dd94c Mon Sep 17 00:00:00 2001 From: Christian Pauly Date: Sun, 4 Oct 2020 10:05:00 +0200 Subject: [PATCH 02/17] fix: Minor design bugs --- lib/components/connection_status_header.dart | 2 +- lib/components/list_items/chat_list_item.dart | 7 ++----- lib/components/theme_switcher.dart | 2 +- lib/views/chat.dart | 2 +- lib/views/chat_list.dart | 2 +- 5 files changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/components/connection_status_header.dart b/lib/components/connection_status_header.dart index 0789f18..c016ac9 100644 --- a/lib/components/connection_status_header.dart +++ b/lib/components/connection_status_header.dart @@ -36,7 +36,7 @@ class _ConnectionStatusHeaderState extends State { ); return AnimatedContainer( - duration: Duration(milliseconds: 500), + duration: Duration(milliseconds: 300), height: _connected ? 0 : 5, child: LinearProgressIndicator(), ); diff --git a/lib/components/list_items/chat_list_item.dart b/lib/components/list_items/chat_list_item.dart index f42f9ba..1111fe5 100644 --- a/lib/components/list_items/chat_list_item.dart +++ b/lib/components/list_items/chat_list_item.dart @@ -143,8 +143,7 @@ class ChatListItem extends StatelessWidget { ? Padding( padding: const EdgeInsets.only(left: 4.0), child: Icon( - Icons.favorite, - color: Colors.grey[400], + Icons.favorite_outline_rounded, size: 16, ), ) @@ -153,8 +152,7 @@ class ChatListItem extends StatelessWidget { ? Padding( padding: const EdgeInsets.only(left: 4.0), child: Icon( - Icons.notifications_off, - color: Colors.grey[400], + Icons.notifications_off_outlined, size: 16, ), ) @@ -164,7 +162,6 @@ class ChatListItem extends StatelessWidget { child: Text( room.timeCreated.localizedTimeShort(context), style: TextStyle( - color: Color(0xFF555555), fontSize: 13, ), ), diff --git a/lib/components/theme_switcher.dart b/lib/components/theme_switcher.dart index 892bd5a..300bf72 100644 --- a/lib/components/theme_switcher.dart +++ b/lib/components/theme_switcher.dart @@ -114,7 +114,7 @@ final ThemeData amoledTheme = ThemeData.dark().copyWith( Color chatListItemColor(BuildContext context, bool activeChat, bool selected) => selected - ? Theme.of(context).primaryColor.withAlpha(50) + ? Theme.of(context).primaryColor.withAlpha(100) : Theme.of(context).brightness == Brightness.light ? activeChat ? Color(0xFFE8E8E8) diff --git a/lib/views/chat.dart b/lib/views/chat.dart index ad726c4..a2f525b 100644 --- a/lib/views/chat.dart +++ b/lib/views/chat.dart @@ -619,7 +619,7 @@ class _ChatState extends State<_Chat> { height: seenByText.isEmpty ? 0 : 24, duration: seenByText.isEmpty ? Duration(milliseconds: 0) - : Duration(milliseconds: 500), + : Duration(milliseconds: 300), alignment: filteredEvents.first.senderId == client.userID diff --git a/lib/views/chat_list.dart b/lib/views/chat_list.dart index 8c94933..e126b5f 100644 --- a/lib/views/chat_list.dart +++ b/lib/views/chat_list.dart @@ -545,7 +545,7 @@ class _ChatListState extends State { children: [ AnimatedContainer( duration: Duration( - milliseconds: 500), + milliseconds: 300), height: displayPresences ? 78 : displayShareStatus From c8d3c9d614986fbf3698493a568f9d6a62c15d1d Mon Sep 17 00:00:00 2001 From: Christian Pauly Date: Sun, 4 Oct 2020 11:25:07 +0200 Subject: [PATCH 03/17] hotfix: Rethrow getDatabase exception --- lib/utils/famedlysdk_store.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/utils/famedlysdk_store.dart b/lib/utils/famedlysdk_store.dart index 5752ce7..95386f3 100644 --- a/lib/utils/famedlysdk_store.dart +++ b/lib/utils/famedlysdk_store.dart @@ -36,6 +36,8 @@ Future getDatabase(Client client) async { await store.setItem('database-password', password); } return _db; + } catch (_) { + rethrow; } finally { _generateDatabaseLock = false; } From 028b1e4ed8f4ab5644bdc6ea6feb1973088e4ac7 Mon Sep 17 00:00:00 2001 From: Christian Pauly Date: Sun, 4 Oct 2020 11:52:06 +0200 Subject: [PATCH 04/17] hotfix: Capture Exception --- lib/components/matrix.dart | 22 ++++++++++++++-------- lib/main.dart | 26 ++++++++++++++------------ lib/utils/famedlysdk_store.dart | 2 -- 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/lib/components/matrix.dart b/lib/components/matrix.dart index cf25467..d4b51ce 100644 --- a/lib/components/matrix.dart +++ b/lib/components/matrix.dart @@ -15,6 +15,7 @@ import 'package:localstorage/localstorage.dart'; import 'package:universal_html/prefer_universal/html.dart' as html; import 'package:url_launcher/url_launcher.dart'; +import '../main.dart'; import '../utils/app_route.dart'; import '../utils/beautify_string_extension.dart'; import '../utils/famedlysdk_store.dart'; @@ -83,15 +84,20 @@ class MatrixState extends State { void _initWithStore() async { var initLoginState = client.onLoginStateChanged.stream.first; - client.database = await getDatabase(client); - client.connect(); - if (await initLoginState == LoginState.logged && PlatformInfos.isMobile) { - await FirebaseController.setupFirebase( - this, - widget.clientName, - ); + try { + client.database = await getDatabase(client); + client.connect(); + if (await initLoginState == LoginState.logged && PlatformInfos.isMobile) { + await FirebaseController.setupFirebase( + this, + widget.clientName, + ); + } + _cleanUpUserStatus(userStatuses); + } catch (e, s) { + client.onLoginStateChanged.sink.addError(e, s); + captureException(e, s); } - _cleanUpUserStatus(userStatuses); } Map getAuthByPassword(String password, [String session]) => { diff --git a/lib/main.dart b/lib/main.dart index 8a28a69..bdab3bb 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -18,23 +18,25 @@ import 'views/chat_list.dart'; final sentry = SentryClient(dsn: '8591d0d863b646feb4f3dda7e5dcab38'); +void captureException(error, stackTrace) async { + final storage = LocalStorage('LocalStorage'); + await storage.ready; + debugPrint(error.toString()); + debugPrint(stackTrace.toString()); + if (storage.getItem('sentry') == true) { + await sentry.captureException( + exception: error, + stackTrace: stackTrace, + ); + } +} + void main() { SystemChrome.setSystemUIOverlayStyle( SystemUiOverlayStyle(statusBarColor: Colors.transparent)); runZonedGuarded( () => runApp(App()), - (error, stackTrace) async { - final storage = LocalStorage('LocalStorage'); - await storage.ready; - debugPrint(error.toString()); - debugPrint(stackTrace.toString()); - if (storage.getItem('sentry') == true) { - await sentry.captureException( - exception: error, - stackTrace: stackTrace, - ); - } - }, + captureException, ); } diff --git a/lib/utils/famedlysdk_store.dart b/lib/utils/famedlysdk_store.dart index 95386f3..5752ce7 100644 --- a/lib/utils/famedlysdk_store.dart +++ b/lib/utils/famedlysdk_store.dart @@ -36,8 +36,6 @@ Future getDatabase(Client client) async { await store.setItem('database-password', password); } return _db; - } catch (_) { - rethrow; } finally { _generateDatabaseLock = false; } From 9b572f59a635435f11f7d5f44698ca13d60577a0 Mon Sep 17 00:00:00 2001 From: Christian Pauly Date: Sun, 4 Oct 2020 12:32:29 +0200 Subject: [PATCH 05/17] fix: More debug logs --- lib/components/matrix.dart | 5 ++++- lib/utils/famedlysdk_store.dart | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/components/matrix.dart b/lib/components/matrix.dart index d4b51ce..cc35c21 100644 --- a/lib/components/matrix.dart +++ b/lib/components/matrix.dart @@ -85,7 +85,9 @@ class MatrixState extends State { void _initWithStore() async { var initLoginState = client.onLoginStateChanged.stream.first; try { - client.database = await getDatabase(client); + client.database = await getDatabase(client).timeout( + Duration(seconds: 15), + ); client.connect(); if (await initLoginState == LoginState.logged && PlatformInfos.isMobile) { await FirebaseController.setupFirebase( @@ -97,6 +99,7 @@ class MatrixState extends State { } catch (e, s) { client.onLoginStateChanged.sink.addError(e, s); captureException(e, s); + rethrow; } } diff --git a/lib/utils/famedlysdk_store.dart b/lib/utils/famedlysdk_store.dart index 5752ce7..246827f 100644 --- a/lib/utils/famedlysdk_store.dart +++ b/lib/utils/famedlysdk_store.dart @@ -31,7 +31,9 @@ Future getDatabase(Client client) async { filename: 'moor.sqlite', password: password, ); + debugPrint('[Moor] Database has been created'); if (needMigration) { + debugPrint('[Moor] Start migration'); await migrate(client.clientName, _db, store); await store.setItem('database-password', password); } From 2f8491b41b0a743bd434dc33ae458ab7423a5447 Mon Sep 17 00:00:00 2001 From: Christian Pauly Date: Sun, 4 Oct 2020 13:07:04 +0200 Subject: [PATCH 06/17] hotfix: initWithStore --- lib/components/matrix.dart | 6 ++---- lib/utils/famedlysdk_store.dart | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/components/matrix.dart b/lib/components/matrix.dart index cc35c21..70a3a1f 100644 --- a/lib/components/matrix.dart +++ b/lib/components/matrix.dart @@ -85,10 +85,8 @@ class MatrixState extends State { void _initWithStore() async { var initLoginState = client.onLoginStateChanged.stream.first; try { - client.database = await getDatabase(client).timeout( - Duration(seconds: 15), - ); - client.connect(); + client.database = await getDatabase(client); + await client.connect(); if (await initLoginState == LoginState.logged && PlatformInfos.isMobile) { await FirebaseController.setupFirebase( this, diff --git a/lib/utils/famedlysdk_store.dart b/lib/utils/famedlysdk_store.dart index 246827f..31ce349 100644 --- a/lib/utils/famedlysdk_store.dart +++ b/lib/utils/famedlysdk_store.dart @@ -31,7 +31,6 @@ Future getDatabase(Client client) async { filename: 'moor.sqlite', password: password, ); - debugPrint('[Moor] Database has been created'); if (needMigration) { debugPrint('[Moor] Start migration'); await migrate(client.clientName, _db, store); From 0209a69722a935aae33c80fcf0cee9333fadd55a Mon Sep 17 00:00:00 2001 From: Christian Pauly Date: Sun, 4 Oct 2020 13:43:17 +0200 Subject: [PATCH 07/17] hotfix: login --- lib/components/matrix.dart | 15 +++++++++------ lib/main.dart | 4 ++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/components/matrix.dart b/lib/components/matrix.dart index 70a3a1f..01e46ad 100644 --- a/lib/components/matrix.dart +++ b/lib/components/matrix.dart @@ -87,13 +87,16 @@ class MatrixState extends State { try { client.database = await getDatabase(client); await client.connect(); - if (await initLoginState == LoginState.logged && PlatformInfos.isMobile) { - await FirebaseController.setupFirebase( - this, - widget.clientName, - ); + final firstLoginState = await initLoginState; + if (firstLoginState == LoginState.logged) { + _cleanUpUserStatus(userStatuses); + if (PlatformInfos.isMobile) { + await FirebaseController.setupFirebase( + this, + widget.clientName, + ); + } } - _cleanUpUserStatus(userStatuses); } catch (e, s) { client.onLoginStateChanged.sink.addError(e, s); captureException(e, s); diff --git a/lib/main.dart b/lib/main.dart index bdab3bb..334eb96 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -19,10 +19,10 @@ import 'views/chat_list.dart'; final sentry = SentryClient(dsn: '8591d0d863b646feb4f3dda7e5dcab38'); void captureException(error, stackTrace) async { - final storage = LocalStorage('LocalStorage'); - await storage.ready; debugPrint(error.toString()); debugPrint(stackTrace.toString()); + final storage = LocalStorage('LocalStorage'); + await storage.ready; if (storage.getItem('sentry') == true) { await sentry.captureException( exception: error, From 6e924cb531ed018c1bc892cb9acd8a35c24ba1df Mon Sep 17 00:00:00 2001 From: Christian Pauly Date: Sun, 4 Oct 2020 14:04:45 +0200 Subject: [PATCH 08/17] fix: Try with select 1 --- lib/utils/famedlysdk_store.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/utils/famedlysdk_store.dart b/lib/utils/famedlysdk_store.dart index 31ce349..87adbcd 100644 --- a/lib/utils/famedlysdk_store.dart +++ b/lib/utils/famedlysdk_store.dart @@ -31,6 +31,8 @@ Future getDatabase(Client client) async { filename: 'moor.sqlite', password: password, ); + // Check if database is open: + debugPrint((await _db.customSelect('SELECT 1').get()).toString()); if (needMigration) { debugPrint('[Moor] Start migration'); await migrate(client.clientName, _db, store); From 824b0cd3632d9dc2f48e59b273528549559b64a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Sun, 4 Oct 2020 12:53:12 +0000 Subject: [PATCH 09/17] Translated using Weblate (Estonian) Currently translated at 99.3% (310 of 312 strings) Translation: FluffyChat/Translations-New Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations-new/et/ --- lib/l10n/intl_et.arb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/l10n/intl_et.arb b/lib/l10n/intl_et.arb index 11b58fe..84d9556 100644 --- a/lib/l10n/intl_et.arb +++ b/lib/l10n/intl_et.arb @@ -1702,5 +1702,10 @@ "@yourOwnUsername": { "type": "text", "placeholders": {} + }, + "privacy": "Privaatsus", + "@privacy": { + "type": "text", + "placeholders": {} } -} \ No newline at end of file +} From 3b2919168e48a026a9d1a3baf31f0f59bd941211 Mon Sep 17 00:00:00 2001 From: Sorunome Date: Sun, 4 Oct 2020 14:54:31 +0200 Subject: [PATCH 10/17] test chinese translation thing for weblate --- lib/l10n/intl_zh.arb | 1637 ++++++++++++++++++++++++++++++++++++- lib/l10n/intl_zh_Hans.arb | 1636 ------------------------------------ 2 files changed, 1636 insertions(+), 1637 deletions(-) delete mode 100644 lib/l10n/intl_zh_Hans.arb diff --git a/lib/l10n/intl_zh.arb b/lib/l10n/intl_zh.arb index 9e26dfe..1c851f5 100644 --- a/lib/l10n/intl_zh.arb +++ b/lib/l10n/intl_zh.arb @@ -1 +1,1636 @@ -{} \ No newline at end of file +{ + "@@locale": "zh", + "@@last_modified": "2020-09-23 11:46:01.529862", + "about": "关于", + "@about": { + "type": "text", + "placeholders": {} + }, + "accept": "接受", + "@accept": { + "type": "text", + "placeholders": {} + }, + "acceptedTheInvitation": "{username} 已接受邀请", + "@acceptedTheInvitation": { + "type": "text", + "placeholders": { + "username": {} + } + }, + "account": "账户", + "@account": { + "type": "text", + "placeholders": {} + }, + "accountInformation": "账户信息", + "@accountInformation": { + "type": "text", + "placeholders": {} + }, + "activatedEndToEndEncryption": "{username}已激活端到端加密", + "@activatedEndToEndEncryption": { + "type": "text", + "placeholders": { + "username": {} + } + }, + "addGroupDescription": "添加一条群组介绍", + "@addGroupDescription": { + "type": "text", + "placeholders": {} + }, + "admin": "管理员", + "@admin": { + "type": "text", + "placeholders": {} + }, + "alias": "别称", + "@alias": { + "type": "text", + "placeholders": {} + }, + "alreadyHaveAnAccount": "已经有账户了?", + "@alreadyHaveAnAccount": { + "type": "text", + "placeholders": {} + }, + "answeredTheCall": "{senderName} 已开始通话", + "@answeredTheCall": { + "type": "text", + "placeholders": { + "senderName": {} + } + }, + "anyoneCanJoin": "任何人可以加入", + "@anyoneCanJoin": { + "type": "text", + "placeholders": {} + }, + "archive": "存档", + "@archive": { + "type": "text", + "placeholders": {} + }, + "archivedRoom": "已存档的会话", + "@archivedRoom": { + "type": "text", + "placeholders": {} + }, + "areGuestsAllowedToJoin": "是否允许游客用户加入", + "@areGuestsAllowedToJoin": { + "type": "text", + "placeholders": {} + }, + "areYouSure": "你确定吗?", + "@areYouSure": { + "type": "text", + "placeholders": {} + }, + "askSSSSCache": "请输入您的安全存储密码或恢复密钥以存储密钥。", + "@askSSSSCache": { + "type": "text", + "placeholders": {} + }, + "askSSSSSign": "", + "@askSSSSSign": { + "type": "text", + "placeholders": {} + }, + "askSSSSVerify": "请输入安全存储密码或恢复密钥以验证您的会话。", + "@askSSSSVerify": { + "type": "text", + "placeholders": {} + }, + "askVerificationRequest": "是否接受来自{username}的验证申请?", + "@askVerificationRequest": { + "type": "text", + "placeholders": { + "username": {} + } + }, + "authentication": "身份验证", + "@authentication": { + "type": "text", + "placeholders": {} + }, + "avatarHasBeenChanged": "头像已更改", + "@avatarHasBeenChanged": { + "type": "text", + "placeholders": {} + }, + "banFromChat": "已被从对话中禁止", + "@banFromChat": { + "type": "text", + "placeholders": {} + }, + "banned": "已被禁止", + "@banned": { + "type": "text", + "placeholders": {} + }, + "bannedUser": "{username}禁止了{targetName}", + "@bannedUser": { + "type": "text", + "placeholders": { + "username": {}, + "targetName": {} + } + }, + "blockDevice": "屏蔽设备", + "@blockDevice": { + "type": "text", + "placeholders": {} + }, + "byDefaultYouWillBeConnectedTo": "您将会默认连接到{homeserver}", + "@byDefaultYouWillBeConnectedTo": { + "type": "text", + "placeholders": { + "homeserver": {} + } + }, + "cachedKeys": "成功保存了密钥!", + "@cachedKeys": { + "type": "text", + "placeholders": {} + }, + "cancel": "取消", + "@cancel": { + "type": "text", + "placeholders": {} + }, + "changedTheChatAvatar": "{username} 更改了会话头像", + "@changedTheChatAvatar": { + "type": "text", + "placeholders": { + "username": {} + } + }, + "changedTheChatDescriptionTo": "{username} 更改了会话介绍为:“{description}”", + "@changedTheChatDescriptionTo": { + "type": "text", + "placeholders": { + "username": {}, + "description": {} + } + }, + "changedTheChatNameTo": "{username} 更改了昵称为:“{chatname}”", + "@changedTheChatNameTo": { + "type": "text", + "placeholders": { + "username": {}, + "chatname": {} + } + }, + "changedTheChatPermissions": "{username} 更改了会话权限", + "@changedTheChatPermissions": { + "type": "text", + "placeholders": { + "username": {} + } + }, + "changedTheDisplaynameTo": "{username} 更改了展示名称为:“{displayname}”", + "@changedTheDisplaynameTo": { + "type": "text", + "placeholders": { + "username": {}, + "displayname": {} + } + }, + "changedTheGuestAccessRules": "{username} 更改了游客访问规则", + "@changedTheGuestAccessRules": { + "type": "text", + "placeholders": { + "username": {} + } + }, + "changedTheGuestAccessRulesTo": "{username} 更改了游客访问规则为:{rules}", + "@changedTheGuestAccessRulesTo": { + "type": "text", + "placeholders": { + "username": {}, + "rules": {} + } + }, + "changedTheHistoryVisibility": "{username} 更改了历史记录观察状态", + "@changedTheHistoryVisibility": { + "type": "text", + "placeholders": { + "username": {} + } + }, + "changedTheHistoryVisibilityTo": "{username} 更改了历史记录观察状态到:{rules}", + "@changedTheHistoryVisibilityTo": { + "type": "text", + "placeholders": { + "username": {}, + "rules": {} + } + }, + "changedTheJoinRules": "{username} 更改了加入的规则", + "@changedTheJoinRules": { + "type": "text", + "placeholders": { + "username": {} + } + }, + "changedTheJoinRulesTo": "{username} 更改了加入的规则为:{joinRules}", + "@changedTheJoinRulesTo": { + "type": "text", + "placeholders": { + "username": {}, + "joinRules": {} + } + }, + "changedTheProfileAvatar": "{username} 更改了他们的头像", + "@changedTheProfileAvatar": { + "type": "text", + "placeholders": { + "username": {} + } + }, + "changedTheRoomAliases": "{username} 更改了房间名", + "@changedTheRoomAliases": { + "type": "text", + "placeholders": { + "username": {} + } + }, + "changedTheRoomInvitationLink": "{username} 更改了邀请链接", + "@changedTheRoomInvitationLink": { + "type": "text", + "placeholders": { + "username": {} + } + }, + "changelog": "更改记录", + "@changelog": { + "type": "text", + "placeholders": {} + }, + "changeTheHomeserver": "更改主机地址", + "@changeTheHomeserver": { + "type": "text", + "placeholders": {} + }, + "changeTheme": "", + "@changeTheme": { + "type": "text", + "placeholders": {} + }, + "changeTheNameOfTheGroup": "更改了群组名称", + "@changeTheNameOfTheGroup": { + "type": "text", + "placeholders": {} + }, + "changeTheServer": "更改服务器", + "@changeTheServer": { + "type": "text", + "placeholders": {} + }, + "changeWallpaper": "更改会话壁纸", + "@changeWallpaper": { + "type": "text", + "placeholders": {} + }, + "channelCorruptedDecryptError": "加密已被破坏", + "@channelCorruptedDecryptError": { + "type": "text", + "placeholders": {} + }, + "chat": "会话", + "@chat": { + "type": "text", + "placeholders": {} + }, + "chatDetails": "会话详情", + "@chatDetails": { + "type": "text", + "placeholders": {} + }, + "chooseAStrongPassword": "输入一个强密码", + "@chooseAStrongPassword": { + "type": "text", + "placeholders": {} + }, + "chooseAUsername": "输入一个昵称", + "@chooseAUsername": { + "type": "text", + "placeholders": {} + }, + "close": "关闭", + "@close": { + "type": "text", + "placeholders": {} + }, + "compareEmojiMatch": "对比并确认这些表情匹配其他那些设备", + "@compareEmojiMatch": { + "type": "text", + "placeholders": {} + }, + "compareNumbersMatch": "", + "@compareNumbersMatch": { + "type": "text", + "placeholders": {} + }, + "confirm": "", + "@confirm": { + "type": "text", + "placeholders": {} + }, + "connect": "", + "@connect": { + "type": "text", + "placeholders": {} + }, + "connectionAttemptFailed": "", + "@connectionAttemptFailed": { + "type": "text", + "placeholders": {} + }, + "contactHasBeenInvitedToTheGroup": "", + "@contactHasBeenInvitedToTheGroup": { + "type": "text", + "placeholders": {} + }, + "contentViewer": "", + "@contentViewer": { + "type": "text", + "placeholders": {} + }, + "copiedToClipboard": "", + "@copiedToClipboard": { + "type": "text", + "placeholders": {} + }, + "copy": "", + "@copy": { + "type": "text", + "placeholders": {} + }, + "couldNotDecryptMessage": "", + "@couldNotDecryptMessage": { + "type": "text", + "placeholders": { + "error": {} + } + }, + "couldNotSetAvatar": "", + "@couldNotSetAvatar": { + "type": "text", + "placeholders": {} + }, + "couldNotSetDisplayname": "", + "@couldNotSetDisplayname": { + "type": "text", + "placeholders": {} + }, + "countParticipants": "", + "@countParticipants": { + "type": "text", + "placeholders": { + "count": {} + } + }, + "create": "", + "@create": { + "type": "text", + "placeholders": {} + }, + "createAccountNow": "", + "@createAccountNow": { + "type": "text", + "placeholders": {} + }, + "createdTheChat": "", + "@createdTheChat": { + "type": "text", + "placeholders": { + "username": {} + } + }, + "createNewGroup": "", + "@createNewGroup": { + "type": "text", + "placeholders": {} + }, + "crossSigningDisabled": "", + "@crossSigningDisabled": { + "type": "text", + "placeholders": {} + }, + "crossSigningEnabled": "", + "@crossSigningEnabled": { + "type": "text", + "placeholders": {} + }, + "currentlyActive": "", + "@currentlyActive": { + "type": "text", + "placeholders": {} + }, + "darkTheme": "", + "@darkTheme": { + "type": "text", + "placeholders": {} + }, + "dateAndTimeOfDay": "", + "@dateAndTimeOfDay": { + "type": "text", + "placeholders": { + "date": {}, + "timeOfDay": {} + } + }, + "dateWithoutYear": "", + "@dateWithoutYear": { + "type": "text", + "placeholders": { + "month": {}, + "day": {} + } + }, + "dateWithYear": "", + "@dateWithYear": { + "type": "text", + "placeholders": { + "year": {}, + "month": {}, + "day": {} + } + }, + "delete": "", + "@delete": { + "type": "text", + "placeholders": {} + }, + "deleteMessage": "", + "@deleteMessage": { + "type": "text", + "placeholders": {} + }, + "deny": "", + "@deny": { + "type": "text", + "placeholders": {} + }, + "device": "", + "@device": { + "type": "text", + "placeholders": {} + }, + "devices": "", + "@devices": { + "type": "text", + "placeholders": {} + }, + "discardPicture": "", + "@discardPicture": { + "type": "text", + "placeholders": {} + }, + "displaynameHasBeenChanged": "", + "@displaynameHasBeenChanged": { + "type": "text", + "placeholders": {} + }, + "donate": "", + "@donate": { + "type": "text", + "placeholders": {} + }, + "downloadFile": "", + "@downloadFile": { + "type": "text", + "placeholders": {} + }, + "editDisplayname": "", + "@editDisplayname": { + "type": "text", + "placeholders": {} + }, + "editJitsiInstance": "", + "@editJitsiInstance": { + "type": "text", + "placeholders": {} + }, + "emoteExists": "", + "@emoteExists": { + "type": "text", + "placeholders": {} + }, + "emoteInvalid": "", + "@emoteInvalid": { + "type": "text", + "placeholders": {} + }, + "emoteSettings": "", + "@emoteSettings": { + "type": "text", + "placeholders": {} + }, + "emoteShortcode": "", + "@emoteShortcode": { + "type": "text", + "placeholders": {} + }, + "emoteWarnNeedToPick": "", + "@emoteWarnNeedToPick": { + "type": "text", + "placeholders": {} + }, + "emptyChat": "", + "@emptyChat": { + "type": "text", + "placeholders": {} + }, + "enableEncryptionWarning": "", + "@enableEncryptionWarning": { + "type": "text", + "placeholders": {} + }, + "encryption": "", + "@encryption": { + "type": "text", + "placeholders": {} + }, + "encryptionAlgorithm": "", + "@encryptionAlgorithm": { + "type": "text", + "placeholders": {} + }, + "encryptionNotEnabled": "", + "@encryptionNotEnabled": { + "type": "text", + "placeholders": {} + }, + "end2endEncryptionSettings": "", + "@end2endEncryptionSettings": { + "type": "text", + "placeholders": {} + }, + "endedTheCall": "", + "@endedTheCall": { + "type": "text", + "placeholders": { + "senderName": {} + } + }, + "enterAGroupName": "", + "@enterAGroupName": { + "type": "text", + "placeholders": {} + }, + "enterAUsername": "", + "@enterAUsername": { + "type": "text", + "placeholders": {} + }, + "enterYourHomeserver": "", + "@enterYourHomeserver": { + "type": "text", + "placeholders": {} + }, + "fileName": "", + "@fileName": { + "type": "text", + "placeholders": {} + }, + "fileSize": "", + "@fileSize": { + "type": "text", + "placeholders": {} + }, + "fluffychat": "", + "@fluffychat": { + "type": "text", + "placeholders": {} + }, + "forward": "", + "@forward": { + "type": "text", + "placeholders": {} + }, + "friday": "", + "@friday": { + "type": "text", + "placeholders": {} + }, + "fromJoining": "", + "@fromJoining": { + "type": "text", + "placeholders": {} + }, + "fromTheInvitation": "", + "@fromTheInvitation": { + "type": "text", + "placeholders": {} + }, + "group": "", + "@group": { + "type": "text", + "placeholders": {} + }, + "groupDescription": "", + "@groupDescription": { + "type": "text", + "placeholders": {} + }, + "groupDescriptionHasBeenChanged": "", + "@groupDescriptionHasBeenChanged": { + "type": "text", + "placeholders": {} + }, + "groupIsPublic": "", + "@groupIsPublic": { + "type": "text", + "placeholders": {} + }, + "groupWith": "", + "@groupWith": { + "type": "text", + "placeholders": { + "displayname": {} + } + }, + "guestsAreForbidden": "", + "@guestsAreForbidden": { + "type": "text", + "placeholders": {} + }, + "guestsCanJoin": "", + "@guestsCanJoin": { + "type": "text", + "placeholders": {} + }, + "hasWithdrawnTheInvitationFor": "", + "@hasWithdrawnTheInvitationFor": { + "type": "text", + "placeholders": { + "username": {}, + "targetName": {} + } + }, + "help": "", + "@help": { + "type": "text", + "placeholders": {} + }, + "homeserverIsNotCompatible": "", + "@homeserverIsNotCompatible": { + "type": "text", + "placeholders": {} + }, + "id": "", + "@id": { + "type": "text", + "placeholders": {} + }, + "identity": "", + "@identity": { + "type": "text", + "placeholders": {} + }, + "incorrectPassphraseOrKey": "", + "@incorrectPassphraseOrKey": { + "type": "text", + "placeholders": {} + }, + "inviteContact": "", + "@inviteContact": { + "type": "text", + "placeholders": {} + }, + "inviteContactToGroup": "", + "@inviteContactToGroup": { + "type": "text", + "placeholders": { + "groupName": {} + } + }, + "invited": "", + "@invited": { + "type": "text", + "placeholders": {} + }, + "invitedUser": "", + "@invitedUser": { + "type": "text", + "placeholders": { + "username": {}, + "targetName": {} + } + }, + "invitedUsersOnly": "", + "@invitedUsersOnly": { + "type": "text", + "placeholders": {} + }, + "inviteText": "", + "@inviteText": { + "type": "text", + "placeholders": { + "username": {}, + "link": {} + } + }, + "isDeviceKeyCorrect": "", + "@isDeviceKeyCorrect": { + "type": "text", + "placeholders": {} + }, + "isTyping": "", + "@isTyping": { + "type": "text", + "placeholders": {} + }, + "joinedTheChat": "", + "@joinedTheChat": { + "type": "text", + "placeholders": { + "username": {} + } + }, + "joinRoom": "", + "@joinRoom": { + "type": "text", + "placeholders": {} + }, + "keysCached": "", + "@keysCached": { + "type": "text", + "placeholders": {} + }, + "keysMissing": "", + "@keysMissing": { + "type": "text", + "placeholders": {} + }, + "kicked": "", + "@kicked": { + "type": "text", + "placeholders": { + "username": {}, + "targetName": {} + } + }, + "kickedAndBanned": "", + "@kickedAndBanned": { + "type": "text", + "placeholders": { + "username": {}, + "targetName": {} + } + }, + "kickFromChat": "", + "@kickFromChat": { + "type": "text", + "placeholders": {} + }, + "lastActiveAgo": "", + "@lastActiveAgo": { + "type": "text", + "placeholders": { + "localizedTimeShort": {} + } + }, + "lastSeenIp": "", + "@lastSeenIp": { + "type": "text", + "placeholders": {} + }, + "lastSeenLongTimeAgo": "", + "@lastSeenLongTimeAgo": { + "type": "text", + "placeholders": {} + }, + "leave": "", + "@leave": { + "type": "text", + "placeholders": {} + }, + "leftTheChat": "", + "@leftTheChat": { + "type": "text", + "placeholders": {} + }, + "license": "", + "@license": { + "type": "text", + "placeholders": {} + }, + "lightTheme": "", + "@lightTheme": { + "type": "text", + "placeholders": {} + }, + "loadCountMoreParticipants": "", + "@loadCountMoreParticipants": { + "type": "text", + "placeholders": { + "count": {} + } + }, + "loadingPleaseWait": "", + "@loadingPleaseWait": { + "type": "text", + "placeholders": {} + }, + "loadMore": "", + "@loadMore": { + "type": "text", + "placeholders": {} + }, + "login": "", + "@login": { + "type": "text", + "placeholders": {} + }, + "logInTo": "", + "@logInTo": { + "type": "text", + "placeholders": { + "homeserver": {} + } + }, + "logout": "", + "@logout": { + "type": "text", + "placeholders": {} + }, + "makeAModerator": "", + "@makeAModerator": { + "type": "text", + "placeholders": {} + }, + "makeAnAdmin": "", + "@makeAnAdmin": { + "type": "text", + "placeholders": {} + }, + "makeSureTheIdentifierIsValid": "", + "@makeSureTheIdentifierIsValid": { + "type": "text", + "placeholders": {} + }, + "messageWillBeRemovedWarning": "", + "@messageWillBeRemovedWarning": { + "type": "text", + "placeholders": {} + }, + "moderator": "", + "@moderator": { + "type": "text", + "placeholders": {} + }, + "monday": "", + "@monday": { + "type": "text", + "placeholders": {} + }, + "muteChat": "", + "@muteChat": { + "type": "text", + "placeholders": {} + }, + "needPantalaimonWarning": "", + "@needPantalaimonWarning": { + "type": "text", + "placeholders": {} + }, + "newMessageInFluffyChat": "", + "@newMessageInFluffyChat": { + "type": "text", + "placeholders": {} + }, + "newPrivateChat": "", + "@newPrivateChat": { + "type": "text", + "placeholders": {} + }, + "newVerificationRequest": "", + "@newVerificationRequest": { + "type": "text", + "placeholders": {} + }, + "noCrossSignBootstrap": "", + "@noCrossSignBootstrap": { + "type": "text", + "placeholders": {} + }, + "noEmotesFound": "", + "@noEmotesFound": { + "type": "text", + "placeholders": {} + }, + "noGoogleServicesWarning": "", + "@noGoogleServicesWarning": { + "type": "text", + "placeholders": {} + }, + "noMegolmBootstrap": "", + "@noMegolmBootstrap": { + "type": "text", + "placeholders": {} + }, + "none": "", + "@none": { + "type": "text", + "placeholders": {} + }, + "noPermission": "", + "@noPermission": { + "type": "text", + "placeholders": {} + }, + "noRoomsFound": "", + "@noRoomsFound": { + "type": "text", + "placeholders": {} + }, + "notSupportedInWeb": "", + "@notSupportedInWeb": { + "type": "text", + "placeholders": {} + }, + "numberSelected": "", + "@numberSelected": { + "type": "text", + "placeholders": { + "number": {} + } + }, + "ok": "", + "@ok": { + "type": "text", + "placeholders": {} + }, + "onlineKeyBackupDisabled": "", + "@onlineKeyBackupDisabled": { + "type": "text", + "placeholders": {} + }, + "onlineKeyBackupEnabled": "", + "@onlineKeyBackupEnabled": { + "type": "text", + "placeholders": {} + }, + "oopsSomethingWentWrong": "", + "@oopsSomethingWentWrong": { + "type": "text", + "placeholders": {} + }, + "openAppToReadMessages": "", + "@openAppToReadMessages": { + "type": "text", + "placeholders": {} + }, + "openCamera": "", + "@openCamera": { + "type": "text", + "placeholders": {} + }, + "optionalGroupName": "", + "@optionalGroupName": { + "type": "text", + "placeholders": {} + }, + "participatingUserDevices": "", + "@participatingUserDevices": { + "type": "text", + "placeholders": {} + }, + "passphraseOrKey": "", + "@passphraseOrKey": { + "type": "text", + "placeholders": {} + }, + "password": "", + "@password": { + "type": "text", + "placeholders": {} + }, + "pickImage": "", + "@pickImage": { + "type": "text", + "placeholders": {} + }, + "pin": "", + "@pin": { + "type": "text", + "placeholders": {} + }, + "play": "", + "@play": { + "type": "text", + "placeholders": { + "fileName": {} + } + }, + "pleaseChooseAUsername": "", + "@pleaseChooseAUsername": { + "type": "text", + "placeholders": {} + }, + "pleaseEnterAMatrixIdentifier": "", + "@pleaseEnterAMatrixIdentifier": { + "type": "text", + "placeholders": {} + }, + "pleaseEnterYourPassword": "", + "@pleaseEnterYourPassword": { + "type": "text", + "placeholders": {} + }, + "pleaseEnterYourUsername": "", + "@pleaseEnterYourUsername": { + "type": "text", + "placeholders": {} + }, + "publicRooms": "", + "@publicRooms": { + "type": "text", + "placeholders": {} + }, + "recording": "", + "@recording": { + "type": "text", + "placeholders": {} + }, + "redactedAnEvent": "", + "@redactedAnEvent": { + "type": "text", + "placeholders": { + "username": {} + } + }, + "reject": "", + "@reject": { + "type": "text", + "placeholders": {} + }, + "rejectedTheInvitation": "", + "@rejectedTheInvitation": { + "type": "text", + "placeholders": { + "username": {} + } + }, + "rejoin": "", + "@rejoin": { + "type": "text", + "placeholders": {} + }, + "remove": "", + "@remove": { + "type": "text", + "placeholders": {} + }, + "removeAllOtherDevices": "", + "@removeAllOtherDevices": { + "type": "text", + "placeholders": {} + }, + "removedBy": "", + "@removedBy": { + "type": "text", + "placeholders": { + "username": {} + } + }, + "removeDevice": "", + "@removeDevice": { + "type": "text", + "placeholders": {} + }, + "removeExile": "", + "@removeExile": { + "type": "text", + "placeholders": {} + }, + "removeMessage": "", + "@removeMessage": { + "type": "text", + "placeholders": {} + }, + "renderRichContent": "", + "@renderRichContent": { + "type": "text", + "placeholders": {} + }, + "reply": "", + "@reply": { + "type": "text", + "placeholders": {} + }, + "requestPermission": "", + "@requestPermission": { + "type": "text", + "placeholders": {} + }, + "requestToReadOlderMessages": "", + "@requestToReadOlderMessages": { + "type": "text", + "placeholders": {} + }, + "revokeAllPermissions": "", + "@revokeAllPermissions": { + "type": "text", + "placeholders": {} + }, + "roomHasBeenUpgraded": "", + "@roomHasBeenUpgraded": { + "type": "text", + "placeholders": {} + }, + "saturday": "", + "@saturday": { + "type": "text", + "placeholders": {} + }, + "searchForAChat": "", + "@searchForAChat": { + "type": "text", + "placeholders": {} + }, + "seenByUser": "", + "@seenByUser": { + "type": "text", + "placeholders": { + "username": {} + } + }, + "seenByUserAndCountOthers": "", + "@seenByUserAndCountOthers": { + "type": "text", + "placeholders": { + "username": {}, + "count": {} + } + }, + "seenByUserAndUser": "", + "@seenByUserAndUser": { + "type": "text", + "placeholders": { + "username": {}, + "username2": {} + } + }, + "send": "", + "@send": { + "type": "text", + "placeholders": {} + }, + "sendAMessage": "", + "@sendAMessage": { + "type": "text", + "placeholders": {} + }, + "sendFile": "", + "@sendFile": { + "type": "text", + "placeholders": {} + }, + "sendImage": "", + "@sendImage": { + "type": "text", + "placeholders": {} + }, + "sentAFile": "", + "@sentAFile": { + "type": "text", + "placeholders": { + "username": {} + } + }, + "sentAnAudio": "", + "@sentAnAudio": { + "type": "text", + "placeholders": { + "username": {} + } + }, + "sentAPicture": "", + "@sentAPicture": { + "type": "text", + "placeholders": { + "username": {} + } + }, + "sentASticker": "", + "@sentASticker": { + "type": "text", + "placeholders": { + "username": {} + } + }, + "sentAVideo": "", + "@sentAVideo": { + "type": "text", + "placeholders": { + "username": {} + } + }, + "sentCallInformations": "", + "@sentCallInformations": { + "type": "text", + "placeholders": { + "senderName": {} + } + }, + "sessionVerified": "", + "@sessionVerified": { + "type": "text", + "placeholders": {} + }, + "setAProfilePicture": "", + "@setAProfilePicture": { + "type": "text", + "placeholders": {} + }, + "setGroupDescription": "", + "@setGroupDescription": { + "type": "text", + "placeholders": {} + }, + "setInvitationLink": "", + "@setInvitationLink": { + "type": "text", + "placeholders": {} + }, + "setStatus": "", + "@setStatus": { + "type": "text", + "placeholders": {} + }, + "settings": "", + "@settings": { + "type": "text", + "placeholders": {} + }, + "share": "", + "@share": { + "type": "text", + "placeholders": {} + }, + "sharedTheLocation": "", + "@sharedTheLocation": { + "type": "text", + "placeholders": { + "username": {} + } + }, + "signUp": "", + "@signUp": { + "type": "text", + "placeholders": {} + }, + "skip": "", + "@skip": { + "type": "text", + "placeholders": {} + }, + "sourceCode": "", + "@sourceCode": { + "type": "text", + "placeholders": {} + }, + "startedACall": "", + "@startedACall": { + "type": "text", + "placeholders": { + "senderName": {} + } + }, + "startYourFirstChat": "", + "@startYourFirstChat": { + "type": "text", + "placeholders": {} + }, + "statusExampleMessage": "", + "@statusExampleMessage": { + "type": "text", + "placeholders": {} + }, + "submit": "", + "@submit": { + "type": "text", + "placeholders": {} + }, + "sunday": "", + "@sunday": { + "type": "text", + "placeholders": {} + }, + "systemTheme": "", + "@systemTheme": { + "type": "text", + "placeholders": {} + }, + "tapToShowMenu": "", + "@tapToShowMenu": { + "type": "text", + "placeholders": {} + }, + "theyDontMatch": "", + "@theyDontMatch": { + "type": "text", + "placeholders": {} + }, + "theyMatch": "", + "@theyMatch": { + "type": "text", + "placeholders": {} + }, + "thisRoomHasBeenArchived": "", + "@thisRoomHasBeenArchived": { + "type": "text", + "placeholders": {} + }, + "thursday": "", + "@thursday": { + "type": "text", + "placeholders": {} + }, + "timeOfDay": "", + "@timeOfDay": { + "type": "text", + "placeholders": { + "hours12": {}, + "hours24": {}, + "minutes": {}, + "suffix": {} + } + }, + "title": "", + "@title": { + "description": "Title for the application", + "type": "text", + "placeholders": {} + }, + "tryToSendAgain": "", + "@tryToSendAgain": { + "type": "text", + "placeholders": {} + }, + "tuesday": "", + "@tuesday": { + "type": "text", + "placeholders": {} + }, + "unbannedUser": "", + "@unbannedUser": { + "type": "text", + "placeholders": { + "username": {}, + "targetName": {} + } + }, + "unblockDevice": "", + "@unblockDevice": { + "type": "text", + "placeholders": {} + }, + "unknownDevice": "", + "@unknownDevice": { + "type": "text", + "placeholders": {} + }, + "unknownEncryptionAlgorithm": "", + "@unknownEncryptionAlgorithm": { + "type": "text", + "placeholders": {} + }, + "unknownEvent": "", + "@unknownEvent": { + "type": "text", + "placeholders": { + "type": {} + } + }, + "unknownSessionVerify": "", + "@unknownSessionVerify": { + "type": "text", + "placeholders": {} + }, + "unmuteChat": "", + "@unmuteChat": { + "type": "text", + "placeholders": {} + }, + "unpin": "", + "@unpin": { + "type": "text", + "placeholders": {} + }, + "unreadChats": "", + "@unreadChats": { + "type": "text", + "placeholders": { + "unreadCount": {} + } + }, + "unreadMessages": "", + "@unreadMessages": { + "type": "text", + "placeholders": { + "unreadEvents": {} + } + }, + "unreadMessagesInChats": "", + "@unreadMessagesInChats": { + "type": "text", + "placeholders": { + "unreadEvents": {}, + "unreadChats": {} + } + }, + "useAmoledTheme": "", + "@useAmoledTheme": { + "type": "text", + "placeholders": {} + }, + "userAndOthersAreTyping": "", + "@userAndOthersAreTyping": { + "type": "text", + "placeholders": { + "username": {}, + "count": {} + } + }, + "userAndUserAreTyping": "", + "@userAndUserAreTyping": { + "type": "text", + "placeholders": { + "username": {}, + "username2": {} + } + }, + "userIsTyping": "", + "@userIsTyping": { + "type": "text", + "placeholders": { + "username": {} + } + }, + "userLeftTheChat": "", + "@userLeftTheChat": { + "type": "text", + "placeholders": { + "username": {} + } + }, + "username": "", + "@username": { + "type": "text", + "placeholders": {} + }, + "userSentUnknownEvent": "", + "@userSentUnknownEvent": { + "type": "text", + "placeholders": { + "username": {}, + "type": {} + } + }, + "verifiedSession": "", + "@verifiedSession": { + "type": "text", + "placeholders": {} + }, + "verify": "", + "@verify": { + "type": "text", + "placeholders": {} + }, + "verifyManual": "", + "@verifyManual": { + "type": "text", + "placeholders": {} + }, + "verifyStart": "", + "@verifyStart": { + "type": "text", + "placeholders": {} + }, + "verifySuccess": "", + "@verifySuccess": { + "type": "text", + "placeholders": {} + }, + "verifyTitle": "", + "@verifyTitle": { + "type": "text", + "placeholders": {} + }, + "verifyUser": "", + "@verifyUser": { + "type": "text", + "placeholders": {} + }, + "videoCall": "", + "@videoCall": { + "type": "text", + "placeholders": {} + }, + "visibilityOfTheChatHistory": "", + "@visibilityOfTheChatHistory": { + "type": "text", + "placeholders": {} + }, + "visibleForAllParticipants": "", + "@visibleForAllParticipants": { + "type": "text", + "placeholders": {} + }, + "visibleForEveryone": "", + "@visibleForEveryone": { + "type": "text", + "placeholders": {} + }, + "voiceMessage": "", + "@voiceMessage": { + "type": "text", + "placeholders": {} + }, + "waitingPartnerAcceptRequest": "", + "@waitingPartnerAcceptRequest": { + "type": "text", + "placeholders": {} + }, + "waitingPartnerEmoji": "", + "@waitingPartnerEmoji": { + "type": "text", + "placeholders": {} + }, + "waitingPartnerNumbers": "", + "@waitingPartnerNumbers": { + "type": "text", + "placeholders": {} + }, + "wallpaper": "", + "@wallpaper": { + "type": "text", + "placeholders": {} + }, + "warningEncryptionInBeta": "", + "@warningEncryptionInBeta": { + "type": "text", + "placeholders": {} + }, + "wednesday": "", + "@wednesday": { + "type": "text", + "placeholders": {} + }, + "welcomeText": "", + "@welcomeText": { + "type": "text", + "placeholders": {} + }, + "whoIsAllowedToJoinThisGroup": "", + "@whoIsAllowedToJoinThisGroup": { + "type": "text", + "placeholders": {} + }, + "writeAMessage": "", + "@writeAMessage": { + "type": "text", + "placeholders": {} + }, + "yes": "", + "@yes": { + "type": "text", + "placeholders": {} + }, + "you": "", + "@you": { + "type": "text", + "placeholders": {} + }, + "youAreInvitedToThisChat": "", + "@youAreInvitedToThisChat": { + "type": "text", + "placeholders": {} + }, + "youAreNoLongerParticipatingInThisChat": "", + "@youAreNoLongerParticipatingInThisChat": { + "type": "text", + "placeholders": {} + }, + "youCannotInviteYourself": "", + "@youCannotInviteYourself": { + "type": "text", + "placeholders": {} + }, + "youHaveBeenBannedFromThisChat": "", + "@youHaveBeenBannedFromThisChat": { + "type": "text", + "placeholders": {} + }, + "yourOwnUsername": "", + "@yourOwnUsername": { + "type": "text", + "placeholders": {} + } +} diff --git a/lib/l10n/intl_zh_Hans.arb b/lib/l10n/intl_zh_Hans.arb deleted file mode 100644 index 068d542..0000000 --- a/lib/l10n/intl_zh_Hans.arb +++ /dev/null @@ -1,1636 +0,0 @@ -{ - "@@locale": "zh_Hans", - "@@last_modified": "2020-09-23 11:46:01.529862", - "about": "关于", - "@about": { - "type": "text", - "placeholders": {} - }, - "accept": "接受", - "@accept": { - "type": "text", - "placeholders": {} - }, - "acceptedTheInvitation": "{username} 已接受邀请", - "@acceptedTheInvitation": { - "type": "text", - "placeholders": { - "username": {} - } - }, - "account": "账户", - "@account": { - "type": "text", - "placeholders": {} - }, - "accountInformation": "账户信息", - "@accountInformation": { - "type": "text", - "placeholders": {} - }, - "activatedEndToEndEncryption": "{username}已激活端到端加密", - "@activatedEndToEndEncryption": { - "type": "text", - "placeholders": { - "username": {} - } - }, - "addGroupDescription": "添加一条群组介绍", - "@addGroupDescription": { - "type": "text", - "placeholders": {} - }, - "admin": "管理员", - "@admin": { - "type": "text", - "placeholders": {} - }, - "alias": "别称", - "@alias": { - "type": "text", - "placeholders": {} - }, - "alreadyHaveAnAccount": "已经有账户了?", - "@alreadyHaveAnAccount": { - "type": "text", - "placeholders": {} - }, - "answeredTheCall": "{senderName} 已开始通话", - "@answeredTheCall": { - "type": "text", - "placeholders": { - "senderName": {} - } - }, - "anyoneCanJoin": "任何人可以加入", - "@anyoneCanJoin": { - "type": "text", - "placeholders": {} - }, - "archive": "存档", - "@archive": { - "type": "text", - "placeholders": {} - }, - "archivedRoom": "已存档的会话", - "@archivedRoom": { - "type": "text", - "placeholders": {} - }, - "areGuestsAllowedToJoin": "是否允许游客用户加入", - "@areGuestsAllowedToJoin": { - "type": "text", - "placeholders": {} - }, - "areYouSure": "你确定吗?", - "@areYouSure": { - "type": "text", - "placeholders": {} - }, - "askSSSSCache": "请输入您的安全存储密码或恢复密钥以存储密钥。", - "@askSSSSCache": { - "type": "text", - "placeholders": {} - }, - "askSSSSSign": "", - "@askSSSSSign": { - "type": "text", - "placeholders": {} - }, - "askSSSSVerify": "请输入安全存储密码或恢复密钥以验证您的会话。", - "@askSSSSVerify": { - "type": "text", - "placeholders": {} - }, - "askVerificationRequest": "是否接受来自{username}的验证申请?", - "@askVerificationRequest": { - "type": "text", - "placeholders": { - "username": {} - } - }, - "authentication": "身份验证", - "@authentication": { - "type": "text", - "placeholders": {} - }, - "avatarHasBeenChanged": "头像已更改", - "@avatarHasBeenChanged": { - "type": "text", - "placeholders": {} - }, - "banFromChat": "已被从对话中禁止", - "@banFromChat": { - "type": "text", - "placeholders": {} - }, - "banned": "已被禁止", - "@banned": { - "type": "text", - "placeholders": {} - }, - "bannedUser": "{username}禁止了{targetName}", - "@bannedUser": { - "type": "text", - "placeholders": { - "username": {}, - "targetName": {} - } - }, - "blockDevice": "屏蔽设备", - "@blockDevice": { - "type": "text", - "placeholders": {} - }, - "byDefaultYouWillBeConnectedTo": "您将会默认连接到{homeserver}", - "@byDefaultYouWillBeConnectedTo": { - "type": "text", - "placeholders": { - "homeserver": {} - } - }, - "cachedKeys": "成功保存了密钥!", - "@cachedKeys": { - "type": "text", - "placeholders": {} - }, - "cancel": "取消", - "@cancel": { - "type": "text", - "placeholders": {} - }, - "changedTheChatAvatar": "{username} 更改了会话头像", - "@changedTheChatAvatar": { - "type": "text", - "placeholders": { - "username": {} - } - }, - "changedTheChatDescriptionTo": "{username} 更改了会话介绍为:“{description}”", - "@changedTheChatDescriptionTo": { - "type": "text", - "placeholders": { - "username": {}, - "description": {} - } - }, - "changedTheChatNameTo": "{username} 更改了昵称为:“{chatname}”", - "@changedTheChatNameTo": { - "type": "text", - "placeholders": { - "username": {}, - "chatname": {} - } - }, - "changedTheChatPermissions": "{username} 更改了会话权限", - "@changedTheChatPermissions": { - "type": "text", - "placeholders": { - "username": {} - } - }, - "changedTheDisplaynameTo": "{username} 更改了展示名称为:“{displayname}”", - "@changedTheDisplaynameTo": { - "type": "text", - "placeholders": { - "username": {}, - "displayname": {} - } - }, - "changedTheGuestAccessRules": "{username} 更改了游客访问规则", - "@changedTheGuestAccessRules": { - "type": "text", - "placeholders": { - "username": {} - } - }, - "changedTheGuestAccessRulesTo": "{username} 更改了游客访问规则为:{rules}", - "@changedTheGuestAccessRulesTo": { - "type": "text", - "placeholders": { - "username": {}, - "rules": {} - } - }, - "changedTheHistoryVisibility": "{username} 更改了历史记录观察状态", - "@changedTheHistoryVisibility": { - "type": "text", - "placeholders": { - "username": {} - } - }, - "changedTheHistoryVisibilityTo": "{username} 更改了历史记录观察状态到:{rules}", - "@changedTheHistoryVisibilityTo": { - "type": "text", - "placeholders": { - "username": {}, - "rules": {} - } - }, - "changedTheJoinRules": "{username} 更改了加入的规则", - "@changedTheJoinRules": { - "type": "text", - "placeholders": { - "username": {} - } - }, - "changedTheJoinRulesTo": "{username} 更改了加入的规则为:{joinRules}", - "@changedTheJoinRulesTo": { - "type": "text", - "placeholders": { - "username": {}, - "joinRules": {} - } - }, - "changedTheProfileAvatar": "{username} 更改了他们的头像", - "@changedTheProfileAvatar": { - "type": "text", - "placeholders": { - "username": {} - } - }, - "changedTheRoomAliases": "{username} 更改了房间名", - "@changedTheRoomAliases": { - "type": "text", - "placeholders": { - "username": {} - } - }, - "changedTheRoomInvitationLink": "{username} 更改了邀请链接", - "@changedTheRoomInvitationLink": { - "type": "text", - "placeholders": { - "username": {} - } - }, - "changelog": "更改记录", - "@changelog": { - "type": "text", - "placeholders": {} - }, - "changeTheHomeserver": "更改主机地址", - "@changeTheHomeserver": { - "type": "text", - "placeholders": {} - }, - "changeTheme": "", - "@changeTheme": { - "type": "text", - "placeholders": {} - }, - "changeTheNameOfTheGroup": "更改了群组名称", - "@changeTheNameOfTheGroup": { - "type": "text", - "placeholders": {} - }, - "changeTheServer": "更改服务器", - "@changeTheServer": { - "type": "text", - "placeholders": {} - }, - "changeWallpaper": "更改会话壁纸", - "@changeWallpaper": { - "type": "text", - "placeholders": {} - }, - "channelCorruptedDecryptError": "加密已被破坏", - "@channelCorruptedDecryptError": { - "type": "text", - "placeholders": {} - }, - "chat": "会话", - "@chat": { - "type": "text", - "placeholders": {} - }, - "chatDetails": "会话详情", - "@chatDetails": { - "type": "text", - "placeholders": {} - }, - "chooseAStrongPassword": "输入一个强密码", - "@chooseAStrongPassword": { - "type": "text", - "placeholders": {} - }, - "chooseAUsername": "输入一个昵称", - "@chooseAUsername": { - "type": "text", - "placeholders": {} - }, - "close": "关闭", - "@close": { - "type": "text", - "placeholders": {} - }, - "compareEmojiMatch": "对比并确认这些表情匹配其他那些设备", - "@compareEmojiMatch": { - "type": "text", - "placeholders": {} - }, - "compareNumbersMatch": "", - "@compareNumbersMatch": { - "type": "text", - "placeholders": {} - }, - "confirm": "", - "@confirm": { - "type": "text", - "placeholders": {} - }, - "connect": "", - "@connect": { - "type": "text", - "placeholders": {} - }, - "connectionAttemptFailed": "", - "@connectionAttemptFailed": { - "type": "text", - "placeholders": {} - }, - "contactHasBeenInvitedToTheGroup": "", - "@contactHasBeenInvitedToTheGroup": { - "type": "text", - "placeholders": {} - }, - "contentViewer": "", - "@contentViewer": { - "type": "text", - "placeholders": {} - }, - "copiedToClipboard": "", - "@copiedToClipboard": { - "type": "text", - "placeholders": {} - }, - "copy": "", - "@copy": { - "type": "text", - "placeholders": {} - }, - "couldNotDecryptMessage": "", - "@couldNotDecryptMessage": { - "type": "text", - "placeholders": { - "error": {} - } - }, - "couldNotSetAvatar": "", - "@couldNotSetAvatar": { - "type": "text", - "placeholders": {} - }, - "couldNotSetDisplayname": "", - "@couldNotSetDisplayname": { - "type": "text", - "placeholders": {} - }, - "countParticipants": "", - "@countParticipants": { - "type": "text", - "placeholders": { - "count": {} - } - }, - "create": "", - "@create": { - "type": "text", - "placeholders": {} - }, - "createAccountNow": "", - "@createAccountNow": { - "type": "text", - "placeholders": {} - }, - "createdTheChat": "", - "@createdTheChat": { - "type": "text", - "placeholders": { - "username": {} - } - }, - "createNewGroup": "", - "@createNewGroup": { - "type": "text", - "placeholders": {} - }, - "crossSigningDisabled": "", - "@crossSigningDisabled": { - "type": "text", - "placeholders": {} - }, - "crossSigningEnabled": "", - "@crossSigningEnabled": { - "type": "text", - "placeholders": {} - }, - "currentlyActive": "", - "@currentlyActive": { - "type": "text", - "placeholders": {} - }, - "darkTheme": "", - "@darkTheme": { - "type": "text", - "placeholders": {} - }, - "dateAndTimeOfDay": "", - "@dateAndTimeOfDay": { - "type": "text", - "placeholders": { - "date": {}, - "timeOfDay": {} - } - }, - "dateWithoutYear": "", - "@dateWithoutYear": { - "type": "text", - "placeholders": { - "month": {}, - "day": {} - } - }, - "dateWithYear": "", - "@dateWithYear": { - "type": "text", - "placeholders": { - "year": {}, - "month": {}, - "day": {} - } - }, - "delete": "", - "@delete": { - "type": "text", - "placeholders": {} - }, - "deleteMessage": "", - "@deleteMessage": { - "type": "text", - "placeholders": {} - }, - "deny": "", - "@deny": { - "type": "text", - "placeholders": {} - }, - "device": "", - "@device": { - "type": "text", - "placeholders": {} - }, - "devices": "", - "@devices": { - "type": "text", - "placeholders": {} - }, - "discardPicture": "", - "@discardPicture": { - "type": "text", - "placeholders": {} - }, - "displaynameHasBeenChanged": "", - "@displaynameHasBeenChanged": { - "type": "text", - "placeholders": {} - }, - "donate": "", - "@donate": { - "type": "text", - "placeholders": {} - }, - "downloadFile": "", - "@downloadFile": { - "type": "text", - "placeholders": {} - }, - "editDisplayname": "", - "@editDisplayname": { - "type": "text", - "placeholders": {} - }, - "editJitsiInstance": "", - "@editJitsiInstance": { - "type": "text", - "placeholders": {} - }, - "emoteExists": "", - "@emoteExists": { - "type": "text", - "placeholders": {} - }, - "emoteInvalid": "", - "@emoteInvalid": { - "type": "text", - "placeholders": {} - }, - "emoteSettings": "", - "@emoteSettings": { - "type": "text", - "placeholders": {} - }, - "emoteShortcode": "", - "@emoteShortcode": { - "type": "text", - "placeholders": {} - }, - "emoteWarnNeedToPick": "", - "@emoteWarnNeedToPick": { - "type": "text", - "placeholders": {} - }, - "emptyChat": "", - "@emptyChat": { - "type": "text", - "placeholders": {} - }, - "enableEncryptionWarning": "", - "@enableEncryptionWarning": { - "type": "text", - "placeholders": {} - }, - "encryption": "", - "@encryption": { - "type": "text", - "placeholders": {} - }, - "encryptionAlgorithm": "", - "@encryptionAlgorithm": { - "type": "text", - "placeholders": {} - }, - "encryptionNotEnabled": "", - "@encryptionNotEnabled": { - "type": "text", - "placeholders": {} - }, - "end2endEncryptionSettings": "", - "@end2endEncryptionSettings": { - "type": "text", - "placeholders": {} - }, - "endedTheCall": "", - "@endedTheCall": { - "type": "text", - "placeholders": { - "senderName": {} - } - }, - "enterAGroupName": "", - "@enterAGroupName": { - "type": "text", - "placeholders": {} - }, - "enterAUsername": "", - "@enterAUsername": { - "type": "text", - "placeholders": {} - }, - "enterYourHomeserver": "", - "@enterYourHomeserver": { - "type": "text", - "placeholders": {} - }, - "fileName": "", - "@fileName": { - "type": "text", - "placeholders": {} - }, - "fileSize": "", - "@fileSize": { - "type": "text", - "placeholders": {} - }, - "fluffychat": "", - "@fluffychat": { - "type": "text", - "placeholders": {} - }, - "forward": "", - "@forward": { - "type": "text", - "placeholders": {} - }, - "friday": "", - "@friday": { - "type": "text", - "placeholders": {} - }, - "fromJoining": "", - "@fromJoining": { - "type": "text", - "placeholders": {} - }, - "fromTheInvitation": "", - "@fromTheInvitation": { - "type": "text", - "placeholders": {} - }, - "group": "", - "@group": { - "type": "text", - "placeholders": {} - }, - "groupDescription": "", - "@groupDescription": { - "type": "text", - "placeholders": {} - }, - "groupDescriptionHasBeenChanged": "", - "@groupDescriptionHasBeenChanged": { - "type": "text", - "placeholders": {} - }, - "groupIsPublic": "", - "@groupIsPublic": { - "type": "text", - "placeholders": {} - }, - "groupWith": "", - "@groupWith": { - "type": "text", - "placeholders": { - "displayname": {} - } - }, - "guestsAreForbidden": "", - "@guestsAreForbidden": { - "type": "text", - "placeholders": {} - }, - "guestsCanJoin": "", - "@guestsCanJoin": { - "type": "text", - "placeholders": {} - }, - "hasWithdrawnTheInvitationFor": "", - "@hasWithdrawnTheInvitationFor": { - "type": "text", - "placeholders": { - "username": {}, - "targetName": {} - } - }, - "help": "", - "@help": { - "type": "text", - "placeholders": {} - }, - "homeserverIsNotCompatible": "", - "@homeserverIsNotCompatible": { - "type": "text", - "placeholders": {} - }, - "id": "", - "@id": { - "type": "text", - "placeholders": {} - }, - "identity": "", - "@identity": { - "type": "text", - "placeholders": {} - }, - "incorrectPassphraseOrKey": "", - "@incorrectPassphraseOrKey": { - "type": "text", - "placeholders": {} - }, - "inviteContact": "", - "@inviteContact": { - "type": "text", - "placeholders": {} - }, - "inviteContactToGroup": "", - "@inviteContactToGroup": { - "type": "text", - "placeholders": { - "groupName": {} - } - }, - "invited": "", - "@invited": { - "type": "text", - "placeholders": {} - }, - "invitedUser": "", - "@invitedUser": { - "type": "text", - "placeholders": { - "username": {}, - "targetName": {} - } - }, - "invitedUsersOnly": "", - "@invitedUsersOnly": { - "type": "text", - "placeholders": {} - }, - "inviteText": "", - "@inviteText": { - "type": "text", - "placeholders": { - "username": {}, - "link": {} - } - }, - "isDeviceKeyCorrect": "", - "@isDeviceKeyCorrect": { - "type": "text", - "placeholders": {} - }, - "isTyping": "", - "@isTyping": { - "type": "text", - "placeholders": {} - }, - "joinedTheChat": "", - "@joinedTheChat": { - "type": "text", - "placeholders": { - "username": {} - } - }, - "joinRoom": "", - "@joinRoom": { - "type": "text", - "placeholders": {} - }, - "keysCached": "", - "@keysCached": { - "type": "text", - "placeholders": {} - }, - "keysMissing": "", - "@keysMissing": { - "type": "text", - "placeholders": {} - }, - "kicked": "", - "@kicked": { - "type": "text", - "placeholders": { - "username": {}, - "targetName": {} - } - }, - "kickedAndBanned": "", - "@kickedAndBanned": { - "type": "text", - "placeholders": { - "username": {}, - "targetName": {} - } - }, - "kickFromChat": "", - "@kickFromChat": { - "type": "text", - "placeholders": {} - }, - "lastActiveAgo": "", - "@lastActiveAgo": { - "type": "text", - "placeholders": { - "localizedTimeShort": {} - } - }, - "lastSeenIp": "", - "@lastSeenIp": { - "type": "text", - "placeholders": {} - }, - "lastSeenLongTimeAgo": "", - "@lastSeenLongTimeAgo": { - "type": "text", - "placeholders": {} - }, - "leave": "", - "@leave": { - "type": "text", - "placeholders": {} - }, - "leftTheChat": "", - "@leftTheChat": { - "type": "text", - "placeholders": {} - }, - "license": "", - "@license": { - "type": "text", - "placeholders": {} - }, - "lightTheme": "", - "@lightTheme": { - "type": "text", - "placeholders": {} - }, - "loadCountMoreParticipants": "", - "@loadCountMoreParticipants": { - "type": "text", - "placeholders": { - "count": {} - } - }, - "loadingPleaseWait": "", - "@loadingPleaseWait": { - "type": "text", - "placeholders": {} - }, - "loadMore": "", - "@loadMore": { - "type": "text", - "placeholders": {} - }, - "login": "", - "@login": { - "type": "text", - "placeholders": {} - }, - "logInTo": "", - "@logInTo": { - "type": "text", - "placeholders": { - "homeserver": {} - } - }, - "logout": "", - "@logout": { - "type": "text", - "placeholders": {} - }, - "makeAModerator": "", - "@makeAModerator": { - "type": "text", - "placeholders": {} - }, - "makeAnAdmin": "", - "@makeAnAdmin": { - "type": "text", - "placeholders": {} - }, - "makeSureTheIdentifierIsValid": "", - "@makeSureTheIdentifierIsValid": { - "type": "text", - "placeholders": {} - }, - "messageWillBeRemovedWarning": "", - "@messageWillBeRemovedWarning": { - "type": "text", - "placeholders": {} - }, - "moderator": "", - "@moderator": { - "type": "text", - "placeholders": {} - }, - "monday": "", - "@monday": { - "type": "text", - "placeholders": {} - }, - "muteChat": "", - "@muteChat": { - "type": "text", - "placeholders": {} - }, - "needPantalaimonWarning": "", - "@needPantalaimonWarning": { - "type": "text", - "placeholders": {} - }, - "newMessageInFluffyChat": "", - "@newMessageInFluffyChat": { - "type": "text", - "placeholders": {} - }, - "newPrivateChat": "", - "@newPrivateChat": { - "type": "text", - "placeholders": {} - }, - "newVerificationRequest": "", - "@newVerificationRequest": { - "type": "text", - "placeholders": {} - }, - "noCrossSignBootstrap": "", - "@noCrossSignBootstrap": { - "type": "text", - "placeholders": {} - }, - "noEmotesFound": "", - "@noEmotesFound": { - "type": "text", - "placeholders": {} - }, - "noGoogleServicesWarning": "", - "@noGoogleServicesWarning": { - "type": "text", - "placeholders": {} - }, - "noMegolmBootstrap": "", - "@noMegolmBootstrap": { - "type": "text", - "placeholders": {} - }, - "none": "", - "@none": { - "type": "text", - "placeholders": {} - }, - "noPermission": "", - "@noPermission": { - "type": "text", - "placeholders": {} - }, - "noRoomsFound": "", - "@noRoomsFound": { - "type": "text", - "placeholders": {} - }, - "notSupportedInWeb": "", - "@notSupportedInWeb": { - "type": "text", - "placeholders": {} - }, - "numberSelected": "", - "@numberSelected": { - "type": "text", - "placeholders": { - "number": {} - } - }, - "ok": "", - "@ok": { - "type": "text", - "placeholders": {} - }, - "onlineKeyBackupDisabled": "", - "@onlineKeyBackupDisabled": { - "type": "text", - "placeholders": {} - }, - "onlineKeyBackupEnabled": "", - "@onlineKeyBackupEnabled": { - "type": "text", - "placeholders": {} - }, - "oopsSomethingWentWrong": "", - "@oopsSomethingWentWrong": { - "type": "text", - "placeholders": {} - }, - "openAppToReadMessages": "", - "@openAppToReadMessages": { - "type": "text", - "placeholders": {} - }, - "openCamera": "", - "@openCamera": { - "type": "text", - "placeholders": {} - }, - "optionalGroupName": "", - "@optionalGroupName": { - "type": "text", - "placeholders": {} - }, - "participatingUserDevices": "", - "@participatingUserDevices": { - "type": "text", - "placeholders": {} - }, - "passphraseOrKey": "", - "@passphraseOrKey": { - "type": "text", - "placeholders": {} - }, - "password": "", - "@password": { - "type": "text", - "placeholders": {} - }, - "pickImage": "", - "@pickImage": { - "type": "text", - "placeholders": {} - }, - "pin": "", - "@pin": { - "type": "text", - "placeholders": {} - }, - "play": "", - "@play": { - "type": "text", - "placeholders": { - "fileName": {} - } - }, - "pleaseChooseAUsername": "", - "@pleaseChooseAUsername": { - "type": "text", - "placeholders": {} - }, - "pleaseEnterAMatrixIdentifier": "", - "@pleaseEnterAMatrixIdentifier": { - "type": "text", - "placeholders": {} - }, - "pleaseEnterYourPassword": "", - "@pleaseEnterYourPassword": { - "type": "text", - "placeholders": {} - }, - "pleaseEnterYourUsername": "", - "@pleaseEnterYourUsername": { - "type": "text", - "placeholders": {} - }, - "publicRooms": "", - "@publicRooms": { - "type": "text", - "placeholders": {} - }, - "recording": "", - "@recording": { - "type": "text", - "placeholders": {} - }, - "redactedAnEvent": "", - "@redactedAnEvent": { - "type": "text", - "placeholders": { - "username": {} - } - }, - "reject": "", - "@reject": { - "type": "text", - "placeholders": {} - }, - "rejectedTheInvitation": "", - "@rejectedTheInvitation": { - "type": "text", - "placeholders": { - "username": {} - } - }, - "rejoin": "", - "@rejoin": { - "type": "text", - "placeholders": {} - }, - "remove": "", - "@remove": { - "type": "text", - "placeholders": {} - }, - "removeAllOtherDevices": "", - "@removeAllOtherDevices": { - "type": "text", - "placeholders": {} - }, - "removedBy": "", - "@removedBy": { - "type": "text", - "placeholders": { - "username": {} - } - }, - "removeDevice": "", - "@removeDevice": { - "type": "text", - "placeholders": {} - }, - "removeExile": "", - "@removeExile": { - "type": "text", - "placeholders": {} - }, - "removeMessage": "", - "@removeMessage": { - "type": "text", - "placeholders": {} - }, - "renderRichContent": "", - "@renderRichContent": { - "type": "text", - "placeholders": {} - }, - "reply": "", - "@reply": { - "type": "text", - "placeholders": {} - }, - "requestPermission": "", - "@requestPermission": { - "type": "text", - "placeholders": {} - }, - "requestToReadOlderMessages": "", - "@requestToReadOlderMessages": { - "type": "text", - "placeholders": {} - }, - "revokeAllPermissions": "", - "@revokeAllPermissions": { - "type": "text", - "placeholders": {} - }, - "roomHasBeenUpgraded": "", - "@roomHasBeenUpgraded": { - "type": "text", - "placeholders": {} - }, - "saturday": "", - "@saturday": { - "type": "text", - "placeholders": {} - }, - "searchForAChat": "", - "@searchForAChat": { - "type": "text", - "placeholders": {} - }, - "seenByUser": "", - "@seenByUser": { - "type": "text", - "placeholders": { - "username": {} - } - }, - "seenByUserAndCountOthers": "", - "@seenByUserAndCountOthers": { - "type": "text", - "placeholders": { - "username": {}, - "count": {} - } - }, - "seenByUserAndUser": "", - "@seenByUserAndUser": { - "type": "text", - "placeholders": { - "username": {}, - "username2": {} - } - }, - "send": "", - "@send": { - "type": "text", - "placeholders": {} - }, - "sendAMessage": "", - "@sendAMessage": { - "type": "text", - "placeholders": {} - }, - "sendFile": "", - "@sendFile": { - "type": "text", - "placeholders": {} - }, - "sendImage": "", - "@sendImage": { - "type": "text", - "placeholders": {} - }, - "sentAFile": "", - "@sentAFile": { - "type": "text", - "placeholders": { - "username": {} - } - }, - "sentAnAudio": "", - "@sentAnAudio": { - "type": "text", - "placeholders": { - "username": {} - } - }, - "sentAPicture": "", - "@sentAPicture": { - "type": "text", - "placeholders": { - "username": {} - } - }, - "sentASticker": "", - "@sentASticker": { - "type": "text", - "placeholders": { - "username": {} - } - }, - "sentAVideo": "", - "@sentAVideo": { - "type": "text", - "placeholders": { - "username": {} - } - }, - "sentCallInformations": "", - "@sentCallInformations": { - "type": "text", - "placeholders": { - "senderName": {} - } - }, - "sessionVerified": "", - "@sessionVerified": { - "type": "text", - "placeholders": {} - }, - "setAProfilePicture": "", - "@setAProfilePicture": { - "type": "text", - "placeholders": {} - }, - "setGroupDescription": "", - "@setGroupDescription": { - "type": "text", - "placeholders": {} - }, - "setInvitationLink": "", - "@setInvitationLink": { - "type": "text", - "placeholders": {} - }, - "setStatus": "", - "@setStatus": { - "type": "text", - "placeholders": {} - }, - "settings": "", - "@settings": { - "type": "text", - "placeholders": {} - }, - "share": "", - "@share": { - "type": "text", - "placeholders": {} - }, - "sharedTheLocation": "", - "@sharedTheLocation": { - "type": "text", - "placeholders": { - "username": {} - } - }, - "signUp": "", - "@signUp": { - "type": "text", - "placeholders": {} - }, - "skip": "", - "@skip": { - "type": "text", - "placeholders": {} - }, - "sourceCode": "", - "@sourceCode": { - "type": "text", - "placeholders": {} - }, - "startedACall": "", - "@startedACall": { - "type": "text", - "placeholders": { - "senderName": {} - } - }, - "startYourFirstChat": "", - "@startYourFirstChat": { - "type": "text", - "placeholders": {} - }, - "statusExampleMessage": "", - "@statusExampleMessage": { - "type": "text", - "placeholders": {} - }, - "submit": "", - "@submit": { - "type": "text", - "placeholders": {} - }, - "sunday": "", - "@sunday": { - "type": "text", - "placeholders": {} - }, - "systemTheme": "", - "@systemTheme": { - "type": "text", - "placeholders": {} - }, - "tapToShowMenu": "", - "@tapToShowMenu": { - "type": "text", - "placeholders": {} - }, - "theyDontMatch": "", - "@theyDontMatch": { - "type": "text", - "placeholders": {} - }, - "theyMatch": "", - "@theyMatch": { - "type": "text", - "placeholders": {} - }, - "thisRoomHasBeenArchived": "", - "@thisRoomHasBeenArchived": { - "type": "text", - "placeholders": {} - }, - "thursday": "", - "@thursday": { - "type": "text", - "placeholders": {} - }, - "timeOfDay": "", - "@timeOfDay": { - "type": "text", - "placeholders": { - "hours12": {}, - "hours24": {}, - "minutes": {}, - "suffix": {} - } - }, - "title": "", - "@title": { - "description": "Title for the application", - "type": "text", - "placeholders": {} - }, - "tryToSendAgain": "", - "@tryToSendAgain": { - "type": "text", - "placeholders": {} - }, - "tuesday": "", - "@tuesday": { - "type": "text", - "placeholders": {} - }, - "unbannedUser": "", - "@unbannedUser": { - "type": "text", - "placeholders": { - "username": {}, - "targetName": {} - } - }, - "unblockDevice": "", - "@unblockDevice": { - "type": "text", - "placeholders": {} - }, - "unknownDevice": "", - "@unknownDevice": { - "type": "text", - "placeholders": {} - }, - "unknownEncryptionAlgorithm": "", - "@unknownEncryptionAlgorithm": { - "type": "text", - "placeholders": {} - }, - "unknownEvent": "", - "@unknownEvent": { - "type": "text", - "placeholders": { - "type": {} - } - }, - "unknownSessionVerify": "", - "@unknownSessionVerify": { - "type": "text", - "placeholders": {} - }, - "unmuteChat": "", - "@unmuteChat": { - "type": "text", - "placeholders": {} - }, - "unpin": "", - "@unpin": { - "type": "text", - "placeholders": {} - }, - "unreadChats": "", - "@unreadChats": { - "type": "text", - "placeholders": { - "unreadCount": {} - } - }, - "unreadMessages": "", - "@unreadMessages": { - "type": "text", - "placeholders": { - "unreadEvents": {} - } - }, - "unreadMessagesInChats": "", - "@unreadMessagesInChats": { - "type": "text", - "placeholders": { - "unreadEvents": {}, - "unreadChats": {} - } - }, - "useAmoledTheme": "", - "@useAmoledTheme": { - "type": "text", - "placeholders": {} - }, - "userAndOthersAreTyping": "", - "@userAndOthersAreTyping": { - "type": "text", - "placeholders": { - "username": {}, - "count": {} - } - }, - "userAndUserAreTyping": "", - "@userAndUserAreTyping": { - "type": "text", - "placeholders": { - "username": {}, - "username2": {} - } - }, - "userIsTyping": "", - "@userIsTyping": { - "type": "text", - "placeholders": { - "username": {} - } - }, - "userLeftTheChat": "", - "@userLeftTheChat": { - "type": "text", - "placeholders": { - "username": {} - } - }, - "username": "", - "@username": { - "type": "text", - "placeholders": {} - }, - "userSentUnknownEvent": "", - "@userSentUnknownEvent": { - "type": "text", - "placeholders": { - "username": {}, - "type": {} - } - }, - "verifiedSession": "", - "@verifiedSession": { - "type": "text", - "placeholders": {} - }, - "verify": "", - "@verify": { - "type": "text", - "placeholders": {} - }, - "verifyManual": "", - "@verifyManual": { - "type": "text", - "placeholders": {} - }, - "verifyStart": "", - "@verifyStart": { - "type": "text", - "placeholders": {} - }, - "verifySuccess": "", - "@verifySuccess": { - "type": "text", - "placeholders": {} - }, - "verifyTitle": "", - "@verifyTitle": { - "type": "text", - "placeholders": {} - }, - "verifyUser": "", - "@verifyUser": { - "type": "text", - "placeholders": {} - }, - "videoCall": "", - "@videoCall": { - "type": "text", - "placeholders": {} - }, - "visibilityOfTheChatHistory": "", - "@visibilityOfTheChatHistory": { - "type": "text", - "placeholders": {} - }, - "visibleForAllParticipants": "", - "@visibleForAllParticipants": { - "type": "text", - "placeholders": {} - }, - "visibleForEveryone": "", - "@visibleForEveryone": { - "type": "text", - "placeholders": {} - }, - "voiceMessage": "", - "@voiceMessage": { - "type": "text", - "placeholders": {} - }, - "waitingPartnerAcceptRequest": "", - "@waitingPartnerAcceptRequest": { - "type": "text", - "placeholders": {} - }, - "waitingPartnerEmoji": "", - "@waitingPartnerEmoji": { - "type": "text", - "placeholders": {} - }, - "waitingPartnerNumbers": "", - "@waitingPartnerNumbers": { - "type": "text", - "placeholders": {} - }, - "wallpaper": "", - "@wallpaper": { - "type": "text", - "placeholders": {} - }, - "warningEncryptionInBeta": "", - "@warningEncryptionInBeta": { - "type": "text", - "placeholders": {} - }, - "wednesday": "", - "@wednesday": { - "type": "text", - "placeholders": {} - }, - "welcomeText": "", - "@welcomeText": { - "type": "text", - "placeholders": {} - }, - "whoIsAllowedToJoinThisGroup": "", - "@whoIsAllowedToJoinThisGroup": { - "type": "text", - "placeholders": {} - }, - "writeAMessage": "", - "@writeAMessage": { - "type": "text", - "placeholders": {} - }, - "yes": "", - "@yes": { - "type": "text", - "placeholders": {} - }, - "you": "", - "@you": { - "type": "text", - "placeholders": {} - }, - "youAreInvitedToThisChat": "", - "@youAreInvitedToThisChat": { - "type": "text", - "placeholders": {} - }, - "youAreNoLongerParticipatingInThisChat": "", - "@youAreNoLongerParticipatingInThisChat": { - "type": "text", - "placeholders": {} - }, - "youCannotInviteYourself": "", - "@youCannotInviteYourself": { - "type": "text", - "placeholders": {} - }, - "youHaveBeenBannedFromThisChat": "", - "@youHaveBeenBannedFromThisChat": { - "type": "text", - "placeholders": {} - }, - "yourOwnUsername": "", - "@yourOwnUsername": { - "type": "text", - "placeholders": {} - } -} \ No newline at end of file From 8a4a195bfa4c712e60c5adbea0e8f8835579bf05 Mon Sep 17 00:00:00 2001 From: Sorunome Date: Sun, 4 Oct 2020 13:23:06 +0000 Subject: [PATCH 11/17] Translated using Weblate (German) Currently translated at 100.0% (312 of 312 strings) Translation: FluffyChat/Translations-New Translate-URL: https://hosted.weblate.org/projects/fluffychat/translations-new/de/ --- lib/l10n/intl_de.arb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/l10n/intl_de.arb b/lib/l10n/intl_de.arb index 5d931a4..0a2bfff 100644 --- a/lib/l10n/intl_de.arb +++ b/lib/l10n/intl_de.arb @@ -1702,5 +1702,20 @@ "@deleteAccount": { "type": "text", "placeholders": {} + }, + "privacy": "Privatsphäre", + "@privacy": { + "type": "text", + "placeholders": {} + }, + "enableEmotesGlobally": "Aktiviere Emotikon-Bündel global", + "@enableEmotesGlobally": { + "type": "text", + "placeholders": {} + }, + "emotePacks": "Emoticon-Bündel für Raum", + "@emotePacks": { + "type": "text", + "placeholders": {} } } From 4f419f65c79a7e455449832c4d754e6e36813c89 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sun, 4 Oct 2020 14:06:34 +0000 Subject: [PATCH 12/17] fix(windows): Recreate windows files to make sure windows compiles --- .gitlab-ci.yml | 28 ++++++++++ .../app/src/main/res/values-night/styles.xml | 18 +++++++ windows/flutter/.template_version | 1 - windows/flutter/CMakeLists.txt | 8 +-- windows/runner/CMakeLists.txt | 2 +- windows/runner/Runner.rc | 51 ++++++++++++++++++ windows/runner/flutter_window.cpp | 51 +++++++++++++++--- windows/runner/flutter_window.h | 14 ++--- windows/runner/main.cpp | 7 ++- windows/runner/resources/app_icon.ico | Bin 33772 -> 12383 bytes windows/runner/run_loop.cpp | 14 ++--- windows/runner/run_loop.h | 14 ++--- windows/runner/utils.h | 6 +-- windows/runner/win32_window.cpp | 33 +++++------- windows/runner/win32_window.h | 16 +++--- windows/runner/window_configuration.cpp | 7 --- windows/runner/window_configuration.h | 18 ------- 17 files changed, 195 insertions(+), 93 deletions(-) create mode 100644 android/app/src/main/res/values-night/styles.xml delete mode 100644 windows/flutter/.template_version delete mode 100644 windows/runner/window_configuration.cpp delete mode 100644 windows/runner/window_configuration.h diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5c0f033..07860ce 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,6 +4,12 @@ image: variables: GIT_SUBMODULE_STRATEGY: recursive +.shared_windows_runners: + tags: + - shared-windows + - windows + - windows-1809 + stages: - coverage - publish @@ -44,6 +50,28 @@ build_web: paths: - build/web/ +build_windows: + extends: + - .shared_windows_runners + stage: publish + script: + # Install chocolately + - Set-ExecutionPolicy Bypass -Scope Process + - Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) + - choco install git -y + - choco install visualstudio2019community -y --package-parameters "--add Microsoft.VisualStudio.Product.BuildTools --includeRecommended --includeOptional --passive --locale en-US" + - cd ..; git clone https://github.com/flutter/flutter.git -b dev; $env:path += ";C:\GitLab-Runner\builds\ChristianPauly\flutter\bin"; cd fluffychat-flutter + - flutter doctor + - flutter config --enable-windows-desktop + - flutter build windows + needs: [] + artifacts: + paths: + - build/windows/runner/Release/ + name: "Binairies" + only: + - main + - tags build_android_debug: stage: coverage diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..449a9f9 --- /dev/null +++ b/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/windows/flutter/.template_version b/windows/flutter/.template_version deleted file mode 100644 index 7ed6ff8..0000000 --- a/windows/flutter/.template_version +++ /dev/null @@ -1 +0,0 @@ -5 diff --git a/windows/flutter/CMakeLists.txt b/windows/flutter/CMakeLists.txt index 98bb564..c7a8c76 100644 --- a/windows/flutter/CMakeLists.txt +++ b/windows/flutter/CMakeLists.txt @@ -34,8 +34,8 @@ add_dependencies(flutter flutter_assemble) # === Wrapper === list(APPEND CPP_WRAPPER_SOURCES_CORE - "engine_method_result.cc" - "standard_codec.cc" + "core_implementations.cc" + "standard_codec.cc" ) list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") list(APPEND CPP_WRAPPER_SOURCES_PLUGIN @@ -80,11 +80,13 @@ add_dependencies(flutter_wrapper_app flutter_assemble) # _phony_ is a non-existent file to force this command to run every time, # since currently there's no way to get a full input/output list from the # flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) add_custom_command( OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} ${CPP_WRAPPER_SOURCES_APP} - ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + ${PHONY_OUTPUT} COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" diff --git a/windows/runner/CMakeLists.txt b/windows/runner/CMakeLists.txt index 83e5aca..977e38b 100644 --- a/windows/runner/CMakeLists.txt +++ b/windows/runner/CMakeLists.txt @@ -7,12 +7,12 @@ add_executable(${BINARY_NAME} WIN32 "run_loop.cpp" "utils.cpp" "win32_window.cpp" - "window_configuration.cpp" "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" "Runner.rc" "runner.exe.manifest" ) apply_standard_settings(${BINARY_NAME}) +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/windows/runner/Runner.rc b/windows/runner/Runner.rc index 7d86499..ed2b95f 100644 --- a/windows/runner/Runner.rc +++ b/windows/runner/Runner.rc @@ -54,6 +54,57 @@ END // remains consistent on all systems. IDI_APP_ICON ICON "resources\\app_icon.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#ifdef FLUTTER_BUILD_NUMBER +#define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER +#else +#define VERSION_AS_NUMBER 1,0,0 +#endif + +#ifdef FLUTTER_BUILD_NAME +#define VERSION_AS_STRING #FLUTTER_BUILD_NAME +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "chat.fluffy" "\0" + VALUE "FileDescription", "A new Flutter project." "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "Fluffychat" "\0" + VALUE "LegalCopyright", "Copyright (C) 2020 chat.fluffy. All rights reserved." "\0" + VALUE "OriginalFilename", "fluffychat.exe" "\0" + VALUE "ProductName", "Fluffychat" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/windows/runner/flutter_window.cpp b/windows/runner/flutter_window.cpp index fe980cf..c422723 100644 --- a/windows/runner/flutter_window.cpp +++ b/windows/runner/flutter_window.cpp @@ -1,5 +1,7 @@ #include "flutter_window.h" +#include + #include "flutter/generated_plugin_registrant.h" FlutterWindow::FlutterWindow(RunLoop* run_loop, @@ -8,22 +10,55 @@ FlutterWindow::FlutterWindow(RunLoop* run_loop, FlutterWindow::~FlutterWindow() {} -void FlutterWindow::OnCreate() { - Win32Window::OnCreate(); +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } - // The size here is arbitrary since SetChildContent will resize it. - flutter_controller_ = - std::make_unique(100, 100, project_); - RegisterPlugins(flutter_controller_.get()); - run_loop_->RegisterFlutterInstance(flutter_controller_.get()); + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + run_loop_->RegisterFlutterInstance(flutter_controller_->engine()); SetChildContent(flutter_controller_->view()->GetNativeWindow()); + return true; } void FlutterWindow::OnDestroy() { if (flutter_controller_) { - run_loop_->UnregisterFlutterInstance(flutter_controller_.get()); + run_loop_->UnregisterFlutterInstance(flutter_controller_->engine()); flutter_controller_ = nullptr; } Win32Window::OnDestroy(); } + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opporutunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/windows/runner/flutter_window.h b/windows/runner/flutter_window.h index 4f41e16..b663ddd 100644 --- a/windows/runner/flutter_window.h +++ b/windows/runner/flutter_window.h @@ -1,14 +1,14 @@ -#ifndef FLUTTER_WINDOW_H_ -#define FLUTTER_WINDOW_H_ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ #include #include +#include + #include "run_loop.h" #include "win32_window.h" -#include - // A window that does nothing but host a Flutter view. class FlutterWindow : public Win32Window { public: @@ -20,8 +20,10 @@ class FlutterWindow : public Win32Window { protected: // Win32Window: - void OnCreate() override; + bool OnCreate() override; void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; private: // The run loop driving events for this window. @@ -34,4 +36,4 @@ class FlutterWindow : public Win32Window { std::unique_ptr flutter_controller_; }; -#endif // FLUTTER_WINDOW_H_ +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/windows/runner/main.cpp b/windows/runner/main.cpp index 11b48e9..68fd370 100644 --- a/windows/runner/main.cpp +++ b/windows/runner/main.cpp @@ -5,7 +5,6 @@ #include "flutter_window.h" #include "run_loop.h" #include "utils.h" -#include "window_configuration.h" int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, _In_ wchar_t *command_line, _In_ int show_command) { @@ -23,9 +22,9 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, flutter::DartProject project(L"data"); FlutterWindow window(&run_loop, project); - Win32Window::Point origin(kFlutterWindowOriginX, kFlutterWindowOriginY); - Win32Window::Size size(kFlutterWindowWidth, kFlutterWindowHeight); - if (!window.CreateAndShow(kFlutterWindowTitle, origin, size)) { + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.CreateAndShow(L"Fluffychat", origin, size)) { return EXIT_FAILURE; } window.SetQuitOnClose(true); diff --git a/windows/runner/resources/app_icon.ico b/windows/runner/resources/app_icon.ico index c04e20caf6370ebb9253ad831cc31de4a9c965f6..f53c6c0053751707f857edab9188c4dcee4f2275 100644 GIT binary patch literal 12383 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 diff --git a/windows/runner/run_loop.cpp b/windows/runner/run_loop.cpp index f91d6d4..2d6636a 100644 --- a/windows/runner/run_loop.cpp +++ b/windows/runner/run_loop.cpp @@ -1,9 +1,6 @@ #include "run_loop.h" -#include -// Don't stomp std::min/std::max -#undef max -#undef min +#include #include @@ -47,20 +44,19 @@ void RunLoop::Run() { } void RunLoop::RegisterFlutterInstance( - flutter::FlutterViewController* flutter_instance) { + flutter::FlutterEngine* flutter_instance) { flutter_instances_.insert(flutter_instance); } void RunLoop::UnregisterFlutterInstance( - flutter::FlutterViewController* flutter_instance) { + flutter::FlutterEngine* flutter_instance) { flutter_instances_.erase(flutter_instance); } RunLoop::TimePoint RunLoop::ProcessFlutterMessages() { TimePoint next_event_time = TimePoint::max(); - for (auto flutter_controller : flutter_instances_) { - std::chrono::nanoseconds wait_duration = - flutter_controller->ProcessMessages(); + for (auto instance : flutter_instances_) { + std::chrono::nanoseconds wait_duration = instance->ProcessMessages(); if (wait_duration != std::chrono::nanoseconds::max()) { next_event_time = std::min(next_event_time, TimePoint::clock::now() + wait_duration); diff --git a/windows/runner/run_loop.h b/windows/runner/run_loop.h index 442a58e..000d362 100644 --- a/windows/runner/run_loop.h +++ b/windows/runner/run_loop.h @@ -1,7 +1,7 @@ -#ifndef RUN_LOOP_H_ -#define RUN_LOOP_H_ +#ifndef RUNNER_RUN_LOOP_H_ +#define RUNNER_RUN_LOOP_H_ -#include +#include #include #include @@ -22,11 +22,11 @@ class RunLoop { // Registers the given Flutter instance for event servicing. void RegisterFlutterInstance( - flutter::FlutterViewController* flutter_instance); + flutter::FlutterEngine* flutter_instance); // Unregisters the given Flutter instance from event servicing. void UnregisterFlutterInstance( - flutter::FlutterViewController* flutter_instance); + flutter::FlutterEngine* flutter_instance); private: using TimePoint = std::chrono::steady_clock::time_point; @@ -34,7 +34,7 @@ class RunLoop { // Processes all currently pending messages for registered Flutter instances. TimePoint ProcessFlutterMessages(); - std::set flutter_instances_; + std::set flutter_instances_; }; -#endif // RUN_LOOP_H_ +#endif // RUNNER_RUN_LOOP_H_ diff --git a/windows/runner/utils.h b/windows/runner/utils.h index d247a66..d792603 100644 --- a/windows/runner/utils.h +++ b/windows/runner/utils.h @@ -1,8 +1,8 @@ -#ifndef CONSOLE_UTILS_H_ -#define CONSOLE_UTILS_H_ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ // Creates a console for the process, and redirects stdout and stderr to // it for both the runner and the Flutter library. void CreateAndAttachConsole(); -#endif // CONSOLE_UTILS_H_ +#endif // RUNNER_UTILS_H_ diff --git a/windows/runner/win32_window.cpp b/windows/runner/win32_window.cpp index 677a9a6..efc3eb9 100644 --- a/windows/runner/win32_window.cpp +++ b/windows/runner/win32_window.cpp @@ -122,9 +122,11 @@ bool Win32Window::CreateAndShow(const std::wstring& title, Scale(size.width, scale_factor), Scale(size.height, scale_factor), nullptr, nullptr, GetModuleHandle(nullptr), this); - OnCreate(); + if (!window) { + return false; + } - return window != nullptr; + return OnCreate(); } // static @@ -152,13 +154,6 @@ Win32Window::MessageHandler(HWND hwnd, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept { - auto window = - reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA)); - - if (window == nullptr) { - return 0; - } - switch (message) { case WM_DESTROY: window_handle_ = nullptr; @@ -179,8 +174,7 @@ Win32Window::MessageHandler(HWND hwnd, return 0; } case WM_SIZE: - RECT rect; - GetClientRect(hwnd, &rect); + RECT rect = GetClientArea(); if (child_content_ != nullptr) { // Size and position the child window. MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, @@ -193,11 +187,6 @@ Win32Window::MessageHandler(HWND hwnd, SetFocus(child_content_); } return 0; - - // Messages that are directly forwarded to embedding. - case WM_FONTCHANGE: - SendMessage(child_content_, WM_FONTCHANGE, NULL, NULL); - return 0; } return DefWindowProc(window_handle_, message, wparam, lparam); @@ -223,8 +212,7 @@ Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { void Win32Window::SetChildContent(HWND content) { child_content_ = content; SetParent(content, window_handle_); - RECT frame; - GetClientRect(window_handle_, &frame); + RECT frame = GetClientArea(); MoveWindow(content, frame.left, frame.top, frame.right - frame.left, frame.bottom - frame.top, true); @@ -232,6 +220,12 @@ void Win32Window::SetChildContent(HWND content) { SetFocus(child_content_); } +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + HWND Win32Window::GetHandle() { return window_handle_; } @@ -240,8 +234,9 @@ void Win32Window::SetQuitOnClose(bool quit_on_close) { quit_on_close_ = quit_on_close; } -void Win32Window::OnCreate() { +bool Win32Window::OnCreate() { // No-op; provided for subclasses. + return true; } void Win32Window::OnDestroy() { diff --git a/windows/runner/win32_window.h b/windows/runner/win32_window.h index 5cbb5d5..17ba431 100644 --- a/windows/runner/win32_window.h +++ b/windows/runner/win32_window.h @@ -1,8 +1,7 @@ -#ifndef WIN32_WINDOW_H_ -#define WIN32_WINDOW_H_ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ -#include -#include +#include #include #include @@ -52,6 +51,9 @@ class Win32Window { // If true, closing this window will quit the application. void SetQuitOnClose(bool quit_on_close); + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + protected: // Processes and route salient window messages for mouse handling, // size change and DPI. Delegates handling of these to member overloads that @@ -62,8 +64,8 @@ class Win32Window { LPARAM const lparam) noexcept; // Called when CreateAndShow is called, allowing subclass window-related - // setup. - virtual void OnCreate(); + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); // Called when Destroy is called. virtual void OnDestroy(); @@ -93,4 +95,4 @@ class Win32Window { HWND child_content_ = nullptr; }; -#endif // WIN32_WINDOW_H_ +#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/windows/runner/window_configuration.cpp b/windows/runner/window_configuration.cpp deleted file mode 100644 index 154f85b..0000000 --- a/windows/runner/window_configuration.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "window_configuration.h" - -const wchar_t* kFlutterWindowTitle = L"fluffychat"; -const unsigned int kFlutterWindowOriginX = 10; -const unsigned int kFlutterWindowOriginY = 10; -const unsigned int kFlutterWindowWidth = 1280; -const unsigned int kFlutterWindowHeight = 720; diff --git a/windows/runner/window_configuration.h b/windows/runner/window_configuration.h deleted file mode 100644 index ea5cead..0000000 --- a/windows/runner/window_configuration.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef WINDOW_CONFIGURATION_ -#define WINDOW_CONFIGURATION_ - -// This is a temporary approach to isolate changes that people are likely to -// make to main.cpp, where the APIs are still in flux. This will reduce the -// need to resolve conflicts or re-create changes slightly differently every -// time the Windows Flutter API surface changes. -// -// Longer term there should be simpler configuration options for common -// customizations like this, without requiring native code changes. - -extern const wchar_t* kFlutterWindowTitle; -extern const unsigned int kFlutterWindowOriginX; -extern const unsigned int kFlutterWindowOriginY; -extern const unsigned int kFlutterWindowWidth; -extern const unsigned int kFlutterWindowHeight; - -#endif // WINDOW_CONFIGURATION_ From 5409fe864b39ec2006d20c8d774672afa204942c Mon Sep 17 00:00:00 2001 From: Christian Pauly Date: Sun, 4 Oct 2020 16:11:18 +0200 Subject: [PATCH 13/17] fix: Desktop images --- lib/components/avatar.dart | 7 ++++++- lib/components/content_banner.dart | 17 ++++++++++++----- lib/components/image_bubble.dart | 26 +++++++++++++++++--------- lib/components/input_bar.dart | 17 ++++++++++++----- lib/components/message_reactions.dart | 14 ++++++++++---- lib/utils/platform_infos.dart | 6 ++++++ lib/views/settings_emotes.dart | 20 ++++++++++++++------ pubspec.lock | 2 +- pubspec.yaml | 2 +- 9 files changed, 79 insertions(+), 32 deletions(-) diff --git a/lib/components/avatar.dart b/lib/components/avatar.dart index 1d450b6..47ca14b 100644 --- a/lib/components/avatar.dart +++ b/lib/components/avatar.dart @@ -1,4 +1,5 @@ import 'package:famedlysdk/famedlysdk.dart'; +import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/utils/string_color.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -41,7 +42,11 @@ class Avatar extends StatelessWidget { onTap: onTap, child: CircleAvatar( radius: size / 2, - backgroundImage: !noPic ? CachedNetworkImageProvider(src) : null, + backgroundImage: !noPic + ? PlatformInfos.isBetaDesktop + ? NetworkImage(src) + : CachedNetworkImageProvider(src) + : null, backgroundColor: noPic ? name?.lightColor ?? Theme.of(context).secondaryHeaderColor : Theme.of(context).secondaryHeaderColor, diff --git a/lib/components/content_banner.dart b/lib/components/content_banner.dart index 40eefde..16292e0 100644 --- a/lib/components/content_banner.dart +++ b/lib/components/content_banner.dart @@ -1,4 +1,5 @@ import 'package:famedlysdk/famedlysdk.dart'; +import 'package:fluffychat/utils/platform_infos.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:cached_network_image/cached_network_image.dart'; @@ -48,11 +49,17 @@ class ContentBanner extends StatelessWidget { opacity: 0.75, child: !loading ? mxContent != null - ? CachedNetworkImage( - imageUrl: src, - height: 300, - fit: BoxFit.cover, - ) + ? PlatformInfos.isBetaDesktop + ? Image.network( + src, + height: 300, + fit: BoxFit.cover, + ) + : CachedNetworkImage( + imageUrl: src, + height: 300, + fit: BoxFit.cover, + ) : Icon(defaultIcon, size: 300) : Icon(defaultIcon, size: 300), ), diff --git a/lib/components/image_bubble.dart b/lib/components/image_bubble.dart index 92ce418..5d12bdd 100644 --- a/lib/components/image_bubble.dart +++ b/lib/components/image_bubble.dart @@ -1,5 +1,6 @@ import 'package:famedlysdk/famedlysdk.dart'; import 'package:fluffychat/utils/app_route.dart'; +import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/views/image_view.dart'; import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; @@ -121,15 +122,22 @@ class _ImageBubbleState extends State { fit: widget.fit, ); } else if (isUnencrypted) { - renderWidget = CachedNetworkImage( - imageUrl: Uri.parse(widget.event.content['url']).getThumbnail( - widget.event.room.client, - width: 800, - height: 800, - method: ThumbnailMethod.scale), - placeholder: (context, url) => generatePlaceholderWidget(), - fit: widget.fit, - ); + final src = Uri.parse(widget.event.content['url']).getThumbnail( + widget.event.room.client, + width: 800, + height: 800, + method: ThumbnailMethod.scale); + renderWidget = PlatformInfos.isBetaDesktop + ? Image.network( + src, + fit: widget.fit, + ) + : CachedNetworkImage( + imageUrl: src, + placeholder: (context, url) => + generatePlaceholderWidget(), + fit: widget.fit, + ); } else { renderWidget = generatePlaceholderWidget(); } diff --git a/lib/components/input_bar.dart b/lib/components/input_bar.dart index 3daebaa..ad1f40d 100644 --- a/lib/components/input_bar.dart +++ b/lib/components/input_bar.dart @@ -1,3 +1,4 @@ +import 'package:fluffychat/utils/platform_infos.dart'; import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; import 'package:famedlysdk/famedlysdk.dart'; @@ -146,11 +147,17 @@ class InputBar extends StatelessWidget { child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - CachedNetworkImage( - imageUrl: url, - width: size, - height: size, - ), + PlatformInfos.isBetaDesktop + ? Image.network( + url, + width: size, + height: size, + ) + : CachedNetworkImage( + imageUrl: url, + width: size, + height: size, + ), SizedBox(width: 6), Text(suggestion['name']), Expanded( diff --git a/lib/components/message_reactions.dart b/lib/components/message_reactions.dart index 2619891..cf09add 100644 --- a/lib/components/message_reactions.dart +++ b/lib/components/message_reactions.dart @@ -1,4 +1,5 @@ import 'package:famedlysdk/famedlysdk.dart'; +import 'package:fluffychat/utils/platform_infos.dart'; import 'package:flutter/material.dart'; import 'package:cached_network_image/cached_network_image.dart'; @@ -92,10 +93,15 @@ class _Reaction extends StatelessWidget { content = Row( mainAxisSize: MainAxisSize.min, children: [ - CachedNetworkImage( - imageUrl: src, - height: fontSize, - ), + PlatformInfos.isBetaDesktop + ? Image.network( + src, + height: fontSize, + ) + : CachedNetworkImage( + imageUrl: src, + height: fontSize, + ), Container(width: 4), Text(count.toString(), style: TextStyle( diff --git a/lib/utils/platform_infos.dart b/lib/utils/platform_infos.dart index 4c072b1..5473a8c 100644 --- a/lib/utils/platform_infos.dart +++ b/lib/utils/platform_infos.dart @@ -4,6 +4,12 @@ import 'package:flutter/foundation.dart'; abstract class PlatformInfos { static bool get isWeb => kIsWeb; + static bool get isMobile => !kIsWeb && (Platform.isAndroid || Platform.isIOS); + + /// For desktops which don't support ChachedNetworkImage yet + static bool get isBetaDesktop => + !kIsWeb && (Platform.isWindows || Platform.isLinux); + static bool get usesTouchscreen => !isMobile; } diff --git a/lib/views/settings_emotes.dart b/lib/views/settings_emotes.dart index 1f088e1..9b5af89 100644 --- a/lib/views/settings_emotes.dart +++ b/lib/views/settings_emotes.dart @@ -1,6 +1,7 @@ import 'package:bot_toast/bot_toast.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:famedlysdk/famedlysdk.dart'; +import 'package:fluffychat/utils/platform_infos.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; @@ -415,12 +416,19 @@ class _EmoteImage extends StatelessWidget { height: size * devicePixelRatio, method: ThumbnailMethod.scale, ); - return CachedNetworkImage( - imageUrl: url, - fit: BoxFit.contain, - width: size, - height: size, - ); + return PlatformInfos.isBetaDesktop + ? Image.network( + url, + fit: BoxFit.contain, + width: size, + height: size, + ) + : CachedNetworkImage( + imageUrl: url, + fit: BoxFit.contain, + width: size, + height: size, + ); } } diff --git a/pubspec.lock b/pubspec.lock index 2d4e578..b74b0f3 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1053,5 +1053,5 @@ packages: source: hosted version: "0.1.2" sdks: - dart: ">=2.10.0-110 <2.11.0" + dart: ">=2.10.0-110 <=2.11.0-161.0.dev" flutter: ">=1.20.0 <2.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 3ce587e..d00bf06 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -33,7 +33,7 @@ dependencies: memoryfilepicker: ^0.1.3 url_launcher: ^5.4.1 url_launcher_web: ^0.1.0 - cached_network_image: ^2.3.1 + cached_network_image: ^2.3.2+1 firebase_messaging: ^7.0.2 flutter_local_notifications: ^1.4.3 matrix_link_text: ^0.1.5 From 25587296e8ac00dfe79e984c21fa8da26bfe19ac Mon Sep 17 00:00:00 2001 From: Sorunome Date: Sun, 4 Oct 2020 14:53:30 +0200 Subject: [PATCH 14/17] Update SDK --- lib/utils/famedlysdk_store.dart | 2 +- pubspec.lock | 4 ++-- pubspec.yaml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/utils/famedlysdk_store.dart b/lib/utils/famedlysdk_store.dart index 87adbcd..b14e4b0 100644 --- a/lib/utils/famedlysdk_store.dart +++ b/lib/utils/famedlysdk_store.dart @@ -168,7 +168,7 @@ Future migrate(String clientName, Database db, Store store) async { roomId, pickle, json.encode(devices), - DateTime.now(), + DateTime.now().millisecondsSinceEpoch, 0, ); } diff --git a/pubspec.lock b/pubspec.lock index b74b0f3..190729a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -180,8 +180,8 @@ packages: dependency: "direct main" description: path: "." - ref: "84cc925b08e97098d00c54fff9c1244f91055de3" - resolved-ref: "84cc925b08e97098d00c54fff9c1244f91055de3" + ref: "74bd1d331b77f45ab0793af7c9e607795b8c16f0" + resolved-ref: "74bd1d331b77f45ab0793af7c9e607795b8c16f0" url: "https://gitlab.com/famedly/famedlysdk.git" source: git version: "0.0.1" diff --git a/pubspec.yaml b/pubspec.yaml index d00bf06..5cda641 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,7 +27,7 @@ dependencies: famedlysdk: git: url: https://gitlab.com/famedly/famedlysdk.git - ref: 84cc925b08e97098d00c54fff9c1244f91055de3 + ref: 74bd1d331b77f45ab0793af7c9e607795b8c16f0 localstorage: ^3.0.1+4 memoryfilepicker: ^0.1.3 From 662e2f10a0f40fb0ed43005f2a17210215d6f37f Mon Sep 17 00:00:00 2001 From: Christian Pauly Date: Sun, 4 Oct 2020 17:01:54 +0200 Subject: [PATCH 15/17] fix: Desktop file picker --- lib/views/chat.dart | 83 +++++++++++++------ lib/views/chat_details.dart | 40 ++++++--- lib/views/settings.dart | 38 ++++++--- lib/views/settings_emotes.dart | 33 ++++++-- lib/views/sign_up.dart | 23 ++--- lib/views/sign_up_password.dart | 11 +-- linux/flutter/generated_plugin_registrant.cc | 4 + linux/flutter/generated_plugins.cmake | 1 + pubspec.lock | 37 +++++++-- pubspec.yaml | 3 +- .../flutter/generated_plugin_registrant.cc | 3 + windows/flutter/generated_plugins.cmake | 1 + 12 files changed, 188 insertions(+), 89 deletions(-) diff --git a/lib/views/chat.dart b/lib/views/chat.dart index a2f525b..0dd0283 100644 --- a/lib/views/chat.dart +++ b/lib/views/chat.dart @@ -3,7 +3,8 @@ import 'dart:io'; import 'dart:math'; import 'package:famedlysdk/famedlysdk.dart'; -import 'package:file_picker_platform_interface/file_picker_platform_interface.dart'; + +import 'package:file_picker_cross/file_picker_cross.dart'; import 'package:fluffychat/components/adaptive_page_layout.dart'; import 'package:fluffychat/components/avatar.dart'; import 'package:fluffychat/components/chat_settings_popup_menu.dart'; @@ -17,6 +18,7 @@ import 'package:fluffychat/components/reply_content.dart'; import 'package:fluffychat/config/app_emojis.dart'; import 'package:fluffychat/utils/app_route.dart'; import 'package:fluffychat/utils/matrix_locals.dart'; +import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/utils/room_status_extension.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -24,7 +26,6 @@ import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:image_picker/image_picker.dart'; -import 'package:memoryfilepicker/memoryfilepicker.dart'; import 'package:pedantic/pedantic.dart'; import 'package:scroll_to_index/scroll_to_index.dart'; @@ -211,38 +212,66 @@ class _ChatState extends State<_Chat> { } void sendFileAction(BuildContext context) async { - var file = await MemoryFilePicker.getFile(); - if (file == null) return; + final result = + await FilePickerCross.importFromStorage(type: FileTypeCross.any); + if (result == null) return; await showDialog( - context: context, - builder: (context) => SendFileDialog( - file: - MatrixFile(bytes: file.bytes, name: file.path).detectFileType, - room: room, - )); + context: context, + builder: (context) => SendFileDialog( + file: MatrixFile( + bytes: result.toUint8List(), + name: result.fileName, + ).detectFileType, + room: room, + ), + ); } void sendImageAction(BuildContext context) async { - var file = await MemoryFilePicker.getFile(type: FileType.image); - if (file == null) return; - final bytes = await file.bytes; + MatrixFile file; + if (PlatformInfos.isMobile) { + final result = await ImagePicker().getImage( + source: ImageSource.gallery, + imageQuality: 50, + maxWidth: 1600, + maxHeight: 1600); + if (result == null) return; + file = MatrixFile( + bytes: await result.readAsBytes(), + name: result.path, + ); + } else { + final result = + await FilePickerCross.importFromStorage(type: FileTypeCross.image); + if (result == null) return; + file = MatrixFile( + bytes: result.toUint8List(), + name: result.fileName, + ); + } await showDialog( - context: context, - builder: (context) => SendFileDialog( - file: MatrixImageFile(bytes: bytes, name: file.path), - room: room, - )); + context: context, + builder: (context) => SendFileDialog( + file: file, + room: room, + ), + ); } void openCameraAction(BuildContext context) async { - var file = await MemoryFilePicker.getImage(source: ImageSource.camera); + var file = await ImagePicker().getImage(source: ImageSource.camera); if (file == null) return; + final bytes = await file.readAsBytes(); await showDialog( - context: context, - builder: (context) => SendFileDialog( - file: MatrixImageFile(bytes: file.bytes, name: file.path), - room: room, - )); + context: context, + builder: (context) => SendFileDialog( + file: MatrixImageFile( + bytes: bytes, + name: file.path, + ), + room: room, + ), + ); } void voiceMessageAction(BuildContext context) async { @@ -888,7 +917,7 @@ class _ChatState extends State<_Chat> { contentPadding: EdgeInsets.all(0), ), ), - if (!kIsWeb) + if (PlatformInfos.isMobile) PopupMenuItem( value: 'camera', child: ListTile( @@ -902,7 +931,7 @@ class _ChatState extends State<_Chat> { contentPadding: EdgeInsets.all(0), ), ), - if (!kIsWeb) + if (PlatformInfos.isMobile) PopupMenuItem( value: 'voice', child: ListTile( @@ -972,7 +1001,7 @@ class _ChatState extends State<_Chat> { ), ), ), - if (!kIsWeb && inputText.isEmpty) + if (PlatformInfos.isMobile && inputText.isEmpty) Container( height: 56, alignment: Alignment.center, diff --git a/lib/views/chat_details.dart b/lib/views/chat_details.dart index fd4e423..d702db3 100644 --- a/lib/views/chat_details.dart +++ b/lib/views/chat_details.dart @@ -1,6 +1,8 @@ import 'package:bot_toast/bot_toast.dart'; import 'package:famedlysdk/famedlysdk.dart'; import 'package:famedlysdk/matrix_api.dart'; + +import 'package:file_picker_cross/file_picker_cross.dart'; import 'package:fluffychat/components/adaptive_page_layout.dart'; import 'package:fluffychat/components/chat_settings_popup_menu.dart'; import 'package:fluffychat/components/content_banner.dart'; @@ -8,6 +10,7 @@ import 'package:fluffychat/components/dialogs/simple_dialogs.dart'; import 'package:fluffychat/components/list_items/participant_list_item.dart'; import 'package:fluffychat/utils/app_route.dart'; import 'package:fluffychat/utils/matrix_locals.dart'; +import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/views/chat_list.dart'; import 'package:fluffychat/views/invitation_selection.dart'; import 'package:flutter/foundation.dart'; @@ -16,7 +19,6 @@ import 'package:flutter/services.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:image_picker/image_picker.dart'; import 'package:matrix_link_text/link_text.dart'; -import 'package:memoryfilepicker/memoryfilepicker.dart'; import './settings_emotes.dart'; import './settings_multiple_emotes.dart'; @@ -104,19 +106,31 @@ class _ChatDetailsState extends State { } void setAvatarAction(BuildContext context) async { - final tempFile = await MemoryFilePicker.getImage( - source: ImageSource.gallery, - imageQuality: 50, - maxWidth: 1600, - maxHeight: 1600); - if (tempFile == null) return; + MatrixFile file; + if (PlatformInfos.isMobile) { + final result = await ImagePicker().getImage( + source: ImageSource.gallery, + imageQuality: 50, + maxWidth: 1600, + maxHeight: 1600); + if (result == null) return; + file = MatrixFile( + bytes: await result.readAsBytes(), + name: result.path, + ); + } else { + final result = await FilePickerCross.importFromStorage( + type: FileTypeCross.image, + ); + if (result == null) return; + file = MatrixFile( + bytes: result.toUint8List(), + name: result.fileName, + ); + } + final success = await SimpleDialogs(context).tryRequestWithLoadingDialog( - widget.room.setAvatar( - MatrixFile( - bytes: tempFile.bytes, - name: tempFile.path, - ), - ), + widget.room.setAvatar(file), ); if (success != false) { BotToast.showText(text: L10n.of(context).avatarHasBeenChanged); diff --git a/lib/views/settings.dart b/lib/views/settings.dart index 20bee60..8896a39 100644 --- a/lib/views/settings.dart +++ b/lib/views/settings.dart @@ -2,8 +2,11 @@ import 'dart:io'; import 'package:bot_toast/bot_toast.dart'; import 'package:famedlysdk/famedlysdk.dart'; +import 'package:file_picker_cross/file_picker_cross.dart'; + import 'package:fluffychat/components/settings_themes.dart'; import 'package:fluffychat/config/app_config.dart'; +import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/utils/sentry_controller.dart'; import 'package:fluffychat/views/settings_devices.dart'; import 'package:fluffychat/views/settings_ignore_list.dart'; @@ -11,7 +14,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:image_picker/image_picker.dart'; -import 'package:memoryfilepicker/memoryfilepicker.dart'; import 'package:url_launcher/url_launcher.dart'; import '../components/adaptive_page_layout.dart'; @@ -138,20 +140,30 @@ class _SettingsState extends State { } void setAvatarAction(BuildContext context) async { - final tempFile = await MemoryFilePicker.getImage( - source: ImageSource.gallery, - imageQuality: 50, - maxWidth: 1600, - maxHeight: 1600); - if (tempFile == null) return; + MatrixFile file; + if (PlatformInfos.isMobile) { + final result = await ImagePicker().getImage( + source: ImageSource.gallery, + imageQuality: 50, + maxWidth: 1600, + maxHeight: 1600); + if (result == null) return; + file = MatrixFile( + bytes: await result.readAsBytes(), + name: result.path, + ); + } else { + final result = + await FilePickerCross.importFromStorage(type: FileTypeCross.image); + if (result == null) return; + file = MatrixFile( + bytes: result.toUint8List(), + name: result.fileName, + ); + } final matrix = Matrix.of(context); final success = await SimpleDialogs(context).tryRequestWithLoadingDialog( - matrix.client.setAvatar( - MatrixFile( - bytes: tempFile.bytes, - name: tempFile.path, - ), - ), + matrix.client.setAvatar(file), ); if (success != false) { setState(() { diff --git a/lib/views/settings_emotes.dart b/lib/views/settings_emotes.dart index 9b5af89..5046031 100644 --- a/lib/views/settings_emotes.dart +++ b/lib/views/settings_emotes.dart @@ -1,12 +1,13 @@ import 'package:bot_toast/bot_toast.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:famedlysdk/famedlysdk.dart'; +import 'package:file_picker_cross/file_picker_cross.dart'; + import 'package:fluffychat/utils/platform_infos.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:image_picker/image_picker.dart'; -import 'package:memoryfilepicker/memoryfilepicker.dart'; import '../components/adaptive_page_layout.dart'; import '../components/dialogs/simple_dialogs.dart'; @@ -458,16 +459,30 @@ class _EmoteImagePickerState extends State<_EmoteImagePicker> { BotToast.showText(text: L10n.of(context).notSupportedInWeb); return; } - var file = await MemoryFilePicker.getImage( - source: ImageSource.gallery, - imageQuality: 50, - maxWidth: 128, - maxHeight: 128); - if (file == null) return; - final matrixFile = MatrixFile(bytes: file.bytes, name: file.path); + MatrixFile file; + if (PlatformInfos.isMobile) { + final result = await ImagePicker().getImage( + source: ImageSource.gallery, + imageQuality: 50, + maxWidth: 1600, + maxHeight: 1600); + if (result == null) return; + file = MatrixFile( + bytes: await result.readAsBytes(), + name: result.path, + ); + } else { + final result = await FilePickerCross.importFromStorage( + type: FileTypeCross.image); + if (result == null) return; + file = MatrixFile( + bytes: result.toUint8List(), + name: result.fileName, + ); + } final uploadResp = await SimpleDialogs(context).tryRequestWithLoadingDialog( - Matrix.of(context).client.upload(matrixFile.bytes, matrixFile.name), + Matrix.of(context).client.upload(file.bytes, file.name), ); setState(() { widget.controller.text = uploadResp; diff --git a/lib/views/sign_up.dart b/lib/views/sign_up.dart index a40c3a2..0d7647c 100644 --- a/lib/views/sign_up.dart +++ b/lib/views/sign_up.dart @@ -1,6 +1,8 @@ import 'dart:math'; import 'package:famedlysdk/famedlysdk.dart'; +import 'package:file_picker_cross/file_picker_cross.dart'; + import 'package:fluffychat/components/matrix.dart'; import 'package:fluffychat/utils/app_route.dart'; import 'package:fluffychat/views/login.dart'; @@ -8,8 +10,6 @@ import 'package:fluffychat/views/sign_up_password.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; -import 'package:image_picker/image_picker.dart'; -import 'package:memoryfilepicker/memoryfilepicker.dart'; class SignUp extends StatefulWidget { @override @@ -20,16 +20,19 @@ class _SignUpState extends State { final TextEditingController usernameController = TextEditingController(); String usernameError; bool loading = false; - MemoryFile avatar; + MatrixFile avatar; void setAvatarAction() async { - var file = await MemoryFilePicker.getImage( - source: ImageSource.gallery, - maxHeight: 512, - maxWidth: 512, - imageQuality: 50, - ); - if (file != null) setState(() => avatar = file); + var file = + await FilePickerCross.importFromStorage(type: FileTypeCross.image); + if (file != null) { + setState( + () => avatar = MatrixFile( + bytes: file.toUint8List(), + name: file.fileName, + ), + ); + } } void signUpAction(BuildContext context) async { diff --git a/lib/views/sign_up_password.dart b/lib/views/sign_up_password.dart index 31a3f78..e0ec9ef 100644 --- a/lib/views/sign_up_password.dart +++ b/lib/views/sign_up_password.dart @@ -2,17 +2,17 @@ import 'dart:math'; import 'package:bot_toast/bot_toast.dart'; import 'package:famedlysdk/famedlysdk.dart'; + import 'package:fluffychat/components/matrix.dart'; import 'package:fluffychat/utils/app_route.dart'; import 'package:fluffychat/views/auth_web_view.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; -import 'package:memoryfilepicker/memoryfilepicker.dart'; import 'chat_list.dart'; class SignUpPassword extends StatefulWidget { - final MemoryFile avatar; + final MatrixFile avatar; final String username; final String displayname; const SignUpPassword(this.username, {this.avatar, this.displayname}); @@ -99,12 +99,7 @@ class _SignUpPasswordState extends State { } if (widget.avatar != null) { try { - await matrix.client.setAvatar( - MatrixFile( - bytes: widget.avatar.bytes, - name: widget.avatar.path, - ), - ); + await matrix.client.setAvatar(widget.avatar); } catch (exception) { BotToast.showText(text: L10n.of(context).couldNotSetAvatar); } diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 026851f..b044cbd 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -4,9 +4,13 @@ #include "generated_plugin_registrant.h" +#include #include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) file_chooser_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FileChooserPlugin"); + file_chooser_plugin_register_with_registrar(file_chooser_registrar); g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 1fc8ed3..6a174de 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + file_chooser url_launcher_linux ) diff --git a/pubspec.lock b/pubspec.lock index b74b0f3..e3b8b40 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -162,6 +162,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.6" + disk_space: + dependency: transitive + description: + name: disk_space + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.3" encrypt: dependency: transitive description: @@ -199,6 +206,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "5.2.1" + file_chooser: + dependency: transitive + description: + name: file_chooser + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.5" file_picker: dependency: transitive description: @@ -206,6 +220,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.13.3" + file_picker_cross: + dependency: "direct main" + description: + name: file_picker_cross + url: "https://pub.dartlang.org" + source: hosted + version: "4.2.2" file_picker_platform_interface: dependency: transitive description: @@ -409,7 +430,7 @@ packages: source: hosted version: "2.1.18" image_picker: - dependency: transitive + dependency: "direct main" description: name: image_picker url: "https://pub.dartlang.org" @@ -499,13 +520,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.1.5" - memoryfilepicker: - dependency: "direct main" - description: - name: memoryfilepicker - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.3" meta: dependency: transitive description: @@ -592,6 +606,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.9.3" + package_info: + dependency: transitive + description: + name: package_info + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.3" password_hash: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index d00bf06..55d76cb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -30,7 +30,8 @@ dependencies: ref: 84cc925b08e97098d00c54fff9c1244f91055de3 localstorage: ^3.0.1+4 - memoryfilepicker: ^0.1.3 + file_picker_cross: ^4.2.2 + image_picker: ^0.6.7+11 url_launcher: ^5.4.1 url_launcher_web: ^0.1.0 cached_network_image: ^2.3.2+1 diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index ddfcf7c..9579d43 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -4,9 +4,12 @@ #include "generated_plugin_registrant.h" +#include #include void RegisterPlugins(flutter::PluginRegistry* registry) { + FileChooserPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FileChooserPlugin")); UrlLauncherPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherPlugin")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 411af46..5c2bdaf 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + file_chooser url_launcher_windows ) From 5e673c6d3d36b6e4628f5cc82582cdbadb61c974 Mon Sep 17 00:00:00 2001 From: Christian Pauly Date: Sun, 4 Oct 2020 17:24:05 +0200 Subject: [PATCH 16/17] fix: Inputbar focus --- lib/components/input_bar.dart | 3 +++ lib/views/chat.dart | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/components/input_bar.dart b/lib/components/input_bar.dart index ad1f40d..90e2cc2 100644 --- a/lib/components/input_bar.dart +++ b/lib/components/input_bar.dart @@ -16,6 +16,7 @@ class InputBar extends StatelessWidget { final TextEditingController controller; final InputDecoration decoration; final ValueChanged onChanged; + final bool autofocus; InputBar({ this.room, @@ -27,6 +28,7 @@ class InputBar extends StatelessWidget { this.controller, this.decoration, this.onChanged, + this.autofocus, }); List> getSuggestions(String text) { @@ -265,6 +267,7 @@ class InputBar extends StatelessWidget { minLines: minLines, maxLines: maxLines, keyboardType: keyboardType, + autofocus: autofocus, onSubmitted: (text) { // fix for library for now onSubmitted(text); diff --git a/lib/views/chat.dart b/lib/views/chat.dart index 0dd0283..0f25fc4 100644 --- a/lib/views/chat.dart +++ b/lib/views/chat.dart @@ -961,7 +961,8 @@ class _ChatState extends State<_Chat> { room: room, minLines: 1, maxLines: kIsWeb ? 1 : 8, - keyboardType: kIsWeb + autofocus: !PlatformInfos.isMobile, + keyboardType: !PlatformInfos.isMobile ? TextInputType.text : TextInputType.multiline, onSubmitted: (String text) { From 7ec349b980bf17185e1f40c8481893cc3c927ed6 Mon Sep 17 00:00:00 2001 From: Christian Pauly Date: Sun, 4 Oct 2020 17:39:49 +0200 Subject: [PATCH 17/17] fix: TextField --- lib/views/chat.dart | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/views/chat.dart b/lib/views/chat.dart index 0f25fc4..1bd701b 100644 --- a/lib/views/chat.dart +++ b/lib/views/chat.dart @@ -134,7 +134,6 @@ class _ChatState extends State<_Chat> { @override void initState() { _scrollController.addListener(_updateScrollController); - super.initState(); } @@ -997,7 +996,10 @@ class _ChatState extends State<_Chat> { timeout: Duration(seconds: 30) .inMilliseconds); } - setState(() => inputText = text); + // Workaround for a current desktop bug + if (!PlatformInfos.isBetaDesktop) { + setState(() => inputText = text); + } }, ), ), @@ -1012,7 +1014,8 @@ class _ChatState extends State<_Chat> { voiceMessageAction(context), ), ), - if (kIsWeb || inputText.isNotEmpty) + if (!PlatformInfos.isMobile || + inputText.isNotEmpty) Container( height: 56, alignment: Alignment.center,