diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c7e8ca..b73fd9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,11 @@ ## 0.0.98 -- Fix: Issue with contact requests +- Fix: Problem during contact requests +- Fix: Problem with deleting a contact - Improve: Video compression with progress updates - Improve: Show message "Flames restored" +- Improve: Show toast message if user was added via QR ## 0.0.96 diff --git a/lib/src/localization/generated/app_localizations.dart b/lib/src/localization/generated/app_localizations.dart index 7234da8..baf00c7 100644 --- a/lib/src/localization/generated/app_localizations.dart +++ b/lib/src/localization/generated/app_localizations.dart @@ -685,7 +685,7 @@ abstract class AppLocalizations { /// No description provided for @settingsPrivacy. /// /// In en, this message translates to: - /// **'Privacy'** + /// **'Privacy & Security'** String get settingsPrivacy; /// No description provided for @settingsPrivacyBlockUsers. @@ -3039,6 +3039,18 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'{count} flames restored'** String chatEntryFlameRestored(Object count); + + /// No description provided for @requestedUserToastText. + /// + /// In en, this message translates to: + /// **'{username} was successfully requested.'** + String requestedUserToastText(Object username); + + /// No description provided for @profileYourQrCode. + /// + /// In en, this message translates to: + /// **'Your QR code'** + String get profileYourQrCode; } class _AppLocalizationsDelegate diff --git a/lib/src/localization/generated/app_localizations_de.dart b/lib/src/localization/generated/app_localizations_de.dart index 065ff9c..6770be7 100644 --- a/lib/src/localization/generated/app_localizations_de.dart +++ b/lib/src/localization/generated/app_localizations_de.dart @@ -326,7 +326,7 @@ class AppLocalizationsDe extends AppLocalizations { String get settingsAppearance => 'Erscheinungsbild'; @override - String get settingsPrivacy => 'Datenschutz'; + String get settingsPrivacy => 'Datenschutz & Sicherheit'; @override String get settingsPrivacyBlockUsers => 'Benutzer blockieren'; @@ -1700,4 +1700,12 @@ class AppLocalizationsDe extends AppLocalizations { String chatEntryFlameRestored(Object count) { return '$count Flammen wiederhergestellt'; } + + @override + String requestedUserToastText(Object username) { + return '$username wurde erfolgreich angefragt.'; + } + + @override + String get profileYourQrCode => 'Dein QR-Code'; } diff --git a/lib/src/localization/generated/app_localizations_en.dart b/lib/src/localization/generated/app_localizations_en.dart index ccf9ad7..eeb70b5 100644 --- a/lib/src/localization/generated/app_localizations_en.dart +++ b/lib/src/localization/generated/app_localizations_en.dart @@ -322,7 +322,7 @@ class AppLocalizationsEn extends AppLocalizations { String get settingsAppearance => 'Appearance'; @override - String get settingsPrivacy => 'Privacy'; + String get settingsPrivacy => 'Privacy & Security'; @override String get settingsPrivacyBlockUsers => 'Block users'; @@ -1688,4 +1688,12 @@ class AppLocalizationsEn extends AppLocalizations { String chatEntryFlameRestored(Object count) { return '$count flames restored'; } + + @override + String requestedUserToastText(Object username) { + return '$username was successfully requested.'; + } + + @override + String get profileYourQrCode => 'Your QR code'; } diff --git a/lib/src/localization/generated/app_localizations_sv.dart b/lib/src/localization/generated/app_localizations_sv.dart index 6a5525a..99799dc 100644 --- a/lib/src/localization/generated/app_localizations_sv.dart +++ b/lib/src/localization/generated/app_localizations_sv.dart @@ -322,7 +322,7 @@ class AppLocalizationsSv extends AppLocalizations { String get settingsAppearance => 'Appearance'; @override - String get settingsPrivacy => 'Privacy'; + String get settingsPrivacy => 'Privacy & Security'; @override String get settingsPrivacyBlockUsers => 'Block users'; @@ -1688,4 +1688,12 @@ class AppLocalizationsSv extends AppLocalizations { String chatEntryFlameRestored(Object count) { return '$count flames restored'; } + + @override + String requestedUserToastText(Object username) { + return '$username was successfully requested.'; + } + + @override + String get profileYourQrCode => 'Your QR code'; } diff --git a/lib/src/localization/translations b/lib/src/localization/translations index 6147155..4c566ea 160000 --- a/lib/src/localization/translations +++ b/lib/src/localization/translations @@ -1 +1 @@ -Subproject commit 6147155ce50caa97864d56e42e49a6f54702785d +Subproject commit 4c566ea0b455d7f5ee81dd93ee4f785dc634befa diff --git a/lib/src/services/api/utils.dart b/lib/src/services/api/utils.dart index 38d5501..6468445 100644 --- a/lib/src/services/api/utils.dart +++ b/lib/src/services/api/utils.dart @@ -81,22 +81,27 @@ Future handleMediaError(MediaFile media) async { ); } -Future importSignalContactAndCreateRequest( +Future importSignalContactAndCreateRequest( server.Response_UserData userdata, ) async { - if (await processSignalUserData(userdata)) { - // 1. Setup notifications keys with the other user - await setupNotificationWithUsers( - forceContact: userdata.userId.toInt(), - ); - // 2. Then send user request - await sendCipherText( - userdata.userId.toInt(), - EncryptedContent( - contactRequest: EncryptedContent_ContactRequest( - type: EncryptedContent_ContactRequest_Type.REQUEST, - ), - ), - ); + if (!await processSignalUserData(userdata)) { + return false; } + + // 1. Setup notifications keys with the other user + await setupNotificationWithUsers( + forceContact: userdata.userId.toInt(), + ); + + // 2. Then send user request + await sendCipherText( + userdata.userId.toInt(), + EncryptedContent( + contactRequest: EncryptedContent_ContactRequest( + type: EncryptedContent_ContactRequest_Type.REQUEST, + ), + ), + ); + + return true; } diff --git a/lib/src/utils/misc.dart b/lib/src/utils/misc.dart index ad9e8d0..401689a 100644 --- a/lib/src/utils/misc.dart +++ b/lib/src/utils/misc.dart @@ -302,7 +302,7 @@ Color getMessageColorFromType( ) { Color color; - if (message.type == MessageType.text.name) { + if (message.type == MessageType.restoreFlameCounter.name) { color = Colors.orange; } else if (message.type == MessageType.text.name) { color = Colors.blueAccent; diff --git a/lib/src/utils/qr.dart b/lib/src/utils/qr.dart index 331b00f..075a878 100644 --- a/lib/src/utils/qr.dart +++ b/lib/src/utils/qr.dart @@ -55,7 +55,7 @@ PublicProfile? parseQrCodeData(Uint8List rawBytes) { return null; } -Future addNewContactFromPublicProfile(PublicProfile profile) async { +Future addNewContactFromPublicProfile(PublicProfile profile) async { final userdata = Response_UserData( userId: profile.userId, publicIdentityKey: profile.publicIdentityKey, @@ -77,5 +77,8 @@ Future addNewContactFromPublicProfile(PublicProfile profile) async { ), ); - if (added > 0) await importSignalContactAndCreateRequest(userdata); + if (added > 0) { + return importSignalContactAndCreateRequest(userdata); + } + return false; } diff --git a/lib/src/views/camera/camera_preview_components/camera_preview_controller_view.dart b/lib/src/views/camera/camera_preview_components/camera_preview_controller_view.dart index 7e48d19..3c9608c 100644 --- a/lib/src/views/camera/camera_preview_components/camera_preview_controller_view.dart +++ b/lib/src/views/camera/camera_preview_components/camera_preview_controller_view.dart @@ -761,7 +761,21 @@ class _CameraPreviewViewState extends State { onTap: () async { c.isLoading = true; widget.mainCameraController.setState(); - await addNewContactFromPublicProfile(c.profile); + if (await addNewContactFromPublicProfile( + c.profile, + ) && + context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + context.lang.requestedUserToastText( + c.profile.username, + ), + ), + duration: const Duration(seconds: 8), + ), + ); + } }, child: Container( padding: const EdgeInsets.all(12), 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 ae866f0..93c623e 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 @@ -10,6 +10,7 @@ import 'package:twonly/src/database/tables/messages.table.dart' import 'package:twonly/src/database/twonly.db.dart'; import 'package:twonly/src/model/memory_item.model.dart'; import 'package:twonly/src/services/mediafiles/mediafile.service.dart'; +import 'package:twonly/src/utils/log.dart'; import 'package:twonly/src/views/chats/chat_messages_components/chat_reaction_row.dart'; import 'package:twonly/src/views/chats/chat_messages_components/entries/chat_audio_entry.dart'; import 'package:twonly/src/views/chats/chat_messages_components/entries/chat_contacts.entry.dart'; @@ -79,6 +80,10 @@ class _ChatListEntryState extends State { if (mediaFiles != null) { mediaService = MediaFileService(mediaFiles); if (mounted) setState(() {}); + } else { + Log.error( + 'Media file not found for ${widget.message.messageId} => ${widget.message.mediaId}', + ); } }); } diff --git a/lib/src/views/contact/contact.view.dart b/lib/src/views/contact/contact.view.dart index b0fc162..6b583f4 100644 --- a/lib/src/views/contact/contact.view.dart +++ b/lib/src/views/contact/contact.view.dart @@ -29,7 +29,7 @@ class ContactView extends StatefulWidget { class _ContactViewState extends State { Contact? _contact; - bool _contactIsStillAGroupMember = true; + List _memberOfGroups = []; late StreamSubscription _contactSub; late StreamSubscription> _groupMemberSub; @@ -44,10 +44,8 @@ class _ContactViewState extends State { }); _groupMemberSub = twonlyDB.groupsDao .watchContactGroupMember(widget.userId) - .listen((update) { - setState(() { - _contactIsStillAGroupMember = update.isNotEmpty; - }); + .listen((groups) async { + _memberOfGroups = groups; }); super.initState(); } @@ -60,7 +58,18 @@ class _ContactViewState extends State { } Future handleUserRemoveRequest(Contact contact) async { - if (_contactIsStillAGroupMember) { + var delete = true; + for (final groupM in _memberOfGroups) { + final group = await twonlyDB.groupsDao.getGroup(groupM.groupId); + if (group?.deletedContent ?? false) { + await twonlyDB.groupsDao.deleteGroup(group!.groupId); + } else { + delete = false; + } + } + if (!mounted) return; + + if (!delete) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(context.lang.deleteUserErrorMessage), @@ -211,26 +220,6 @@ class _ContactViewState extends State { setState(() {}); }, ), - // BetterListTile( - // icon: FontAwesomeIcons.eraser, - // iconSize: 16, - // text: context.lang.deleteAllContactMessages, - // onTap: () async { - // final block = await showAlertDialog( - // context, - // context.lang.deleteAllContactMessages, - // context.lang.deleteAllContactMessagesBody( - // getContactDisplayName(contact), - // ), - // ); - // if (block) { - // if (context.mounted) { - // await twonlyDB.messagesDao - // .deleteMessagesByContactId(contact.userId); - // } - // } - // }, - // ), BetterListTile( icon: FontAwesomeIcons.flag, text: context.lang.reportUser, diff --git a/lib/src/views/settings/privacy.view.dart b/lib/src/views/settings/privacy.view.dart index 5e006c4..976fe36 100644 --- a/lib/src/views/settings/privacy.view.dart +++ b/lib/src/views/settings/privacy.view.dart @@ -43,6 +43,13 @@ class _PrivacyViewState extends State { ), onTap: () => context.push(Routes.settingsPrivacyBlockUsers), ), + ListTile( + title: Text(context.lang.contactVerifyNumberTitle), + onTap: () async { + await context.push(Routes.settingsPublicProfile); + setState(() {}); + }, + ), ], ), ); diff --git a/lib/src/views/settings/profile/profile.view.dart b/lib/src/views/settings/profile/profile.view.dart index 5132401..71bed4e 100644 --- a/lib/src/views/settings/profile/profile.view.dart +++ b/lib/src/views/settings/profile/profile.view.dart @@ -120,6 +120,17 @@ class _ProfileViewState extends State { ), const SizedBox(height: 20), const Divider(), + BetterListTile( + leading: const Padding( + padding: EdgeInsets.only(right: 5, left: 1), + child: FaIcon( + FontAwesomeIcons.qrcode, + size: 20, + ), + ), + onTap: () => context.push(Routes.settingsPublicProfile), + text: context.lang.profileYourQrCode, + ), BetterListTile( leading: const Padding( padding: EdgeInsets.only(right: 5, left: 1),