From 268488dab09628e3aee56c139a63c0b9b0e5fc09 Mon Sep 17 00:00:00 2001 From: otsmr Date: Tue, 14 Oct 2025 14:16:55 +0200 Subject: [PATCH] fixing new analysis results --- analysis_options.yaml | 1 + lib/app.dart | 22 +- lib/src/database/daos/contacts_dao.dart | 30 ++- lib/src/database/daos/media_uploads_dao.dart | 8 +- .../daos/message_retransmissions.dao.dart | 45 ++-- lib/src/database/daos/messages_dao.dart | 184 ++++++++++------ lib/src/database/daos/signal_dao.dart | 49 +++-- .../signal/connect_identity_key_store.dart | 27 ++- .../signal/connect_sender_key_store.dart | 7 +- .../signal/connect_session_store.dart | 39 ++-- .../signal/connect_signal_protocol_store.dart | 23 +- lib/src/database/twonly_database.dart | 112 ++++++---- lib/src/model/json/message.dart | 31 +-- lib/src/model/memory_item.model.dart | 23 +- lib/src/services/api.service.dart | 31 ++- lib/src/services/api/media_download.dart | 18 +- lib/src/services/api/media_upload.dart | 68 ++++-- lib/src/services/api/messages.dart | 20 +- lib/src/services/api/server_messages.dart | 30 ++- lib/src/services/api/utils.dart | 3 +- lib/src/services/fcm.service.dart | 2 + .../background.notifications.dart | 12 +- .../notifications/pushkeys.notifications.dart | 67 +++--- .../notifications/setup.notifications.dart | 5 +- .../services/signal/encryption.signal.dart | 20 +- lib/src/services/signal/prekeys.signal.dart | 18 +- lib/src/services/signal/utils.signal.dart | 3 +- .../create_backup.twonly_safe.dart | 11 +- .../twonly_safe/restore.twonly_safe.dart | 27 ++- lib/src/utils/log.dart | 3 +- lib/src/utils/misc.dart | 182 +-------------- .../permissions_view.dart | 2 +- .../save_to_gallery.dart | 18 +- .../video_recording_time.dart | 4 +- .../zoom_selector.dart | 49 +++-- .../camera_preview_controller_view.dart | 69 +++--- lib/src/views/camera/camera_send_to_view.dart | 21 +- .../camera/image_editor/action_button.dart | 2 +- .../camera/image_editor/data/image_item.dart | 2 +- .../image_editor/layers/draw_layer.dart | 17 +- .../image_editor/layers/emoji_layer.dart | 11 +- .../image_editor/layers/filter_layer.dart | 6 +- .../layers/filters/location_filter.dart | 4 +- .../image_editor/layers/text_layer.dart | 33 +-- .../camera/image_editor/layers_viewer.dart | 6 +- .../image_editor/modules/all_emojis.dart | 29 +-- .../best_friends_selector.dart | 14 +- .../views/camera/share_image_editor_view.dart | 61 +++--- lib/src/views/camera/share_image_view.dart | 93 ++++---- lib/src/views/chats/add_new_user.view.dart | 33 +-- lib/src/views/chats/chat_list.view.dart | 207 ++++++++++-------- .../backup_notice.card.dart | 8 +- .../connection_info.comp.dart | 10 +- .../chat_list_components/demo_user.card.dart | 2 +- .../chat_list_components/feedback_btn.dart | 8 +- lib/src/views/chats/chat_messages.view.dart | 70 +++--- .../chat_list_entry.dart | 6 +- .../chat_media_entry.dart | 20 +- .../chat_reaction_row.dart | 4 +- .../chat_text_entry.dart | 6 +- .../in_chat_media_viewer.dart | 20 +- .../message_actions.dart | 6 +- .../message_context_menu.dart | 22 +- .../message_send_state_icon.dart | 4 +- .../response_container.dart | 20 +- lib/src/views/chats/media_viewer.view.dart | 111 ++++++---- lib/src/views/chats/start_new_chat.view.dart | 68 +++--- lib/src/views/components/animate_icon.dart | 7 +- lib/src/views/components/app_outdated.dart | 9 +- .../views/components/better_list_title.dart | 17 +- lib/src/views/components/better_text.dart | 34 +-- lib/src/views/components/flame.dart | 3 +- .../views/components/notification_badge.dart | 9 +- .../views/components/user_context_menu.dart | 42 ++-- lib/src/views/components/verified_shield.dart | 15 +- .../components/video_player_wrapper.dart | 32 +-- lib/src/views/contact/contact.view.dart | 30 ++- .../views/contact/contact_verify.view.dart | 43 ++-- .../contact/contact_verify_qr_scan.view.dart | 7 +- lib/src/views/home.view.dart | 68 +++--- lib/src/views/memories/memories.view.dart | 48 ++-- .../memories/memories_photo_slider.view.dart | 27 ++- lib/src/views/onboarding/recover.view.dart | 43 ++-- lib/src/views/onboarding/register.view.dart | 202 +++++++++-------- lib/src/views/settings/account.view.dart | 36 +-- .../settings/account/refund_credits.view.dart | 12 +- lib/src/views/settings/appearance.view.dart | 14 +- .../views/settings/backup/backup.view.dart | 40 ++-- .../backup/twonly_safe_backup.view.dart | 76 ++++--- .../backup/twonly_safe_server.view.dart | 9 +- .../settings/chat/chat_reactions.view.dart | 8 +- .../settings/chat/chat_settings.view.dart | 12 +- .../views/settings/data_and_storage.view.dart | 20 +- .../views/settings/help/changelog.view.dart | 52 +++-- .../views/settings/help/contact_us.view.dart | 32 +-- lib/src/views/settings/help/credits.view.dart | 29 +-- .../views/settings/help/diagnostics.view.dart | 16 +- lib/src/views/settings/help/faq.view.dart | 4 +- lib/src/views/settings/help/help.view.dart | 79 ++++--- lib/src/views/settings/notification.view.dart | 7 +- lib/src/views/settings/privacy.view.dart | 12 +- .../settings/privacy_view_block.users.dart | 25 ++- .../settings/profile/modify_avatar.view.dart | 7 +- .../views/settings/profile/profile.view.dart | 36 +-- .../views/settings/settings_main.view.dart | 167 ++++++++------ .../subscription/additional_users.view.dart | 51 +++-- .../settings/subscription/checkout.view.dart | 35 +-- .../manage_subscription.view.dart | 11 +- .../subscription/select_payment.view.dart | 47 ++-- .../subscription/subscription.view.dart | 139 +++++++----- .../subscription/transaction.view.dart | 5 +- .../settings/subscription/voucher.view.dart | 11 +- lib/src/views/tutorial/show_tutorial.dart | 16 +- lib/src/views/tutorial/tutorials.dart | 8 +- 114 files changed, 2175 insertions(+), 1664 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 1a25be6..0887d9d 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -10,6 +10,7 @@ analyzer: inference_failure_on_instance_creation: ignore avoid_positional_boolean_parameters: ignore inference_failure_on_collection_literal: ignore + matching_super_parameters: ignore exclude: - "lib/src/model/protobuf/**" - "lib/src/model/protobuf/api/websocket/**" diff --git a/lib/app.dart b/lib/app.dart index 0de5d7d..6c9d781 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -23,21 +23,23 @@ class _AppState extends State with WidgetsBindingObserver { bool wasPaused = false; @override - void initState() { + Future initState() async { super.initState(); globalIsAppInBackground = false; WidgetsBinding.instance.addObserver(this); - globalCallbackConnectionState = ({required bool isConnected}) { - context.read().updateConnectionState(isConnected); - setUserPlan(); + globalCallbackConnectionState = ({required bool isConnected}) async { + await context + .read() + .updateConnectionState(isConnected); + await setUserPlan(); }; - globalCallbackUpdatePlan = (String planId) { - context.read().updatePlan(planId); + globalCallbackUpdatePlan = (String planId) async { + await context.read().updatePlan(planId); }; - initAsync(); + await initAsync(); } Future setUserPlan() async { @@ -77,12 +79,12 @@ class _AppState extends State with WidgetsBindingObserver { if (wasPaused) { globalIsAppInBackground = false; twonlyDB.markUpdated(); - apiService.connect(force: true); + unawaited(apiService.connect(force: true)); } } else if (state == AppLifecycleState.paused) { wasPaused = true; globalIsAppInBackground = true; - handleUploadWhenAppGoesBackground(); + unawaited(handleUploadWhenAppGoesBackground()); } } @@ -138,7 +140,7 @@ class _AppState extends State with WidgetsBindingObserver { initialRoute: '/', routes: { '/': (context) => const AppMainWidget(initialPage: 1), - '/chats': (context) => const AppMainWidget(initialPage: 0) + '/chats': (context) => const AppMainWidget(initialPage: 0), }, ); }, diff --git a/lib/src/database/daos/contacts_dao.dart b/lib/src/database/daos/contacts_dao.dart index f889628..2335003 100644 --- a/lib/src/database/daos/contacts_dao.dart +++ b/lib/src/database/daos/contacts_dao.dart @@ -10,6 +10,7 @@ class ContactsDao extends DatabaseAccessor with _$ContactsDaoMixin { // this constructor is required so that the main database can create an instance // of this object. + // ignore: matching_super_parameters ContactsDao(super.db); Future insertContact(ContactsCompanion contact) async { @@ -102,7 +103,9 @@ class ContactsDao extends DatabaseAccessor } Future updateContact( - int userId, ContactsCompanion updatedValues) async { + int userId, + ContactsCompanion updatedValues, + ) async { await (update(contacts)..where((c) => c.userId.equals(userId))) .write(updatedValues); if (updatedValues.blocked.present || @@ -117,10 +120,12 @@ class ContactsDao extends DatabaseAccessor Stream> watchNotAcceptedContacts() { return (select(contacts) - ..where((t) => - t.accepted.equals(false) & - t.archived.equals(false) & - t.blocked.equals(false))) + ..where( + (t) => + t.accepted.equals(false) & + t.archived.equals(false) & + t.blocked.equals(false), + )) .watch(); // return (select(contacts)).watch(); } @@ -132,10 +137,12 @@ class ContactsDao extends DatabaseAccessor Stream> watchContactsForShareView() { return (select(contacts) - ..where((t) => - t.accepted.equals(true) & - t.blocked.equals(false) & - t.deleted.equals(false)) + ..where( + (t) => + t.accepted.equals(true) & + t.blocked.equals(false) & + t.deleted.equals(false), + ) ..orderBy([(t) => OrderingTerm.desc(t.lastMessageExchange)])) .watch(); } @@ -177,8 +184,9 @@ class ContactsDao extends DatabaseAccessor Stream watchContactsRequested() { final count = contacts.requested.count(distinct: true); final query = selectOnly(contacts) - ..where(contacts.requested.equals(true) & - contacts.accepted.equals(true).not()) + ..where( + contacts.requested.equals(true) & contacts.accepted.equals(true).not(), + ) ..addColumns([count]); return query.map((row) => row.read(count)).watchSingle(); } diff --git a/lib/src/database/daos/media_uploads_dao.dart b/lib/src/database/daos/media_uploads_dao.dart index 4ac6961..97135b3 100644 --- a/lib/src/database/daos/media_uploads_dao.dart +++ b/lib/src/database/daos/media_uploads_dao.dart @@ -8,17 +8,21 @@ part 'media_uploads_dao.g.dart'; @DriftAccessor(tables: [MediaUploads]) class MediaUploadsDao extends DatabaseAccessor with _$MediaUploadsDaoMixin { + // ignore: matching_super_parameters MediaUploadsDao(super.db); Future> getMediaUploadsForRetry() { return (select(mediaUploads) ..where( - (t) => t.state.equals(UploadState.receiverNotified.name).not())) + (t) => t.state.equals(UploadState.receiverNotified.name).not(), + )) .get(); } Future updateMediaUpload( - int mediaUploadId, MediaUploadsCompanion updatedValues) { + int mediaUploadId, + MediaUploadsCompanion updatedValues, + ) { return (update(mediaUploads) ..where((c) => c.mediaUploadId.equals(mediaUploadId))) .write(updatedValues); diff --git a/lib/src/database/daos/message_retransmissions.dao.dart b/lib/src/database/daos/message_retransmissions.dao.dart index 49cb0a9..6c45077 100644 --- a/lib/src/database/daos/message_retransmissions.dao.dart +++ b/lib/src/database/daos/message_retransmissions.dao.dart @@ -10,10 +10,12 @@ class MessageRetransmissionDao extends DatabaseAccessor with _$MessageRetransmissionDaoMixin { // this constructor is required so that the main database can create an instance // of this object. + // ignore: matching_super_parameters MessageRetransmissionDao(super.db); Future insertRetransmission( - MessageRetransmissionsCompanion message) async { + MessageRetransmissionsCompanion message, + ) async { try { return await into(messageRetransmissions).insert(message); } catch (e) { @@ -25,18 +27,22 @@ class MessageRetransmissionDao extends DatabaseAccessor Future purgeOldRetransmissions() async { // delete entries older than two weeks await (delete(messageRetransmissions) - ..where((t) => (t.acknowledgeByServerAt.isSmallerThanValue( - DateTime.now().subtract( - const Duration(days: 25), - ), - )))) + ..where( + (t) => (t.acknowledgeByServerAt.isSmallerThanValue( + DateTime.now().subtract( + const Duration(days: 25), + ), + )), + )) .go(); } Future> getRetransmitAbleMessages() async { final countDeleted = await (delete(messageRetransmissions) - ..where((t) => - t.encryptedHash.isNull() & t.acknowledgeByServerAt.isNotNull())) + ..where( + (t) => + t.encryptedHash.isNull() & t.acknowledgeByServerAt.isNotNull(), + )) .go(); if (countDeleted > 0) { @@ -51,7 +57,8 @@ class MessageRetransmissionDao extends DatabaseAccessor } SingleOrNullSelectable getRetransmissionById( - int retransmissionId) { + int retransmissionId, + ) { return select(messageRetransmissions) ..where((t) => t.retransmissionId.equals(retransmissionId)); } @@ -67,9 +74,11 @@ class MessageRetransmissionDao extends DatabaseAccessor Future resetAckStatusFor(int fromUserId, Uint8List encryptedHash) async { return ((update(messageRetransmissions)) - ..where((m) => - m.contactId.equals(fromUserId) & - m.encryptedHash.equals(encryptedHash))) + ..where( + (m) => + m.contactId.equals(fromUserId) & + m.encryptedHash.equals(encryptedHash), + )) .write( const MessageRetransmissionsCompanion( acknowledgeByServerAt: Value(null), @@ -78,11 +87,15 @@ class MessageRetransmissionDao extends DatabaseAccessor } Future getRetransmissionFromHash( - int fromUserId, Uint8List encryptedHash) async { + int fromUserId, + Uint8List encryptedHash, + ) async { return ((select(messageRetransmissions)) - ..where((m) => - m.contactId.equals(fromUserId) & - m.encryptedHash.equals(encryptedHash))) + ..where( + (m) => + m.contactId.equals(fromUserId) & + m.encryptedHash.equals(encryptedHash), + )) .getSingleOrNull(); } diff --git a/lib/src/database/daos/messages_dao.dart b/lib/src/database/daos/messages_dao.dart index 95891f4..f655b27 100644 --- a/lib/src/database/daos/messages_dao.dart +++ b/lib/src/database/daos/messages_dao.dart @@ -11,26 +11,31 @@ class MessagesDao extends DatabaseAccessor with _$MessagesDaoMixin { // this constructor is required so that the main database can create an instance // of this object. + // ignore: matching_super_parameters MessagesDao(super.db); Stream> watchMessageNotOpened(int contactId) { return (select(messages) - ..where((t) => - t.openedAt.isNull() & - t.contactId.equals(contactId) & - t.errorWhileSending.equals(false)) + ..where( + (t) => + t.openedAt.isNull() & + t.contactId.equals(contactId) & + t.errorWhileSending.equals(false), + ) ..orderBy([(t) => OrderingTerm.desc(t.sendAt)])) .watch(); } Stream> watchMediaMessageNotOpened(int contactId) { return (select(messages) - ..where((t) => - t.openedAt.isNull() & - t.contactId.equals(contactId) & - t.errorWhileSending.equals(false) & - t.messageOtherId.isNotNull() & - t.kind.equals(MessageKind.media.name)) + ..where( + (t) => + t.openedAt.isNull() & + t.contactId.equals(contactId) & + t.errorWhileSending.equals(false) & + t.messageOtherId.isNotNull() & + t.kind.equals(MessageKind.media.name), + ) ..orderBy([(t) => OrderingTerm.asc(t.sendAt)])) .watch(); } @@ -45,27 +50,33 @@ class MessagesDao extends DatabaseAccessor Stream> watchAllMessagesFrom(int contactId) { return (select(messages) - ..where((t) => - t.contactId.equals(contactId) & - t.contentJson.isNotNull() & - (t.openedAt.isNull() | - t.mediaStored.equals(true) | - t.openedAt.isBiggerThanValue( - DateTime.now().subtract(const Duration(days: 1))))) + ..where( + (t) => + t.contactId.equals(contactId) & + t.contentJson.isNotNull() & + (t.openedAt.isNull() | + t.mediaStored.equals(true) | + t.openedAt.isBiggerThanValue( + DateTime.now().subtract(const Duration(days: 1)), + )), + ) ..orderBy([(t) => OrderingTerm.asc(t.sendAt)])) .watch(); } Future removeOldMessages() { return (update(messages) - ..where((t) => - (t.openedAt.isSmallerThanValue( - DateTime.now().subtract(const Duration(days: 1)), - ) | - (t.sendAt.isSmallerThanValue( - DateTime.now().subtract(const Duration(days: 1))) & - t.errorWhileSending.equals(true))) & - t.kind.equals(MessageKind.textMessage.name))) + ..where( + (t) => + (t.openedAt.isSmallerThanValue( + DateTime.now().subtract(const Duration(days: 1)), + ) | + (t.sendAt.isSmallerThanValue( + DateTime.now().subtract(const Duration(days: 1)), + ) & + t.errorWhileSending.equals(true))) & + t.kind.equals(MessageKind.textMessage.name), + )) .write(const MessagesCompanion(contentJson: Value(null))); } @@ -99,13 +110,15 @@ class MessagesDao extends DatabaseAccessor Future> getAllNonACKMessagesFromUser() { return (select(messages) - ..where((t) => - t.acknowledgeByUser.equals(false) & - t.messageOtherId.isNull() & - t.errorWhileSending.equals(false) & - t.sendAt.isBiggerThanValue( - DateTime.now().subtract(const Duration(minutes: 10)), - ))) + ..where( + (t) => + t.acknowledgeByUser.equals(false) & + t.messageOtherId.isNull() & + t.errorWhileSending.equals(false) & + t.sendAt.isBiggerThanValue( + DateTime.now().subtract(const Duration(minutes: 10)), + ), + )) .get(); } @@ -133,11 +146,13 @@ class MessagesDao extends DatabaseAccessor Future openedAllNonMediaMessages(int contactId) { final updates = MessagesCompanion(openedAt: Value(DateTime.now())); return (update(messages) - ..where((t) => - t.contactId.equals(contactId) & - t.messageOtherId.isNotNull() & - t.openedAt.isNull() & - t.kind.equals(MessageKind.media.name).not())) + ..where( + (t) => + t.contactId.equals(contactId) & + t.messageOtherId.isNotNull() & + t.openedAt.isNull() & + t.kind.equals(MessageKind.media.name).not(), + )) .write(updates); } @@ -148,44 +163,59 @@ class MessagesDao extends DatabaseAccessor const updates = MessagesCompanion(downloadState: Value(DownloadState.pending)); return (update(messages) - ..where((t) => - t.messageOtherId.isNotNull() & - t.downloadState.equals(DownloadState.downloading.index) & - t.kind.equals(MessageKind.media.name))) + ..where( + (t) => + t.messageOtherId.isNotNull() & + t.downloadState.equals(DownloadState.downloading.index) & + t.kind.equals(MessageKind.media.name), + )) .write(updates); } Future openedAllNonMediaMessagesFromOtherUser(int contactId) { final updates = MessagesCompanion(openedAt: Value(DateTime.now())); return (update(messages) - ..where((t) => - t.contactId.equals(contactId) & - t.messageOtherId - .isNull() & // only mark messages open that where send - t.openedAt.isNull() & - t.kind.equals(MessageKind.media.name).not())) + ..where( + (t) => + t.contactId.equals(contactId) & + t.messageOtherId + .isNull() & // only mark messages open that where send + t.openedAt.isNull() & + t.kind.equals(MessageKind.media.name).not(), + )) .write(updates); } Future updateMessageByOtherUser( - int userId, int messageId, MessagesCompanion updatedValues) { + int userId, + int messageId, + MessagesCompanion updatedValues, + ) { return (update(messages) - ..where((c) => - c.contactId.equals(userId) & c.messageId.equals(messageId))) + ..where( + (c) => c.contactId.equals(userId) & c.messageId.equals(messageId), + )) .write(updatedValues); } Future updateMessageByOtherMessageId( - int userId, int messageOtherId, MessagesCompanion updatedValues) { + int userId, + int messageOtherId, + MessagesCompanion updatedValues, + ) { return (update(messages) - ..where((c) => - c.contactId.equals(userId) & - c.messageOtherId.equals(messageOtherId))) + ..where( + (c) => + c.contactId.equals(userId) & + c.messageOtherId.equals(messageOtherId), + )) .write(updatedValues); } Future updateMessageByMessageId( - int messageId, MessagesCompanion updatedValues) { + int messageId, + MessagesCompanion updatedValues, + ) { return (update(messages)..where((c) => c.messageId.equals(messageId))) .write(updatedValues); } @@ -207,17 +237,22 @@ class MessagesDao extends DatabaseAccessor Future deleteMessagesByContactId(int contactId) { return (delete(messages) - ..where((t) => - t.contactId.equals(contactId) & t.mediaStored.equals(false))) + ..where( + (t) => t.contactId.equals(contactId) & t.mediaStored.equals(false), + )) .go(); } Future deleteMessagesByContactIdAndOtherMessageId( - int contactId, int messageOtherId) { + int contactId, + int messageOtherId, + ) { return (delete(messages) - ..where((t) => - t.contactId.equals(contactId) & - t.messageOtherId.equals(messageOtherId))) + ..where( + (t) => + t.contactId.equals(contactId) & + t.messageOtherId.equals(messageOtherId), + )) .go(); } @@ -234,9 +269,11 @@ class MessagesDao extends DatabaseAccessor int messageOtherId, ) async { final query = select(messages) - ..where((t) => - t.messageOtherId.equals(messageOtherId) & - t.contactId.equals(fromUserId)); + ..where( + (t) => + t.messageOtherId.equals(messageOtherId) & + t.contactId.equals(fromUserId), + ); final entry = await query.get(); return entry.isNotEmpty; } @@ -252,16 +289,23 @@ class MessagesDao extends DatabaseAccessor } SingleOrNullSelectable getMessageByOtherMessageId( - int fromUserId, int messageId) { + int fromUserId, + int messageId, + ) { return select(messages) - ..where((t) => - t.messageOtherId.equals(messageId) & t.contactId.equals(fromUserId)); + ..where( + (t) => + t.messageOtherId.equals(messageId) & t.contactId.equals(fromUserId), + ); } SingleOrNullSelectable getMessageByIdAndContactId( - int fromUserId, int messageId) { + int fromUserId, + int messageId, + ) { return select(messages) - ..where((t) => - t.messageId.equals(messageId) & t.contactId.equals(fromUserId)); + ..where( + (t) => t.messageId.equals(messageId) & t.contactId.equals(fromUserId), + ); } } diff --git a/lib/src/database/daos/signal_dao.dart b/lib/src/database/daos/signal_dao.dart index 3ce89cc..f74796c 100644 --- a/lib/src/database/daos/signal_dao.dart +++ b/lib/src/database/daos/signal_dao.dart @@ -7,13 +7,16 @@ import 'package:twonly/src/utils/log.dart'; part 'signal_dao.g.dart'; -@DriftAccessor(tables: [ - SignalContactPreKeys, - SignalContactSignedPreKeys, -]) +@DriftAccessor( + tables: [ + SignalContactPreKeys, + SignalContactSignedPreKeys, + ], +) class SignalDao extends DatabaseAccessor with _$SignalDaoMixin { // this constructor is required so that the main database can create an instance // of this object. + // ignore: matching_super_parameters SignalDao(super.db); Future deleteAllByContactId(int contactId) async { await (delete(signalContactPreKeys) @@ -48,9 +51,11 @@ class SignalDao extends DatabaseAccessor with _$SignalDaoMixin { if (preKey != null) { // remove the pre key... await (delete(signalContactPreKeys) - ..where((tbl) => - tbl.contactId.equals(contactId) & - tbl.preKeyId.equals(preKey.preKeyId))) + ..where( + (tbl) => + tbl.contactId.equals(contactId) & + tbl.preKeyId.equals(preKey.preKeyId), + )) .go(); return preKey; } @@ -59,7 +64,8 @@ class SignalDao extends DatabaseAccessor with _$SignalDaoMixin { // 3: Insert multiple pre-keys Future insertPreKeys( - List preKeys) async { + List preKeys, + ) async { for (final preKey in preKeys) { try { await into(signalContactPreKeys).insert(preKey); @@ -78,7 +84,8 @@ class SignalDao extends DatabaseAccessor with _$SignalDaoMixin { // 5: Insert or update signed pre-key by contact ID Future insertOrUpdateSignedPreKeyByContactId( - SignalContactSignedPreKeysCompanion signedPreKey) async { + SignalContactSignedPreKeysCompanion signedPreKey, + ) async { await (delete(signalContactSignedPreKeys) ..where((t) => t.contactId.equals(signedPreKey.contactId.value))) .go(); @@ -88,19 +95,23 @@ class SignalDao extends DatabaseAccessor with _$SignalDaoMixin { Future purgeOutDatedPreKeys() async { // other pre keys are valid 25 days await (delete(signalContactSignedPreKeys) - ..where((t) => (t.createdAt.isSmallerThanValue( - DateTime.now().subtract( - const Duration(days: 25), - ), - )))) + ..where( + (t) => (t.createdAt.isSmallerThanValue( + DateTime.now().subtract( + const Duration(days: 25), + ), + )), + )) .go(); // own pre keys are valid for 40 days await (delete(twonlyDB.signalPreKeyStores) - ..where((t) => (t.createdAt.isSmallerThanValue( - DateTime.now().subtract( - const Duration(days: 40), - ), - )))) + ..where( + (t) => (t.createdAt.isSmallerThanValue( + DateTime.now().subtract( + const Duration(days: 40), + ), + )), + )) .go(); } } diff --git a/lib/src/database/signal/connect_identity_key_store.dart b/lib/src/database/signal/connect_identity_key_store.dart index aa2fe55..47d4d88 100644 --- a/lib/src/database/signal/connect_identity_key_store.dart +++ b/lib/src/database/signal/connect_identity_key_store.dart @@ -13,9 +13,11 @@ class ConnectIdentityKeyStore extends IdentityKeyStore { @override Future getIdentity(SignalProtocolAddress address) async { final identity = await (twonlyDB.select(twonlyDB.signalIdentityKeyStores) - ..where((t) => - t.deviceId.equals(address.getDeviceId()) & - t.name.equals(address.getName()))) + ..where( + (t) => + t.deviceId.equals(address.getDeviceId()) & + t.name.equals(address.getName()), + )) .getSingleOrNull(); if (identity == null) return null; return IdentityKey.fromBytes(identity.identityKey, 0); @@ -28,8 +30,11 @@ class ConnectIdentityKeyStore extends IdentityKeyStore { Future getLocalRegistrationId() async => localRegistrationId; @override - Future isTrustedIdentity(SignalProtocolAddress address, - IdentityKey? identityKey, Direction? direction) async { + Future isTrustedIdentity( + SignalProtocolAddress address, + IdentityKey? identityKey, + Direction? direction, + ) async { final trusted = await getIdentity(address); if (identityKey == null) { return false; @@ -41,7 +46,9 @@ class ConnectIdentityKeyStore extends IdentityKeyStore { @override Future saveIdentity( - SignalProtocolAddress address, IdentityKey? identityKey) async { + SignalProtocolAddress address, + IdentityKey? identityKey, + ) async { if (identityKey == null) { return false; } @@ -55,9 +62,11 @@ class ConnectIdentityKeyStore extends IdentityKeyStore { ); } else { await (twonlyDB.update(twonlyDB.signalIdentityKeyStores) - ..where((t) => - t.deviceId.equals(address.getDeviceId()) & - t.name.equals(address.getName()))) + ..where( + (t) => + t.deviceId.equals(address.getDeviceId()) & + t.name.equals(address.getName()), + )) .write( SignalIdentityKeyStoresCompanion( identityKey: Value(identityKey.serialize()), diff --git a/lib/src/database/signal/connect_sender_key_store.dart b/lib/src/database/signal/connect_sender_key_store.dart index 3639e73..e9b0ee2 100644 --- a/lib/src/database/signal/connect_sender_key_store.dart +++ b/lib/src/database/signal/connect_sender_key_store.dart @@ -11,14 +11,17 @@ class ConnectSenderKeyStore extends SenderKeyStore { .getSingleOrNull(); if (identity == null) { throw InvalidKeyIdException( - 'No such sender key record! - $senderKeyName'); + 'No such sender key record! - $senderKeyName', + ); } return SenderKeyRecord.fromSerialized(identity.senderKey); } @override Future storeSenderKey( - SenderKeyName senderKeyName, SenderKeyRecord record) async { + SenderKeyName senderKeyName, + SenderKeyRecord record, + ) async { await twonlyDB.into(twonlyDB.signalSenderKeyStores).insert( SignalSenderKeyStoresCompanion( senderKey: Value(record.serialize()), diff --git a/lib/src/database/signal/connect_session_store.dart b/lib/src/database/signal/connect_session_store.dart index 889b749..d851600 100644 --- a/lib/src/database/signal/connect_session_store.dart +++ b/lib/src/database/signal/connect_session_store.dart @@ -7,9 +7,11 @@ class ConnectSessionStore extends SessionStore { @override Future containsSession(SignalProtocolAddress address) async { final sessions = await (twonlyDB.select(twonlyDB.signalSessionStores) - ..where((tbl) => - tbl.deviceId.equals(address.getDeviceId()) & - tbl.name.equals(address.getName()))) + ..where( + (tbl) => + tbl.deviceId.equals(address.getDeviceId()) & + tbl.name.equals(address.getName()), + )) .get(); return sessions.isNotEmpty; } @@ -24,9 +26,11 @@ class ConnectSessionStore extends SessionStore { @override Future deleteSession(SignalProtocolAddress address) async { await (twonlyDB.delete(twonlyDB.signalSessionStores) - ..where((tbl) => - tbl.deviceId.equals(address.getDeviceId()) & - tbl.name.equals(address.getName()))) + ..where( + (tbl) => + tbl.deviceId.equals(address.getDeviceId()) & + tbl.name.equals(address.getName()), + )) .go(); } @@ -34,7 +38,8 @@ class ConnectSessionStore extends SessionStore { Future> getSubDeviceSessions(String name) async { final deviceIds = await (twonlyDB.select(twonlyDB.signalSessionStores) ..where( - (tbl) => tbl.deviceId.equals(1).not() & tbl.name.equals(name))) + (tbl) => tbl.deviceId.equals(1).not() & tbl.name.equals(name), + )) .get(); return deviceIds.map((row) => row.deviceId).toList(); } @@ -42,9 +47,11 @@ class ConnectSessionStore extends SessionStore { @override Future loadSession(SignalProtocolAddress address) async { final dbSession = await (twonlyDB.select(twonlyDB.signalSessionStores) - ..where((tbl) => - tbl.deviceId.equals(address.getDeviceId()) & - tbl.name.equals(address.getName()))) + ..where( + (tbl) => + tbl.deviceId.equals(address.getDeviceId()) & + tbl.name.equals(address.getName()), + )) .get(); if (dbSession.isEmpty) { @@ -56,7 +63,9 @@ class ConnectSessionStore extends SessionStore { @override Future storeSession( - SignalProtocolAddress address, SessionRecord record) async { + SignalProtocolAddress address, + SessionRecord record, + ) async { final sessionCompanion = SignalSessionStoresCompanion( deviceId: Value(address.getDeviceId()), name: Value(address.getName()), @@ -69,9 +78,11 @@ class ConnectSessionStore extends SessionStore { .insert(sessionCompanion); } else { await (twonlyDB.update(twonlyDB.signalSessionStores) - ..where((tbl) => - tbl.deviceId.equals(address.getDeviceId()) & - tbl.name.equals(address.getName()))) + ..where( + (tbl) => + tbl.deviceId.equals(address.getDeviceId()) & + tbl.name.equals(address.getName()), + )) .write(sessionCompanion); } } diff --git a/lib/src/database/signal/connect_signal_protocol_store.dart b/lib/src/database/signal/connect_signal_protocol_store.dart index 3a6913a..f84774d 100644 --- a/lib/src/database/signal/connect_signal_protocol_store.dart +++ b/lib/src/database/signal/connect_signal_protocol_store.dart @@ -6,7 +6,9 @@ import 'package:twonly/src/database/signal/connect_signed_pre_key_store.dart'; class ConnectSignalProtocolStore implements SignalProtocolStore { ConnectSignalProtocolStore( - IdentityKeyPair identityKeyPair, int registrationId) { + IdentityKeyPair identityKeyPair, + int registrationId, + ) { _identityKeyStore = ConnectIdentityKeyStore(identityKeyPair, registrationId); } @@ -27,12 +29,17 @@ class ConnectSignalProtocolStore implements SignalProtocolStore { @override Future saveIdentity( - SignalProtocolAddress address, IdentityKey? identityKey) async => + SignalProtocolAddress address, + IdentityKey? identityKey, + ) async => _identityKeyStore.saveIdentity(address, identityKey); @override - Future isTrustedIdentity(SignalProtocolAddress address, - IdentityKey? identityKey, Direction direction) async => + Future isTrustedIdentity( + SignalProtocolAddress address, + IdentityKey? identityKey, + Direction direction, + ) async => _identityKeyStore.isTrustedIdentity(address, identityKey, direction); @override @@ -67,7 +74,9 @@ class ConnectSignalProtocolStore implements SignalProtocolStore { @override Future storeSession( - SignalProtocolAddress address, SessionRecord record) async { + SignalProtocolAddress address, + SessionRecord record, + ) async { await sessionStore.storeSession(address, record); } @@ -95,7 +104,9 @@ class ConnectSignalProtocolStore implements SignalProtocolStore { @override Future storeSignedPreKey( - int signedPreKeyId, SignedPreKeyRecord record) async { + int signedPreKeyId, + SignedPreKeyRecord record, + ) async { await signedPreKeyStore.storeSignedPreKey(signedPreKeyId, record); } diff --git a/lib/src/database/twonly_database.dart b/lib/src/database/twonly_database.dart index 16f6070..26e79b2 100644 --- a/lib/src/database/twonly_database.dart +++ b/lib/src/database/twonly_database.dart @@ -23,30 +23,34 @@ import 'package:twonly/src/utils/log.dart'; part 'twonly_database.g.dart'; // You can then create a database class that includes this table -@DriftDatabase(tables: [ - Contacts, - Messages, - MediaUploads, - SignalIdentityKeyStores, - SignalPreKeyStores, - SignalSenderKeyStores, - SignalSessionStores, - SignalContactPreKeys, - SignalContactSignedPreKeys, - MessageRetransmissions -], daos: [ - MessagesDao, - ContactsDao, - MediaUploadsDao, - SignalDao, - MessageRetransmissionDao -]) +@DriftDatabase( + tables: [ + Contacts, + Messages, + MediaUploads, + SignalIdentityKeyStores, + SignalPreKeyStores, + SignalSenderKeyStores, + SignalSessionStores, + SignalContactPreKeys, + SignalContactSignedPreKeys, + MessageRetransmissions, + ], + daos: [ + MessagesDao, + ContactsDao, + MediaUploadsDao, + SignalDao, + MessageRetransmissionDao, + ], +) class TwonlyDatabase extends _$TwonlyDatabase { TwonlyDatabase([QueryExecutor? e]) : super( e ?? _openConnection(), ); + // ignore: matching_super_parameters TwonlyDatabase.forTesting(DatabaseConnection super.connection); @override @@ -74,17 +78,21 @@ class TwonlyDatabase extends _$TwonlyDatabase { from2To3: (m, schema) async { await m.addColumn(schema.contacts, schema.contacts.archived); await m.addColumn( - schema.contacts, schema.contacts.deleteMessagesAfterXMinutes); + schema.contacts, + schema.contacts.deleteMessagesAfterXMinutes, + ); }, from3To4: (m, schema) async { await m.createTable(schema.mediaUploads); - await m.alterTable(TableMigration( - schema.mediaUploads, - columnTransformer: { - schema.mediaUploads.metadata: - schema.mediaUploads.metadata.cast(), - }, - )); + await m.alterTable( + TableMigration( + schema.mediaUploads, + columnTransformer: { + schema.mediaUploads.metadata: + schema.mediaUploads.metadata.cast(), + }, + ), + ); }, from4To5: (m, schema) async { await m.createTable(schema.mediaDownloads); @@ -102,13 +110,15 @@ class TwonlyDatabase extends _$TwonlyDatabase { await m.addColumn(schema.contacts, schema.contacts.lastFlameSync); }, from8To9: (m, schema) async { - await m.alterTable(TableMigration( - schema.mediaUploads, - columnTransformer: { - schema.mediaUploads.metadata: - schema.mediaUploads.metadata.cast(), - }, - )); + await m.alterTable( + TableMigration( + schema.mediaUploads, + columnTransformer: { + schema.mediaUploads.metadata: + schema.mediaUploads.metadata.cast(), + }, + ), + ); }, from9To10: (m, schema) async { await m.createTable(schema.signalContactPreKeys); @@ -119,22 +129,30 @@ class TwonlyDatabase extends _$TwonlyDatabase { await m.createTable(schema.messageRetransmissions); }, from11To12: (m, schema) async { - await m.addColumn(schema.messageRetransmissions, - schema.messageRetransmissions.willNotGetACKByUser); + await m.addColumn( + schema.messageRetransmissions, + schema.messageRetransmissions.willNotGetACKByUser, + ); }, from12To13: (m, schema) async { await m.dropColumn( - schema.messageRetransmissions, 'will_not_get_a_c_k_by_user'); + schema.messageRetransmissions, + 'will_not_get_a_c_k_by_user', + ); }, from13To14: (m, schema) async { - await m.addColumn(schema.messageRetransmissions, - schema.messageRetransmissions.encryptedHash); + await m.addColumn( + schema.messageRetransmissions, + schema.messageRetransmissions.encryptedHash, + ); }, from14To15: (m, schema) async { await m.dropColumn(schema.mediaUploads, 'upload_tokens'); await m.dropColumn(schema.mediaUploads, 'already_notified'); await m.addColumn( - schema.messages, schema.messages.mediaRetransmissionState); + schema.messages, + schema.messages.mediaRetransmissionState, + ); }, from15To16: (m, schema) async { await m.deleteTable('media_downloads'); @@ -150,8 +168,8 @@ class TwonlyDatabase extends _$TwonlyDatabase { Future printTableSizes() async { final result = await customSelect( - 'SELECT name, SUM(pgsize) as size FROM dbstat GROUP BY name') - .get(); + 'SELECT name, SUM(pgsize) as size FROM dbstat GROUP BY name', + ).get(); for (final row in result) { final tableName = row.read('name'); @@ -173,11 +191,13 @@ class TwonlyDatabase extends _$TwonlyDatabase { await delete(signalContactPreKeys).go(); await delete(signalContactSignedPreKeys).go(); await (delete(signalPreKeyStores) - ..where((t) => (t.createdAt.isSmallerThanValue( - DateTime.now().subtract( - const Duration(days: 25), - ), - )))) + ..where( + (t) => (t.createdAt.isSmallerThanValue( + DateTime.now().subtract( + const Duration(days: 25), + ), + )), + )) .go(); } } diff --git a/lib/src/model/json/message.dart b/lib/src/model/json/message.dart index be48336..7a115fb 100644 --- a/lib/src/model/json/message.dart +++ b/lib/src/model/json/message.dart @@ -65,7 +65,9 @@ class MessageJson { messageSenderId: (json['messageSenderId'] as num?)?.toInt(), retransId: (json['retransId'] as num?)?.toInt(), content: MessageContent.fromJson( - kind, json['content'] as Map), + kind, + json['content'] as Map, + ), timestamp: DateTime.fromMillisecondsSinceEpoch(json['timestamp'] as int), ); } @@ -185,13 +187,14 @@ class TextMessageContent extends MessageContent { static TextMessageContent fromJson(Map json) { return TextMessageContent( - text: json['text'] as String, - responseToOtherMessageId: json.containsKey('responseToOtherMessageId') - ? json['responseToOtherMessageId'] as int? - : null, - responseToMessageId: json.containsKey('responseToMessageId') - ? json['responseToMessageId'] as int? - : null); + text: json['text'] as String, + responseToOtherMessageId: json.containsKey('responseToOtherMessageId') + ? json['responseToOtherMessageId'] as int? + : null, + responseToMessageId: json.containsKey('responseToMessageId') + ? json['responseToMessageId'] as int? + : null, + ); } @override @@ -297,10 +300,11 @@ class PushKeyContent extends MessageContent { } class FlameSyncContent extends MessageContent { - FlameSyncContent( - {required this.flameCounter, - required this.bestFriend, - required this.lastFlameCounterChange}); + FlameSyncContent({ + required this.flameCounter, + required this.bestFriend, + required this.lastFlameCounterChange, + }); int flameCounter; DateTime lastFlameCounterChange; bool bestFriend; @@ -310,7 +314,8 @@ class FlameSyncContent extends MessageContent { flameCounter: json['flameCounter'] as int, bestFriend: json['bestFriend'] as bool, lastFlameCounterChange: DateTime.fromMillisecondsSinceEpoch( - json['lastFlameCounterChange'] as int), + json['lastFlameCounterChange'] as int, + ), ); } diff --git a/lib/src/model/memory_item.model.dart b/lib/src/model/memory_item.model.dart index b79487e..8e57d55 100644 --- a/lib/src/model/memory_item.model.dart +++ b/lib/src/model/memory_item.model.dart @@ -67,21 +67,24 @@ class MemoryItem { var mirrorVideo = false; if (videoPath != null) { final content = MediaMessageContent.fromJson( - jsonDecode(message.contentJson!) as Map); + jsonDecode(message.contentJson!) as Map, + ); mirrorVideo = content.mirrorVideo; } items .putIfAbsent( - id, - () => MemoryItem( - id: id, - messages: [], - date: message.sendAt, - mirrorVideo: mirrorVideo, - thumbnailPath: thumbnailFile, - imagePath: imagePath, - videoPath: videoPath)) + id, + () => MemoryItem( + id: id, + messages: [], + date: message.sendAt, + mirrorVideo: mirrorVideo, + thumbnailPath: thumbnailFile, + imagePath: imagePath, + videoPath: videoPath, + ), + ) .messages .add(message); } diff --git a/lib/src/services/api.service.dart b/lib/src/services/api.service.dart index fc23916..f1a88ed 100644 --- a/lib/src/services/api.service.dart +++ b/lib/src/services/api.service.dart @@ -119,9 +119,10 @@ class ApiService { Future startReconnectionTimer() async { reconnectionTimer?.cancel(); - reconnectionTimer ??= Timer(Duration(seconds: _reconnectionDelay), () { + reconnectionTimer ??= + Timer(Duration(seconds: _reconnectionDelay), () async { reconnectionTimer = null; - connect(force: true); + await connect(force: true); }); _reconnectionDelay += 5; } @@ -143,9 +144,9 @@ class ApiService { } connectivitySubscription = Connectivity() .onConnectivityChanged - .listen((List result) { + .listen((List result) async { if (!result.contains(ConnectivityResult.none)) { - connect(force: true); + await connect(force: true); } // Received changes in available connectivity types! }); @@ -186,14 +187,14 @@ class ApiService { bool get isConnected => _channel != null && _channel!.closeCode != null; - void _onDone() { + Future _onDone() async { Log.info('websocket closed without error'); - onClosed(); + await onClosed(); } - void _onError(dynamic e) { + Future _onError(dynamic e) async { Log.error('websocket error: $e'); - onClosed(); + await onClosed(); } Future _onData(dynamic msgBuffer) async { @@ -441,7 +442,9 @@ class ApiService { const storage = FlutterSecureStorage(); await storage.write( - key: SecureStorageKeys.apiAuthToken, value: apiAuthTokenB64); + key: SecureStorageKeys.apiAuthToken, + value: apiAuthTokenB64, + ); await tryAuthenticateWithToken(userData.userId); } @@ -575,7 +578,10 @@ class ApiService { } Future switchToPayedPlan( - String planId, bool payMonthly, bool autoRenewal) async { + String planId, + bool payMonthly, + bool autoRenewal, + ) async { final get = ApplicationData_SwitchToPayedPlan() ..planId = planId ..payMonthly = payMonthly @@ -676,7 +682,10 @@ class ApiService { } Future sendTextMessage( - int target, Uint8List msg, List? pushData) async { + int target, + Uint8List msg, + List? pushData, + ) async { final testMessage = ApplicationData_TextMessage() ..userId = Int64(target) ..body = msg; diff --git a/lib/src/services/api/media_download.dart b/lib/src/services/api/media_download.dart index 3d89180..4148d9d 100644 --- a/lib/src/services/api/media_download.dart +++ b/lib/src/services/api/media_download.dart @@ -40,8 +40,8 @@ Map> defaultAutoDownloadOptions = { ConnectivityResult.mobile.name: [], ConnectivityResult.wifi.name: [ DownloadMediaTypes.video.name, - DownloadMediaTypes.image.name - ] + DownloadMediaTypes.image.name, + ], }; Future isAllowedToDownload(bool isVideo) async { @@ -121,7 +121,8 @@ Mutex protectDownload = Mutex(); Future startDownloadMedia(Message message, bool force) async { Log.info( - 'Download blocked for ${message.messageId} because of network state.'); + 'Download blocked for ${message.messageId} because of network state.', + ); if (message.contentJson == null) { Log.error('Content of ${message.messageId} not found.'); await handleMediaError(message); @@ -147,7 +148,8 @@ Future startDownloadMedia(Message message, bool force) async { if (!force && !await isAllowedToDownload(content.isVideo)) { Log.warn( - 'Download blocked for ${message.messageId} because of network state.'); + 'Download blocked for ${message.messageId} because of network state.', + ); return; } @@ -160,7 +162,8 @@ Future startDownloadMedia(Message message, bool force) async { if (msg.downloadState != DownloadState.pending) { Log.error( - '${message.messageId} is already downloaded or is downloading.'); + '${message.messageId} is already downloaded or is downloading.', + ); return true; } @@ -317,7 +320,8 @@ Future handleEncryptedFile(int messageId) async { await writeMediaFile(msg.messageId, 'png', imageBytes); } catch (e) { Log.error( - 'could not decrypt the media file in the second try. reporting error to user: $e'); + 'could not decrypt the media file in the second try. reporting error to user: $e', + ); await handleMediaError(msg); return; } @@ -461,7 +465,7 @@ Future purgeMediaFiles(Directory directory) async { if ((message == null) || (message.openedAt != null && !message.mediaStored && - message.acknowledgeByServer == true) || + message.acknowledgeByServer) || message.errorWhileSending) { file.deleteSync(); } diff --git a/lib/src/services/api/media_upload.dart b/lib/src/services/api/media_upload.dart index 815032c..96c35a4 100644 --- a/lib/src/services/api/media_upload.dart +++ b/lib/src/services/api/media_upload.dart @@ -75,16 +75,19 @@ Future initFileDownloader() async { } case TaskProgressUpdate(): Log.info( - 'Progress update for ${update.task} with progress ${update.progress}'); + 'Progress update for ${update.task} with progress ${update.progress}', + ); } }); await FileDownloader().start(); try { - await FileDownloader().configure(androidConfig: [ - (Config.bypassTLSCertificateValidation, kDebugMode), - ]); + var androidConfig = []; + if (kDebugMode) { + androidConfig = [(Config.bypassTLSCertificateValidation, kDebugMode)]; + } + await FileDownloader().configure(androidConfig: androidConfig); } catch (e) { Log.error(e); } @@ -201,7 +204,9 @@ Future addVideoToUpload(int mediaUploadId, File videoFilePath) async { } Future addOrModifyImageToUpload( - int mediaUploadId, Uint8List imageBytes) async { + int mediaUploadId, + Uint8List imageBytes, +) async { Uint8List imageBytesCompressed; final stopwatch = Stopwatch()..start(); @@ -236,7 +241,8 @@ Future addOrModifyImageToUpload( stopwatch.stop(); Log.info( - 'Compression the image took: ${stopwatch.elapsedMilliseconds} milliseconds'); + 'Compression the image took: ${stopwatch.elapsedMilliseconds} milliseconds', + ); Log.info('Raw images size in bytes: ${imageBytesCompressed.length}'); // stopwatch.reset(); @@ -285,7 +291,6 @@ Future encryptMediaFiles( Future? videoHandler, ) async { Log.info('$mediaUploadId encrypting files'); - // ignore: cast_nullable_to_non_nullable var dataToEncrypt = await imageHandler; /// if there is a video wait until it is finished with compression @@ -332,8 +337,14 @@ Future encryptMediaFiles( unawaited(handleNextMediaUploadSteps(mediaUploadId)); } -Future finalizeUpload(int mediaUploadId, List contactIds, - bool isRealTwonly, bool isVideo, bool mirrorVideo, int maxShowTime) async { +Future finalizeUpload( + int mediaUploadId, + List contactIds, + bool isRealTwonly, + bool isVideo, + bool mirrorVideo, + int maxShowTime, +) async { final metadata = MediaUploadMetadata() ..contactIds = contactIds ..isRealTwonly = isRealTwonly @@ -474,7 +485,8 @@ Future handleUploadStatusUpdate(TaskStatusUpdate update) async { } } Log.info( - 'Status update for ${update.task.taskId} with status ${update.status}'); + 'Status update for ${update.task.taskId} with status ${update.status}', + ); } Future handleUploadSuccess(MediaUpload media) async { @@ -565,7 +577,8 @@ Future handleMediaUpload(MediaUpload media) async { if (contact == null || contact.deleted) { Log.warn( - 'Contact deleted ${message.contactId} or not found in database.'); + 'Contact deleted ${message.contactId} or not found in database.', + ); await twonlyDB.messagesDao.updateMessageByMessageId( message.messageId, const MessagesCompanion(errorWhileSending: Value(true)), @@ -708,11 +721,13 @@ Future uploadFileFast( ); requestMultipart.headers['x-twonly-auth-token'] = apiAuthToken; - requestMultipart.files.add(http.MultipartFile.fromBytes( - 'file', - uploadRequestFile, - filename: 'upload', - )); + requestMultipart.files.add( + http.MultipartFile.fromBytes( + 'file', + uploadRequestFile, + filename: 'upload', + ), + ); final response = await requestMultipart.send(); if (response.statusCode == 200) { @@ -790,7 +805,10 @@ Future readSendMediaFile(int mediaUploadId, String type) async { } Future writeSendMediaFile( - int mediaUploadId, String type, Uint8List data) async { + int mediaUploadId, + String type, + Uint8List data, +) async { final basePath = await getMediaFilePath(mediaUploadId, 'send'); final file = File('$basePath.$type'); await file.writeAsBytes(data); @@ -838,8 +856,11 @@ List extractUint8Lists(Uint8List combinedList) { final byteData = ByteData.sublistView(combinedList); final sizeOfList1 = byteData.getInt32(0); final list1 = Uint8List.view(combinedList.buffer, 4, sizeOfList1); - final list2 = Uint8List.view(combinedList.buffer, 4 + sizeOfList1, - combinedList.lengthInBytes - 4 - sizeOfList1); + final list2 = Uint8List.view( + combinedList.buffer, + 4 + sizeOfList1, + combinedList.lengthInBytes - 4 - sizeOfList1, + ); return [list1, list2]; } @@ -853,9 +874,12 @@ String uint8ListToHex(List bytes) { return bytes.map((byte) => byte.toRadixString(16).padLeft(2, '0')).join(); } -Uint8List hexToUint8List(String hex) => Uint8List.fromList(List.generate( - hex.length ~/ 2, - (i) => int.parse(hex.substring(i * 2, i * 2 + 2), radix: 16))); +Uint8List hexToUint8List(String hex) => Uint8List.fromList( + List.generate( + hex.length ~/ 2, + (i) => int.parse(hex.substring(i * 2, i * 2 + 2), radix: 16), + ), + ); Uint8List createDownloadToken() { final random = Random(); diff --git a/lib/src/services/api/messages.dart b/lib/src/services/api/messages.dart index 969827a..e7ddee9 100644 --- a/lib/src/services/api/messages.dart +++ b/lib/src/services/api/messages.dart @@ -52,11 +52,13 @@ Future sendRetransmitMessage(int retransId) async { return; } - final json = MessageJson.fromJson(jsonDecode( - utf8.decode( - gzip.decode(retrans.plaintextContent), - ), - ) as Map); + final json = MessageJson.fromJson( + jsonDecode( + utf8.decode( + gzip.decode(retrans.plaintextContent), + ), + ) as Map, + ); Log.info('Retransmitting $retransId: ${json.kind} to ${retrans.contactId}'); @@ -183,9 +185,11 @@ Future encryptAndSendMessageAsync( Uint8List.fromList(gzip.encode(utf8.encode(jsonEncode(msg.toJson())))); await twonlyDB.messageRetransmissionDao.updateRetransmission( - retransId, - MessageRetransmissionsCompanion( - plaintextContent: Value(plaintextContent))); + retransId, + MessageRetransmissionsCompanion( + plaintextContent: Value(plaintextContent), + ), + ); // this can now be done in the background... unawaited(sendRetransmitMessage(retransId)); diff --git a/lib/src/services/api/server_messages.dart b/lib/src/services/api/server_messages.dart index c969e5d..f3515a3 100644 --- a/lib/src/services/api/server_messages.dart +++ b/lib/src/services/api/server_messages.dart @@ -131,7 +131,8 @@ Future handleNewMessage(int fromUserId, Uint8List body) async { } case MessageKind.signalDecryptError: Log.error( - 'Got signal decrypt error from other user! Sending all non ACK messages again.'); + 'Got signal decrypt error from other user! Sending all non ACK messages again.', + ); final content = message.content; if (content is SignalDecryptErrorContent) { @@ -303,7 +304,9 @@ Future handleNewMessage(int fromUserId, Uint8List body) async { ); final msg = await twonlyDB.messagesDao .getMessageByIdAndContactId( - fromUserId, message.messageReceiverId!) + fromUserId, + message.messageReceiverId!, + ) .getSingleOrNull(); if (msg != null && msg.mediaUploadId != null) { final filePath = @@ -329,7 +332,8 @@ Future handleNewMessage(int fromUserId, Uint8List body) async { .deleteMessagesByMessageId(openedMessage.messageId); } else { Log.error( - 'Got a duplicated message from other user: ${message.messageSenderId!}'); + 'Got a duplicated message from other user: ${message.messageSenderId!}', + ); final ok = client.Response_Ok()..none = true; return client.Response()..ok = ok; } @@ -387,9 +391,11 @@ Future handleNewMessage(int fromUserId, Uint8List body) async { responseToMessageId: Value(responseToMessageId), responseToOtherMessageId: Value(responseToOtherMessageId), openedAt: Value(openedAt), - downloadState: Value(message.kind == MessageKind.media - ? DownloadState.pending - : DownloadState.downloaded), + downloadState: Value( + message.kind == MessageKind.media + ? DownloadState.pending + : DownloadState.downloaded, + ), sendAt: Value(message.timestamp), ); @@ -440,9 +446,11 @@ Future handleRequestNewPreKey() async { final prekeysList = []; for (var i = 0; i < localPreKeys.length; i++) { - prekeysList.add(client.Response_PreKey() - ..id = Int64(localPreKeys[i].id) - ..prekey = localPreKeys[i].getKeyPair().publicKey.serialize()); + prekeysList.add( + client.Response_PreKey() + ..id = Int64(localPreKeys[i].id) + ..prekey = localPreKeys[i].getKeyPair().publicKey.serialize(), + ); } final prekeys = client.Response_Prekeys(prekeys: prekeysList); final ok = client.Response_Ok()..prekeys = prekeys; @@ -450,7 +458,9 @@ Future handleRequestNewPreKey() async { } Future handleContactRequest( - int fromUserId, MessageJson message) async { + int fromUserId, + MessageJson message, +) async { // request the username by the server so an attacker can not // forge the displayed username in the contact request final username = await apiService.getUsername(fromUserId); diff --git a/lib/src/services/api/utils.dart b/lib/src/services/api/utils.dart index e67254d..3c42df9 100644 --- a/lib/src/services/api/utils.dart +++ b/lib/src/services/api/utils.dart @@ -44,7 +44,8 @@ ClientToServer createClientToServerFromHandshake(Handshake handshake) { } ClientToServer createClientToServerFromApplicationData( - ApplicationData applicationData) { + ApplicationData applicationData, +) { final v0 = client.V0() ..seq = Int64() ..applicationdata = applicationData; diff --git a/lib/src/services/fcm.service.dart b/lib/src/services/fcm.service.dart index 303fc68..899936f 100644 --- a/lib/src/services/fcm.service.dart +++ b/lib/src/services/fcm.service.dart @@ -1,3 +1,5 @@ +// ignore_for_file: unreachable_from_main + import 'dart:io' show Platform; import 'package:firebase_core/firebase_core.dart'; diff --git a/lib/src/services/notifications/background.notifications.dart b/lib/src/services/notifications/background.notifications.dart index fc6c455..294fd03 100644 --- a/lib/src/services/notifications/background.notifications.dart +++ b/lib/src/services/notifications/background.notifications.dart @@ -98,7 +98,9 @@ Future handlePushData(String pushDataB64) async { } Future tryDecryptMessage( - List key, EncryptedPushNotification push) async { + List key, + EncryptedPushNotification push, +) async { try { final chacha20 = FlutterChacha20.poly1305Aead(); final secretKeyData = SecretKeyData(key); @@ -190,7 +192,9 @@ Future showLocalPushNotificationWithoutUserId( const darwinNotificationDetails = DarwinNotificationDetails(); const notificationDetails = NotificationDetails( - android: androidNotificationDetails, iOS: darwinNotificationDetails); + android: androidNotificationDetails, + iOS: darwinNotificationDetails, + ); await flutterLocalNotificationsPlugin.show( 2, @@ -307,7 +311,9 @@ String getPushNotificationText(PushNotification pushNotification) { var contentText = pushNotificationText[pushNotification.kind.name] ?? ''; if (pushNotification.hasReactionContent()) { contentText = contentText.replaceAll( - '{{reaction}}', pushNotification.reactionContent); + '{{reaction}}', + pushNotification.reactionContent, + ); } return contentText; } diff --git a/lib/src/services/notifications/pushkeys.notifications.dart b/lib/src/services/notifications/pushkeys.notifications.dart index 258297a..5488cc1 100644 --- a/lib/src/services/notifications/pushkeys.notifications.dart +++ b/lib/src/services/notifications/pushkeys.notifications.dart @@ -18,8 +18,10 @@ import 'package:twonly/src/services/api/messages.dart'; import 'package:twonly/src/utils/log.dart'; /// This function must be called after the database is setup -Future setupNotificationWithUsers( - {bool force = false, int? forceContact}) async { +Future setupNotificationWithUsers({ + bool force = false, + int? forceContact, +}) async { var pushUsers = await getPushKeys(SecureStorageKeys.receivingPushKeys); // HotFIX: Search for user with id 0 if not there remove all @@ -29,11 +31,13 @@ Future setupNotificationWithUsers( Log.info('Clearing push keys'); await setPushKeys(SecureStorageKeys.receivingPushKeys, []); pushUsers = await getPushKeys(SecureStorageKeys.receivingPushKeys) - ..add(PushUser( - userId: Int64(), - displayName: 'NoUser', - pushKeys: [], - )); + ..add( + PushUser( + userId: Int64(), + displayName: 'NoUser', + pushKeys: [], + ), + ); } var wasChanged = false; @@ -51,7 +55,8 @@ Future setupNotificationWithUsers( DateTime.now().subtract(Duration(days: 5 + random.nextInt(5))); final lastKey = pushUser.pushKeys.last; final createdAt = DateTime.fromMillisecondsSinceEpoch( - lastKey.createdAtUnixTimestamp.toInt()); + lastKey.createdAtUnixTimestamp.toInt(), + ); if (force || (forceContact == contact.userId) || @@ -82,12 +87,14 @@ Future setupNotificationWithUsers( createdAtUnixTimestamp: Int64(DateTime.now().millisecondsSinceEpoch), ); await sendNewPushKey(contact.userId, pushKey); - pushUsers.add(PushUser( - userId: Int64(contact.userId), - displayName: getContactDisplayName(contact), - blocked: contact.blocked, - pushKeys: [pushKey], - )); + pushUsers.add( + PushUser( + userId: Int64(contact.userId), + displayName: getContactDisplayName(contact), + blocked: contact.blocked, + pushKeys: [pushKey], + ), + ); } } @@ -119,13 +126,15 @@ Future updatePushUser(Contact contact) async { final pushUser = pushKeys.firstWhereOrNull((x) => x.userId == contact.userId); if (pushUser == null) { - pushKeys.add(PushUser( - userId: Int64(contact.userId), - displayName: getContactDisplayName(contact), - pushKeys: [], - blocked: contact.blocked, - lastMessageId: Int64(), - )); + pushKeys.add( + PushUser( + userId: Int64(contact.userId), + displayName: getContactDisplayName(contact), + pushKeys: [], + blocked: contact.blocked, + lastMessageId: Int64(), + ), + ); } else { pushUser ..displayName = getContactDisplayName(contact) @@ -145,13 +154,15 @@ Future handleNewPushKey(int fromUserId, my.PushKeyContent pushKey) async { .getContactByUserId(fromUserId) .getSingleOrNull(); if (contact == null) return; - pushKeys.add(PushUser( - userId: Int64(fromUserId), - displayName: getContactDisplayName(contact), - pushKeys: [], - blocked: contact.blocked, - lastMessageId: Int64(), - )); + pushKeys.add( + PushUser( + userId: Int64(fromUserId), + displayName: getContactDisplayName(contact), + pushKeys: [], + blocked: contact.blocked, + lastMessageId: Int64(), + ), + ); pushUser = pushKeys.firstWhereOrNull((x) => x.userId == fromUserId); } diff --git a/lib/src/services/notifications/setup.notifications.dart b/lib/src/services/notifications/setup.notifications.dart index 4631320..03ff634 100644 --- a/lib/src/services/notifications/setup.notifications.dart +++ b/lib/src/services/notifications/setup.notifications.dart @@ -1,3 +1,5 @@ +// ignore_for_file: unreachable_from_main + import 'dart:async'; import 'dart:io'; import 'dart:ui' as ui; @@ -18,7 +20,8 @@ void notificationTapBackground(NotificationResponse notificationResponse) { if (notificationResponse.input?.isNotEmpty ?? false) { // ignore: avoid_print print( - 'notification action tapped with input: ${notificationResponse.input}'); + 'notification action tapped with input: ${notificationResponse.input}', + ); } } diff --git a/lib/src/services/signal/encryption.signal.dart b/lib/src/services/signal/encryption.signal.dart index 9307db5..8087fac 100644 --- a/lib/src/services/signal/encryption.signal.dart +++ b/lib/src/services/signal/encryption.signal.dart @@ -15,7 +15,9 @@ import 'package:twonly/src/utils/misc.dart'; final lockingSignalEncryption = Mutex(); Future signalEncryptMessage( - int target, Uint8List plaintextContent) async { + int target, + Uint8List plaintextContent, +) async { return lockingSignalEncryption.protect(() async { try { final signalStore = (await getSignalStore())!; @@ -95,7 +97,9 @@ Future signalDecryptMessage(int source, Uint8List msg) async { final signalStore = (await getSignalStore())!; final session = SessionCipher.fromStore( - signalStore, SignalProtocolAddress(source.toString(), defaultDeviceId)); + signalStore, + SignalProtocolAddress(source.toString(), defaultDeviceId), + ); final msgs = removeLastXBytes(msg, 4); if (msgs == null) { @@ -115,11 +119,13 @@ Future signalDecryptMessage(int source, Uint8List msg) async { Log.error('Type not known: $type'); return null; } - return MessageJson.fromJson(jsonDecode( - utf8.decode( - gzip.decode(plaintext), - ), - ) as Map); + return MessageJson.fromJson( + jsonDecode( + utf8.decode( + gzip.decode(plaintext), + ), + ) as Map, + ); } catch (e) { Log.error(e.toString()); return null; diff --git a/lib/src/services/signal/prekeys.signal.dart b/lib/src/services/signal/prekeys.signal.dart index 4f50493..9ce59be 100644 --- a/lib/src/services/signal/prekeys.signal.dart +++ b/lib/src/services/signal/prekeys.signal.dart @@ -37,7 +37,8 @@ Future requestNewPrekeysForContact(int contactId) async { final otherKeys = await apiService.getPreKeysByUserId(contactId); if (otherKeys != null) { Log.info( - 'got fresh ${otherKeys.preKeys.length} pre keys from other $contactId!'); + 'got fresh ${otherKeys.preKeys.length} pre keys from other $contactId!', + ); final preKeys = otherKeys.preKeys .map( (preKey) => SignalContactPreKeysCompanion( @@ -74,13 +75,14 @@ Future requestNewSignedPreKeyForContact(int contactId) async { if (signedPreKey != null) { Log.info('got fresh signed pre keys from other $contactId!'); await twonlyDB.signalDao.insertOrUpdateSignedPreKeyByContactId( - SignalContactSignedPreKeysCompanion( - contactId: Value(contactId), - signedPreKey: Value(Uint8List.fromList(signedPreKey.signedPrekey)), - signedPreKeySignature: - Value(Uint8List.fromList(signedPreKey.signedPrekeySignature)), - signedPreKeyId: Value(signedPreKey.signedPrekeyId.toInt()), - )); + SignalContactSignedPreKeysCompanion( + contactId: Value(contactId), + signedPreKey: Value(Uint8List.fromList(signedPreKey.signedPrekey)), + signedPreKeySignature: + Value(Uint8List.fromList(signedPreKey.signedPrekeySignature)), + signedPreKeyId: Value(signedPreKey.signedPrekeyId.toInt()), + ), + ); } else { Log.error('could not load new signed pre key for user $contactId'); } diff --git a/lib/src/services/signal/utils.signal.dart b/lib/src/services/signal/utils.signal.dart index e883132..ef4a1cd 100644 --- a/lib/src/services/signal/utils.signal.dart +++ b/lib/src/services/signal/utils.signal.dart @@ -8,7 +8,8 @@ Future getSignalStore() async { } Future getSignalStoreFromIdentity( - SignalIdentity signalIdentity) async { + SignalIdentity signalIdentity, +) async { final identityKeyPair = IdentityKeyPair.fromSerialized(signalIdentity.identityKeyPairU8List); diff --git a/lib/src/services/twonly_safe/create_backup.twonly_safe.dart b/lib/src/services/twonly_safe/create_backup.twonly_safe.dart index e954c9b..5d18482 100644 --- a/lib/src/services/twonly_safe/create_backup.twonly_safe.dart +++ b/lib/src/services/twonly_safe/create_backup.twonly_safe.dart @@ -34,7 +34,7 @@ Future performTwonlySafeBackup({bool force = false}) async { } final lastUpdateTime = user.twonlySafeBackup!.lastBackupDone; - if (force != true && lastUpdateTime != null) { + if (!force && lastUpdateTime != null) { if (lastUpdateTime .isAfter(DateTime.now().subtract(const Duration(days: 1)))) { return; @@ -163,7 +163,8 @@ Future performTwonlySafeBackup({bool force = false}) async { await encryptedBackupBytesFile.writeAsBytes(encryptedBackupBytes); Log.info( - 'Create twonly Safe backup with a size of ${encryptedBackupBytes.length} bytes.'); + 'Create twonly Safe backup with a size of ${encryptedBackupBytes.length} bytes.', + ); if (user.backupServer != null) { if (encryptedBackupBytes.length > user.backupServer!.maxBackupBytes) { @@ -205,7 +206,8 @@ Future handleBackupStatusUpdate(TaskStatusUpdate update) async { if (update.status == TaskStatus.failed || update.status == TaskStatus.canceled) { Log.error( - 'twonly Safe upload failed. ${update.responseStatusCode} ${update.responseBody} ${update.responseHeaders} ${update.exception}'); + 'twonly Safe upload failed. ${update.responseStatusCode} ${update.responseBody} ${update.responseHeaders} ${update.exception}', + ); await updateUserdata((user) { if (user.twonlySafeBackup != null) { user.twonlySafeBackup!.backupUploadState = LastBackupUploadState.failed; @@ -214,7 +216,8 @@ Future handleBackupStatusUpdate(TaskStatusUpdate update) async { }); } else if (update.status == TaskStatus.complete) { Log.error( - 'twonly Safe uploaded with status code ${update.responseStatusCode}'); + 'twonly Safe uploaded with status code ${update.responseStatusCode}', + ); await updateUserdata((user) { if (user.twonlySafeBackup != null) { user.twonlySafeBackup!.backupUploadState = diff --git a/lib/src/services/twonly_safe/restore.twonly_safe.dart b/lib/src/services/twonly_safe/restore.twonly_safe.dart index c925cb7..471bef2 100644 --- a/lib/src/services/twonly_safe/restore.twonly_safe.dart +++ b/lib/src/services/twonly_safe/restore.twonly_safe.dart @@ -37,9 +37,12 @@ Future recoverTwonlySafe( late http.Response response; try { - response = await http.get(Uri.parse(backupServerUrl), headers: { - HttpHeaders.acceptHeader: 'application/octet-stream', - }); + response = await http.get( + Uri.parse(backupServerUrl), + headers: { + HttpHeaders.acceptHeader: 'application/octet-stream', + }, + ); } catch (e) { Log.error('Error fetching backup: $e'); throw Exception('Backup server could not be reached. ($e)'); @@ -110,7 +113,8 @@ Future handleBackupData( // for each day add 400 message ids final dummyMessagesCounter = (lastMessageSend + 1) * 400; Log.info( - 'Creating $dummyMessagesCounter dummy messages to increase message counter as last message was $lastMessageSend days ago.'); + 'Creating $dummyMessagesCounter dummy messages to increase message counter as last message was $lastMessageSend days ago.', + ); for (var i = 0; i < dummyMessagesCounter; i++) { await database.messagesDao.insertMessage( MessagesCompanion( @@ -129,14 +133,17 @@ Future handleBackupData( final secureStorage = jsonDecode(backupContent.secureStorageJson); await storage.write( - key: SecureStorageKeys.signalIdentity, - value: secureStorage[SecureStorageKeys.signalIdentity] as String); + key: SecureStorageKeys.signalIdentity, + value: secureStorage[SecureStorageKeys.signalIdentity] as String, + ); await storage.write( - key: SecureStorageKeys.signalSignedPreKey, - value: secureStorage[SecureStorageKeys.signalSignedPreKey] as String); + key: SecureStorageKeys.signalSignedPreKey, + value: secureStorage[SecureStorageKeys.signalSignedPreKey] as String, + ); await storage.write( - key: SecureStorageKeys.userData, - value: secureStorage[SecureStorageKeys.userData] as String); + key: SecureStorageKeys.userData, + value: secureStorage[SecureStorageKeys.userData] as String, + ); await updateUserdata((u) { u.deviceId += 1; return u; diff --git a/lib/src/utils/log.dart b/lib/src/utils/log.dart index 818c1b6..8917f23 100644 --- a/lib/src/utils/log.dart +++ b/lib/src/utils/log.dart @@ -11,7 +11,8 @@ void initLogger() { await _writeLogToFile(record); if (kDebugMode) { print( - '${record.level.name} [twonly] ${record.loggerName} > ${record.message}'); + '${record.level.name} [twonly] ${record.loggerName} > ${record.message}', + ); } }); } diff --git a/lib/src/utils/misc.dart b/lib/src/utils/misc.dart index 41f2bff..7c234d1 100644 --- a/lib/src/utils/misc.dart +++ b/lib/src/utils/misc.dart @@ -1,7 +1,6 @@ import 'dart:convert'; import 'dart:math'; -import 'package:drift/drift.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -10,8 +9,6 @@ import 'package:gal/gal.dart'; import 'package:intl/intl.dart'; import 'package:local_auth/local_auth.dart'; import 'package:provider/provider.dart'; -import 'package:twonly/globals.dart'; -import 'package:twonly/src/database/tables/messages_table.dart'; import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/localization/generated/app_localizations.dart'; import 'package:twonly/src/model/json/message.dart'; @@ -133,13 +130,16 @@ Future getCompressedImage(Uint8List imageBytes) async { return result; } -Future authenticateUser(String localizedReason, - {bool force = true}) async { +Future authenticateUser( + String localizedReason, { + bool force = true, +}) async { try { final auth = LocalAuthentication(); final didAuthenticate = await auth.authenticate( - localizedReason: localizedReason, - options: const AuthenticationOptions(useErrorDialogs: false)); + localizedReason: localizedReason, + options: const AuthenticationOptions(useErrorDialogs: false), + ); if (didAuthenticate) { return true; } @@ -218,171 +218,6 @@ String truncateString(String input, {int maxLength = 20}) { return input; } -Future insertDemoContacts() async { - final commonUsernames = [ - 'James', - 'Mary', - 'John', - 'Patricia', - 'Robert', - 'Jennifer', - 'Michael', - 'Linda', - 'William', - 'Elizabeth', - 'David', - 'Barbara', - 'Richard', - 'Susan', - 'Joseph', - 'Jessica', - 'Charles', - 'Sarah', - 'Thomas', - 'Karen', - ]; - final contactConfigs = >[ - {'count': 3, 'requested': true}, - {'count': 4, 'requested': false, 'accepted': true}, - {'count': 1, 'accepted': true, 'blocked': true}, - {'count': 1, 'accepted': true, 'archived': true}, - {'count': 2, 'accepted': true, 'pinned': true}, - {'count': 1, 'requested': false}, - ]; - - var counter = 0; - - for (final config in contactConfigs) { - for (var i = 0; i < (config['count'] as int); i++) { - if (counter >= commonUsernames.length) { - break; - } - final username = commonUsernames[counter]; - final userId = Random().nextInt(1000000); - await twonlyDB.contactsDao.insertContact( - ContactsCompanion( - username: Value(username), - userId: Value(userId), - requested: Value(config['requested'] as bool? ?? false), - accepted: Value(config['accepted'] as bool? ?? false), - blocked: Value(config['blocked'] as bool? ?? false), - archived: Value(config['archived'] as bool? ?? false), - pinned: Value(config['pinned'] as bool? ?? false), - ), - ); - if (config['accepted'] as bool? ?? false) { - for (var i = 0; i < 20; i++) { - final chatId = Random().nextInt(chatMessages.length); - await twonlyDB.messagesDao.insertMessage( - MessagesCompanion( - contactId: Value(userId), - kind: const Value(MessageKind.textMessage), - sendAt: Value(chatMessages[chatId][1] as DateTime), - acknowledgeByServer: const Value(true), - acknowledgeByUser: const Value(true), - messageOtherId: - Value(Random().nextBool() ? Random().nextInt(10000) : null), - // responseToOtherMessageId: Value(content.responseToMessageId), - // responseToMessageId: Value(content.responseToOtherMessageId), - downloadState: const Value(DownloadState.downloaded), - contentJson: Value( - jsonEncode(TextMessageContent( - text: chatMessages[chatId][0] as String)), - ), - ), - ); - } - } - counter++; - } - } -} - -Future createFakeDemoData() async { - await insertDemoContacts(); -} - -List> chatMessages = [ - [ - 'Lorem ipsum dolor sit amet.', - DateTime.now().subtract(const Duration(minutes: 20)) - ], - [ - 'Consectetur adipiscing elit.', - DateTime.now().subtract(const Duration(minutes: 19)) - ], - [ - 'Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', - DateTime.now().subtract(const Duration(minutes: 18)) - ], - [ - 'Ut enim ad minim veniam.', - DateTime.now().subtract(const Duration(minutes: 17)) - ], - [ - 'Quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.', - DateTime.now().subtract(const Duration(minutes: 16)) - ], - [ - 'Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.', - DateTime.now().subtract(const Duration(minutes: 15)) - ], - [ - 'Excepteur sint occaecat cupidatat non proident.', - DateTime.now().subtract(const Duration(minutes: 14)) - ], - [ - 'Sunt in culpa qui officia deserunt mollit anim id est laborum.', - DateTime.now().subtract(const Duration(minutes: 13)) - ], - [ - 'Curabitur pretium tincidunt lacus.', - DateTime.now().subtract(const Duration(minutes: 12)) - ], - ['Nulla facilisi.', DateTime.now().subtract(const Duration(minutes: 11))], - [ - 'Aenean lacinia bibendum nulla sed consectetur.', - DateTime.now().subtract(const Duration(minutes: 10)) - ], - [ - 'Sed posuere consectetur est at lobortis.', - DateTime.now().subtract(const Duration(minutes: 9)) - ], - [ - 'Vestibulum id ligula porta felis euismod semper.', - DateTime.now().subtract(const Duration(minutes: 8)) - ], - [ - 'Cras justo odio, dapibus ac facilisis in, egestas eget quam.', - DateTime.now().subtract(const Duration(minutes: 7)) - ], - [ - 'Morbi leo risus, porta ac consectetur ac, vestibulum at eros.', - DateTime.now().subtract(const Duration(minutes: 6)) - ], - [ - 'Praesent commodo cursus magna, vel scelerisque nisl consectetur et.', - DateTime.now().subtract(const Duration(minutes: 5)) - ], - [ - 'Donec ullamcorper nulla non metus auctor fringilla.', - DateTime.now().subtract(const Duration(minutes: 4)) - ], - [ - 'Etiam porta sem malesuada magna mollis euismod.', - DateTime.now().subtract(const Duration(minutes: 3)) - ], - [ - 'Aenean lacinia bibendum nulla sed consectetur.', - DateTime.now().subtract(const Duration(minutes: 2)) - ], - [ - 'Nullam quis risus eget urna mollis ornare vel eu leo.', - DateTime.now().subtract(const Duration(minutes: 1)) - ], - ['Curabitur blandit tempus porttitor.', DateTime.now()], -]; - String formatDateTime(BuildContext context, DateTime? dateTime) { if (dateTime == null) { return 'Never'; @@ -426,7 +261,8 @@ MediaMessageContent? getMediaContent(Message message) { try { if (message.contentJson == null) return null; return MediaMessageContent.fromJson( - jsonDecode(message.contentJson!) as Map); + jsonDecode(message.contentJson!) as Map, + ); } catch (e) { Log.error(e); return null; diff --git a/lib/src/views/camera/camera_preview_components/permissions_view.dart b/lib/src/views/camera/camera_preview_components/permissions_view.dart index fead6f4..411fb54 100644 --- a/lib/src/views/camera/camera_preview_components/permissions_view.dart +++ b/lib/src/views/camera/camera_preview_components/permissions_view.dart @@ -30,7 +30,7 @@ class PermissionHandlerViewState extends State { final statuses = await [ Permission.camera, // Permission.microphone, - Permission.notification + Permission.notification, ].request(); // } catch (e) {} // You can request multiple permissions at once. diff --git a/lib/src/views/camera/camera_preview_components/save_to_gallery.dart b/lib/src/views/camera/camera_preview_components/save_to_gallery.dart index 2f67d3f..b522422 100644 --- a/lib/src/views/camera/camera_preview_components/save_to_gallery.dart +++ b/lib/src/views/camera/camera_preview_components/save_to_gallery.dart @@ -61,7 +61,8 @@ class SaveToGalleryButtonState extends State { } else { final random = Random(); final token = uint8ListToHex( - List.generate(32, (i) => random.nextInt(256))); + List.generate(32, (i) => random.nextInt(256)), + ); memoryPath = join(memoryPath, token); } final user = await getUser(); @@ -111,18 +112,21 @@ class SaveToGalleryButtonState extends State { children: [ if (_imageSaving || widget.isLoading) const SizedBox( - width: 12, - height: 12, - child: CircularProgressIndicator(strokeWidth: 1)) + width: 12, + height: 12, + child: CircularProgressIndicator(strokeWidth: 1), + ) else _imageSaved ? const Icon(Icons.check) : const FaIcon(FontAwesomeIcons.floppyDisk), if (widget.displayButtonLabel) const SizedBox(width: 10), if (widget.displayButtonLabel) - Text(_imageSaved - ? context.lang.shareImagedEditorSavedImage - : context.lang.shareImagedEditorSaveImage) + Text( + _imageSaved + ? context.lang.shareImagedEditorSavedImage + : context.lang.shareImagedEditorSaveImage, + ), ], ), ); diff --git a/lib/src/views/camera/camera_preview_components/video_recording_time.dart b/lib/src/views/camera/camera_preview_components/video_recording_time.dart index a2478cb..bcbc11c 100644 --- a/lib/src/views/camera/camera_preview_components/video_recording_time.dart +++ b/lib/src/views/camera/camera_preview_components/video_recording_time.dart @@ -47,11 +47,11 @@ class VideoRecordingTimer extends StatelessWidget { Shadow( color: Color.fromARGB(122, 0, 0, 0), blurRadius: 5, - ) + ), ], ), ), - ) + ), ], ), ), diff --git a/lib/src/views/camera/camera_preview_components/zoom_selector.dart b/lib/src/views/camera/camera_preview_components/zoom_selector.dart index a6d4400..6b4061f 100644 --- a/lib/src/views/camera/camera_preview_components/zoom_selector.dart +++ b/lib/src/views/camera/camera_preview_components/zoom_selector.dart @@ -43,9 +43,9 @@ class _CameraZoomButtonsState extends State { bool _isDisposed = false; @override - void initState() { + Future initState() async { super.initState(); - initAsync(); + await initAsync(); } Future initAsync() async { @@ -121,25 +121,26 @@ class _CameraZoomButtonsState extends State { ), ), TextButton( - style: zoomButtonStyle.copyWith( - foregroundColor: WidgetStateProperty.all( - isMiddleFocused ? Colors.yellow : Colors.white, - ), + style: zoomButtonStyle.copyWith( + foregroundColor: WidgetStateProperty.all( + isMiddleFocused ? Colors.yellow : Colors.white, ), - onPressed: () async { - if (showWideAngleZoomIOS && - widget.selectedCameraDetails.cameraId == 2) { - await widget.selectCamera(0, true, false); - } else { - widget.updateScaleFactor(1.0); - } - }, - child: Text( - isMiddleFocused - ? '${beautifulZoomScale(widget.scaleFactor)}x' - : '1.0x', - style: zoomTextStyle, - )), + ), + onPressed: () async { + if (showWideAngleZoomIOS && + widget.selectedCameraDetails.cameraId == 2) { + await widget.selectCamera(0, true, false); + } else { + widget.updateScaleFactor(1.0); + } + }, + child: Text( + isMiddleFocused + ? '${beautifulZoomScale(widget.scaleFactor)}x' + : '1.0x', + style: zoomTextStyle, + ), + ), TextButton( style: zoomButtonStyle.copyWith( foregroundColor: WidgetStateProperty.all( @@ -152,9 +153,11 @@ class _CameraZoomButtonsState extends State { .toDouble(); widget.updateScaleFactor(level); }, - child: Text('${beautifulZoomScale(maxLevel.toDouble())}x', - style: zoomTextStyle), - ) + child: Text( + '${beautifulZoomScale(maxLevel.toDouble())}x', + style: zoomTextStyle, + ), + ), ], ), ), diff --git a/lib/src/views/camera/camera_preview_controller_view.dart b/lib/src/views/camera/camera_preview_controller_view.dart index 43eeb01..c57c392 100644 --- a/lib/src/views/camera/camera_preview_controller_view.dart +++ b/lib/src/views/camera/camera_preview_controller_view.dart @@ -94,7 +94,10 @@ class CameraPreviewControllerView extends StatelessWidget { }); final Contact? sendTo; final Future Function( - int sCameraId, bool init, bool enableAudio) selectCamera; + int sCameraId, + bool init, + bool enableAudio, + ) selectCamera; final CameraController? cameraController; final SelectedCameraDetails selectedCameraDetails; final ScreenshotController screenshotController; @@ -114,10 +117,12 @@ class CameraPreviewControllerView extends StatelessWidget { screenshotController: screenshotController, ); } else { - return PermissionHandlerView(onSuccess: () { - // setState(() {}); - selectCamera(0, true, false); - }); + return PermissionHandlerView( + onSuccess: () async { + // setState(() {}); + await selectCamera(0, true, false); + }, + ); } } else { return Container(); @@ -138,7 +143,10 @@ class CameraPreviewView extends StatefulWidget { }); final Contact? sendTo; final Future Function( - int sCameraId, bool init, bool enableAudio) selectCamera; + int sCameraId, + bool init, + bool enableAudio, + ) selectCamera; final CameraController? cameraController; final SelectedCameraDetails selectedCameraDetails; final ScreenshotController screenshotController; @@ -165,9 +173,9 @@ class _CameraPreviewViewState extends State { final GlobalKey navigatorKey = GlobalKey(); @override - void initState() { + Future initState() async { super.initState(); - initAsync(); + await initAsync(); } Future initAsync() async { @@ -212,9 +220,12 @@ class _CameraPreviewViewState extends State { widget.cameraController == null) { return; } - await widget.cameraController?.setZoomLevel(newScale.clamp( + await widget.cameraController?.setZoomLevel( + newScale.clamp( widget.selectedCameraDetails.minAvailableZoom, - widget.selectedCameraDetails.maxAvailableZoom)); + widget.selectedCameraDetails.maxAvailableZoom, + ), + ); setState(() { widget.selectedCameraDetails.scaleFactor = newScale; }); @@ -284,8 +295,10 @@ class _CameraPreviewViewState extends State { } Future pushMediaEditor( - Future? imageBytes, File? videoFilePath, - {bool sharedFromGallery = false}) async { + Future? imageBytes, + File? videoFilePath, { + bool sharedFromGallery = false, + }) async { final shouldReturn = await Navigator.push( context, PageRouteBuilder( @@ -314,7 +327,6 @@ class _CameraPreviewViewState extends State { if (!mounted) return true; // shouldReturn is null when the user used the back button if (shouldReturn != null && shouldReturn) { - // ignore: use_build_context_synchronously if (widget.sendTo == null) { globalUpdateOfHomeViewPageIndex(0); } else { @@ -323,7 +335,10 @@ class _CameraPreviewViewState extends State { return true; } await widget.selectCamera( - widget.selectedCameraDetails.cameraId, false, false); + widget.selectedCameraDetails.cameraId, + false, + false, + ); return false; } @@ -395,7 +410,7 @@ class _CameraPreviewViewState extends State { try { await cameraController?.startVideoRecording(); videoRecordingTimer = - Timer.periodic(const Duration(milliseconds: 15), (timer) { + Timer.periodic(const Duration(milliseconds: 15), (timer) async { setState(() { currentTime = DateTime.now(); }); @@ -404,7 +419,7 @@ class _CameraPreviewViewState extends State { maxVideoRecordingTime) { timer.cancel(); videoRecordingTimer = null; - stopVideoRecording(); + await stopVideoRecording(); } }); setState(() { @@ -466,7 +481,6 @@ class _CameraPreviewViewState extends State { Log.error('$e'); try { if (context.mounted) { - // ignore: use_build_context_synchronously ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Error: $e'), @@ -496,7 +510,7 @@ class _CameraPreviewViewState extends State { }); }, onLongPressMoveUpdate: onPanUpdate, - onLongPressStart: (details) { + onLongPressStart: (details) async { setState(() { basePanY = details.localPosition.dy; baseScaleFactor = widget.selectedCameraDetails.scaleFactor; @@ -510,14 +524,14 @@ class _CameraPreviewViewState extends State { Rect.fromLTWH(0, 0, renderBox.size.width, renderBox.size.height); if (containerRect.contains(localPosition)) { - startVideoRecording(); + await startVideoRecording(); } }, - onLongPressEnd: (a) { - stopVideoRecording(); + onLongPressEnd: (a) async { + await stopVideoRecording(); }, - onPanEnd: (a) { - stopVideoRecording(); + onPanEnd: (a) async { + await stopVideoRecording(); }, onPanUpdate: onPanUpdate, child: Stack( @@ -553,9 +567,10 @@ class _CameraPreviewViewState extends State { tooltipText: context.lang.switchFrontAndBackCamera, onPressed: () async { await widget.selectCamera( - (widget.selectedCameraDetails.cameraId + 1) % 2, - false, - false); + (widget.selectedCameraDetails.cameraId + 1) % 2, + false, + false, + ); }, ), ActionButton( @@ -676,7 +691,7 @@ class _CameraPreviewViewState extends State { ), ), ), - if (!isVideoRecording) const SizedBox(width: 80) + if (!isVideoRecording) const SizedBox(width: 80), ], ), ], diff --git a/lib/src/views/camera/camera_send_to_view.dart b/lib/src/views/camera/camera_send_to_view.dart index 37660e6..7a03a43 100644 --- a/lib/src/views/camera/camera_send_to_view.dart +++ b/lib/src/views/camera/camera_send_to_view.dart @@ -18,23 +18,30 @@ class CameraSendToViewState extends State { SelectedCameraDetails selectedCameraDetails = SelectedCameraDetails(); @override - void initState() { + Future initState() async { super.initState(); - selectCamera(0, true, false); + await selectCamera(0, true, false); } @override - void dispose() { - cameraController?.dispose(); + Future dispose() async { + await cameraController?.dispose(); cameraController = null; selectedCameraDetails = SelectedCameraDetails(); super.dispose(); } Future selectCamera( - int sCameraId, bool init, bool enableAudio) async { + int sCameraId, + bool init, + bool enableAudio, + ) async { final opts = await initializeCameraController( - selectedCameraDetails, sCameraId, init, enableAudio); + selectedCameraDetails, + sCameraId, + init, + enableAudio, + ); if (opts != null) { selectedCameraDetails = opts.$1; cameraController = opts.$2; @@ -47,7 +54,7 @@ class CameraSendToViewState extends State { Future toggleSelectedCamera() async { if (cameraController == null) return; // do not allow switching camera when recording - if (cameraController!.value.isRecordingVideo == true) { + if (cameraController!.value.isRecordingVideo) { return; } await cameraController!.dispose(); diff --git a/lib/src/views/camera/image_editor/action_button.dart b/lib/src/views/camera/image_editor/action_button.dart index b5d84e9..d5307e6 100644 --- a/lib/src/views/camera/image_editor/action_button.dart +++ b/lib/src/views/camera/image_editor/action_button.dart @@ -31,7 +31,7 @@ class ActionButton extends StatelessWidget { Shadow( color: Color.fromARGB(122, 0, 0, 0), blurRadius: 5, - ) + ), ], ), onPressed: () { diff --git a/lib/src/views/camera/image_editor/data/image_item.dart b/lib/src/views/camera/image_editor/data/image_item.dart index 5b3ddb4..6468ca7 100755 --- a/lib/src/views/camera/image_editor/data/image_item.dart +++ b/lib/src/views/camera/image_editor/data/image_item.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; class ImageItem { ImageItem([dynamic image]) { - if (image != null) load(image); + if (image != null) unawaited(load(image)); } int width = 1; int height = 1; diff --git a/lib/src/views/camera/image_editor/layers/draw_layer.dart b/lib/src/views/camera/image_editor/layers/draw_layer.dart index 22facf4..bc2ccd9 100644 --- a/lib/src/views/camera/image_editor/layers/draw_layer.dart +++ b/lib/src/views/camera/image_editor/layers/draw_layer.dart @@ -167,8 +167,10 @@ class _DrawLayerState extends State { begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: colors, - stops: List.generate(colors.length, - (index) => index / (colors.length - 1)), + stops: List.generate( + colors.length, + (index) => index / (colors.length - 1), + ), ), borderRadius: BorderRadius.circular(10), ), @@ -187,12 +189,12 @@ class _DrawLayerState extends State { onChangeStart: (value) => { setState(() { showMagnifyingGlass = true; - }) + }), }, onChangeEnd: (value) => { setState(() { showMagnifyingGlass = false; - }) + }), }, divisions: 100, ), @@ -209,9 +211,10 @@ class _DrawLayerState extends State { ), if (!widget.layerData.isEditing) Positioned.fill( - child: Container( - color: Colors.transparent, - )) + child: Container( + color: Colors.transparent, + ), + ), ], ); } diff --git a/lib/src/views/camera/image_editor/layers/emoji_layer.dart b/lib/src/views/camera/image_editor/layers/emoji_layer.dart index 30c795b..0e5b7d7 100755 --- a/lib/src/views/camera/image_editor/layers/emoji_layer.dart +++ b/lib/src/views/camera/image_editor/layers/emoji_layer.dart @@ -39,8 +39,9 @@ class _EmojiLayerState extends State { WidgetsBinding.instance.addPostFrameCallback((_) { setState(() { widget.layerData.offset = Offset( - MediaQuery.of(context).size.width / 2 - (153 / 2), - MediaQuery.of(context).size.height / 2 - (153 / 2) - 100); + MediaQuery.of(context).size.width / 2 - (153 / 2), + MediaQuery.of(context).size.height / 2 - (153 / 2) - 100, + ); }); display = true; }); @@ -87,8 +88,8 @@ class _EmojiLayerState extends State { setState(() {}); }, - onScaleUpdate: (details) { - if (twoPointerWhereDown == true && details.pointerCount != 2) { + onScaleUpdate: (details) async { + if (twoPointerWhereDown && details.pointerCount != 2) { return; } final outlineBox = @@ -109,7 +110,7 @@ class _EmojiLayerState extends State { if (isAtTheBottom && isInTheCenter) { if (!deleteLayer) { - HapticFeedback.heavyImpact(); + await HapticFeedback.heavyImpact(); } deleteLayer = true; } else { diff --git a/lib/src/views/camera/image_editor/layers/filter_layer.dart b/lib/src/views/camera/image_editor/layers/filter_layer.dart index b5318f6..32ce9b1 100644 --- a/lib/src/views/camera/image_editor/layers/filter_layer.dart +++ b/lib/src/views/camera/image_editor/layers/filter_layer.dart @@ -61,7 +61,7 @@ class FilterText extends StatelessWidget { Shadow( color: Color.fromARGB(122, 0, 0, 0), blurRadius: 5, - ) + ), ], ), ); @@ -78,12 +78,12 @@ class _FilterLayerState extends State { ]; @override - void initState() { + Future initState() async { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { pageController.jumpToPage(1); }); - initAsync(); + await initAsync(); } Future initAsync() async { diff --git a/lib/src/views/camera/image_editor/layers/filters/location_filter.dart b/lib/src/views/camera/image_editor/layers/filters/location_filter.dart index c51b7ea..94cedf1 100644 --- a/lib/src/views/camera/image_editor/layers/filters/location_filter.dart +++ b/lib/src/views/camera/image_editor/layers/filters/location_filter.dart @@ -24,9 +24,9 @@ class _LocationFilterState extends State { Response_Location? location; @override - void initState() { + Future initState() async { super.initState(); - initAsync(); + await initAsync(); } Future initAsync() async { diff --git a/lib/src/views/camera/image_editor/layers/text_layer.dart b/lib/src/views/camera/image_editor/layers/text_layer.dart index a1ce9a9..71026fc 100755 --- a/lib/src/views/camera/image_editor/layers/text_layer.dart +++ b/lib/src/views/camera/image_editor/layers/text_layer.dart @@ -40,10 +40,11 @@ class _TextViewState extends State { WidgetsBinding.instance.addPostFrameCallback((_) { setState(() { widget.layerData.offset = Offset( - 0, - MediaQuery.of(context).size.height / 2 - - 150 + - (widget.layerData.textLayersBefore * 40)); + 0, + MediaQuery.of(context).size.height / 2 - + 150 + + (widget.layerData.textLayersBefore * 40), + ); textController.text = widget.layerData.text; }); }); @@ -68,28 +69,28 @@ class _TextViewState extends State { autofocus: true, maxLines: null, minLines: 1, - onEditingComplete: () { + onEditingComplete: () async { setState(() { widget.layerData.isDeleted = textController.text == ''; widget.layerData.isEditing = false; widget.layerData.text = textController.text; }); - context + await context .read() .updateSomeTextViewIsAlreadyEditing(false); if (widget.onUpdate != null) { widget.onUpdate!(); } }, - onTapOutside: (a) { + onTapOutside: (a) async { widget.layerData.text = textController.text; Future.delayed(const Duration(milliseconds: 100), () { if (context.mounted) { - setState(() { + setState(() async { widget.layerData.isDeleted = textController.text == ''; widget.layerData.isEditing = false; - context + await context .read() .updateSomeTextViewIsAlreadyEditing(false); if (widget.onUpdate != null) { @@ -99,7 +100,7 @@ class _TextViewState extends State { } }); - context + await context .read() .updateSomeTextViewIsAlreadyEditing(false); }, @@ -150,24 +151,26 @@ class _TextViewState extends State { .someTextViewIsAlreadyEditing) ? null : () { - setState(() { - context + setState(() async { + await context .read() .updateSomeTextViewIsAlreadyEditing(true); widget.layerData.isEditing = true; }); }, - onScaleUpdate: (detail) { + onScaleUpdate: (detail) async { if (detail.pointerCount == 1) { widget.layerData.offset = Offset( - 0, widget.layerData.offset.dy + detail.focalPointDelta.dy); + 0, + widget.layerData.offset.dy + detail.focalPointDelta.dy, + ); } final renderBox = _widgetKey.currentContext!.findRenderObject()! as RenderBox; if (widget.layerData.offset.dy > renderBox.size.height - 80) { if (!deleteLayer) { - HapticFeedback.heavyImpact(); + await HapticFeedback.heavyImpact(); } deleteLayer = true; } else { diff --git a/lib/src/views/camera/image_editor/layers_viewer.dart b/lib/src/views/camera/image_editor/layers_viewer.dart index f6155f3..0fcf148 100644 --- a/lib/src/views/camera/image_editor/layers_viewer.dart +++ b/lib/src/views/camera/image_editor/layers_viewer.dart @@ -33,8 +33,10 @@ class LayersViewer extends StatelessWidget { ); }), ...layers - .where((layerItem) => - layerItem is EmojiLayerData || layerItem is DrawLayerData) + .where( + (layerItem) => + layerItem is EmojiLayerData || layerItem is DrawLayerData, + ) .map((layerItem) { if (layerItem is EmojiLayerData) { return EmojiLayer( diff --git a/lib/src/views/camera/image_editor/modules/all_emojis.dart b/lib/src/views/camera/image_editor/modules/all_emojis.dart index c995b4e..90e1e5c 100755 --- a/lib/src/views/camera/image_editor/modules/all_emojis.dart +++ b/lib/src/views/camera/image_editor/modules/all_emojis.dart @@ -14,9 +14,9 @@ class _EmojisState extends State { List lastUsed = emojis; @override - void initState() { + Future initState() async { super.initState(); - initAsync(); + await initAsync(); } Future initAsync() async { @@ -86,22 +86,23 @@ class _EmojisState extends State { ), children: lastUsed.map((String emoji) { return GridTile( - child: GestureDetector( - onTap: () { - selectEmojis(emoji); - }, - child: Container( - padding: EdgeInsets.zero, - alignment: Alignment.center, - child: Text( - emoji, - style: const TextStyle(fontSize: 35), + child: GestureDetector( + onTap: () async { + await selectEmojis(emoji); + }, + child: Container( + padding: EdgeInsets.zero, + alignment: Alignment.center, + child: Text( + emoji, + style: const TextStyle(fontSize: 35), + ), ), ), - )); + ); }).toList(), ), - ) + ), ], ), ), diff --git a/lib/src/views/camera/share_image_components/best_friends_selector.dart b/lib/src/views/camera/share_image_components/best_friends_selector.dart index 1562716..86ba2c9 100644 --- a/lib/src/views/camera/share_image_components/best_friends_selector.dart +++ b/lib/src/views/camera/share_image_components/best_friends_selector.dart @@ -59,8 +59,10 @@ class BestFriendsSelector extends StatelessWidget { ], borderRadius: BorderRadius.circular(8), ), - child: Text(context.lang.shareImagedSelectAll, - style: const TextStyle(fontSize: 10)), + child: Text( + context.lang.shareImagedSelectAll, + style: const TextStyle(fontSize: 10), + ), ), ), ], @@ -127,7 +129,8 @@ class UserCheckbox extends StatelessWidget { return Container( padding: const EdgeInsets.symmetric( - horizontal: 3), // Padding inside the container + horizontal: 3, + ), // Padding inside the container child: GestureDetector( onTap: () { onChanged(user.userId, !isChecked); @@ -172,7 +175,7 @@ class UserCheckbox extends StatelessWidget { } return FlameCounterWidget(user, snapshot.data!); }, - ) + ), ], ), Expanded(child: Container()), @@ -184,7 +187,8 @@ class UserCheckbox extends StatelessWidget { return const BorderSide(width: 0); } return BorderSide( - color: Theme.of(context).colorScheme.outline); + color: Theme.of(context).colorScheme.outline, + ); }, ), onChanged: (bool? value) { diff --git a/lib/src/views/camera/share_image_editor_view.dart b/lib/src/views/camera/share_image_editor_view.dart index 3e5565b..e366a1c 100644 --- a/lib/src/views/camera/share_image_editor_view.dart +++ b/lib/src/views/camera/share_image_editor_view.dart @@ -72,25 +72,25 @@ class _ShareImageEditorView extends State { Future? videoUploadHandler; @override - void initState() { + Future initState() async { super.initState(); - initAsync(); - initMediaFileUpload(); + await initAsync(); + await initMediaFileUpload(); layers.add(FilterLayerData()); if (widget.sendTo != null) { selectedUserIds.add(widget.sendTo!.userId); } if (widget.imageBytes != null) { - loadImage(widget.imageBytes!); + await loadImage(widget.imageBytes!); } else if (widget.videoFilePath != null) { setState(() { sendingOrLoadingImage = false; loadingImage = false; }); videoController = VideoPlayerController.file(widget.videoFilePath!); - videoController?.setLooping(true); - videoController?.initialize().then((_) { - videoController!.play(); + await videoController?.setLooping(true); + await videoController?.initialize().then((_) async { + await videoController!.play(); setState(() {}); // ignore: invalid_return_type_for_catch_error, argument_type_not_assignable_to_error_handler }).catchError(Log.error); @@ -121,10 +121,10 @@ class _ShareImageEditorView extends State { } @override - void dispose() { + Future dispose() async { isDisposed = true; layers.clear(); - videoController?.dispose(); + await videoController?.dispose(); super.dispose(); } @@ -155,9 +155,11 @@ class _ShareImageEditorView extends State { if (layers.any((x) => x.isEditing)) return; undoLayers.clear(); removedLayers.clear(); - layers.add(TextLayerData( - textLayersBefore: layers.whereType().length, - )); + layers.add( + TextLayerData( + textLayersBefore: layers.whereType().length, + ), + ); setState(() {}); }, ), @@ -301,7 +303,7 @@ class _ShareImageEditorView extends State { setState(() {}); }, ), - const SizedBox(width: 70) + const SizedBox(width: 70), ]; } @@ -329,7 +331,6 @@ class _ShareImageEditorView extends State { ), ) as bool?; if (wasSend != null && wasSend && mounted) { - // ignore: use_build_context_synchronously Navigator.pop(context, true); } else { await videoController?.play(); @@ -345,7 +346,8 @@ class _ShareImageEditorView extends State { } setState(() {}); image = await screenshotController.capture( - pixelRatio: (widget.useHighQuality) ? pixelRatio : 1); + pixelRatio: (widget.useHighQuality) ? pixelRatio : 1, + ); for (final x in layers) { x.showCustomButtons = true; } @@ -397,11 +399,16 @@ class _ShareImageEditorView extends State { sendingOrLoadingImage = false; }); if (mounted) { - await Navigator.push(context, MaterialPageRoute(builder: (context) { - return SubscriptionView( - redirectError: err, - ); - })); + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return SubscriptionView( + redirectError: err, + ); + }, + ), + ); } } else { final imageHandler = addOrModifyImageToUpload(mediaUploadId!, imageBytes); @@ -456,10 +463,12 @@ class _ShareImageEditorView extends State { layers = layers.where((x) => !x.isDeleted).toList(); undoLayers.clear(); removedLayers.clear(); - layers.add(TextLayerData( - offset: Offset(0, tabDownPosition), - textLayersBefore: layers.whereType().length, - )); + layers.add( + TextLayerData( + offset: Offset(0, tabDownPosition), + textLayersBefore: layers.whereType().length, + ), + ); setState(() {}); }, child: MediaViewSizing( @@ -508,7 +517,9 @@ class _ShareImageEditorView extends State { style: ButtonStyle( padding: WidgetStateProperty.all( const EdgeInsets.symmetric( - vertical: 10, horizontal: 30), + vertical: 10, + horizontal: 30, + ), ), ), label: Text( diff --git a/lib/src/views/camera/share_image_view.dart b/lib/src/views/camera/share_image_view.dart index 9d9fd65..f6db164 100644 --- a/lib/src/views/camera/share_image_view.dart +++ b/lib/src/views/camera/share_image_view.dart @@ -58,19 +58,19 @@ class _ShareImageView extends State { String lastQuery = ''; @override - void initState() { + Future initState() async { super.initState(); final allContacts = twonlyDB.contactsDao.watchContactsForShareView(); - contactSub = allContacts.listen((allContacts) { + contactSub = allContacts.listen((allContacts) async { setState(() { contacts = allContacts; }); - updateUsers(allContacts.where((x) => !x.archived).toList()); + await updateUsers(allContacts.where((x) => !x.archived).toList()); }); - initAsync(); + await initAsync(); } Future initAsync() async { @@ -80,16 +80,19 @@ class _ShareImageView extends State { addOrModifyImageToUpload(widget.mediaUploadId, imageBytes!); // start with the pre upload of the media file... await encryptMediaFiles( - widget.mediaUploadId, imageHandler, widget.videoUploadHandler); + widget.mediaUploadId, + imageHandler, + widget.videoUploadHandler, + ); } if (!mounted) return; setState(() {}); } @override - void dispose() { + Future dispose() async { super.dispose(); - contactSub.cancel(); + await contactSub.cancel(); } Future updateUsers(List users) async { @@ -103,7 +106,8 @@ class _ShareImageView extends State { } // If flameCounter is the same, compare by totalMediaCounter return b.totalMediaCounter.compareTo( - a.totalMediaCounter); // Sort by totalMediaCounter in descending order + a.totalMediaCounter, + ); // Sort by totalMediaCounter in descending order }); // Separate best friends and other users @@ -132,18 +136,24 @@ class _ShareImageView extends State { Future _filterUsers(String query) async { lastQuery = query; if (query.isEmpty) { - await updateUsers(contacts - .where((x) => - !x.archived || - !hideArchivedUsers || - widget.selectedUserIds.contains(x.userId)) - .toList()); + await updateUsers( + contacts + .where( + (x) => + !x.archived || + !hideArchivedUsers || + widget.selectedUserIds.contains(x.userId), + ) + .toList(), + ); return; } final usersFiltered = contacts - .where((user) => getContactDisplayName(user) - .toLowerCase() - .contains(query.toLowerCase())) + .where( + (user) => getContactDisplayName(user) + .toLowerCase() + .contains(query.toLowerCase()), + ) .toList(); await updateUsers(usersFiltered); } @@ -214,21 +224,21 @@ class _ShareImageView extends State { return const BorderSide(width: 0); } return BorderSide( - color: Theme.of(context) - .colorScheme - .outline); + color: + Theme.of(context).colorScheme.outline, + ); }, ), onChanged: (a) { - setState(() { + setState(() async { hideArchivedUsers = !hideArchivedUsers; - _filterUsers(lastQuery); + await _filterUsers(lastQuery); }); }, ), - ) + ), ], - ) + ), ], ), Expanded( @@ -238,7 +248,7 @@ class _ShareImageView extends State { isRealTwonly: widget.isRealTwonly, updateStatus: updateStatus, ), - ) + ), ], ), ), @@ -270,12 +280,16 @@ class _ShareImageView extends State { if (!context.mounted) return; if (err != null) { - await Navigator.push(context, - MaterialPageRoute(builder: (context) { - return SubscriptionView( - redirectError: err, - ); - })); + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return SubscriptionView( + redirectError: err, + ); + }, + ), + ); } else { setState(() { sendingImage = true; @@ -305,14 +319,15 @@ class _ShareImageView extends State { } }, style: ButtonStyle( - padding: WidgetStateProperty.all( - const EdgeInsets.symmetric(vertical: 10, horizontal: 30), - ), - backgroundColor: WidgetStateProperty.all( - imageBytes == null || widget.selectedUserIds.isEmpty - ? Theme.of(context).colorScheme.secondary - : Theme.of(context).colorScheme.primary, - )), + padding: WidgetStateProperty.all( + const EdgeInsets.symmetric(vertical: 10, horizontal: 30), + ), + backgroundColor: WidgetStateProperty.all( + imageBytes == null || widget.selectedUserIds.isEmpty + ? Theme.of(context).colorScheme.secondary + : Theme.of(context).colorScheme.primary, + ), + ), label: Text( context.lang.shareImagedEditorSendImage, style: const TextStyle(fontSize: 17), diff --git a/lib/src/views/chats/add_new_user.view.dart b/lib/src/views/chats/add_new_user.view.dart index 2bec5f7..ebf3910 100644 --- a/lib/src/views/chats/add_new_user.view.dart +++ b/lib/src/views/chats/add_new_user.view.dart @@ -38,16 +38,16 @@ class _SearchUsernameView extends State { @override void initState() { super.initState(); - contactsStream = twonlyDB.contactsDao - .watchNotAcceptedContacts() - .listen((update) => setState(() { - contacts = update; - })); + contactsStream = twonlyDB.contactsDao.watchNotAcceptedContacts().listen( + (update) => setState(() { + contacts = update; + }), + ); } @override - void dispose() { - contactsStream.cancel(); + Future dispose() async { + await contactsStream.cancel(); super.dispose(); } @@ -69,8 +69,11 @@ class _SearchUsernameView extends State { }); if (userdata == null) { - await showAlertDialog(context, context.lang.searchUsernameNotFound, - context.lang.searchUsernameNotFoundBody(searchUserName.text)); + await showAlertDialog( + context, + context.lang.searchUsernameNotFound, + context.lang.searchUsernameNotFoundBody(searchUserName.text), + ); return; } @@ -141,8 +144,8 @@ class _SearchUsernameView extends State { Padding( padding: const EdgeInsets.symmetric(horizontal: 10), child: TextField( - onSubmitted: (_) { - _addNewUser(context); + onSubmitted: (_) async { + await _addNewUser(context); }, onChanged: (value) { searchUserName.text = value.toLowerCase(); @@ -166,7 +169,7 @@ class _SearchUsernameView extends State { ), Expanded( child: ContactsListView(contacts), - ) + ), ], ), ), @@ -209,8 +212,10 @@ class ContactsListView extends StatelessWidget { Tooltip( message: context.lang.searchUserNameBlockUserTooltip, child: IconButton( - icon: const Icon(Icons.person_off_rounded, - color: Color.fromARGB(164, 244, 67, 54)), + icon: const Icon( + Icons.person_off_rounded, + color: Color.fromARGB(164, 244, 67, 54), + ), onPressed: () async { const update = ContactsCompanion(blocked: Value(true)); await twonlyDB.contactsDao.updateContact(contact.userId, update); diff --git a/lib/src/views/chats/chat_list.view.dart b/lib/src/views/chats/chat_list.view.dart index 98f6994..4ca14d1 100644 --- a/lib/src/views/chats/chat_list.view.dart +++ b/lib/src/views/chats/chat_list.view.dart @@ -54,7 +54,7 @@ class _ChatListViewState extends State { @override void initState() { - initAsync(); + unawaited(initAsync()); super.initState(); } @@ -95,11 +95,16 @@ class _ChatListViewState extends State { // only show changelog to people who already have contacts // this prevents that this is shown directly after the user registered if (_contacts.isNotEmpty) { - await Navigator.push(context, MaterialPageRoute(builder: (context) { - return ChangeLogView( - changeLog: changeLog, - ); - })); + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return ChangeLogView( + changeLog: changeLog, + ); + }, + ), + ); } } } @@ -107,7 +112,7 @@ class _ChatListViewState extends State { @override void dispose() { tutorial?.cancel(); - _contactsSub.cancel(); + unawaited(_contactsSub.cancel()); super.dispose(); } @@ -117,49 +122,61 @@ class _ChatListViewState extends State { final planId = context.watch().plan; return Scaffold( appBar: AppBar( - title: Row(children: [ - GestureDetector( - onTap: () async { - await Navigator.push(context, - MaterialPageRoute(builder: (context) { - return const ProfileView(); - })); - _user = await getUser(); - if (!mounted) return; - setState(() {}); - }, - child: ContactAvatar( - userData: _user, - fontSize: 14, - color: context.color.onSurface.withAlpha(20), - ), - ), - const SizedBox(width: 10), - const Text('twonly '), - if (planId != 'Free') + title: Row( + children: [ GestureDetector( - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (context) { - return const SubscriptionView(); - })); + onTap: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const ProfileView(); + }, + ), + ); + _user = await getUser(); + if (!mounted) return; + setState(() {}); }, - child: Container( - decoration: BoxDecoration( - color: context.color.primary, - borderRadius: BorderRadius.circular(15), - ), - padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 3), - child: Text( - planId, - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: isDarkMode(context) ? Colors.black : Colors.white, + child: ContactAvatar( + userData: _user, + fontSize: 14, + color: context.color.onSurface.withAlpha(20), + ), + ), + const SizedBox(width: 10), + const Text('twonly '), + if (planId != 'Free') + GestureDetector( + onTap: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const SubscriptionView(); + }, + ), + ); + }, + child: Container( + decoration: BoxDecoration( + color: context.color.primary, + borderRadius: BorderRadius.circular(15), + ), + padding: + const EdgeInsets.symmetric(horizontal: 5, vertical: 3), + child: Text( + planId, + style: TextStyle( + fontSize: 10, + fontWeight: FontWeight.bold, + color: isDarkMode(context) ? Colors.black : Colors.white, + ), ), ), ), - ), - ]), + ], + ), actions: [ const FeedbackIconButton(), StreamBuilder( @@ -174,8 +191,8 @@ class _ChatListViewState extends State { child: IconButton( key: searchForOtherUsers, icon: const FaIcon(FontAwesomeIcons.userPlus, size: 18), - onPressed: () { - Navigator.push( + onPressed: () async { + await Navigator.push( context, MaterialPageRoute( builder: (context) => const AddNewUserView(), @@ -199,7 +216,7 @@ class _ChatListViewState extends State { setState(() {}); }, icon: const FaIcon(FontAwesomeIcons.gear, size: 19), - ) + ), ], ), body: Stack( @@ -216,17 +233,17 @@ class _ChatListViewState extends State { child: Padding( padding: const EdgeInsets.all(10), child: OutlinedButton.icon( - icon: const Icon(Icons.person_add), - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const AddNewUserView(), - ), - ); - }, - label: - Text(context.lang.chatListViewSearchUserNameBtn)), + icon: const Icon(Icons.person_add), + onPressed: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const AddNewUserView(), + ), + ); + }, + label: Text(context.lang.chatListViewSearchUserNameBtn), + ), ), ) : RefreshIndicator( @@ -285,12 +302,14 @@ class _ChatListViewState extends State { floatingActionButton: Padding( padding: const EdgeInsets.only(bottom: 30), child: FloatingActionButton( - onPressed: () { - Navigator.push( + onPressed: () async { + await Navigator.push( context, - MaterialPageRoute(builder: (context) { - return const StartNewChatView(); - }), + MaterialPageRoute( + builder: (context) { + return const StartNewChatView(); + }, + ), ); }, child: const FaIcon(FontAwesomeIcons.penToSquare), @@ -333,9 +352,9 @@ class _UserListItem extends State { } @override - void dispose() { - messagesNotOpenedStream.cancel(); - lastMessageStream.cancel(); + Future dispose() async { + await messagesNotOpenedStream.cancel(); + await lastMessageStream.cancel(); super.dispose(); } @@ -399,11 +418,14 @@ class _UserListItem extends State { Future onTap() async { if (currentMessage == null) { - await Navigator.push(context, MaterialPageRoute( - builder: (context) { - return CameraSendToView(widget.user); - }, - )); + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return CameraSendToView(widget.user); + }, + ), + ); return; } @@ -417,9 +439,11 @@ class _UserListItem extends State { case DownloadState.downloaded: await Navigator.push( context, - MaterialPageRoute(builder: (context) { - return MediaViewerView(widget.user); - }), + MaterialPageRoute( + builder: (context) { + return MediaViewerView(widget.user); + }, + ), ); return; case DownloadState.downloading: @@ -429,9 +453,11 @@ class _UserListItem extends State { if (!mounted) return; await Navigator.push( context, - MaterialPageRoute(builder: (context) { - return ChatMessagesView(widget.user); - }), + MaterialPageRoute( + builder: (context) { + return ChatMessagesView(widget.user); + }, + ), ); } @@ -480,16 +506,19 @@ class _UserListItem extends State { trailing: (widget.user.deleted) ? null : IconButton( - onPressed: () { - Navigator.push(context, MaterialPageRoute( - builder: (context) { - if (hasNonOpenedMediaFile) { - return ChatMessagesView(widget.user); - } else { - return CameraSendToView(widget.user); - } - }, - )); + onPressed: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + if (hasNonOpenedMediaFile) { + return ChatMessagesView(widget.user); + } else { + return CameraSendToView(widget.user); + } + }, + ), + ); }, icon: FaIcon( hasNonOpenedMediaFile @@ -500,7 +529,7 @@ class _UserListItem extends State { ), onTap: onTap, ), - ) + ), ], ); } diff --git a/lib/src/views/chats/chat_list_components/backup_notice.card.dart b/lib/src/views/chats/chat_list_components/backup_notice.card.dart index bb717ce..2ee29b4 100644 --- a/lib/src/views/chats/chat_list_components/backup_notice.card.dart +++ b/lib/src/views/chats/chat_list_components/backup_notice.card.dart @@ -14,9 +14,9 @@ class _BackupNoticeCardState extends State { bool showBackupNotice = false; @override - void initState() { - initAsync(); + Future initState() async { super.initState(); + await initAsync(); } Future initAsync() async { @@ -74,8 +74,8 @@ class _BackupNoticeCardState extends State { ), const SizedBox(width: 10), FilledButton( - onPressed: () { - Navigator.push( + onPressed: () async { + await Navigator.push( context, MaterialPageRoute( builder: (context) => const BackupView(), diff --git a/lib/src/views/chats/chat_list_components/connection_info.comp.dart b/lib/src/views/chats/chat_list_components/connection_info.comp.dart index 524a273..9ef2bdd 100644 --- a/lib/src/views/chats/chat_list_components/connection_info.comp.dart +++ b/lib/src/views/chats/chat_list_components/connection_info.comp.dart @@ -34,11 +34,13 @@ class _ConnectionInfoWidgetState extends State _widthAnim = TweenSequence([ TweenSequenceItem( - tween: Tween(begin: minBarWidth, end: maxBarWidth), - weight: 50), + tween: Tween(begin: minBarWidth, end: maxBarWidth), + weight: 50, + ), TweenSequenceItem( - tween: Tween(begin: maxBarWidth, end: minBarWidth), - weight: 50), + tween: Tween(begin: maxBarWidth, end: minBarWidth), + weight: 50, + ), ]).animate(CurvedAnimation(parent: _controller, curve: Curves.easeInOut)); // Delay start by 2 seconds diff --git a/lib/src/views/chats/chat_list_components/demo_user.card.dart b/lib/src/views/chats/chat_list_components/demo_user.card.dart index eb09495..abfab5e 100644 --- a/lib/src/views/chats/chat_list_components/demo_user.card.dart +++ b/lib/src/views/chats/chat_list_components/demo_user.card.dart @@ -30,7 +30,7 @@ class DemoUserCard extends StatelessWidget { ); }, child: const Text('Register'), - ) + ), ], ), ); diff --git a/lib/src/views/chats/chat_list_components/feedback_btn.dart b/lib/src/views/chats/chat_list_components/feedback_btn.dart index 108d3b8..dd25ecf 100644 --- a/lib/src/views/chats/chat_list_components/feedback_btn.dart +++ b/lib/src/views/chats/chat_list_components/feedback_btn.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:twonly/src/utils/misc.dart'; @@ -17,7 +19,7 @@ class _FeedbackIconButtonState extends State { @override void initState() { super.initState(); - initAsync(); + unawaited(initAsync()); } Future initAsync() async { @@ -35,8 +37,8 @@ class _FeedbackIconButtonState extends State { } return IconButton( - onPressed: () { - Navigator.push( + onPressed: () async { + await Navigator.push( context, MaterialPageRoute( builder: (context) => const ContactUsView(), diff --git a/lib/src/views/chats/chat_messages.view.dart b/lib/src/views/chats/chat_messages.view.dart index 208a97f..407f929 100644 --- a/lib/src/views/chats/chat_messages.view.dart +++ b/lib/src/views/chats/chat_messages.view.dart @@ -87,11 +87,11 @@ class _ChatMessagesViewState extends State { int? focusedScrollItem; @override - void initState() { + Future initState() async { super.initState(); user = widget.contact; textFieldFocus = FocusNode(); - initStreams(); + await initStreams(); tutorial = Timer(const Duration(seconds: 1), () async { tutorial = null; @@ -101,12 +101,12 @@ class _ChatMessagesViewState extends State { } @override - void dispose() { - super.dispose(); - userSub.cancel(); - messageSub.cancel(); + Future dispose() async { + await userSub.cancel(); + await messageSub.cancel(); tutorial?.cancel(); textFieldFocus.dispose(); + super.dispose(); } Future initStreams() async { @@ -196,10 +196,14 @@ class _ChatMessagesViewState extends State { chatItems.add(ChatItem.time(msg.sendAt)); lastDate = msg.sendAt; } - chatItems.add(ChatItem.message(ChatMessage( - message: msg, - responseTo: responseTo, - ))); + chatItems.add( + ChatItem.message( + ChatMessage( + message: msg, + responseTo: responseTo, + ), + ), + ); } } @@ -253,7 +257,8 @@ class _ChatMessagesViewState extends State { Future scrollToMessage(int messageId) async { final index = messages.indexWhere( - (x) => x.isMessage && x.message!.message.messageId == messageId); + (x) => x.isMessage && x.message!.message.messageId == messageId, + ); if (index == -1) return; setState(() { focusedScrollItem = index; @@ -278,10 +283,15 @@ class _ChatMessagesViewState extends State { child: Scaffold( appBar: AppBar( title: GestureDetector( - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (context) { - return ContactView(widget.contact.userId); - })); + onTap: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return ContactView(widget.contact.userId); + }, + ), + ); }, child: Row( children: [ @@ -298,7 +308,7 @@ class _ChatMessagesViewState extends State { Text(getContactDisplayName(user)), const SizedBox(width: 10), if (user.verified) - VerifiedShield(key: verifyShieldKey, user) + VerifiedShield(key: verifyShieldKey, user), ], ), ), @@ -331,12 +341,13 @@ class _ChatMessagesViewState extends State { final chatMessage = messages[i].message!; return Transform.translate( offset: Offset( - (focusedScrollItem == i) - ? (chatMessage.message.messageOtherId == null) - ? -8 - : 8 - : 0, - 0), + (focusedScrollItem == i) + ? (chatMessage.message.messageOtherId == null) + ? -8 + : 8 + : 0, + 0, + ), child: Transform.scale( scale: (focusedScrollItem == i) ? 1.05 : 1, child: ChatListEntry( @@ -389,7 +400,7 @@ class _ChatMessagesViewState extends State { FontAwesomeIcons.xmark, size: 16, ), - ) + ), ], ), ), @@ -415,8 +426,8 @@ class _ChatMessagesViewState extends State { currentInputText = value; setState(() {}); }, - onSubmitted: (_) { - _sendMessage(); + onSubmitted: (_) async { + await _sendMessage(); }, decoration: inputTextMessageDeco(context), ), @@ -425,15 +436,16 @@ class _ChatMessagesViewState extends State { IconButton( padding: const EdgeInsets.all(15), icon: const FaIcon( - FontAwesomeIcons.solidPaperPlane), + FontAwesomeIcons.solidPaperPlane, + ), onPressed: _sendMessage, ) else IconButton( icon: const FaIcon(FontAwesomeIcons.camera), padding: const EdgeInsets.all(15), - onPressed: () { - Navigator.push( + onPressed: () async { + await Navigator.push( context, MaterialPageRoute( builder: (context) { @@ -442,7 +454,7 @@ class _ChatMessagesViewState extends State { ), ); }, - ) + ), ], ), ), diff --git a/lib/src/views/chats/chat_messages_components/chat_list_entry.dart b/lib/src/views/chats/chat_messages_components/chat_list_entry.dart index 3b1d831..4ba5c6b 100644 --- a/lib/src/views/chats/chat_messages_components/chat_list_entry.dart +++ b/lib/src/views/chats/chat_messages_components/chat_list_entry.dart @@ -42,8 +42,10 @@ class _ChatListEntryState extends State { @override void initState() { super.initState(); - final msgContent = MessageContent.fromJson(widget.msg.message.kind, - jsonDecode(widget.msg.message.contentJson!) as Map); + final msgContent = MessageContent.fromJson( + widget.msg.message.kind, + jsonDecode(widget.msg.message.contentJson!) as Map, + ); if (msgContent is TextMessageContent) { textMessage = msgContent.text; } diff --git a/lib/src/views/chats/chat_messages_components/chat_media_entry.dart b/lib/src/views/chats/chat_messages_components/chat_media_entry.dart index 09b477c..5569514 100644 --- a/lib/src/views/chats/chat_messages_components/chat_media_entry.dart +++ b/lib/src/views/chats/chat_messages_components/chat_media_entry.dart @@ -37,9 +37,9 @@ class _ChatMediaEntryState extends State { bool canBeReopened = false; @override - void initState() { + Future initState() async { super.initState(); - checkIfTutorialCanBeShown(); + await checkIfTutorialCanBeShown(); } Future checkIfTutorialCanBeShown() async { @@ -60,9 +60,9 @@ class _ChatMediaEntryState extends State { canBeReopened = true; }); } - Future.delayed(const Duration(seconds: 1), () { + Future.delayed(const Duration(seconds: 1), () async { if (!mounted) return; - showReopenMediaFilesTutorial(context, reopenMediaFile); + await showReopenMediaFilesTutorial(context, reopenMediaFile); }); } } @@ -101,10 +101,14 @@ class _ChatMediaEntryState extends State { widget.message.openedAt == null) { await Navigator.push( context, - MaterialPageRoute(builder: (context) { - return MediaViewerView(widget.contact, - initialMessage: widget.message); - }), + MaterialPageRoute( + builder: (context) { + return MediaViewerView( + widget.contact, + initialMessage: widget.message, + ); + }, + ), ); await checkIfTutorialCanBeShown(); } else if (widget.message.downloadState == DownloadState.pending) { diff --git a/lib/src/views/chats/chat_messages_components/chat_reaction_row.dart b/lib/src/views/chats/chat_messages_components/chat_reaction_row.dart index 8f57e45..113400d 100644 --- a/lib/src/views/chats/chat_messages_components/chat_reaction_row.dart +++ b/lib/src/views/chats/chat_messages_components/chat_reaction_row.dart @@ -29,7 +29,9 @@ class _ReactionRowState extends State { var hasOneReopened = false; for (final reaction in widget.otherReactions.reversed) { final content = MessageContent.fromJson( - reaction.kind, jsonDecode(reaction.contentJson!) as Map); + reaction.kind, + jsonDecode(reaction.contentJson!) as Map, + ); if (content is ReopenedMediaFileContent) { if (hasOneReopened) continue; diff --git a/lib/src/views/chats/chat_messages_components/chat_text_entry.dart b/lib/src/views/chats/chat_messages_components/chat_text_entry.dart index c249ae9..f161c52 100644 --- a/lib/src/views/chats/chat_messages_components/chat_text_entry.dart +++ b/lib/src/views/chats/chat_messages_components/chat_text_entry.dart @@ -34,7 +34,11 @@ class ChatTextEntry extends StatelessWidget { maxWidth: MediaQuery.of(context).size.width * 0.8, ), padding: EdgeInsets.only( - left: 10, top: 4, bottom: 4, right: hasReaction ? 30 : 10), + left: 10, + top: 4, + bottom: 4, + right: hasReaction ? 30 : 10, + ), decoration: BoxDecoration( color: message.responseTo == null ? getMessageColor(message.message) diff --git a/lib/src/views/chats/chat_messages_components/in_chat_media_viewer.dart b/lib/src/views/chats/chat_messages_components/in_chat_media_viewer.dart index 1a130c2..6b34a7f 100644 --- a/lib/src/views/chats/chat_messages_components/in_chat_media_viewer.dart +++ b/lib/src/views/chats/chat_messages_components/in_chat_media_viewer.dart @@ -35,10 +35,10 @@ class _InChatMediaViewerState extends State { Timer? _timer; @override - void initState() { + Future initState() async { super.initState(); - loadIndexAsync(); - initStream(); + await loadIndexAsync(); + await initStream(); } Future loadIndexAsync() async { @@ -55,8 +55,10 @@ class _InChatMediaViewerState extends State { bool loadIndex() { if (widget.message.mediaStored) { - final index = widget.galleryItems.indexWhere((x) => - x.id == (widget.message.mediaUploadId ?? widget.message.messageId)); + final index = widget.galleryItems.indexWhere( + (x) => + x.id == (widget.message.mediaUploadId ?? widget.message.messageId), + ); if (index != -1) { galleryItemIndex = index; return true; @@ -66,9 +68,9 @@ class _InChatMediaViewerState extends State { } @override - void dispose() { + Future dispose() async { super.dispose(); - messageStream?.cancel(); + await messageStream?.cancel(); _timer?.cancel(); // videoController?.dispose(); } @@ -122,7 +124,9 @@ class _InChatMediaViewerState extends State { ), child: Padding( padding: EdgeInsets.symmetric( - vertical: (widget.canBeReopened) ? 5 : 10.0, horizontal: 4), + vertical: (widget.canBeReopened) ? 5 : 10.0, + horizontal: 4, + ), child: MessageSendStateIcon( [widget.message], mainAxisAlignment: MainAxisAlignment.center, diff --git a/lib/src/views/chats/chat_messages_components/message_actions.dart b/lib/src/views/chats/chat_messages_components/message_actions.dart index 2e289e4..261a685 100644 --- a/lib/src/views/chats/chat_messages_components/message_actions.dart +++ b/lib/src/views/chats/chat_messages_components/message_actions.dart @@ -1,5 +1,3 @@ -// ignore_for_file: avoid_dynamic_calls, inference_failure_on_function_invocation - import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; @@ -25,12 +23,12 @@ class _SlidingResponseWidgetState extends State { bool gotFeedback = false; void _onHorizontalDragUpdate(DragUpdateDetails details) { - setState(() { + setState(() async { _offsetX += details.delta.dx; if (_offsetX > 40) { _offsetX = 40; if (!gotFeedback) { - HapticFeedback.heavyImpact(); + await HapticFeedback.heavyImpact(); gotFeedback = true; } } diff --git a/lib/src/views/chats/chat_messages_components/message_context_menu.dart b/lib/src/views/chats/chat_messages_components/message_context_menu.dart index 91c0834..26fe88e 100644 --- a/lib/src/views/chats/chat_messages_components/message_context_menu.dart +++ b/lib/src/views/chats/chat_messages_components/message_context_menu.dart @@ -1,4 +1,4 @@ -// ignore_for_file: avoid_dynamic_calls, inference_failure_on_function_invocation +// ignore_for_file: inference_failure_on_function_invocation import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -30,9 +30,9 @@ class MessageContextMenu extends StatelessWidget { Widget build(BuildContext context) { return PieMenu( onPressed: () => (), - onToggle: (menuOpen) { + onToggle: (menuOpen) async { if (menuOpen) { - HapticFeedback.heavyImpact(); + await HapticFeedback.heavyImpact(); } }, actions: [ @@ -51,11 +51,11 @@ class MessageContextMenu extends StatelessWidget { await sendTextMessage( message.contactId, TextMessageContent( - text: layer.text, - responseToMessageId: message.messageOtherId, - responseToOtherMessageId: (message.messageOtherId == null) - ? message.messageId - : null), + text: layer.text, + responseToMessageId: message.messageOtherId, + responseToOtherMessageId: + (message.messageOtherId == null) ? message.messageId : null, + ), (message.messageOtherId != null) ? PushNotification( kind: (message.kind == MessageKind.textMessage) @@ -77,10 +77,10 @@ class MessageContextMenu extends StatelessWidget { ), PieAction( tooltip: Text(context.lang.copy), - onSelect: () { + onSelect: () async { final text = getMessageText(message); - Clipboard.setData(ClipboardData(text: text)); - HapticFeedback.heavyImpact(); + await Clipboard.setData(ClipboardData(text: text)); + await HapticFeedback.heavyImpact(); }, child: const FaIcon(FontAwesomeIcons.solidCopy), ), diff --git a/lib/src/views/chats/chat_messages_components/message_send_state_icon.dart b/lib/src/views/chats/chat_messages_components/message_send_state_icon.dart index 9d0968e..f6c2cda 100644 --- a/lib/src/views/chats/chat_messages_components/message_send_state_icon.dart +++ b/lib/src/views/chats/chat_messages_components/message_send_state_icon.dart @@ -198,8 +198,8 @@ class _MessageSendStateIconState extends State { Transform( transform: Matrix4.identity() - ..scale(0.7) // Scale to half - ..translate(3.0, 5), + ..scaleByDouble(0.7, 0.7, 0.7, 0.7) // Scale to half + ..translateByDouble(3, 5, 0, 1), // Move down by 10 pixels (adjust as needed) alignment: Alignment.center, child: icons[1], diff --git a/lib/src/views/chats/chat_messages_components/response_container.dart b/lib/src/views/chats/chat_messages_components/response_container.dart index 322fde3..ba90e6e 100644 --- a/lib/src/views/chats/chat_messages_components/response_container.dart +++ b/lib/src/views/chats/chat_messages_components/response_container.dart @@ -125,9 +125,9 @@ class _ResponsePreviewState extends State { File? thumbnailPath; @override - void initState() { - initAsync(); + Future initState() async { super.initState(); + await initAsync(); } Future initAsync() async { @@ -145,8 +145,10 @@ class _ResponsePreviewState extends State { if (widget.message.kind == MessageKind.textMessage) { if (widget.message.contentJson != null) { - final content = MessageContent.fromJson(MessageKind.textMessage, - jsonDecode(widget.message.contentJson!) as Map); + final content = MessageContent.fromJson( + MessageKind.textMessage, + jsonDecode(widget.message.contentJson!) as Map, + ); if (content is TextMessageContent) { subtitle = truncateString(content.text); } @@ -154,7 +156,9 @@ class _ResponsePreviewState extends State { } if (widget.message.kind == MessageKind.media) { final content = MessageContent.fromJson( - MessageKind.media, jsonDecode(widget.message.contentJson!) as Map); + MessageKind.media, + jsonDecode(widget.message.contentJson!) as Map, + ); if (content is MediaMessageContent) { subtitle = content.isVideo ? 'Video' : 'Image'; } @@ -189,7 +193,7 @@ class _ResponsePreviewState extends State { username, style: const TextStyle(fontWeight: FontWeight.bold), ), - if (subtitle != null) Text(subtitle) + if (subtitle != null) Text(subtitle), ], ), ); @@ -216,7 +220,7 @@ class _ResponsePreviewState extends State { username, style: const TextStyle(fontWeight: FontWeight.bold), ), - if (subtitle != null) Text(subtitle) + if (subtitle != null) Text(subtitle), ], ), ), @@ -224,7 +228,7 @@ class _ResponsePreviewState extends State { SizedBox( height: widget.showBorder ? 100 : 210, child: Image.file(thumbnailPath!), - ) + ), ], ), ); diff --git a/lib/src/views/chats/media_viewer.view.dart b/lib/src/views/chats/media_viewer.view.dart index de08f44..c3d4f0d 100644 --- a/lib/src/views/chats/media_viewer.view.dart +++ b/lib/src/views/chats/media_viewer.view.dart @@ -71,24 +71,24 @@ class _MediaViewerViewState extends State { TextEditingController textMessageController = TextEditingController(); @override - void initState() { + Future initState() async { super.initState(); if (widget.initialMessage != null) { allMediaFiles = [widget.initialMessage!]; } - asyncLoadNextMedia(true); + await asyncLoadNextMedia(true); } @override - void dispose() { + Future dispose() async { nextMediaTimer?.cancel(); progressTimer?.cancel(); - _noScreenshot.screenshotOn(); - _subscription.cancel(); - downloadStateListener?.cancel(); - videoController?.dispose(); + await _noScreenshot.screenshotOn(); + await _subscription.cancel(); + await downloadStateListener?.cancel(); + await videoController?.dispose(); super.dispose(); } @@ -96,7 +96,7 @@ class _MediaViewerViewState extends State { final messages = twonlyDB.messagesDao.watchMediaMessageNotOpened(widget.contact.userId); - _subscription = messages.listen((messages) { + _subscription = messages.listen((messages) async { for (final msg in messages) { // if (!allMediaFiles.any((m) => m.messageId == msg.messageId)) { // allMediaFiles.add(msg); @@ -116,7 +116,7 @@ class _MediaViewerViewState extends State { } setState(() {}); if (firstRun) { - loadCurrentMediaFile(); + await loadCurrentMediaFile(); // ignore: parameter_assignments firstRun = false; } @@ -201,7 +201,9 @@ class _MediaViewerViewState extends State { } Future handleNextDownloadedMedia( - Message current, bool showTwonly) async { + Message current, + bool showTwonly, + ) async { final content = MediaMessageContent.fromJson(jsonDecode(current.contentJson!) as Map); @@ -237,9 +239,9 @@ class _MediaViewerViewState extends State { videoController = VideoPlayerController.file(File(videoPathTmp.path)); await videoController ?.setLooping(content.maxShowTime == gMediaShowInfinite); - await videoController?.initialize().then((_) { - videoController!.play(); - videoController?.addListener(() { + await videoController?.initialize().then((_) async { + await videoController!.play(); + videoController?.addListener(() async { setState(() { progress = 1 - videoController!.value.position.inSeconds / @@ -248,7 +250,7 @@ class _MediaViewerViewState extends State { if (content.maxShowTime != gMediaShowInfinite) { if (videoController?.value.position == videoController?.value.duration) { - nextMediaOrExit(); + await nextMediaOrExit(); } } }); @@ -288,9 +290,10 @@ class _MediaViewerViewState extends State { void startTimer() { nextMediaTimer?.cancel(); progressTimer?.cancel(); - nextMediaTimer = Timer(canBeSeenUntil!.difference(DateTime.now()), () { + nextMediaTimer = + Timer(canBeSeenUntil!.difference(DateTime.now()), () async { if (context.mounted) { - nextMediaOrExit(); + await nextMediaOrExit(); } }); progressTimer = Timer.periodic(const Duration(milliseconds: 10), (timer) { @@ -371,9 +374,10 @@ class _MediaViewerViewState extends State { children: [ if (imageSaving) const SizedBox( - width: 10, - height: 10, - child: CircularProgressIndicator(strokeWidth: 1)) + width: 10, + height: 10, + child: CircularProgressIndicator(strokeWidth: 1), + ) else imageSaved ? const Icon(Icons.check) @@ -443,11 +447,14 @@ class _MediaViewerViewState extends State { progressTimer?.cancel(); await videoController?.pause(); if (!mounted) return; - await Navigator.push(context, MaterialPageRoute( - builder: (context) { - return CameraSendToView(widget.contact); - }, - )); + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return CameraSendToView(widget.contact); + }, + ), + ); if (mounted && maxShowTime != gMediaShowInfinite) { await nextMediaOrExit(); } else { @@ -474,7 +481,7 @@ class _MediaViewerViewState extends State { if ((imageBytes != null || videoController != null) && (canBeSeenUntil == null || progress >= 0)) GestureDetector( - onTap: () { + onTap: () async { if (showSendTextMessageInput) { setState(() { showShortReactions = false; @@ -482,7 +489,7 @@ class _MediaViewerViewState extends State { }); return; } - nextMediaOrExit(); + await nextMediaOrExit(); }, child: MediaViewSizing( bottomNavigation: bottomNavigation(), @@ -501,8 +508,12 @@ class _MediaViewerViewState extends State { child: Image.memory( imageBytes!, fit: BoxFit.contain, - frameBuilder: (context, child, frame, - wasSynchronouslyLoaded) { + frameBuilder: ( + context, + child, + frame, + wasSynchronouslyLoaded, + ) { if (wasSynchronouslyLoaded) return child; return AnimatedSwitcher( duration: const Duration(milliseconds: 200), @@ -527,8 +538,8 @@ class _MediaViewerViewState extends State { if (isRealTwonly && imageBytes == null) Positioned.fill( child: GestureDetector( - onTap: () { - loadCurrentMediaFile(showTwonly: true); + onTap: () async { + await loadCurrentMediaFile(showTwonly: true); }, child: Column( children: [ @@ -604,7 +615,7 @@ class _MediaViewerViewState extends State { Shadow( color: Color.fromARGB(122, 0, 0, 0), blurRadius: 5, - ) + ), ], ), ), @@ -617,7 +628,11 @@ class _MediaViewerViewState extends State { child: Container( color: context.color.surface, padding: const EdgeInsets.only( - bottom: 10, left: 20, right: 20, top: 10), + bottom: 10, + left: 20, + right: 20, + top: 10, + ), child: Row( children: [ IconButton( @@ -644,9 +659,9 @@ class _MediaViewerViewState extends State { ), IconButton( icon: const FaIcon(FontAwesomeIcons.solidPaperPlane), - onPressed: () { + onPressed: () async { if (textMessageController.text.isNotEmpty) { - sendTextMessage( + await sendTextMessage( widget.contact.userId, TextMessageContent( text: textMessageController.text, @@ -664,7 +679,7 @@ class _MediaViewerViewState extends State { showShortReactions = false; }); }, - ) + ), ], ), ), @@ -722,9 +737,9 @@ class _ReactionButtonsState extends State { EmojiAnimation.animatedIcons.keys.toList().sublist(0, 6); @override - void initState() { + Future initState() async { super.initState(); - initAsync(); + await initAsync(); } Future initAsync() async { @@ -765,14 +780,16 @@ class _ReactionButtonsState extends State { mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.end, children: secondRowEmojis - .map((emoji) => EmojiReactionWidget( - userId: widget.userId, - responseToMessageId: widget.responseToMessageId, - hide: widget.hide, - show: widget.show, - isVideo: widget.isVideo, - emoji: emoji as String, - )) + .map( + (emoji) => EmojiReactionWidget( + userId: widget.userId, + responseToMessageId: widget.responseToMessageId, + hide: widget.hide, + show: widget.show, + isVideo: widget.isVideo, + emoji: emoji as String, + ), + ) .toList(), ), if (secondRowEmojis.isNotEmpty) const SizedBox(height: 15), @@ -830,8 +847,8 @@ class _EmojiReactionWidgetState extends State { duration: const Duration(milliseconds: 200), curve: Curves.linearToEaseOut, child: GestureDetector( - onTap: () { - sendTextMessage( + onTap: () async { + await sendTextMessage( widget.userId, TextMessageContent( text: widget.emoji, diff --git a/lib/src/views/chats/start_new_chat.view.dart b/lib/src/views/chats/start_new_chat.view.dart index a68b823..32e97fd 100644 --- a/lib/src/views/chats/start_new_chat.view.dart +++ b/lib/src/views/chats/start_new_chat.view.dart @@ -32,20 +32,21 @@ class _StartNewChatView extends State { final stream = twonlyDB.contactsDao.watchContactsForStartNewChat(); - contactSub = stream.listen((update) { - update.sort((a, b) => - getContactDisplayName(a).compareTo(getContactDisplayName(b))); + contactSub = stream.listen((update) async { + update.sort( + (a, b) => getContactDisplayName(a).compareTo(getContactDisplayName(b)), + ); setState(() { allContacts = update; }); - filterUsers(); + await filterUsers(); }); } @override - void dispose() { + Future dispose() async { + await contactSub.cancel(); super.dispose(); - contactSub.cancel(); } Future filterUsers() async { @@ -56,9 +57,11 @@ class _StartNewChatView extends State { return; } final usersFiltered = allContacts - .where((user) => getContactDisplayName(user) - .toLowerCase() - .contains(searchUserName.value.text.toLowerCase())) + .where( + (user) => getContactDisplayName(user) + .toLowerCase() + .contains(searchUserName.value.text.toLowerCase()), + ) .toList(); setState(() { contacts = usersFiltered; @@ -82,8 +85,8 @@ class _StartNewChatView extends State { Padding( padding: const EdgeInsets.symmetric(horizontal: 10), child: TextField( - onChanged: (_) { - filterUsers(); + onChanged: (_) async { + await filterUsers(); }, controller: searchUserName, decoration: getInputDecoration( @@ -97,7 +100,7 @@ class _StartNewChatView extends State { child: UserList( contacts, ), - ) + ), ], ), ), @@ -130,8 +133,8 @@ class UserList extends StatelessWidget { size: 13, ), ), - onTap: () { - Navigator.push( + onTap: () async { + await Navigator.push( context, MaterialPageRoute( builder: (context) => const AddNewUserView(), @@ -160,29 +163,34 @@ class UserList extends StatelessWidget { ), const Spacer(), IconButton( - icon: FaIcon(FontAwesomeIcons.boxOpen, - size: 13, - color: user.archived ? null : Colors.transparent), - onPressed: user.archived - ? () async { - const update = - ContactsCompanion(archived: Value(false)); - await twonlyDB.contactsDao - .updateContact(user.userId, update); - } - : null) + icon: FaIcon( + FontAwesomeIcons.boxOpen, + size: 13, + color: user.archived ? null : Colors.transparent, + ), + onPressed: user.archived + ? () async { + const update = + ContactsCompanion(archived: Value(false)); + await twonlyDB.contactsDao + .updateContact(user.userId, update); + } + : null, + ), ], ), leading: ContactAvatar( contact: user, fontSize: 13, ), - onTap: () { - Navigator.pushReplacement( + onTap: () async { + await Navigator.pushReplacement( context, - MaterialPageRoute(builder: (context) { - return ChatMessagesView(user); - }), + MaterialPageRoute( + builder: (context) { + return ChatMessagesView(user); + }, + ), ); }, ), diff --git a/lib/src/views/components/animate_icon.dart b/lib/src/views/components/animate_icon.dart index 78ba086..267a400 100644 --- a/lib/src/views/components/animate_icon.dart +++ b/lib/src/views/components/animate_icon.dart @@ -6,7 +6,8 @@ import 'package:twonly/src/views/camera/image_editor/data/data.dart'; // from https://github.com/eitanliu/emoji_regex/tree/master RegExp emojiRegex() => RegExp( - r'[#*0-9]\uFE0F?\u20E3|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26AA\u26B0\u26B1\u26BD\u26BE\u26C4\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0-\u26F5\u26F7\u26F8\u26FA\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B55\u3030\u303D\u3297\u3299]\uFE0F?|[\u261D\u270C\u270D](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|[\u270A\u270B](?:\uD83C[\uDFFB-\uDFFF])?|[\u23E9-\u23EC\u23F0\u23F3\u25FD\u2693\u26A1\u26AB\u26C5\u26CE\u26D4\u26EA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2795-\u2797\u27B0\u27BF\u2B50]|\u26F9(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|\u2764\uFE0F?(?:\u200D(?:\uD83D\uDD25|\uD83E\uDE79))?|\uD83C(?:[\uDC04\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]\uFE0F?|[\uDF85\uDFC2\uDFC7](?:\uD83C[\uDFFB-\uDFFF])?|[\uDFC3\uDFC4\uDFCA](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDFCB\uDFCC](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF]|\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uDDF4\uD83C\uDDF2|\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uDDF6\uD83C\uDDE6|\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF]|\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uDDFC\uD83C[\uDDEB\uDDF8]|\uDDFD\uD83C\uDDF0|\uDDFE\uD83C[\uDDEA\uDDF9]|\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uDFF3\uFE0F?(?:\u200D(?:\u26A7\uFE0F?|\uD83C\uDF08))?|\uDFF4(?:\u200D\u2620\uFE0F?|\uDB40\uDC67\uDB40\uDC62\uDB40(?:\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDC73\uDB40\uDC63\uDB40\uDC74|\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F)?)|\uD83D(?:[\uDC08\uDC26](?:\u200D\u2B1B)?|[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3]\uFE0F?|[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC](?:\uD83C[\uDFFB-\uDFFF])?|[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD74\uDD90](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC25\uDC27-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEDC-\uDEDF\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB\uDFF0]|\uDC15(?:\u200D\uD83E\uDDBA)?|\uDC3B(?:\u200D\u2744\uFE0F?)?|\uDC41\uFE0F?(?:\u200D\uD83D\uDDE8\uFE0F?)?|\uDC68(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDC68\uDC69]\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFE])))?))?|\uDC69(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?[\uDC68\uDC69]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?|\uDC69\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?))|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFE])))?))?|\uDC6F(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDD75(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDE2E(?:\u200D\uD83D\uDCA8)?|\uDE35(?:\u200D\uD83D\uDCAB)?|\uDE36(?:\u200D\uD83C\uDF2B\uFE0F?)?)|\uD83E(?:[\uDD0C\uDD0F\uDD18-\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5\uDEC3-\uDEC5\uDEF0\uDEF2-\uDEF8](?:\uD83C[\uDFFB-\uDFFF])?|[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDDDE\uDDDF](?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD0D\uDD0E\uDD10-\uDD17\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCC\uDDD0\uDDE0-\uDDFF\uDE70-\uDE7C\uDE80-\uDE88\uDE90-\uDEBD\uDEBF-\uDEC2\uDECE-\uDEDB\uDEE0-\uDEE8]|\uDD3C(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF])?|\uDDD1(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?))?|\uDEF1(?:\uD83C(?:\uDFFB(?:\u200D\uD83E\uDEF2\uD83C[\uDFFC-\uDFFF])?|\uDFFC(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFD-\uDFFF])?|\uDFFD(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])?|\uDFFE(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFD\uDFFF])?|\uDFFF(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFE])?))?)'); + r'[#*0-9]\uFE0F?\u20E3|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26AA\u26B0\u26B1\u26BD\u26BE\u26C4\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0-\u26F5\u26F7\u26F8\u26FA\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B55\u3030\u303D\u3297\u3299]\uFE0F?|[\u261D\u270C\u270D](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|[\u270A\u270B](?:\uD83C[\uDFFB-\uDFFF])?|[\u23E9-\u23EC\u23F0\u23F3\u25FD\u2693\u26A1\u26AB\u26C5\u26CE\u26D4\u26EA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2795-\u2797\u27B0\u27BF\u2B50]|\u26F9(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|\u2764\uFE0F?(?:\u200D(?:\uD83D\uDD25|\uD83E\uDE79))?|\uD83C(?:[\uDC04\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]\uFE0F?|[\uDF85\uDFC2\uDFC7](?:\uD83C[\uDFFB-\uDFFF])?|[\uDFC3\uDFC4\uDFCA](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDFCB\uDFCC](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF]|\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uDDF4\uD83C\uDDF2|\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uDDF6\uD83C\uDDE6|\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF]|\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uDDFC\uD83C[\uDDEB\uDDF8]|\uDDFD\uD83C\uDDF0|\uDDFE\uD83C[\uDDEA\uDDF9]|\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uDFF3\uFE0F?(?:\u200D(?:\u26A7\uFE0F?|\uD83C\uDF08))?|\uDFF4(?:\u200D\u2620\uFE0F?|\uDB40\uDC67\uDB40\uDC62\uDB40(?:\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDC73\uDB40\uDC63\uDB40\uDC74|\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F)?)|\uD83D(?:[\uDC08\uDC26](?:\u200D\u2B1B)?|[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3]\uFE0F?|[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC](?:\uD83C[\uDFFB-\uDFFF])?|[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD74\uDD90](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC25\uDC27-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEDC-\uDEDF\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB\uDFF0]|\uDC15(?:\u200D\uD83E\uDDBA)?|\uDC3B(?:\u200D\u2744\uFE0F?)?|\uDC41\uFE0F?(?:\u200D\uD83D\uDDE8\uFE0F?)?|\uDC68(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDC68\uDC69]\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFE])))?))?|\uDC69(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?[\uDC68\uDC69]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?|\uDC69\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?))|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFE])))?))?|\uDC6F(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDD75(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDE2E(?:\u200D\uD83D\uDCA8)?|\uDE35(?:\u200D\uD83D\uDCAB)?|\uDE36(?:\u200D\uD83C\uDF2B\uFE0F?)?)|\uD83E(?:[\uDD0C\uDD0F\uDD18-\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5\uDEC3-\uDEC5\uDEF0\uDEF2-\uDEF8](?:\uD83C[\uDFFB-\uDFFF])?|[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDDDE\uDDDF](?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD0D\uDD0E\uDD10-\uDD17\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCC\uDDD0\uDDE0-\uDDFF\uDE70-\uDE7C\uDE80-\uDE88\uDE90-\uDEBD\uDEBF-\uDEC2\uDECE-\uDEDB\uDEE0-\uDEE8]|\uDD3C(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF])?|\uDDD1(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?))?|\uDEF1(?:\uD83C(?:\uDFFB(?:\u200D\uD83E\uDEF2\uD83C[\uDFFC-\uDFFF])?|\uDFFC(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFD-\uDFFF])?|\uDFFD(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])?|\uDFFE(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFD\uDFFF])?|\uDFFF(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFE])?))?)', + ); bool isEmoji(String character) { final matches = emojiRegex().allMatches(character); @@ -233,7 +234,9 @@ class EmojiAnimationFlying extends StatelessWidget { Widget build(BuildContext context) { return TweenAnimationBuilder( tween: Tween( - begin: startPosition, end: 1), // Adjust end value as needed + begin: startPosition, + end: 1, + ), // Adjust end value as needed duration: duration, curve: Curves.linearToEaseOut, builder: (context, value, child) { diff --git a/lib/src/views/components/app_outdated.dart b/lib/src/views/components/app_outdated.dart index 2dfca67..952cf98 100644 --- a/lib/src/views/components/app_outdated.dart +++ b/lib/src/views/components/app_outdated.dart @@ -100,9 +100,12 @@ class _AppOutdatedState extends State { if (Platform.isAndroid) const SizedBox(height: 5), if (Platform.isAndroid) ElevatedButton( - onPressed: () { - launchUrl(Uri.parse( - 'https://play.google.com/store/apps/details?id=eu.twonly')); + onPressed: () async { + await launchUrl( + Uri.parse( + 'https://play.google.com/store/apps/details?id=eu.twonly', + ), + ); }, style: ElevatedButton.styleFrom( shape: RoundedRectangleBorder( diff --git a/lib/src/views/components/better_list_title.dart b/lib/src/views/components/better_list_title.dart index b120c9e..b7ad83c 100644 --- a/lib/src/views/components/better_list_title.dart +++ b/lib/src/views/components/better_list_title.dart @@ -2,14 +2,15 @@ import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; class BetterListTile extends StatelessWidget { - const BetterListTile( - {required this.icon, - required this.text, - required this.onTap, - super.key, - this.color, - this.subtitle, - this.iconSize = 20}); + const BetterListTile({ + required this.icon, + required this.text, + required this.onTap, + super.key, + this.color, + this.subtitle, + this.iconSize = 20, + }); final IconData icon; final String text; final Widget? subtitle; diff --git a/lib/src/views/components/better_text.dart b/lib/src/views/components/better_text.dart index 9841e2d..2373f9f 100644 --- a/lib/src/views/components/better_text.dart +++ b/lib/src/views/components/better_text.dart @@ -27,23 +27,25 @@ class BetterText extends StatelessWidget { } final url = match.group(0); - spans.add(TextSpan( - text: url, - style: const TextStyle( - decoration: TextDecoration.underline, - decorationColor: Colors.white, + spans.add( + TextSpan( + text: url, + style: const TextStyle( + decoration: TextDecoration.underline, + decorationColor: Colors.white, + ), + recognizer: TapGestureRecognizer() + ..onTap = () async { + final lUrl = + Uri.parse(url!.startsWith('http') ? url : 'http://$url'); + try { + await launchUrl(lUrl); + } catch (e) { + Log.error('Could not launch $e'); + } + }, ), - recognizer: TapGestureRecognizer() - ..onTap = () async { - final lUrl = - Uri.parse(url!.startsWith('http') ? url : 'http://$url'); - try { - await launchUrl(lUrl); - } catch (e) { - Log.error('Could not launch $e'); - } - }, - )); + ); lastMatchEnd = match.end; } diff --git a/lib/src/views/components/flame.dart b/lib/src/views/components/flame.dart index 2fc4ccc..2f3c80a 100644 --- a/lib/src/views/components/flame.dart +++ b/lib/src/views/components/flame.dart @@ -28,7 +28,8 @@ class FlameCounterWidget extends StatelessWidget { SizedBox( height: 15, child: EmojiAnimation( - emoji: (globalBestFriendUserId == user.userId) ? '❤️‍🔥' : '🔥'), + emoji: (globalBestFriendUserId == user.userId) ? '❤️‍🔥' : '🔥', + ), ), ], ); diff --git a/lib/src/views/components/notification_badge.dart b/lib/src/views/components/notification_badge.dart index 47c2645..dd4e0ac 100644 --- a/lib/src/views/components/notification_badge.dart +++ b/lib/src/views/components/notification_badge.dart @@ -1,8 +1,11 @@ import 'package:flutter/material.dart'; class NotificationBadge extends StatelessWidget { - const NotificationBadge( - {required this.count, required this.child, super.key}); + const NotificationBadge({ + required this.count, + required this.child, + super.key, + }); final String count; final Widget child; @@ -35,7 +38,7 @@ class NotificationBadge extends StatelessWidget { ), ), ), - ) + ), ], ); } diff --git a/lib/src/views/components/user_context_menu.dart b/lib/src/views/components/user_context_menu.dart index 8b7666a..2b30fce 100644 --- a/lib/src/views/components/user_context_menu.dart +++ b/lib/src/views/components/user_context_menu.dart @@ -27,9 +27,9 @@ class _UserContextMenuState extends State { Widget build(BuildContext context) { return PieMenu( onPressed: () => (), - onToggle: (menuOpen) { + onToggle: (menuOpen) async { if (menuOpen) { - HapticFeedback.heavyImpact(); + await HapticFeedback.heavyImpact(); } }, actions: [ @@ -59,12 +59,15 @@ class _UserContextMenuState extends State { ), PieAction( tooltip: Text(context.lang.contextMenuOpenChat), - onSelect: () { - Navigator.push(context, MaterialPageRoute( - builder: (context) { - return ChatMessagesView(widget.contact); - }, - )); + onSelect: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return ChatMessagesView(widget.contact); + }, + ), + ); }, child: const FaIcon(FontAwesomeIcons.solidComments), ), @@ -82,9 +85,11 @@ class _UserContextMenuState extends State { .updateContact(widget.contact.userId, update); } }, - child: FaIcon(widget.contact.pinned - ? FontAwesomeIcons.thumbtackSlash - : FontAwesomeIcons.thumbtack), + child: FaIcon( + widget.contact.pinned + ? FontAwesomeIcons.thumbtackSlash + : FontAwesomeIcons.thumbtack, + ), ), ], child: widget.child, @@ -137,12 +142,15 @@ class _UserContextMenuBlocked extends State { ), PieAction( tooltip: Text(context.lang.contextMenuUserProfile), - onSelect: () { - Navigator.push(context, MaterialPageRoute( - builder: (context) { - return ContactView(widget.contact.userId); - }, - )); + onSelect: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return ContactView(widget.contact.userId); + }, + ), + ); }, child: const FaIcon(FontAwesomeIcons.user), ), diff --git a/lib/src/views/components/verified_shield.dart b/lib/src/views/components/verified_shield.dart index 101a20c..27c1c45 100644 --- a/lib/src/views/components/verified_shield.dart +++ b/lib/src/views/components/verified_shield.dart @@ -11,12 +11,15 @@ class VerifiedShield extends StatelessWidget { @override Widget build(BuildContext context) { return GestureDetector( - onTap: () { - Navigator.push(context, MaterialPageRoute( - builder: (context) { - return ContactVerifyView(contact); - }, - )); + onTap: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return ContactVerifyView(contact); + }, + ), + ); }, child: Tooltip( message: contact.verified diff --git a/lib/src/views/components/video_player_wrapper.dart b/lib/src/views/components/video_player_wrapper.dart index 2ed4be2..2b72827 100644 --- a/lib/src/views/components/video_player_wrapper.dart +++ b/lib/src/views/components/video_player_wrapper.dart @@ -4,8 +4,11 @@ import 'package:flutter/material.dart'; import 'package:video_player/video_player.dart'; class VideoPlayerWrapper extends StatefulWidget { - const VideoPlayerWrapper( - {required this.videoPath, required this.mirrorVideo, super.key}); + const VideoPlayerWrapper({ + required this.videoPath, + required this.mirrorVideo, + super.key, + }); final File videoPath; final bool mirrorVideo; @@ -17,23 +20,22 @@ class _VideoPlayerWrapperState extends State { late VideoPlayerController _controller; @override - void initState() { + Future initState() async { super.initState(); - _controller = VideoPlayerController.file(widget.videoPath) - ..initialize().then((_) { - if (context.mounted) { - setState(() { - _controller - ..setLooping(true) - ..play(); - }); - } - }); + _controller = VideoPlayerController.file(widget.videoPath); + + await _controller.initialize().then((_) async { + if (context.mounted) { + await _controller.setLooping(true); + await _controller.play(); + setState(() {}); + } + }); } @override - void dispose() { - _controller.dispose(); + Future dispose() async { + await _controller.dispose(); super.dispose(); } diff --git a/lib/src/views/contact/contact.view.dart b/lib/src/views/contact/contact.view.dart index 2a772fb..31fcfde 100644 --- a/lib/src/views/contact/contact.view.dart +++ b/lib/src/views/contact/contact.view.dart @@ -72,7 +72,8 @@ class _ContactViewState extends State { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text( - 'Es ist ein Fehler aufgetreten. Bitte versuche es später erneut.'), + 'Es ist ein Fehler aufgetreten. Bitte versuche es später erneut.', + ), duration: Duration(seconds: 3), ), ); @@ -116,8 +117,9 @@ class _ContactViewState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ Padding( - padding: const EdgeInsets.only(right: 10), - child: VerifiedShield(contact)), + padding: const EdgeInsets.only(right: 10), + child: VerifiedShield(contact), + ), Text( getContactDisplayName(contact), style: const TextStyle(fontSize: 20), @@ -151,12 +153,15 @@ class _ContactViewState extends State { BetterListTile( icon: FontAwesomeIcons.shieldHeart, text: context.lang.contactVerifyNumberTitle, - onTap: () { - Navigator.push(context, MaterialPageRoute( - builder: (context) { - return ContactVerifyView(contact); - }, - )); + onTap: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return ContactVerifyView(contact); + }, + ), + ); }, ), BetterListTile( @@ -168,7 +173,8 @@ class _ContactViewState extends State { context, context.lang.deleteAllContactMessages, context.lang.deleteAllContactMessagesBody( - getContactDisplayName(contact)), + getContactDisplayName(contact), + ), ); if (block) { if (context.mounted) { @@ -204,7 +210,9 @@ class _ContactViewState extends State { } Future showNicknameChangeDialog( - BuildContext context, Contact contact) { + BuildContext context, + Contact contact, +) { final controller = TextEditingController(text: getContactDisplayName(contact)); diff --git a/lib/src/views/contact/contact_verify.view.dart b/lib/src/views/contact/contact_verify.view.dart index cfe9c65..4ccc494 100644 --- a/lib/src/views/contact/contact_verify.view.dart +++ b/lib/src/views/contact/contact_verify.view.dart @@ -36,15 +36,15 @@ class _ContactVerifyViewState extends State { Uint8List? _qrCodeImageBytes; @override - void initState() { + Future initState() async { super.initState(); _contact = widget.contact; - loadAsync(); + await loadAsync(); } @override - void dispose() { - _contactSub.cancel(); + Future dispose() async { + await _contactSub.cancel(); super.dispose(); } @@ -86,14 +86,17 @@ class _ContactVerifyViewState extends State { Future openQrScanner() async { if (_fingerprint == null) return; - final isValid = await Navigator.push(context, MaterialPageRoute( - builder: (context) { - return ContactVerifyQrScanView( - widget.contact, - fingerprint: _fingerprint!, - ); - }, - )) as bool?; + final isValid = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return ContactVerifyQrScanView( + widget.contact, + fingerprint: _fingerprint!, + ); + }, + ), + ) as bool?; if (isValid == null) { return; // user just returned... } @@ -205,7 +208,8 @@ class _ContactVerifyViewState extends State { padding: const EdgeInsets.symmetric(horizontal: 30), child: Text( context.lang.contactVerifyNumberLongDesc( - getContactDisplayName(_contact)), + getContactDisplayName(_contact), + ), textAlign: TextAlign.center, ), ), @@ -213,9 +217,12 @@ class _ContactVerifyViewState extends State { padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 10), child: GestureDetector( - onTap: () { - launchUrl(Uri.parse( - 'https://twonly.eu/en/faq/security/verify-security-number.html')); + onTap: () async { + await launchUrl( + Uri.parse( + 'https://twonly.eu/en/faq/security/verify-security-number.html', + ), + ); }, child: Text( 'Read more.', @@ -226,7 +233,7 @@ class _ContactVerifyViewState extends State { ), ), ), - ) + ), ], ), bottomNavigationBar: SafeArea( @@ -248,7 +255,7 @@ class _ContactVerifyViewState extends State { label: Text( context.lang.contactVerifyNumberMarkAsVerified, ), - ) + ), ], ), ), diff --git a/lib/src/views/contact/contact_verify_qr_scan.view.dart b/lib/src/views/contact/contact_verify_qr_scan.view.dart index 097e594..566a833 100644 --- a/lib/src/views/contact/contact_verify_qr_scan.view.dart +++ b/lib/src/views/contact/contact_verify_qr_scan.view.dart @@ -7,8 +7,11 @@ import 'package:twonly/src/database/twonly_database.dart'; import 'package:twonly/src/utils/log.dart'; class ContactVerifyQrScanView extends StatefulWidget { - const ContactVerifyQrScanView(this.contact, - {required this.fingerprint, super.key}); + const ContactVerifyQrScanView( + this.contact, { + required this.fingerprint, + super.key, + }); final Fingerprint fingerprint; final Contact contact; diff --git a/lib/src/views/home.view.dart b/lib/src/views/home.view.dart index f796dc0..2644bca 100644 --- a/lib/src/views/home.view.dart +++ b/lib/src/views/home.view.dart @@ -72,11 +72,11 @@ class HomeViewState extends State { } if (cameraController == null && !initCameraStarted && offsetRatio < 1) { initCameraStarted = true; - selectCamera(selectedCameraDetails.cameraId, false, false); + unawaited(selectCamera(selectedCameraDetails.cameraId, false, false)); } if (offsetRatio == 1) { - disableCameraTimer = Timer(const Duration(milliseconds: 500), () { - cameraController?.dispose(); + disableCameraTimer = Timer(const Duration(milliseconds: 500), () async { + await cameraController?.dispose(); cameraController = null; selectedCameraDetails = SelectedCameraDetails(); disableCameraTimer = null; @@ -86,7 +86,7 @@ class HomeViewState extends State { } @override - void initState() { + Future initState() async { super.initState(); activePageIdx = widget.initialPage; globalUpdateOfHomeViewPageIndex = (index) { @@ -99,15 +99,15 @@ class HomeViewState extends State { .listen((NotificationResponse? response) async { globalUpdateOfHomeViewPageIndex(0); }); - selectCamera(0, true, false); - initAsync(); + await selectCamera(0, true, false); + await initAsync(); } @override - void dispose() { - selectNotificationStream.close(); + Future dispose() async { + await selectNotificationStream.close(); disableCameraTimer?.cancel(); - cameraController?.dispose(); + await cameraController?.dispose(); super.dispose(); } @@ -117,7 +117,11 @@ class HomeViewState extends State { bool enableAudio, ) async { final opts = await initializeCameraController( - selectedCameraDetails, sCameraId, init, enableAudio); + selectedCameraDetails, + sCameraId, + init, + enableAudio, + ); if (opts != null) { selectedCameraDetails = opts.$1; cameraController = opts.$2; @@ -131,7 +135,7 @@ class HomeViewState extends State { Future toggleSelectedCamera() async { if (cameraController == null) return; // do not allow switching camera when recording - if (cameraController!.value.isRecordingVideo == true) { + if (cameraController!.value.isRecordingVideo) { return; } await cameraController!.dispose(); @@ -185,21 +189,22 @@ class HomeViewState extends State { ), ), Positioned( - left: 0, - top: 0, - right: 0, - bottom: (offsetRatio > 0.25) - ? MediaQuery.sizeOf(context).height * 2 - : 0, - child: Opacity( - opacity: 1 - (offsetRatio * 4) % 1, - child: CameraPreviewControllerView( - cameraController: cameraController, - screenshotController: screenshotController, - selectedCameraDetails: selectedCameraDetails, - selectCamera: selectCamera, - ), - )), + left: 0, + top: 0, + right: 0, + bottom: (offsetRatio > 0.25) + ? MediaQuery.sizeOf(context).height * 2 + : 0, + child: Opacity( + opacity: 1 - (offsetRatio * 4) % 1, + child: CameraPreviewControllerView( + cameraController: cameraController, + screenshotController: screenshotController, + selectedCameraDetails: selectedCameraDetails, + selectCamera: selectCamera, + ), + ), + ), ], ), ), @@ -207,10 +212,11 @@ class HomeViewState extends State { showSelectedLabels: false, showUnselectedLabels: false, unselectedIconTheme: IconThemeData( - color: - Theme.of(context).colorScheme.inverseSurface.withAlpha(150)), + color: Theme.of(context).colorScheme.inverseSurface.withAlpha(150), + ), selectedIconTheme: IconThemeData( - color: Theme.of(context).colorScheme.inverseSurface), + color: Theme.of(context).colorScheme.inverseSurface, + ), items: const [ BottomNavigationBarItem( icon: FaIcon(FontAwesomeIcons.solidComments), @@ -227,8 +233,8 @@ class HomeViewState extends State { ], onTap: (int index) { activePageIdx = index; - setState(() { - homeViewPageController.animateToPage( + setState(() async { + await homeViewPageController.animateToPage( index, duration: const Duration(milliseconds: 100), curve: Curves.bounceIn, diff --git a/lib/src/views/memories/memories.view.dart b/lib/src/views/memories/memories.view.dart index 2d16c24..e34df6d 100644 --- a/lib/src/views/memories/memories.view.dart +++ b/lib/src/views/memories/memories.view.dart @@ -27,14 +27,14 @@ class MemoriesViewState extends State { StreamSubscription>? messageSub; @override - void initState() { + Future initState() async { super.initState(); - initAsync(); + await initAsync(); } @override - void dispose() { - messageSub?.cancel(); + Future dispose() async { + await messageSub?.cancel(); super.dispose(); } @@ -71,15 +71,17 @@ class MemoriesViewState extends State { break; } final creationDate = file.lastModifiedSync(); - items.add(MemoryItem( - id: int.parse(fileName.split('.')[0]), - messages: [], - date: creationDate, - mirrorVideo: false, - thumbnailPath: thumbnailFile, - imagePath: imagePath, - videoPath: videoPath, - )); + items.add( + MemoryItem( + id: int.parse(fileName.split('.')[0]), + messages: [], + date: creationDate, + mirrorVideo: false, + thumbnailPath: thumbnailFile, + imagePath: imagePath, + videoPath: videoPath, + ), + ); } } } @@ -98,8 +100,9 @@ class MemoriesViewState extends State { var lastMonth = ''; galleryItems = await loadMemoriesDirectory(); for (final item in galleryItems) { - items.remove(item - .id); // prefer the stored one and not the saved on in the chat.... + items.remove( + item.id, + ); // prefer the stored one and not the saved on in the chat.... } galleryItems += items.values.toList(); galleryItems.sort((a, b) => b.date.compareTo(a.date)); @@ -125,19 +128,20 @@ class MemoriesViewState extends State { child: (galleryItems.isEmpty) ? Center( child: Text( - context.lang.memoriesEmpty, - textAlign: TextAlign.center, - )) + context.lang.memoriesEmpty, + textAlign: TextAlign.center, + ), + ) : ListView.builder( itemCount: months.length * 2, itemBuilder: (context, mIndex) { if (mIndex.isEven) { return Padding( padding: const EdgeInsets.all(8), - child: Text(months[(mIndex / 2).toInt()]), + child: Text(months[(mIndex ~/ 2)]), ); } - final index = ((mIndex - 1) / 2).toInt(); + final index = (mIndex - 1) ~/ 2; return GridView.builder( shrinkWrap: true, physics: const ClampingScrollPhysics(), @@ -151,8 +155,8 @@ class MemoriesViewState extends State { final gaIndex = orderedByMonth[months[index]]![gIndex]; return MemoriesItemThumbnail( galleryItem: galleryItems[gaIndex], - onTap: () { - open(context, gaIndex); + onTap: () async { + await open(context, gaIndex); }, ); }, diff --git a/lib/src/views/memories/memories_photo_slider.view.dart b/lib/src/views/memories/memories_photo_slider.view.dart index 8ac1d3a..a1c0103 100644 --- a/lib/src/views/memories/memories_photo_slider.view.dart +++ b/lib/src/views/memories/memories_photo_slider.view.dart @@ -126,8 +126,8 @@ class _MemoriesPhotoSliderViewState extends State { children: [ FilledButton.icon( icon: const FaIcon(FontAwesomeIcons.solidPaperPlane), - onPressed: () { - Navigator.push( + onPressed: () async { + await Navigator.push( context, MaterialPageRoute( builder: (context) => ShareImageEditorView( @@ -144,13 +144,16 @@ class _MemoriesPhotoSliderViewState extends State { ); }, style: ButtonStyle( - padding: WidgetStateProperty.all( - const EdgeInsets.symmetric( - vertical: 10, horizontal: 30), + padding: WidgetStateProperty.all( + const EdgeInsets.symmetric( + vertical: 10, + horizontal: 30, ), - backgroundColor: WidgetStateProperty.all( - Theme.of(context).colorScheme.primary, - )), + ), + backgroundColor: WidgetStateProperty.all( + Theme.of(context).colorScheme.primary, + ), + ), label: Text( context.lang.shareImagedEditorSendImage, style: const TextStyle(fontSize: 17), @@ -173,12 +176,12 @@ class _MemoriesPhotoSliderViewState extends State { Positioned( right: 5, child: PopupMenuButton( - onSelected: (String result) { + onSelected: (String result) async { if (result == 'delete') { - deleteFile(); + await deleteFile(); } if (result == 'export') { - exportFile(); + await exportFile(); } }, itemBuilder: (BuildContext context) => @@ -197,7 +200,7 @@ class _MemoriesPhotoSliderViewState extends State { // ), ], ), - ) + ), ], ), ), diff --git a/lib/src/views/onboarding/recover.view.dart b/lib/src/views/onboarding/recover.view.dart index 67e312c..4590aef 100644 --- a/lib/src/views/onboarding/recover.view.dart +++ b/lib/src/views/onboarding/recover.view.dart @@ -63,8 +63,8 @@ class _BackupRecoveryViewState extends State { title: Text('twonly Safe ${context.lang.twonlySafeRecoverTitle}'), actions: [ IconButton( - onPressed: () { - showAlertDialog( + onPressed: () async { + await showAlertDialog( context, 'twonly Safe', context.lang.backupTwonlySafeLongDesc, @@ -72,7 +72,7 @@ class _BackupRecoveryViewState extends State { }, icon: const FaIcon(FontAwesomeIcons.circleInfo), iconSize: 18, - ) + ), ], ), body: Padding( @@ -128,17 +128,21 @@ class _BackupRecoveryViewState extends State { size: 16, ), ), - ) + ), ], ), const SizedBox(height: 30), Center( child: OutlinedButton( onPressed: () async { - backupServer = await Navigator.push(context, - MaterialPageRoute(builder: (context) { - return const TwonlySafeServerView(); - })); + backupServer = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const TwonlySafeServerView(); + }, + ), + ); setState(() {}); }, child: Text(context.lang.backupExpertSettings), @@ -146,17 +150,18 @@ class _BackupRecoveryViewState extends State { ), const SizedBox(height: 10), Center( - child: FilledButton.icon( - onPressed: (!isLoading) ? _recoverTwonlySafe : null, - icon: isLoading - ? const SizedBox( - height: 12, - width: 12, - child: CircularProgressIndicator(strokeWidth: 1), - ) - : const Icon(Icons.lock_clock_rounded), - label: Text(context.lang.twonlySafeRecoverBtn), - )) + child: FilledButton.icon( + onPressed: (!isLoading) ? _recoverTwonlySafe : null, + icon: isLoading + ? const SizedBox( + height: 12, + width: 12, + child: CircularProgressIndicator(strokeWidth: 1), + ) + : const Icon(Icons.lock_clock_rounded), + label: Text(context.lang.twonlySafeRecoverBtn), + ), + ), ], ), ), diff --git a/lib/src/views/onboarding/register.view.dart b/lib/src/views/onboarding/register.view.dart index 748e247..84edc97 100644 --- a/lib/src/views/onboarding/register.view.dart +++ b/lib/src/views/onboarding/register.view.dart @@ -105,92 +105,93 @@ class _RegisterViewState extends State { title: const Text(''), ), body: Padding( - padding: const EdgeInsets.all(10), - child: Padding( - padding: const EdgeInsets.only(left: 10, right: 10), - child: ListView( - children: [ - const SizedBox(height: 50), - Text( - context.lang.registerTitle, + padding: const EdgeInsets.all(10), + child: Padding( + padding: const EdgeInsets.only(left: 10, right: 10), + child: ListView( + children: [ + const SizedBox(height: 50), + Text( + context.lang.registerTitle, + textAlign: TextAlign.center, + style: const TextStyle(fontSize: 30), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: Text( + context.lang.registerSlogan, textAlign: TextAlign.center, - style: const TextStyle(fontSize: 30), + style: const TextStyle(fontSize: 12), ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 30), + ), + const SizedBox(height: 60), + Center( + child: Padding( + padding: const EdgeInsets.only(left: 10, right: 10), child: Text( - context.lang.registerSlogan, + context.lang.registerUsernameSlogan, textAlign: TextAlign.center, - style: const TextStyle(fontSize: 12), + style: const TextStyle(fontSize: 15), ), ), - const SizedBox(height: 60), - Center( - child: Padding( - padding: const EdgeInsets.only(left: 10, right: 10), - child: Text( - context.lang.registerUsernameSlogan, - textAlign: TextAlign.center, - style: const TextStyle(fontSize: 15), - ), - ), + ), + const SizedBox(height: 15), + TextField( + controller: usernameController, + onChanged: (value) { + usernameController.text = value.toLowerCase(); + usernameController.selection = TextSelection.fromPosition( + TextPosition(offset: usernameController.text.length), + ); + setState(() { + _isValidUserName = usernameController.text.length >= 3; + }); + }, + inputFormatters: [ + LengthLimitingTextInputFormatter(12), + FilteringTextInputFormatter.allow(RegExp('[a-z0-9A-Z]')), + ], + style: const TextStyle(fontSize: 17), + decoration: getInputDecoration( + context.lang.registerUsernameDecoration, ), - const SizedBox(height: 15), - TextField( - controller: usernameController, - onChanged: (value) { - usernameController.text = value.toLowerCase(); - usernameController.selection = TextSelection.fromPosition( - TextPosition(offset: usernameController.text.length), - ); - setState(() { - _isValidUserName = usernameController.text.length >= 3; - }); - }, - inputFormatters: [ - LengthLimitingTextInputFormatter(12), - FilteringTextInputFormatter.allow(RegExp('[a-z0-9A-Z]')), - ], - style: const TextStyle(fontSize: 17), - decoration: getInputDecoration( - context.lang.registerUsernameDecoration, - ), + ), + const SizedBox(height: 10), + Text( + context.lang.registerUsernameLimits, + style: TextStyle( + color: _showUserNameError ? Colors.red : Colors.transparent, + fontSize: 12, ), - const SizedBox(height: 10), - Text( - context.lang.registerUsernameLimits, - style: TextStyle( - color: _showUserNameError ? Colors.red : Colors.transparent, - fontSize: 12, - ), - textAlign: TextAlign.center, - ), - // const SizedBox(height: 5), - // Center( - // child: Padding( - // padding: EdgeInsets.only(left: 10, right: 10), - // child: Text( - // context.lang.registerUsernameLimits, - // textAlign: TextAlign.center, - // style: const TextStyle(fontSize: 9), - // ), - // ), - // ), - // const SizedBox(height: 30), - // Center( - // child: Text( - // context.lang.registerTwonlyCodeText, - // textAlign: TextAlign.center, - // ), - // ), - // const SizedBox(height: 10), - // TextField( - // controller: inviteCodeController, - // decoration: - // getInputDecoration(context.lang.registerTwonlyCodeLabel), - // ), - const SizedBox(height: 30), - Column(children: [ + textAlign: TextAlign.center, + ), + // const SizedBox(height: 5), + // Center( + // child: Padding( + // padding: EdgeInsets.only(left: 10, right: 10), + // child: Text( + // context.lang.registerUsernameLimits, + // textAlign: TextAlign.center, + // style: const TextStyle(fontSize: 9), + // ), + // ), + // ), + // const SizedBox(height: 30), + // Center( + // child: Text( + // context.lang.registerTwonlyCodeText, + // textAlign: TextAlign.center, + // ), + // ), + // const SizedBox(height: 10), + // TextField( + // controller: inviteCodeController, + // decoration: + // getInputDecoration(context.lang.registerTwonlyCodeLabel), + // ), + const SizedBox(height: 30), + Column( + children: [ FilledButton.icon( icon: _isTryingToRegister ? const SizedBox( @@ -204,14 +205,18 @@ class _RegisterViewState extends State { : const Icon(Icons.group), onPressed: createNewUser, style: ButtonStyle( - padding: WidgetStateProperty.all( - const EdgeInsets.symmetric( - vertical: 10, horizontal: 30), + padding: WidgetStateProperty.all( + const EdgeInsets.symmetric( + vertical: 10, + horizontal: 30, ), - backgroundColor: _isTryingToRegister - ? WidgetStateProperty.all( - Colors.grey) - : null), + ), + backgroundColor: _isTryingToRegister + ? WidgetStateProperty.all( + Colors.grey, + ) + : null, + ), label: Text( context.lang.registerSubmitButton, style: const TextStyle(fontSize: 17), @@ -222,22 +227,27 @@ class _RegisterViewState extends State { mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ OutlinedButton.icon( - onPressed: () { - Navigator.push(context, MaterialPageRoute( - builder: (context) { - return const BackupRecoveryView(); - }, - )); + onPressed: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const BackupRecoveryView(); + }, + ), + ); }, label: Text(context.lang.twonlySafeRecoverBtn), ), ], ), - ]), - // ), - ], - ), - )), + ], + ), + // ), + ], + ), + ), + ), ); } } diff --git a/lib/src/views/settings/account.view.dart b/lib/src/views/settings/account.view.dart index 085be3d..64da2e0 100644 --- a/lib/src/views/settings/account.view.dart +++ b/lib/src/views/settings/account.view.dart @@ -25,18 +25,20 @@ class _AccountViewState extends State { bool hasRemainingBallance = false; @override - void initState() { - initAsync(); + Future initState() async { super.initState(); + await initAsync(); } Future initAsync() async { final ballance = await loadPlanBalance(useCache: false); if (ballance == null || !mounted) return; var ballanceInCents = ballance.transactions - .where((x) => - x.transactionType != Response_TransactionTypes.ThanksForTesting || - kDebugMode) + .where( + (x) => + x.transactionType != Response_TransactionTypes.ThanksForTesting || + kDebugMode, + ) .map((a) => a.depositCents.toInt()) .sum; if (ballanceInCents < 0) { @@ -93,9 +95,11 @@ class _AccountViewState extends State { subtitle: (formattedBallance == null) ? Text(context.lang.settingsAccountDeleteAccountNoInternet) : hasRemainingBallance - ? Text(context.lang - .settingsAccountDeleteAccountWithBallance( - formattedBallance!)) + ? Text( + context.lang.settingsAccountDeleteAccountWithBallance( + formattedBallance!, + ), + ) : Text(context.lang.settingsAccountDeleteAccountNoBallance), onLongPress: kDebugMode ? () async { @@ -110,12 +114,16 @@ class _AccountViewState extends State { ? null : () async { if (hasRemainingBallance) { - final canGoNext = await Navigator.push(context, - MaterialPageRoute(builder: (context) { - return RefundCreditsView( - formattedBalance: formattedBallance!, - ); - })) as bool?; + final canGoNext = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return RefundCreditsView( + formattedBalance: formattedBallance!, + ); + }, + ), + ) as bool?; unawaited(initAsync()); if (canGoNext == null || !canGoNext) return; } diff --git a/lib/src/views/settings/account/refund_credits.view.dart b/lib/src/views/settings/account/refund_credits.view.dart index 2f6ea2e..1e997bf 100644 --- a/lib/src/views/settings/account/refund_credits.view.dart +++ b/lib/src/views/settings/account/refund_credits.view.dart @@ -34,10 +34,14 @@ class _RefundCreditsViewState extends State { ListTile( title: const Text('Create a Voucher'), onTap: () async { - await Navigator.push(context, - MaterialPageRoute(builder: (context) { - return const VoucherView(); - })); + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const VoucherView(); + }, + ), + ); if (context.mounted) { Navigator.pop(context, false); } diff --git a/lib/src/views/settings/appearance.view.dart b/lib/src/views/settings/appearance.view.dart index 00685a4..4873299 100644 --- a/lib/src/views/settings/appearance.view.dart +++ b/lib/src/views/settings/appearance.view.dart @@ -16,9 +16,9 @@ class _AppearanceViewState extends State { bool showFeedbackShortcut = false; @override - void initState() { + Future initState() async { super.initState(); - initAsync(); + await initAsync(); } Future initAsync() async { @@ -99,10 +99,12 @@ class _AppearanceViewState extends State { children: [ ListTile( title: Text(context.lang.settingsAppearanceTheme), - subtitle: Text(selectedTheme.name, - style: const TextStyle(color: Colors.grey)), - onTap: () { - _showSelectThemeMode(context); + subtitle: Text( + selectedTheme.name, + style: const TextStyle(color: Colors.grey), + ), + onTap: () async { + await _showSelectThemeMode(context); }, ), ListTile( diff --git a/lib/src/views/settings/backup/backup.view.dart b/lib/src/views/settings/backup/backup.view.dart index f3d2f5e..144c939 100644 --- a/lib/src/views/settings/backup/backup.view.dart +++ b/lib/src/views/settings/backup/backup.view.dart @@ -33,9 +33,9 @@ class _BackupViewState extends State { final PageController pageController = PageController(); @override - void initState() { - initAsync(); + Future initState() async { super.initState(); + await initAsync(); gUpdateBackupView = initAsync; } @@ -113,7 +113,9 @@ class _BackupViewState extends State { ( context.lang.backupLastBackupDate, formatDateTime( - context, twonlySafeBackup!.lastBackupDone) + context, + twonlySafeBackup!.lastBackupDone, + ) ), ( context.lang.backupLastBackupSize, @@ -122,7 +124,7 @@ class _BackupViewState extends State { ( context.lang.backupLastBackupResult, backupStatus(twonlySafeBackup!.backupUploadState) - ) + ), ].map((pair) { return TableRow( children: [ @@ -159,15 +161,16 @@ class _BackupViewState extends State { }); }, child: Text(context.lang.backupTwonlySaveNow), - ) + ), ], ), onTap: () async { if (twonlySafeBackup != null) { final disable = await showAlertDialog( - context, - context.lang.deleteBackupTitle, - context.lang.deleteBackupBody); + context, + context.lang.deleteBackupTitle, + context.lang.deleteBackupBody, + ); if (disable) { await disableTwonlySafe(); } @@ -175,10 +178,14 @@ class _BackupViewState extends State { setState(() { isLoading = true; }); - await Navigator.push(context, - MaterialPageRoute(builder: (context) { - return const TwonlyIdentityBackupView(); - })); + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const TwonlyIdentityBackupView(); + }, + ), + ); } await initAsync(); }, @@ -195,7 +202,8 @@ class _BackupViewState extends State { showSelectedLabels: true, showUnselectedLabels: true, unselectedIconTheme: IconThemeData( - color: Theme.of(context).colorScheme.inverseSurface.withAlpha(150)), + color: Theme.of(context).colorScheme.inverseSurface.withAlpha(150), + ), selectedIconTheme: IconThemeData(color: Theme.of(context).colorScheme.inverseSurface), items: [ @@ -210,8 +218,8 @@ class _BackupViewState extends State { ], onTap: (int index) { activePageIdx = index; - setState(() { - pageController.animateToPage( + setState(() async { + await pageController.animateToPage( index, duration: const Duration(milliseconds: 100), curve: Curves.bounceIn, @@ -271,7 +279,7 @@ class BackupOption extends StatelessWidget { onPressed: onTap, child: Text(context.lang.enable), ), - ) + ), ], ), ), diff --git a/lib/src/views/settings/backup/twonly_safe_backup.view.dart b/lib/src/views/settings/backup/twonly_safe_backup.view.dart index 795d661..7d7915f 100644 --- a/lib/src/views/settings/backup/twonly_safe_backup.view.dart +++ b/lib/src/views/settings/backup/twonly_safe_backup.view.dart @@ -66,8 +66,8 @@ class _TwonlyIdentityBackupViewState extends State { title: const Text('twonly Safe'), actions: [ IconButton( - onPressed: () { - showAlertDialog( + onPressed: () async { + await showAlertDialog( context, 'twonly Safe', context.lang.backupTwonlySafeLongDesc, @@ -75,7 +75,7 @@ class _TwonlyIdentityBackupViewState extends State { }, icon: const FaIcon(FontAwesomeIcons.circleInfo), iconSize: 18, - ) + ), ], ), body: Padding( @@ -119,7 +119,7 @@ class _TwonlyIdentityBackupViewState extends State { size: 16, ), ), - ) + ), ], ), Padding( @@ -127,11 +127,12 @@ class _TwonlyIdentityBackupViewState extends State { child: Text( context.lang.backupPasswordRequirement, style: TextStyle( - fontSize: 13, - color: (passwordCtrl.text.length < 8 && - passwordCtrl.text.isNotEmpty) - ? Colors.red - : Colors.transparent), + fontSize: 13, + color: (passwordCtrl.text.length < 8 && + passwordCtrl.text.isNotEmpty) + ? Colors.red + : Colors.transparent, + ), ), ), const SizedBox(height: 5), @@ -152,42 +153,49 @@ class _TwonlyIdentityBackupViewState extends State { child: Text( context.lang.passwordRepeatedNotEqual, style: TextStyle( - fontSize: 13, - color: (passwordCtrl.text != repeatedPasswordCtrl.text && - repeatedPasswordCtrl.text.isNotEmpty) - ? Colors.red - : Colors.transparent), + fontSize: 13, + color: (passwordCtrl.text != repeatedPasswordCtrl.text && + repeatedPasswordCtrl.text.isNotEmpty) + ? Colors.red + : Colors.transparent, + ), ), ), const SizedBox(height: 10), Center( child: OutlinedButton( - onPressed: () { - Navigator.push(context, MaterialPageRoute(builder: (context) { - return const TwonlySafeServerView(); - })); + onPressed: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const TwonlySafeServerView(); + }, + ), + ); }, child: Text(context.lang.backupExpertSettings), ), ), const SizedBox(height: 10), Center( - child: FilledButton.icon( - onPressed: (!isLoading && - (passwordCtrl.text == repeatedPasswordCtrl.text && - passwordCtrl.text.length >= 8 || - kDebugMode)) - ? onPressedEnableTwonlySafe - : null, - icon: isLoading - ? const SizedBox( - height: 12, - width: 12, - child: CircularProgressIndicator(strokeWidth: 1), - ) - : const Icon(Icons.lock_clock_rounded), - label: Text(context.lang.backupEnableBackup), - )) + child: FilledButton.icon( + onPressed: (!isLoading && + (passwordCtrl.text == repeatedPasswordCtrl.text && + passwordCtrl.text.length >= 8 || + kDebugMode)) + ? onPressedEnableTwonlySafe + : null, + icon: isLoading + ? const SizedBox( + height: 12, + width: 12, + child: CircularProgressIndicator(strokeWidth: 1), + ) + : const Icon(Icons.lock_clock_rounded), + label: Text(context.lang.backupEnableBackup), + ), + ), ], ), ), diff --git a/lib/src/views/settings/backup/twonly_safe_server.view.dart b/lib/src/views/settings/backup/twonly_safe_server.view.dart index e2e3aa2..9318eae 100644 --- a/lib/src/views/settings/backup/twonly_safe_server.view.dart +++ b/lib/src/views/settings/backup/twonly_safe_server.view.dart @@ -22,10 +22,10 @@ class _TwonlySafeServerViewState extends State { final TextEditingController _passwordController = TextEditingController(); @override - void initState() { + Future initState() async { _urlController.text = 'https://'; super.initState(); - initAsync(); + await initAsync(); } Future initAsync() async { @@ -86,7 +86,8 @@ class _TwonlySafeServerViewState extends State { } else { // If the server did not return a 200 OK response, throw an exception. throw Exception( - 'Got invalid status code ${response.statusCode} from server.'); + 'Got invalid status code ${response.statusCode} from server.', + ); } } catch (e) { Log.error('$e'); @@ -172,7 +173,7 @@ class _TwonlySafeServerViewState extends State { }, child: Text(context.lang.backupResetServer), ), - ) + ), ], ), ), diff --git a/lib/src/views/settings/chat/chat_reactions.view.dart b/lib/src/views/settings/chat/chat_reactions.view.dart index ce1acf1..bd53127 100644 --- a/lib/src/views/settings/chat/chat_reactions.view.dart +++ b/lib/src/views/settings/chat/chat_reactions.view.dart @@ -15,9 +15,9 @@ class _ChatReactionSelectionView extends State { List selectedEmojis = []; @override - void initState() { + Future initState() async { super.initState(); - initAsync(); + await initAsync(); } Future initAsync() async { @@ -66,8 +66,8 @@ class _ChatReactionSelectionView extends State { itemBuilder: (context, index) { final emoji = EmojiAnimation.animatedIcons.keys.elementAt(index); return GestureDetector( - onTap: () { - _onEmojiSelected(emoji); + onTap: () async { + await _onEmojiSelected(emoji); }, child: Card( color: selectedEmojis.contains(emoji) diff --git a/lib/src/views/settings/chat/chat_settings.view.dart b/lib/src/views/settings/chat/chat_settings.view.dart index f37b2ed..1a20c27 100644 --- a/lib/src/views/settings/chat/chat_settings.view.dart +++ b/lib/src/views/settings/chat/chat_settings.view.dart @@ -26,10 +26,14 @@ class _ChatSettingsViewState extends State { ListTile( title: Text(context.lang.settingsPreSelectedReactions), onTap: () async { - await Navigator.push(context, - MaterialPageRoute(builder: (context) { - return const ChatReactionSelectionView(); - })); + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const ChatReactionSelectionView(); + }, + ), + ); }, ), ], diff --git a/lib/src/views/settings/data_and_storage.view.dart b/lib/src/views/settings/data_and_storage.view.dart index 559c50b..440e8b1 100644 --- a/lib/src/views/settings/data_and_storage.view.dart +++ b/lib/src/views/settings/data_and_storage.view.dart @@ -16,9 +16,9 @@ class _DataAndStorageViewState extends State { bool storeMediaFilesInGallery = true; @override - void initState() { + Future initState() async { super.initState(); - initAsync(); + await initAsync(); } Future initAsync() async { @@ -32,7 +32,9 @@ class _DataAndStorageViewState extends State { } Future showAutoDownloadOptions( - BuildContext context, ConnectivityResult connectionMode) async { + BuildContext context, + ConnectivityResult connectionMode, + ) async { // ignore: inference_failure_on_function_invocation await showDialog( context: context, @@ -86,8 +88,8 @@ class _DataAndStorageViewState extends State { autoDownloadOptions[ConnectivityResult.mobile.name]!.join(', '), style: const TextStyle(color: Colors.grey), ), - onTap: () { - showAutoDownloadOptions(context, ConnectivityResult.mobile); + onTap: () async { + await showAutoDownloadOptions(context, ConnectivityResult.mobile); }, ), ListTile( @@ -96,8 +98,8 @@ class _DataAndStorageViewState extends State { autoDownloadOptions[ConnectivityResult.wifi.name]!.join(', '), style: const TextStyle(color: Colors.grey), ), - onTap: () { - showAutoDownloadOptions(context, ConnectivityResult.wifi); + onTap: () async { + await showAutoDownloadOptions(context, ConnectivityResult.wifi); }, ), ], @@ -168,7 +170,9 @@ class _AutoDownloadOptionsDialogState extends State { } Future _updateAutoDownloadSetting( - DownloadMediaTypes type, bool? value) async { + DownloadMediaTypes type, + bool? value, + ) async { if (value == null) return; // Update the autoDownloadOptions based on the checkbox state diff --git a/lib/src/views/settings/help/changelog.view.dart b/lib/src/views/settings/help/changelog.view.dart index 68f8d5b..e68e48a 100644 --- a/lib/src/views/settings/help/changelog.view.dart +++ b/lib/src/views/settings/help/changelog.view.dart @@ -22,32 +22,36 @@ List parseMarkdown(BuildContext context, String markdown) { // ), // )); } else if (line.startsWith('## ')) { - widgets.add(Padding( - padding: const EdgeInsets.only(top: 20, bottom: 10), - child: Text( - line.substring(3), // Remove the '## ' part - textAlign: TextAlign.center, - style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + widgets.add( + Padding( + padding: const EdgeInsets.only(top: 20, bottom: 10), + child: Text( + line.substring(3), // Remove the '## ' part + textAlign: TextAlign.center, + style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), ), - )); + ); } // Check for bullet points else if (line.startsWith('- ')) { - widgets.add(Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(top: 7), - child: Icon( - Icons.brightness_1, - size: 7, - color: context.color.onSurface, - ), - ), // Bullet point icon - const SizedBox(width: 8), // Space between bullet and text - Expanded(child: Text(line.substring(2))), // Remove the '- ' part - ], - )); + widgets.add( + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(top: 7), + child: Icon( + Icons.brightness_1, + size: 7, + color: context.color.onSurface, + ), + ), // Bullet point icon + const SizedBox(width: 8), // Space between bullet and text + Expanded(child: Text(line.substring(2))), // Remove the '- ' part + ], + ), + ); } else { widgets.add(Text(line)); } @@ -70,12 +74,12 @@ class _ChangeLogViewState extends State { bool hideChangeLog = false; @override - void initState() { + Future initState() async { super.initState(); if (widget.changeLog != null) { changeLog = widget.changeLog!; } else { - initAsync(); + await initAsync(); } } diff --git a/lib/src/views/settings/help/contact_us.view.dart b/lib/src/views/settings/help/contact_us.view.dart index 2ab0474..6d30400 100644 --- a/lib/src/views/settings/help/contact_us.view.dart +++ b/lib/src/views/settings/help/contact_us.view.dart @@ -65,11 +65,13 @@ class _ContactUsState extends State { ); requestMultipart.headers['x-twonly-auth-token'] = apiAuthToken; - requestMultipart.files.add(http.MultipartFile.fromBytes( - 'file', - uploadRequestBytes, - filename: 'upload', - )); + requestMultipart.files.add( + http.MultipartFile.fromBytes( + 'file', + uploadRequestBytes, + filename: 'upload', + ), + ); final response = await requestMultipart.send(); if (response.statusCode == 200) { @@ -228,8 +230,8 @@ $debugLogToken mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ GestureDetector( - onTap: () { - launchUrl(Uri.parse('https://twonly.eu/en/faq/')); + onTap: () async { + await launchUrl(Uri.parse('https://twonly.eu/en/faq/')); }, child: Text( context.lang.contactUsFaq, @@ -245,12 +247,16 @@ $debugLogToken final fullMessage = await _getFeedbackText(); if (!context.mounted) return; - final feedbackSend = await Navigator.push(context, - MaterialPageRoute(builder: (context) { - return SubmitMessage( - fullMessage: fullMessage, - ); - })); + final feedbackSend = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return SubmitMessage( + fullMessage: fullMessage, + ); + }, + ), + ); if (feedbackSend == true && context.mounted) { Navigator.pop(context); diff --git a/lib/src/views/settings/help/credits.view.dart b/lib/src/views/settings/help/credits.view.dart index 49c1a1e..e214ed4 100644 --- a/lib/src/views/settings/help/credits.view.dart +++ b/lib/src/views/settings/help/credits.view.dart @@ -24,8 +24,8 @@ class UrlListTitle extends StatelessWidget { leading: leading, title: (title != null) ? Text(title!) : null, subtitle: subtitle == null ? null : Text(subtitle!), - onTap: () { - launchUrl(Uri.parse(url)); + onTap: () async { + await launchUrl(Uri.parse(url)); }, trailing: const FaIcon(FontAwesomeIcons.arrowUpRightFromSquare, size: 15), ); @@ -43,9 +43,9 @@ class _CreditsViewState extends State { List sticker = []; @override - void initState() { + Future initState() async { super.initState(); - initAsync(); + await initAsync(); } Future initAsync() async { @@ -83,10 +83,11 @@ class _CreditsViewState extends State { const Divider(), const ListTile( title: Center( - child: Text( - 'Animations', - style: TextStyle(fontWeight: FontWeight.bold), - )), + child: Text( + 'Animations', + style: TextStyle(fontWeight: FontWeight.bold), + ), + ), ), const UrlListTitle( title: 'selfie fast Animation', @@ -144,10 +145,11 @@ class _CreditsViewState extends State { if (sticker.isNotEmpty) const ListTile( title: Center( - child: Text( - 'Filters', - style: TextStyle(fontWeight: FontWeight.bold), - )), + child: Text( + 'Filters', + style: TextStyle(fontWeight: FontWeight.bold), + ), + ), ), ...sticker.map( (x) => UrlListTitle( @@ -155,7 +157,8 @@ class _CreditsViewState extends State { height: 50, width: 50, child: CachedNetworkImage( - imageUrl: 'https://twonly.eu/${x.imageSrc}'), + imageUrl: 'https://twonly.eu/${x.imageSrc}', + ), ), title: '', url: x.source, diff --git a/lib/src/views/settings/help/diagnostics.view.dart b/lib/src/views/settings/help/diagnostics.view.dart index 67c8317..7f27dd8 100644 --- a/lib/src/views/settings/help/diagnostics.view.dart +++ b/lib/src/views/settings/help/diagnostics.view.dart @@ -14,9 +14,9 @@ class DiagnosticsView extends StatefulWidget { class _DiagnosticsViewState extends State { final ScrollController _scrollController = ScrollController(); - void _scrollToBottom() { + Future _scrollToBottom() async { // Assuming the button is at the bottom of the scroll view - _scrollController.animateTo( + await _scrollController.animateTo( _scrollController.position.maxScrollExtent, // Scroll to the bottom duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, @@ -66,11 +66,13 @@ class _DiagnosticsViewState extends State { if (result.status != ShareResultStatus.success) { await Clipboard.setData( - ClipboardData(text: logText)); + ClipboardData(text: logText), + ); if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( - content: Text('Log copied to clipboard!')), + content: Text('Log copied to clipboard!'), + ), ); } } @@ -87,13 +89,15 @@ class _DiagnosticsViewState extends State { if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( const SnackBar( - content: Text('Log file deleted!')), + content: Text('Log file deleted!'), + ), ); } else { if (!context.mounted) return; ScaffoldMessenger.of(context).showSnackBar( const SnackBar( - content: Text('Log file does not exist.')), + content: Text('Log file does not exist.'), + ), ); } }, diff --git a/lib/src/views/settings/help/faq.view.dart b/lib/src/views/settings/help/faq.view.dart index 299eeca..753cf8a 100644 --- a/lib/src/views/settings/help/faq.view.dart +++ b/lib/src/views/settings/help/faq.view.dart @@ -21,10 +21,10 @@ class _FaqViewState extends State { bool noInternet = false; @override - void initState() { + Future initState() async { super.initState(); domain = 'https://twonly.eu'; - _fetchFAQData(); + await _fetchFAQData(); } Future _fetchFAQData() async { diff --git a/lib/src/views/settings/help/help.view.dart b/lib/src/views/settings/help/help.view.dart index 9c8476e..1a8f4b6 100644 --- a/lib/src/views/settings/help/help.view.dart +++ b/lib/src/views/settings/help/help.view.dart @@ -24,18 +24,28 @@ class HelpView extends StatelessWidget { children: [ ListTile( title: Text(context.lang.settingsHelpFAQ), - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (context) { - return const FaqView(); - })); + onTap: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const FaqView(); + }, + ), + ); }, ), ListTile( title: Text(context.lang.settingsHelpContactUs), - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (context) { - return const ContactUsView(); - })); + onTap: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const ContactUsView(); + }, + ), + ); }, ), ListTile( @@ -77,50 +87,65 @@ class HelpView extends StatelessWidget { ), ListTile( title: Text(context.lang.settingsHelpCredits), - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (context) { - return const CreditsView(); - })); + onTap: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const CreditsView(); + }, + ), + ); }, ), ListTile( title: Text(context.lang.settingsHelpDiagnostics), onTap: () async { - await Navigator.push(context, - MaterialPageRoute(builder: (context) { - return const DiagnosticsView(); - })); + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const DiagnosticsView(); + }, + ), + ); }, ), ListTile( title: const Text('Changelog'), onTap: () async { - await Navigator.push(context, - MaterialPageRoute(builder: (context) { - return const ChangeLogView(); - })); + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const ChangeLogView(); + }, + ), + ); }, ), ListTile( title: const Text('Open Source'), - onTap: () { - launchUrl(Uri.parse('https://github.com/twonlyapp/twonly-app')); + onTap: () async { + await launchUrl( + Uri.parse('https://github.com/twonlyapp/twonly-app'), + ); }, trailing: const FaIcon(FontAwesomeIcons.arrowUpRightFromSquare, size: 15), ), ListTile( title: Text(context.lang.settingsHelpImprint), - onTap: () { - launchUrl(Uri.parse('https://twonly.eu/de/legal/')); + onTap: () async { + await launchUrl(Uri.parse('https://twonly.eu/de/legal/')); }, trailing: const FaIcon(FontAwesomeIcons.arrowUpRightFromSquare, size: 15), ), ListTile( title: Text(context.lang.settingsHelpTerms), - onTap: () { - launchUrl(Uri.parse('https://twonly.eu/de/legal/agb.html')); + onTap: () async { + await launchUrl(Uri.parse('https://twonly.eu/de/legal/agb.html')); }, trailing: const FaIcon(FontAwesomeIcons.arrowUpRightFromSquare, size: 15), @@ -132,7 +157,7 @@ class HelpView extends StatelessWidget { 'Delete Retransmission messages', 'Only do this if you know what you are doing :)', ); - if (okay == true) { + if (okay) { await twonlyDB.messageRetransmissionDao .clearRetransmissionTable(); } diff --git a/lib/src/views/settings/notification.view.dart b/lib/src/views/settings/notification.view.dart index a4518a6..db9be48 100644 --- a/lib/src/views/settings/notification.view.dart +++ b/lib/src/views/settings/notification.view.dart @@ -44,9 +44,10 @@ class NotificationView extends StatelessWidget { ); } else { final run = await showAlertDialog( - context, - context.lang.settingsNotifyTroubleshootingNoProblem, - context.lang.settingsNotifyTroubleshootingNoProblemDesc); + context, + context.lang.settingsNotifyTroubleshootingNoProblem, + context.lang.settingsNotifyTroubleshootingNoProblemDesc, + ); if (run) { final user = await getUser(); diff --git a/lib/src/views/settings/privacy.view.dart b/lib/src/views/settings/privacy.view.dart index 0611bfa..c3c50c3 100644 --- a/lib/src/views/settings/privacy.view.dart +++ b/lib/src/views/settings/privacy.view.dart @@ -41,10 +41,14 @@ class _PrivacyViewState extends State { }, ), onTap: () async { - await Navigator.push(context, - MaterialPageRoute(builder: (context) { - return const PrivacyViewBlockUsers(); - })); + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const PrivacyViewBlockUsers(); + }, + ), + ); }, ), ], diff --git a/lib/src/views/settings/privacy_view_block.users.dart b/lib/src/views/settings/privacy_view_block.users.dart index b98ffa0..2acce07 100644 --- a/lib/src/views/settings/privacy_view_block.users.dart +++ b/lib/src/views/settings/privacy_view_block.users.dart @@ -21,10 +21,10 @@ class _PrivacyViewBlockUsers extends State { String filter = ''; @override - void initState() { + Future initState() async { super.initState(); allUsers = twonlyDB.contactsDao.watchAllContacts(); - loadAsync(); + await loadAsync(); } Future loadAsync() async { @@ -81,7 +81,7 @@ class _PrivacyViewBlockUsers extends State { ); }, ), - ) + ), ], ), ), @@ -105,7 +105,8 @@ class UserList extends StatelessWidget { Widget build(BuildContext context) { // Step 1: Sort the users alphabetically users.sort( - (a, b) => getContactDisplayName(a).compareTo(getContactDisplayName(b))); + (a, b) => getContactDisplayName(a).compareTo(getContactDisplayName(b)), + ); return ListView.builder( restorationId: 'new_message_users_list', @@ -115,18 +116,20 @@ class UserList extends StatelessWidget { return UserContextMenuBlocked( contact: user, child: ListTile( - title: Row(children: [ - Text(getContactDisplayName(user)), - ]), + title: Row( + children: [ + Text(getContactDisplayName(user)), + ], + ), leading: ContactAvatar(contact: user, fontSize: 15), trailing: Checkbox( value: user.blocked, - onChanged: (bool? value) { - block(context, user.userId, value); + onChanged: (bool? value) async { + await block(context, user.userId, value); }, ), - onTap: () { - block(context, user.userId, !user.blocked); + onTap: () async { + await block(context, user.userId, !user.blocked); }, ), ); diff --git a/lib/src/views/settings/profile/modify_avatar.view.dart b/lib/src/views/settings/profile/modify_avatar.view.dart index acb08f2..0a489da 100644 --- a/lib/src/views/settings/profile/modify_avatar.view.dart +++ b/lib/src/views/settings/profile/modify_avatar.view.dart @@ -119,9 +119,10 @@ class _ModifyAvatarState extends State { ), IconButton( icon: const Icon(FontAwesomeIcons.rotateLeft), - onLongPress: () { - PersistentAvatarMakerController.clearAvatarMaker(); - _avatarMakerController.restoreState(); + onLongPress: () async { + await PersistentAvatarMakerController + .clearAvatarMaker(); + await _avatarMakerController.restoreState(); }, onPressed: _avatarMakerController.restoreState, ), diff --git a/lib/src/views/settings/profile/profile.view.dart b/lib/src/views/settings/profile/profile.view.dart index 3e83c43..5abd278 100644 --- a/lib/src/views/settings/profile/profile.view.dart +++ b/lib/src/views/settings/profile/profile.view.dart @@ -21,9 +21,9 @@ class _ProfileViewState extends State { PersistentAvatarMakerController(customizedPropertyCategories: []); @override - void initState() { + Future initState() async { super.initState(); - initAsync(); + await initAsync(); } Future initAsync() async { @@ -63,18 +63,19 @@ class _ProfileViewState extends State { child: SizedBox( height: 35, child: ElevatedButton.icon( - icon: const Icon(Icons.edit), - label: Text(context.lang.settingsProfileCustomizeAvatar), - onPressed: () async { - await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const ModifyAvatar(), - ), - ); - await _avatarMakerController.performRestore(); - setState(() {}); - }), + icon: const Icon(Icons.edit), + label: Text(context.lang.settingsProfileCustomizeAvatar), + onPressed: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const ModifyAvatar(), + ), + ); + await _avatarMakerController.performRestore(); + setState(() {}); + }, + ), ), ), const SizedBox(height: 20), @@ -98,7 +99,9 @@ class _ProfileViewState extends State { } Future showDisplayNameChangeDialog( - BuildContext context, String currentName) { + BuildContext context, + String currentName, +) { final controller = TextEditingController(text: currentName); return showDialog( @@ -110,7 +113,8 @@ Future showDisplayNameChangeDialog( controller: controller, autofocus: true, decoration: InputDecoration( - hintText: context.lang.settingsProfileEditDisplayNameNew), + hintText: context.lang.settingsProfileEditDisplayNameNew, + ), ), actions: [ TextButton( diff --git a/lib/src/views/settings/settings_main.view.dart b/lib/src/views/settings/settings_main.view.dart index 0d22132..e67246c 100644 --- a/lib/src/views/settings/settings_main.view.dart +++ b/lib/src/views/settings/settings_main.view.dart @@ -28,9 +28,9 @@ class _SettingsMainViewState extends State { UserData? userData; @override - void initState() { + Future initState() async { super.initState(); - initAsync(); + await initAsync(); } Future initAsync() async { @@ -55,11 +55,14 @@ class _SettingsMainViewState extends State { Expanded( child: GestureDetector( onTap: () async { - await Navigator.push(context, MaterialPageRoute( - builder: (context) { - return const ProfileView(); - }, - )); + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const ProfileView(); + }, + ), + ); await initAsync(); }, child: ColoredBox( @@ -106,114 +109,144 @@ class _SettingsMainViewState extends State { BetterListTile( icon: FontAwesomeIcons.user, text: context.lang.settingsAccount, - onTap: () { - Navigator.push(context, MaterialPageRoute( - builder: (context) { - return const AccountView(); - }, - )); + onTap: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const AccountView(); + }, + ), + ); }, ), BetterListTile( icon: FontAwesomeIcons.shieldHeart, text: context.lang.settingsSubscription, - onTap: () { - Navigator.push(context, MaterialPageRoute( - builder: (context) { - return const SubscriptionView(); - }, - )); + onTap: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const SubscriptionView(); + }, + ), + ); }, ), BetterListTile( icon: Icons.lock_clock_rounded, text: context.lang.settingsBackup, - onTap: () { - Navigator.push(context, MaterialPageRoute( - builder: (context) { - return const BackupView(); - }, - )); + onTap: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const BackupView(); + }, + ), + ); }, ), const Divider(), BetterListTile( icon: FontAwesomeIcons.sun, text: context.lang.settingsAppearance, - onTap: () { - Navigator.push(context, MaterialPageRoute( - builder: (context) { - return const AppearanceView(); - }, - )); + onTap: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const AppearanceView(); + }, + ), + ); }, ), BetterListTile( icon: FontAwesomeIcons.comment, text: context.lang.settingsChats, - onTap: () { - Navigator.push(context, MaterialPageRoute( - builder: (context) { - return const ChatSettingsView(); - }, - )); + onTap: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const ChatSettingsView(); + }, + ), + ); }, ), BetterListTile( icon: FontAwesomeIcons.lock, text: context.lang.settingsPrivacy, - onTap: () { - Navigator.push(context, MaterialPageRoute( - builder: (context) { - return const PrivacyView(); - }, - )); + onTap: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const PrivacyView(); + }, + ), + ); }, ), BetterListTile( icon: FontAwesomeIcons.bell, text: context.lang.settingsNotification, - onTap: () { - Navigator.push(context, MaterialPageRoute( - builder: (context) { - return const NotificationView(); - }, - )); + onTap: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const NotificationView(); + }, + ), + ); }, ), BetterListTile( icon: FontAwesomeIcons.chartPie, iconSize: 15, text: context.lang.settingsStorageData, - onTap: () { - Navigator.push(context, MaterialPageRoute( - builder: (context) { - return const DataAndStorageView(); - }, - )); + onTap: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const DataAndStorageView(); + }, + ), + ); }, ), const Divider(), BetterListTile( icon: FontAwesomeIcons.circleQuestion, text: context.lang.settingsHelp, - onTap: () { - Navigator.push(context, MaterialPageRoute( - builder: (context) { - return const HelpView(); - }, - )); + onTap: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const HelpView(); + }, + ), + ); }, ), BetterListTile( icon: FontAwesomeIcons.shareFromSquare, text: context.lang.inviteFriends, - onTap: () { - Navigator.push(context, MaterialPageRoute( - builder: (context) { - return const ShareWithFriendsView(); - }, - )); + onTap: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const ShareWithFriendsView(); + }, + ), + ); }, ), ], diff --git a/lib/src/views/settings/subscription/additional_users.view.dart b/lib/src/views/settings/subscription/additional_users.view.dart index b382dd4..5b4c4d6 100644 --- a/lib/src/views/settings/subscription/additional_users.view.dart +++ b/lib/src/views/settings/subscription/additional_users.view.dart @@ -48,10 +48,10 @@ class _AdditionalUsersViewState extends State { Response_PlanBallance? ballance; @override - void initState() { + Future initState() async { super.initState(); ballance = widget.ballance; - initAsync(force: false); + await initAsync(force: false); } Future initAsync({required bool force}) async { @@ -86,12 +86,14 @@ class _AdditionalUsersViewState extends State { ), ), if (ballance != null) - ...ballance!.additionalAccounts.map((e) => AdditionalAccount( - account: e, - refresh: () { - initAsync(force: true); - }, - )), + ...ballance!.additionalAccounts.map( + (e) => AdditionalAccount( + account: e, + refresh: () async { + await initAsync(force: true); + }, + ), + ), if (plusInvites.isNotEmpty) ListTile( title: Text( @@ -149,10 +151,10 @@ class _AdditionalAccountState extends State { late String username; @override - void initState() { + Future initState() async { super.initState(); username = widget.account.userId.toString(); - initAsync(); + await initAsync(); } Future initAsync() async { @@ -181,7 +183,9 @@ class _AdditionalAccountState extends State { Text( username, style: const TextStyle( - fontSize: 20, fontWeight: FontWeight.bold), + fontSize: 20, + fontWeight: FontWeight.bold, + ), ), const SizedBox(height: 4), Text( @@ -194,9 +198,10 @@ class _AdditionalAccountState extends State { icon: const FaIcon(FontAwesomeIcons.userXmark, size: 16), onPressed: () async { final remove = await showAlertDialog( - context, - 'Remove this additional user', - 'The additional user will automatically be downgraded to the preview plan after removal and you will receive a new invitation code to give to another person.'); + context, + 'Remove this additional user', + 'The additional user will automatically be downgraded to the preview plan after removal and you will receive a new invitation code to give to another person.', + ); if (remove) { final res = await apiService .removeAdditionalUser(widget.account.userId); @@ -206,10 +211,13 @@ class _AdditionalAccountState extends State { } else { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text(errorCodeToText( - context, - res.error as ErrorCode, - ))), + content: Text( + errorCodeToText( + context, + res.error as ErrorCode, + ), + ), + ), ); } } @@ -230,9 +238,10 @@ class AdditionalUserInvite extends StatefulWidget { } class _AdditionalUserInviteState extends State { - void _copyVoucherId() { - Clipboard.setData(ClipboardData(text: widget.invite.inviteCode)); - HapticFeedback.heavyImpact(); + Future _copyVoucherId() async { + await Clipboard.setData(ClipboardData(text: widget.invite.inviteCode)); + await HapticFeedback.heavyImpact(); + if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('${widget.invite.inviteCode} copied.')), ); diff --git a/lib/src/views/settings/subscription/checkout.view.dart b/lib/src/views/settings/subscription/checkout.view.dart index ea70f93..174c2d2 100644 --- a/lib/src/views/settings/subscription/checkout.view.dart +++ b/lib/src/views/settings/subscription/checkout.view.dart @@ -123,22 +123,27 @@ class _CheckoutViewState extends State { Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: FilledButton( - onPressed: () async { - final success = await Navigator.push(context, - MaterialPageRoute(builder: (context) { - return SelectPaymentView( - planId: widget.planId, - payMonthly: paidMonthly, - refund: widget.refund, - ); - })) as bool?; - if (success != null && success && context.mounted) { - Navigator.pop(context); - } - }, - child: Text(context.lang.selectPaymentMethod)), + onPressed: () async { + final success = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return SelectPaymentView( + planId: widget.planId, + payMonthly: paidMonthly, + refund: widget.refund, + ); + }, + ), + ) as bool?; + if (success != null && success && context.mounted) { + Navigator.pop(context); + } + }, + child: Text(context.lang.selectPaymentMethod), + ), ), - const SizedBox(height: 20) + const SizedBox(height: 20), ], ), ), diff --git a/lib/src/views/settings/subscription/manage_subscription.view.dart b/lib/src/views/settings/subscription/manage_subscription.view.dart index 3e2a0db..144846c 100644 --- a/lib/src/views/settings/subscription/manage_subscription.view.dart +++ b/lib/src/views/settings/subscription/manage_subscription.view.dart @@ -27,13 +27,13 @@ class _ManageSubscriptionViewState extends State { bool? autoRenewal; @override - void initState() { + Future initState() async { super.initState(); ballance = widget.ballance; if (ballance != null) { autoRenewal = ballance!.autoRenewal; } - initAsync(true); + await initAsync(true); } Future initAsync(bool force) async { @@ -52,7 +52,8 @@ class _ManageSubscriptionViewState extends State { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text(errorCodeToText(context, res.error as ErrorCode))), + content: Text(errorCodeToText(context, res.error as ErrorCode)), + ), ); } } @@ -89,8 +90,8 @@ class _ManageSubscriptionViewState extends State { onTap: toggleRenewalOption, trailing: Switch( value: autoRenewal!, - onChanged: (a) { - toggleRenewalOption(); + onChanged: (a) async { + await toggleRenewalOption(); }, ), ), diff --git a/lib/src/views/settings/subscription/select_payment.view.dart b/lib/src/views/settings/subscription/select_payment.view.dart index 834447a..443cc42 100644 --- a/lib/src/views/settings/subscription/select_payment.view.dart +++ b/lib/src/views/settings/subscription/select_payment.view.dart @@ -40,10 +40,10 @@ class _SelectPaymentViewState extends State { PaymentMethods paymentMethods = PaymentMethods.twonlyCredit; @override - void initState() { + Future initState() async { super.initState(); setCheckout(true); - initAsync(); + await initAsync(); } Future initAsync() async { @@ -121,7 +121,7 @@ class _SelectPaymentViewState extends State { Text( '${context.lang.currentBalance}: ${localePrizing(context, balanceInCents!)}', style: const TextStyle(fontSize: 10), - ) + ), ], ), Checkbox( @@ -154,10 +154,14 @@ class _SelectPaymentViewState extends State { padding: const EdgeInsets.symmetric(horizontal: 16), child: FilledButton( onPressed: () async { - await Navigator.push(context, - MaterialPageRoute(builder: (context) { - return const VoucherView(); - })); + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const VoucherView(); + }, + ), + ); await initAsync(); }, child: Text(context.lang.chargeCredit), @@ -233,7 +237,10 @@ class _SelectPaymentViewState extends State { onPressed: canPay ? () async { final res = await apiService.switchToPayedPlan( - widget.planId!, widget.payMonthly!, tryAutoRenewal); + widget.planId!, + widget.payMonthly!, + tryAutoRenewal, + ); if (!context.mounted) return; if (res.isSuccess) { await updateUsersPlan(context, widget.planId!); @@ -247,9 +254,13 @@ class _SelectPaymentViewState extends State { } else { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text( - errorCodeToText(context, res.error as ErrorCode), - )), + content: Text( + errorCodeToText( + context, + res.error as ErrorCode, + ), + ), + ), ); } } @@ -261,8 +272,11 @@ class _SelectPaymentViewState extends State { mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ TextButton( - onPressed: () => launchUrl(Uri.parse( - 'https://twonly.eu/de/legal/#revocation-policy')), + onPressed: () => launchUrl( + Uri.parse( + 'https://twonly.eu/de/legal/#revocation-policy', + ), + ), child: const Text( 'Widerrufsbelehrung', style: TextStyle(color: Colors.blue), @@ -270,15 +284,16 @@ class _SelectPaymentViewState extends State { ), TextButton( onPressed: () => launchUrl( - Uri.parse('https://twonly.eu/de/legal/agb.html')), + Uri.parse('https://twonly.eu/de/legal/agb.html'), + ), child: const Text( 'ABG', style: TextStyle(color: Colors.blue), ), - ) + ), ], ), - const SizedBox(height: 20) + const SizedBox(height: 20), ], ), ), diff --git a/lib/src/views/settings/subscription/subscription.view.dart b/lib/src/views/settings/subscription/subscription.view.dart index 25f967c..f829aad 100644 --- a/lib/src/views/settings/subscription/subscription.view.dart +++ b/lib/src/views/settings/subscription/subscription.view.dart @@ -66,8 +66,11 @@ int calculateRefund(Response_PlanBallance current) { if (current.paymentPeriodDays == YEARLY_PAYMENT_DAYS) { final elapsedDays = DateTime.now() - .difference(DateTime.fromMillisecondsSinceEpoch( - current.lastPaymentDoneUnixTimestamp.toInt() * 1000)) + .difference( + DateTime.fromMillisecondsSinceEpoch( + current.lastPaymentDoneUnixTimestamp.toInt() * 1000, + ), + ) .inDays; if (elapsedDays < current.paymentPeriodDays.toInt()) { // User has yearly plan with 10€ @@ -83,8 +86,11 @@ int calculateRefund(Response_PlanBallance current) { } } else { final elapsedDays = DateTime.now() - .difference(DateTime.fromMillisecondsSinceEpoch( - current.lastPaymentDoneUnixTimestamp.toInt() * 1000)) + .difference( + DateTime.fromMillisecondsSinceEpoch( + current.lastPaymentDoneUnixTimestamp.toInt() * 1000, + ), + ) .inDays; if (elapsedDays > 14) { refund = 0; @@ -109,9 +115,9 @@ class _SubscriptionViewState extends State { String? additionalOwnerName; @override - void initState() { + Future initState() async { super.initState(); - initAsync(); + await initAsync(); } Future initAsync() async { @@ -140,7 +146,8 @@ class _SubscriptionViewState extends State { if (ballance != null) { final lastPaymentDateTime = DateTime.fromMillisecondsSinceEpoch( - ballance!.lastPaymentDoneUnixTimestamp.toInt() * 1000); + ballance!.lastPaymentDoneUnixTimestamp.toInt() * 1000, + ); if (isPayingUser) { nextPayment = lastPaymentDateTime .add(Duration(days: ballance!.paymentPeriodDays.toInt())); @@ -226,12 +233,16 @@ class _SubscriptionViewState extends State { PlanCard( planId: 'Pro', onTap: () async { - await Navigator.push(context, - MaterialPageRoute(builder: (context) { - return const CheckoutView( - planId: 'Pro', - ); - })); + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const CheckoutView( + planId: 'Pro', + ); + }, + ), + ); await initAsync(); }, ), @@ -240,16 +251,20 @@ class _SubscriptionViewState extends State { planId: 'Family', refund: refund, onTap: () async { - await Navigator.push(context, - MaterialPageRoute(builder: (context) { - return CheckoutView( - planId: 'Family', - refund: (refund > 0) ? refund : null, - disableMonthlyOption: currentPlan == 'Pro' && - ballance!.paymentPeriodDays.toInt() == - YEARLY_PAYMENT_DAYS, - ); - })); + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return CheckoutView( + planId: 'Family', + refund: (refund > 0) ? refund : null, + disableMonthlyOption: currentPlan == 'Pro' && + ballance!.paymentPeriodDays.toInt() == + YEARLY_PAYMENT_DAYS, + ); + }, + ), + ); await initAsync(); }, ), @@ -281,16 +296,21 @@ class _SubscriptionViewState extends State { text: context.lang.manageSubscription, subtitle: (nextPayment != null) ? Text( - '${context.lang.nextPayment}: ${DateFormat.yMMMMd(myLocale.toString()).format(nextPayment)}') + '${context.lang.nextPayment}: ${DateFormat.yMMMMd(myLocale.toString()).format(nextPayment)}', + ) : null, onTap: () async { - await Navigator.push(context, - MaterialPageRoute(builder: (context) { - return ManageSubscriptionView( - ballance: ballance, - nextPayment: nextPayment, - ); - })); + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return ManageSubscriptionView( + ballance: ballance, + nextPayment: nextPayment, + ); + }, + ), + ); await initAsync(); }, ), @@ -300,14 +320,19 @@ class _SubscriptionViewState extends State { subtitle: (formattedBalance != null) ? Text('${context.lang.currentBalance}: $formattedBalance') : null, - onTap: () { + onTap: () async { if (formattedBalance == null) return; - Navigator.push(context, MaterialPageRoute(builder: (context) { - return TransactionView( - transactions: ballance?.transactions, - formattedBalance: formattedBalance!, - ); - })); + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return TransactionView( + transactions: ballance?.transactions, + formattedBalance: formattedBalance!, + ); + }, + ), + ); }, ), if (isPayingUser || currentPlan == 'Tester') @@ -316,12 +341,16 @@ class _SubscriptionViewState extends State { text: context.lang.manageAdditionalUsers, subtitle: loaded ? Text('${context.lang.open}: 3') : null, onTap: () async { - await Navigator.push(context, - MaterialPageRoute(builder: (context) { - return AdditionalUsersView( - ballance: ballance, - ); - })); + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return AdditionalUsersView( + ballance: ballance, + ); + }, + ), + ); await initAsync(); }, ), @@ -329,14 +358,18 @@ class _SubscriptionViewState extends State { icon: FontAwesomeIcons.ticket, text: context.lang.createOrRedeemVoucher, onTap: () async { - await Navigator.push(context, - MaterialPageRoute(builder: (context) { - return const VoucherView(); - })); + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return const VoucherView(); + }, + ), + ); await initAsync(); }, ), - const SizedBox(height: 30) + const SizedBox(height: 30), ], ), ); @@ -488,7 +521,7 @@ class PlanCard extends StatelessWidget { ? Text(context.lang.redeemUserInviteCodeTitle) : Text(context.lang.upgradeToPaidPlanButton(planId)), ), - ) + ), ], ), ), @@ -553,8 +586,10 @@ Future redeemUserInviteCode(BuildContext context, String newPlan) async { } else { ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text( - errorCodeToText(context, res.error as ErrorCode))), + content: Text( + errorCodeToText(context, res.error as ErrorCode), + ), + ), ); } if (!context.mounted) return; diff --git a/lib/src/views/settings/subscription/transaction.view.dart b/lib/src/views/settings/subscription/transaction.view.dart index 87de74c..70a597b 100644 --- a/lib/src/views/settings/subscription/transaction.view.dart +++ b/lib/src/views/settings/subscription/transaction.view.dart @@ -46,7 +46,7 @@ class _TransactionViewState extends State { ), ), if (widget.transactions != null) - ...widget.transactions!.map((x) => TransactionCard(transaction: x)) + ...widget.transactions!.map((x) => TransactionCard(transaction: x)), ], ), ); @@ -94,7 +94,8 @@ class _TransactionCardState extends State { ).format(widget.transaction.depositCents.toInt() / 100); final timestamp = DateTime.fromMillisecondsSinceEpoch( - widget.transaction.createdAtUnixTimestamp.toInt() * 1000); + widget.transaction.createdAtUnixTimestamp.toInt() * 1000, + ); return Card( margin: const EdgeInsets.all(10), diff --git a/lib/src/views/settings/subscription/voucher.view.dart b/lib/src/views/settings/subscription/voucher.view.dart index 23cfbd1..d92f722 100644 --- a/lib/src/views/settings/subscription/voucher.view.dart +++ b/lib/src/views/settings/subscription/voucher.view.dart @@ -17,9 +17,9 @@ class _VoucherViewState extends State { List vouchers = []; @override - void initState() { + Future initState() async { super.initState(); - initAsync(); + await initAsync(); } Future initAsync() async { @@ -85,10 +85,11 @@ class VoucherCard extends StatefulWidget { } class _VoucherCardState extends State { - void _copyVoucherId() { + Future _copyVoucherId() async { if (!widget.voucher.redeemed) { - Clipboard.setData(ClipboardData(text: widget.voucher.voucherId)); - HapticFeedback.heavyImpact(); + await Clipboard.setData(ClipboardData(text: widget.voucher.voucherId)); + await HapticFeedback.heavyImpact(); + if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('${widget.voucher.voucherId} copied.')), ); diff --git a/lib/src/views/tutorial/show_tutorial.dart b/lib/src/views/tutorial/show_tutorial.dart index e727aa9..61f548e 100644 --- a/lib/src/views/tutorial/show_tutorial.dart +++ b/lib/src/views/tutorial/show_tutorial.dart @@ -49,7 +49,11 @@ Future checkIfTutorialAlreadyShown(String tutorialId) async { } TargetFocus getTargetFocus( - BuildContext context, GlobalKey key, String title, String body) { + BuildContext context, + GlobalKey key, + String title, + String body, +) { final renderBox = key.currentContext!.findRenderObject()! as RenderBox; final position = renderBox.localToGlobal(Offset.zero); final screenHeight = MediaQuery.of(context).size.height; @@ -73,7 +77,11 @@ TargetFocus getTargetFocus( TargetContent( align: ContentAlign.custom, customPosition: CustomTargetContentPosition( - left: 0, right: 0, top: top, bottom: bottom), + left: 0, + right: 0, + top: top, + bottom: bottom, + ), child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, @@ -97,10 +105,10 @@ TargetFocus getTargetFocus( fontSize: 16, ), ), - ) + ), ], ), - ) + ), ], ); } diff --git a/lib/src/views/tutorial/tutorials.dart b/lib/src/views/tutorial/tutorials.dart index 31f98fe..77af385 100644 --- a/lib/src/views/tutorial/tutorials.dart +++ b/lib/src/views/tutorial/tutorials.dart @@ -21,7 +21,7 @@ Future showChatListTutorialSearchOtherUsers( searchForOtherUsers, context.lang.tutorialChatListSearchUsersTitle, context.lang.tutorialChatListSearchUsersDesc, - ) + ), ]; await showTutorial(context, targets); }); @@ -42,7 +42,7 @@ Future showChatListTutorialContextMenu( firstUserListItemKey, context.lang.tutorialChatListContextMenuTitle, context.lang.tutorialChatListContextMenuDesc, - ) + ), ]; await showTutorial(context, targets); }); @@ -63,7 +63,7 @@ Future showVerifyShieldTutorial( firstUserListItemKey, context.lang.tutorialChatMessagesVerifyShieldTitle, context.lang.tutorialChatMessagesVerifyShieldDesc, - ) + ), ]; await showTutorial(context, targets); }); @@ -84,7 +84,7 @@ Future showReopenMediaFilesTutorial( firstUserListItemKey, context.lang.tutorialChatMessagesReopenMessageTitle, context.lang.tutorialChatMessagesReopenMessageDesc, - ) + ), ]; await showTutorial(context, targets); });