Hide tab bar when single tab

This commit is contained in:
Janez T
2026-03-05 11:51:23 +01:00
parent 0cb1d49804
commit 162d5333ce
5 changed files with 54 additions and 47 deletions

View File

@@ -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;

View File

@@ -43,7 +43,7 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>77</string>
<string>80</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSBluetoothAlwaysUsageDescription</key>

View File

@@ -5,22 +5,17 @@
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.001023">
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.00024">
</testcase>
<testcase classname="fastlane.lanes" name="1: increment_build_number" time="0.446008">
<testcase classname="fastlane.lanes" name="1: increment_build_number" time="0.420141">
</testcase>
<testcase classname="fastlane.lanes" name="2: build_app" time="104.515166">
</testcase>
<testcase classname="fastlane.lanes" name="3: upload_to_app_store" time="268.810436">
<testcase classname="fastlane.lanes" name="2: build_app" time="46.949616">
</testcase>

View File

@@ -212,9 +212,11 @@ class _ImageMessageBubbleState extends State<ImageMessageBubble> {
int pathLen = 0,
}) async {
if (_isRequesting) return;
final conn = context.read<ConnectionProvider>();
var sender = _resolveSender(envelope);
if (sender == null) {
final conn = context.read<ConnectionProvider>();
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<ImageMessageBubble> {
}
setState(() => _errorText = null);
final conn = context.read<ConnectionProvider>();
final imageProvider = context.read<ip.ImageProvider>();
final deviceKey = conn.deviceInfo.publicKey;
if (deviceKey == null || deviceKey.length < 6) {
@@ -295,6 +296,7 @@ class _ImageMessageBubbleState extends State<ImageMessageBubble> {
);
} 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<ImageMessageBubble> {
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<ImageMessageBubble> {
Contact? _resolveSender(ImageEnvelope envelope) {
final contactsProvider = context.read<ContactsProvider>();
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<ImageMessageBubble> {
}
}
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<ImageMessageBubble> {
Future<void> _showBlockingAlert(String title, String message) async {
if (!mounted) return;
_showToast('$title: $message');
await showDialog<void>(
context: context,
builder: (dialogContext) => AlertDialog(

View File

@@ -207,9 +207,11 @@ class _VoiceMessageBubbleState extends State<VoiceMessageBubble> {
int pathLen = 0,
}) async {
if (_isRequesting) return;
final connectionProvider = context.read<ConnectionProvider>();
var sender = _resolveSenderContact();
if (sender == null) {
final connectionProvider = context.read<ConnectionProvider>();
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<VoiceMessageBubble> {
_errorText = null;
});
final connectionProvider = context.read<ConnectionProvider>();
final deviceKey = connectionProvider.deviceInfo.publicKey;
if (deviceKey == null || deviceKey.length < 6) {
await _showBlockingAlert(
@@ -310,6 +311,7 @@ class _VoiceMessageBubbleState extends State<VoiceMessageBubble> {
void _setUnavailable() {
if (!mounted) return;
_showToast(AppLocalizations.of(context)!.voiceUnavailable);
setState(() {
_isRequesting = false;
_autoPlayWhenReady = false;
@@ -319,6 +321,20 @@ class _VoiceMessageBubbleState extends State<VoiceMessageBubble> {
Contact? _resolveSenderContact() {
final contactsProvider = context.read<ContactsProvider>();
// 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<VoiceMessageBubble> {
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<VoiceMessageBubble> {
Future<void> _showBlockingAlert(String title, String message) async {
if (!mounted) return;
_showToast('$title: $message');
await showDialog<void>(
context: context,
builder: (dialogContext) => AlertDialog(