diff --git a/ios/Podfile.lock b/ios/Podfile.lock index ecb8d62..32c6051 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -241,7 +241,7 @@ PODS: - sqlite3/perf-threadsafe - sqlite3/rtree - sqlite3/session - - SwiftProtobuf (1.32.0) + - SwiftProtobuf (1.33.1) - url_launcher_ios (0.0.1): - Flutter - video_player_avfoundation (0.0.1): @@ -421,7 +421,7 @@ SPEC CHECKSUMS: sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 sqlite3: 73513155ec6979715d3904ef53a8d68892d4032b sqlite3_flutter_libs: 83f8e9f5b6554077f1d93119fe20ebaa5f3a9ef1 - SwiftProtobuf: 81e341191afbddd64aa031bd12862dccfab2f639 + SwiftProtobuf: 533a18409c3ca3a6156b2b1e46afd0f69e751aba url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b video_player_avfoundation: dd410b52df6d2466a42d28550e33e4146928280a diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index e3773d4..fa4cdb6 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -52,7 +52,7 @@ handleMedia( mediaType = MediaType.audio; } + int? displayLimitInMilliseconds; + if (media.hasDisplayLimitInMilliseconds()) { + if (media.displayLimitInMilliseconds.toInt() < 1000) { + displayLimitInMilliseconds = + media.displayLimitInMilliseconds.toInt() * 1000; + } else { + displayLimitInMilliseconds = media.displayLimitInMilliseconds.toInt(); + } + } + final mediaFile = await twonlyDB.mediaFilesDao.insertMedia( MediaFilesCompanion( downloadState: const Value(DownloadState.pending), type: Value(mediaType), requiresAuthentication: Value(media.requiresAuthentication), displayLimitInMilliseconds: Value( - media.hasDisplayLimitInMilliseconds() - ? media.displayLimitInMilliseconds.toInt() - : null, + displayLimitInMilliseconds, ), downloadToken: Value(Uint8List.fromList(media.downloadToken)), encryptionKey: Value(Uint8List.fromList(media.encryptionKey)), diff --git a/lib/src/services/api/mediafiles/upload.service.dart b/lib/src/services/api/mediafiles/upload.service.dart index 7fa39d9..9712f16 100644 --- a/lib/src/services/api/mediafiles/upload.service.dart +++ b/lib/src/services/api/mediafiles/upload.service.dart @@ -54,6 +54,11 @@ Future initializeMediaUpload( int? displayLimitInMilliseconds, { bool isDraftMedia = false, }) async { + if (displayLimitInMilliseconds != null && displayLimitInMilliseconds < 1000) { + // in case the time was set in seconds... + // ignore: parameter_assignments + displayLimitInMilliseconds = displayLimitInMilliseconds * 1000; + } final chacha20 = FlutterChacha20.poly1305Aead(); final encryptionKey = await (await chacha20.newSecretKey()).extract(); final encryptionNonce = chacha20.newNonce(); diff --git a/lib/src/services/mediafiles/mediafile.service.dart b/lib/src/services/mediafiles/mediafile.service.dart index 00bed5a..2dab6fd 100644 --- a/lib/src/services/mediafiles/mediafile.service.dart +++ b/lib/src/services/mediafiles/mediafile.service.dart @@ -157,7 +157,7 @@ class MediaFileService { MediaFilesCompanion( requiresAuthentication: Value(requiresAuthentication), displayLimitInMilliseconds: - requiresAuthentication ? const Value(12) : const Value.absent(), + requiresAuthentication ? const Value(12000) : const Value.absent(), ), ); await updateFromDB(); diff --git a/lib/src/services/notifications/pushkeys.notifications.dart b/lib/src/services/notifications/pushkeys.notifications.dart index b02ab0f..613db6a 100644 --- a/lib/src/services/notifications/pushkeys.notifications.dart +++ b/lib/src/services/notifications/pushkeys.notifications.dart @@ -362,36 +362,49 @@ Future encryptPushNotification( Future> getPushKeys(String storageKey) async { const storage = FlutterSecureStorage(); - final pushKeysProto = await storage.read( - key: storageKey, - iOptions: const IOSOptions( - groupId: 'CN332ZUGRP.eu.twonly.shared', - accessibility: KeychainAccessibility.first_unlock, - ), - ); - if (pushKeysProto == null) return []; - final pushKeysRaw = base64Decode(pushKeysProto); - return PushUsers.fromBuffer(pushKeysRaw).users; + try { + final pushKeysProto = await storage.read( + key: storageKey, + iOptions: const IOSOptions( + groupId: 'CN332ZUGRP.eu.twonly.shared', + accessibility: KeychainAccessibility.first_unlock, + ), + ); + if (pushKeysProto == null) return []; + final pushKeysRaw = base64Decode(pushKeysProto); + return PushUsers.fromBuffer(pushKeysRaw).users; + } catch (e) { + Log.error(e); + } + return []; } Future setPushKeys(String storageKey, List pushKeys) async { const storage = FlutterSecureStorage(); - await storage.delete( - key: storageKey, - iOptions: const IOSOptions( - groupId: 'CN332ZUGRP.eu.twonly.shared', - accessibility: KeychainAccessibility.first_unlock, - ), - ); + try { + await storage.delete( + key: storageKey, + iOptions: const IOSOptions( + groupId: 'CN332ZUGRP.eu.twonly.shared', + accessibility: KeychainAccessibility.first_unlock, + ), + ); + } catch (e) { + Log.error(e); + } final jsonString = base64Encode(PushUsers(users: pushKeys).writeToBuffer()); - await storage.write( - key: storageKey, - value: jsonString, - iOptions: const IOSOptions( - groupId: 'CN332ZUGRP.eu.twonly.shared', - accessibility: KeychainAccessibility.first_unlock, - ), - ); + try { + await storage.write( + key: storageKey, + value: jsonString, + iOptions: const IOSOptions( + groupId: 'CN332ZUGRP.eu.twonly.shared', + accessibility: KeychainAccessibility.first_unlock, + ), + ); + } catch (e) { + Log.error(e); + } } diff --git a/lib/src/views/camera/share_image_editor_view.dart b/lib/src/views/camera/share_image_editor_view.dart index 3db605c..d38c36e 100644 --- a/lib/src/views/camera/share_image_editor_view.dart +++ b/lib/src/views/camera/share_image_editor_view.dart @@ -192,7 +192,7 @@ class _ShareImageEditorView extends State { ? '0' : media.displayLimitInMilliseconds == null ? '∞' - : media.displayLimitInMilliseconds.toString(), + : (media.displayLimitInMilliseconds! ~/ 1000).toString(), child: ActionButton( (media.type == MediaType.video) ? media.displayLimitInMilliseconds == null @@ -211,11 +211,13 @@ class _ShareImageEditorView extends State { } int? maxShowTime; if (media.displayLimitInMilliseconds == null) { - maxShowTime = 1; - } else if (media.displayLimitInMilliseconds == 1) { - maxShowTime = 5; - } else if (media.displayLimitInMilliseconds == 5) { - maxShowTime = 20; + maxShowTime = 1000; + } else if (media.displayLimitInMilliseconds == 1000) { + maxShowTime = 5000; + } else if (media.displayLimitInMilliseconds == 5000) { + maxShowTime = 12000; + } else if (media.displayLimitInMilliseconds == 12000) { + maxShowTime = 20000; } await mediaService.setDisplayLimit(maxShowTime); if (!mounted) return; diff --git a/lib/src/views/chats/media_viewer.view.dart b/lib/src/views/chats/media_viewer.view.dart index 471cc42..9a62a59 100644 --- a/lib/src/views/chats/media_viewer.view.dart +++ b/lib/src/views/chats/media_viewer.view.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:collection'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:lottie/lottie.dart'; @@ -54,7 +55,7 @@ class _MediaViewerViewState extends State { bool imageSaved = false; bool imageSaving = false; - bool displayTwonlyPresent = true; + bool displayTwonlyPresent = false; final emojiKey = GlobalKey(); StreamSubscription? downloadStateListener; @@ -63,6 +64,8 @@ class _MediaViewerViewState extends State { late StreamSubscription> _subscription; TextEditingController textMessageController = TextEditingController(); + final HashSet _alreadyOpenedMediaIds = HashSet(); + @override void initState() { super.initState(); @@ -92,6 +95,13 @@ class _MediaViewerViewState extends State { _subscription = messages.listen((messages) async { for (final msg in messages) { + if (_alreadyOpenedMediaIds.contains(msg.mediaId)) { + continue; + } + if (msg.mediaId == null) { + continue; + } + if (msg.mediaId == currentMedia?.mediaFile.mediaId) { // The update of the current Media in case of a download is done in loadCurrentMediaFile continue; @@ -195,13 +205,17 @@ class _MediaViewerViewState extends State { bool showTwonly, ) async { if (allMediaFiles.isEmpty) return; - currentMessage = allMediaFiles.removeAt(0); final currentMediaLocal = - await MediaFileService.fromMediaId(currentMessage!.mediaId!); + await MediaFileService.fromMediaId(allMediaFiles.first.mediaId!); if (currentMediaLocal == null || !mounted) return; if (currentMediaLocal.mediaFile.requiresAuthentication) { - if (!showTwonly) return; + if (!showTwonly) { + setState(() { + displayTwonlyPresent = true; + }); + return; + } final isAuth = await authenticateUser( context.lang.mediaViewerAuthReason, @@ -209,10 +223,20 @@ class _MediaViewerViewState extends State { ); if (!isAuth) { await nextMediaOrExit(); + setState(() { + displayTwonlyPresent = false; + }); return; } } + _alreadyOpenedMediaIds.add(allMediaFiles.first.mediaId!); + currentMessage = allMediaFiles.removeAt(0); + + setState(() { + displayTwonlyPresent = false; + }); + await notifyContactAboutOpeningMessage( currentMessage!.senderId!, [currentMessage!.messageId], @@ -490,9 +514,7 @@ class _MediaViewerViewState extends State { ), ), ), - if (currentMedia != null && - currentMedia!.mediaFile.requiresAuthentication && - displayTwonlyPresent) + if (displayTwonlyPresent) Positioned.fill( child: GestureDetector( onTap: () { diff --git a/pubspec.lock b/pubspec.lock index 4d2c37e..63801d5 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -705,18 +705,19 @@ packages: dependency: "direct main" description: path: flutter_secure_storage - ref: "71b75a36f35f2ce945998e20c6c6aa1820babfc6" - resolved-ref: "71b75a36f35f2ce945998e20c6c6aa1820babfc6" + ref: a06ead81809c900e7fc421a30db0adf3b5919139 + resolved-ref: a06ead81809c900e7fc421a30db0adf3b5919139 url: "https://github.com/juliansteenbakker/flutter_secure_storage.git" source: git version: "10.0.0-beta.4" flutter_secure_storage_darwin: - dependency: transitive + dependency: "direct overridden" description: - name: flutter_secure_storage_darwin - sha256: f226f2a572bed96bc6542198ebaec227150786e34311d455a7e2d3d06d951845 - url: "https://pub.dev" - source: hosted + path: flutter_secure_storage_darwin + ref: a06ead81809c900e7fc421a30db0adf3b5919139 + resolved-ref: a06ead81809c900e7fc421a30db0adf3b5919139 + url: "https://github.com/juliansteenbakker/flutter_secure_storage.git" + source: git version: "0.1.0" flutter_secure_storage_linux: dependency: transitive diff --git a/pubspec.yaml b/pubspec.yaml index c43b7fb..f964597 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,7 +3,7 @@ description: "twonly, a privacy-friendly way to connect with friends through sec publish_to: 'none' -version: 0.0.64+64 +version: 0.0.66+66 environment: sdk: ^3.6.0 @@ -36,7 +36,7 @@ dependencies: flutter_secure_storage: git: url: https://github.com/juliansteenbakker/flutter_secure_storage.git - ref: 71b75a36f35f2ce945998e20c6c6aa1820babfc6 # from develop + ref: a06ead81809c900e7fc421a30db0adf3b5919139 # from develop path: flutter_secure_storage/ flutter_svg: ^2.0.17 flutter_volume_controller: ^1.3.4 @@ -77,6 +77,12 @@ dependencies: dependency_overrides: + flutter_secure_storage_darwin: + git: + url: https://github.com/juliansteenbakker/flutter_secure_storage.git + ref: a06ead81809c900e7fc421a30db0adf3b5919139 # from develop + path: flutter_secure_storage_darwin/ + flutter_android_volume_keydown: git: url: https://github.com/yenchieh/flutter_android_volume_keydown.git