diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 9d7850c..a0ff4e0 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -489,7 +489,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 80; DEVELOPMENT_TEAM = JND55328G8; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -511,7 +511,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 80; DEVELOPMENT_TEAM = JND55328G8; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; @@ -530,7 +530,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 80; DEVELOPMENT_TEAM = JND55328G8; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; @@ -547,7 +547,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 80; DEVELOPMENT_TEAM = JND55328G8; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; @@ -679,7 +679,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 80; DEVELOPMENT_TEAM = JND55328G8; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -702,7 +702,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 77; + CURRENT_PROJECT_VERSION = 80; DEVELOPMENT_TEAM = JND55328G8; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 8acb499..4ec43d7 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -43,7 +43,7 @@ CFBundleSignature ???? CFBundleVersion - 77 + 80 LSRequiresIPhoneOS NSBluetoothAlwaysUsageDescription diff --git a/ios/fastlane/report.xml b/ios/fastlane/report.xml index db2228f..a253cf9 100644 --- a/ios/fastlane/report.xml +++ b/ios/fastlane/report.xml @@ -5,22 +5,17 @@ - + - + - - - - - - + diff --git a/lib/widgets/messages/image_message_bubble.dart b/lib/widgets/messages/image_message_bubble.dart index ae11fb0..db028f0 100644 --- a/lib/widgets/messages/image_message_bubble.dart +++ b/lib/widgets/messages/image_message_bubble.dart @@ -212,9 +212,11 @@ class _ImageMessageBubbleState extends State { int pathLen = 0, }) async { if (_isRequesting) return; + final conn = context.read(); var sender = _resolveSender(envelope); - if (sender == null) { - final conn = context.read(); + if (sender == null || + sender.outPathLen < 0 || + sender.outPathLen > _maxFetchHops) { await conn.getContacts(); if (!mounted) return; sender = _resolveSender(envelope); @@ -247,7 +249,6 @@ class _ImageMessageBubbleState extends State { } setState(() => _errorText = null); - final conn = context.read(); final imageProvider = context.read(); final deviceKey = conn.deviceInfo.publicKey; if (deviceKey == null || deviceKey.length < 6) { @@ -295,6 +296,7 @@ class _ImageMessageBubbleState extends State { ); } catch (_) { if (mounted) { + _showToast('Image fetch failed to send request'); setState(() { _isRequesting = false; _errorText = 'Image unavailable right now'; @@ -323,7 +325,11 @@ class _ImageMessageBubbleState extends State { if (mounted && _isRequesting && !imageProvider.isComplete(envelope.sessionId)) { - setState(() => _isRequesting = false); + _showToast('Image fetch timed out'); + setState(() { + _isRequesting = false; + _errorText = 'Image fetch timed out'; + }); } }, ); @@ -331,19 +337,8 @@ class _ImageMessageBubbleState extends State { Contact? _resolveSender(ImageEnvelope envelope) { final contactsProvider = context.read(); - final senderPrefix = widget.message.senderPublicKeyPrefix; - if (senderPrefix != null && senderPrefix.length >= 6) { - final c = contactsProvider.findContactByPrefix( - Uint8List.fromList(senderPrefix.sublist(0, 6)), - ); - if (c != null) return c; - } - final contact = contactsProvider.findContactByPrefixHex( - envelope.senderKey6, - ); - if (contact != null) return contact; - // For sent direct messages, fetch must target the recipient peer. + // For sent direct messages, fetch must target the recipient peer first. final recipientKey = widget.message.recipientPublicKey; if (widget.isSentByMe && recipientKey != null && recipientKey.isNotEmpty) { final byKey = contactsProvider.findContactByKey(recipientKey); @@ -356,6 +351,18 @@ class _ImageMessageBubbleState extends State { } } + final senderPrefix = widget.message.senderPublicKeyPrefix; + if (senderPrefix != null && senderPrefix.length >= 6) { + final c = contactsProvider.findContactByPrefix( + Uint8List.fromList(senderPrefix.sublist(0, 6)), + ); + if (c != null) return c; + } + final contact = contactsProvider.findContactByPrefixHex( + envelope.senderKey6, + ); + if (contact != null) return contact; + final senderName = widget.message.senderName?.trim(); if (senderName != null && senderName.isNotEmpty) { for (final c in contactsProvider.contacts) { @@ -377,6 +384,7 @@ class _ImageMessageBubbleState extends State { Future _showBlockingAlert(String title, String message) async { if (!mounted) return; + _showToast('$title: $message'); await showDialog( context: context, builder: (dialogContext) => AlertDialog( diff --git a/lib/widgets/messages/voice_message_bubble.dart b/lib/widgets/messages/voice_message_bubble.dart index 07a2cc3..28260d7 100644 --- a/lib/widgets/messages/voice_message_bubble.dart +++ b/lib/widgets/messages/voice_message_bubble.dart @@ -207,9 +207,11 @@ class _VoiceMessageBubbleState extends State { int pathLen = 0, }) async { if (_isRequesting) return; + final connectionProvider = context.read(); var sender = _resolveSenderContact(); - if (sender == null) { - final connectionProvider = context.read(); + if (sender == null || + sender.outPathLen < 0 || + sender.outPathLen > _maxFetchHops) { await connectionProvider.getContacts(); if (!mounted) return; sender = _resolveSenderContact(); @@ -246,7 +248,6 @@ class _VoiceMessageBubbleState extends State { _errorText = null; }); - final connectionProvider = context.read(); final deviceKey = connectionProvider.deviceInfo.publicKey; if (deviceKey == null || deviceKey.length < 6) { await _showBlockingAlert( @@ -310,6 +311,7 @@ class _VoiceMessageBubbleState extends State { void _setUnavailable() { if (!mounted) return; + _showToast(AppLocalizations.of(context)!.voiceUnavailable); setState(() { _isRequesting = false; _autoPlayWhenReady = false; @@ -319,6 +321,20 @@ class _VoiceMessageBubbleState extends State { Contact? _resolveSenderContact() { final contactsProvider = context.read(); + + // For sent direct messages, fetch must target the recipient peer first. + final recipientKey = widget.message.recipientPublicKey; + if (widget.isSentByMe && recipientKey != null && recipientKey.isNotEmpty) { + final byKey = contactsProvider.findContactByKey(recipientKey); + if (byKey != null) return byKey; + if (recipientKey.length >= 6) { + final byPrefix = contactsProvider.findContactByPrefix( + Uint8List.fromList(recipientKey.sublist(0, 6)), + ); + if (byPrefix != null) return byPrefix; + } + } + final senderPrefix = widget.message.senderPublicKeyPrefix; if (senderPrefix != null && senderPrefix.length >= 6) { final contact = contactsProvider.findContactByPrefix( @@ -335,19 +351,6 @@ class _VoiceMessageBubbleState extends State { if (contact != null) return contact; } - // For sent direct messages, fetch must target the recipient peer. - final recipientKey = widget.message.recipientPublicKey; - if (widget.isSentByMe && recipientKey != null && recipientKey.isNotEmpty) { - final byKey = contactsProvider.findContactByKey(recipientKey); - if (byKey != null) return byKey; - if (recipientKey.length >= 6) { - final byPrefix = contactsProvider.findContactByPrefix( - Uint8List.fromList(recipientKey.sublist(0, 6)), - ); - if (byPrefix != null) return byPrefix; - } - } - final senderName = widget.message.senderName?.trim(); if (senderName != null && senderName.isNotEmpty) { for (final contact in contactsProvider.contacts) { @@ -369,6 +372,7 @@ class _VoiceMessageBubbleState extends State { Future _showBlockingAlert(String title, String message) async { if (!mounted) return; + _showToast('$title: $message'); await showDialog( context: context, builder: (dialogContext) => AlertDialog(