Compare commits

...

4 Commits

Author SHA1 Message Date
Janez T
4e76898c8d Update pubspec version 2026-03-07 11:33:58 +01:00
Janez T
7214c73aea Remove gates and sync pubspec 2026-03-07 11:33:58 +01:00
Janez Troha
beb960cf62 Merge pull request #12 from MGJ520/main
Fix the Chinese translation switching issue
2026-03-07 09:32:32 +01:00
MGJ
01afcd2ea7 Fix the Chinese translation switching issue 2026-03-07 11:22:21 +08:00
7 changed files with 127 additions and 34 deletions

View File

@@ -171,7 +171,7 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/vibration/ios"
SPEC CHECKSUMS:
audioplayers_darwin: 4f9ca89d92d3d21cec7ec580e78ca888e5fb68bd
audioplayers_darwin: 835ced6edd4c9fc8ebb0a7cc9e294a91d99917d5
codec2_flutter: 15e24fa897d9d903a2afb1cc5a17ae3ac88b6d6f
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c

View File

@@ -5,22 +5,22 @@
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000239">
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000273">
</testcase>
<testcase classname="fastlane.lanes" name="1: increment_build_number" time="0.427601">
<testcase classname="fastlane.lanes" name="1: increment_build_number" time="0.453879">
</testcase>
<testcase classname="fastlane.lanes" name="2: build_app" time="110.117264">
<testcase classname="fastlane.lanes" name="2: build_app" time="117.623994">
</testcase>
<testcase classname="fastlane.lanes" name="3: upload_to_app_store" time="269.473315">
<testcase classname="fastlane.lanes" name="3: upload_to_app_store" time="209.300865">
</testcase>

View File

@@ -202,6 +202,21 @@ class AppProvider with ChangeNotifier {
}
}
String? _resolveContactNameForNotification(Uint8List? publicKey) {
if (publicKey == null || publicKey.isEmpty) return null;
Contact? contact;
if (publicKey.length >= 32) {
contact = contactsProvider.findContactByKey(publicKey);
}
contact ??= publicKey.length >= 6
? contactsProvider.findContactByPrefix(
Uint8List.fromList(publicKey.sublist(0, 6)),
)
: null;
return contact?.advName;
}
/// Load simple mode setting from shared preferences
Future<void> _loadSimpleMode() async {
try {
@@ -437,6 +452,10 @@ class AppProvider with ChangeNotifier {
void _setupCallbacks() {
// Monitor connection state changes to start/stop location tracking
connectionProvider.addListener(_handleConnectionStateChange);
messagesProvider.resolveContactNameCallback =
_resolveContactNameForNotification;
messagesProvider.resolveChannelNameCallback =
channelsProvider.getChannelDisplayName;
voiceProvider.sendRawPacketCallback =
({

View File

@@ -11,6 +11,7 @@ import '../services/notification_service.dart';
import '../utils/sar_message_parser.dart';
import '../utils/drawing_message_parser.dart';
import '../utils/voice_message_parser.dart';
import '../utils/image_message_parser.dart';
import '../l10n/app_localizations.dart';
import 'helpers/message_retry_manager.dart';
@@ -79,6 +80,9 @@ class MessagesProvider with ChangeNotifier {
Future<void> Function({required Contact contact, required int failureStreak})?
onDirectPathFailedCallback;
String? Function(Uint8List? publicKey)? resolveContactNameCallback;
String Function(int channelIdx)? resolveChannelNameCallback;
List<Message> get messages => List.unmodifiable(_messages);
List<Message> get contactMessages =>
@@ -576,33 +580,31 @@ class MessagesProvider with ChangeNotifier {
/// Trigger notification for regular message
Future<void> _triggerMessageNotification(Message message) async {
try {
// Get sender name from message
final senderName =
message.senderName ?? message.senderKeyShort ?? 'Unknown';
// Determine if it's a channel message
final senderName = _resolveParticipantName(
publicKey: message.senderPublicKeyPrefix,
fallback: message.senderName ?? message.senderKeyShort,
);
final isChannelMessage = message.isChannelMessage;
// Get channel name if available
String? channelName;
if (isChannelMessage) {
// You could map channelIdx to channel name here if needed
// For now, use "Public" for channel 0
channelName = message.channelIdx == 0
? 'Public'
: 'Channel ${message.channelIdx}';
}
final channelName = isChannelMessage
? _resolveChannelName(message.channelIdx)
: null;
final messageText = _buildNotificationMessageText(
message,
senderName: senderName,
isChannelMessage: isChannelMessage,
channelName: channelName,
);
debugPrint('🔔 [MessagesProvider] Triggering message notification');
debugPrint(' Sender: $senderName');
debugPrint(' Type: ${isChannelMessage ? "Channel" : "Direct"}');
debugPrint(
' Message: ${message.text.substring(0, message.text.length > 50 ? 50 : message.text.length)}...',
' Message: ${messageText.substring(0, messageText.length > 50 ? 50 : messageText.length)}...',
);
await _notificationService.showMessageNotification(
senderName: senderName,
messageText: message.text,
messageText: messageText,
isChannelMessage: isChannelMessage,
channelName: channelName,
localizations: _localizations,
@@ -614,6 +616,78 @@ class MessagesProvider with ChangeNotifier {
}
}
String _resolveParticipantName({
required Uint8List? publicKey,
String? fallback,
}) {
final resolved = resolveContactNameCallback?.call(publicKey)?.trim();
if (resolved != null && resolved.isNotEmpty) {
return resolved;
}
final normalizedFallback = fallback?.trim();
if (normalizedFallback != null && normalizedFallback.isNotEmpty) {
return normalizedFallback;
}
return 'Unknown';
}
String _resolveChannelName(int? channelIdx) {
final idx = channelIdx ?? 0;
final resolved = resolveChannelNameCallback?.call(idx).trim();
if (resolved != null && resolved.isNotEmpty) {
return resolved;
}
return idx == 0 ? 'Public' : 'Channel $idx';
}
String _buildNotificationMessageText(
Message message, {
required String senderName,
required bool isChannelMessage,
String? channelName,
}) {
final voiceEnvelope = VoiceEnvelope.tryParseText(message.text);
if (voiceEnvelope != null) {
final seconds = (voiceEnvelope.durationMs / 1000).ceil();
final route = isChannelMessage
? 'Channel: ${channelName ?? _resolveChannelName(message.channelIdx)}'
: 'From: $senderName';
return '$route\nVoice message - ${voiceEnvelope.mode.label} - ${seconds}s - ${voiceEnvelope.total} packets';
}
final imageEnvelope = ImageEnvelope.tryParse(message.text);
if (imageEnvelope != null) {
final route = isChannelMessage
? 'Channel: ${channelName ?? _resolveChannelName(message.channelIdx)}'
: 'From: $senderName';
return '$route\nImage - ${imageEnvelope.format.label} - ${imageEnvelope.width}x${imageEnvelope.height} - ${_formatBytes(imageEnvelope.sizeBytes)}';
}
if (!isChannelMessage && message.recipientPublicKey != null) {
final recipientName = _resolveParticipantName(
publicKey: message.recipientPublicKey,
fallback: null,
);
if (recipientName != 'Unknown') {
return 'From: $senderName\nTo: $recipientName\n${message.text}';
}
}
if (isChannelMessage && channelName != null && channelName.isNotEmpty) {
return 'Channel: $channelName\n${message.text}';
}
return message.text;
}
String _formatBytes(int bytes) {
if (bytes < 1024) return '$bytes B';
final kib = bytes / 1024;
if (kib < 1024) return '${kib.toStringAsFixed(kib >= 10 ? 0 : 1)} KB';
final mib = kib / 1024;
return '${mib.toStringAsFixed(mib >= 10 ? 0 : 1)} MB';
}
/// Persist messages to storage (async, non-blocking)
Future<void> _persistMessages() async {
try {

View File

@@ -64,7 +64,7 @@ class LocalePreferences {
return 'Italiano';
case 'el':
return 'Greek';
case 'cn':
case 'zh':
return '简体中文';
default:
return locale.languageCode;
@@ -90,7 +90,7 @@ class LocalePreferences {
return 'Italiano';
case 'el':
return 'Ελληνικά';
case 'cn':
case 'zh':
return '简体中文';
default:
return locale.languageCode;

View File

@@ -29,10 +29,10 @@ packages:
dependency: "direct main"
description:
name: audioplayers
sha256: "5441fa0ceb8807a5ad701199806510e56afde2b4913d9d17c2f19f2902cf0ae4"
sha256: a72dd459d1a48f61a6fb9c0134dba26597c9236af40639ff0eb70eb4e0baab70
url: "https://pub.dev"
source: hosted
version: "6.5.1"
version: "6.6.0"
audioplayers_android:
dependency: transitive
description:
@@ -45,10 +45,10 @@ packages:
dependency: transitive
description:
name: audioplayers_darwin
sha256: "0811d6924904ca13f9ef90d19081e4a87f7297ddc19fc3d31f60af1aaafee333"
sha256: c994b3bb3a921e4904ac40e013fbc94488e824fd7c1de6326f549943b0b44a91
url: "https://pub.dev"
source: hosted
version: "6.3.0"
version: "6.4.0"
audioplayers_linux:
dependency: transitive
description:
@@ -69,18 +69,18 @@ packages:
dependency: transitive
description:
name: audioplayers_web
sha256: "1c0f17cec68455556775f1e50ca85c40c05c714a99c5eb1d2d57cc17ba5522d7"
sha256: faa8fa6587f996a6f604433b53af44c57a1407d4fe8dff5766cf63d6875e8de9
url: "https://pub.dev"
source: hosted
version: "5.1.1"
version: "5.2.0"
audioplayers_windows:
dependency: transitive
description:
name: audioplayers_windows
sha256: "4048797865105b26d47628e6abb49231ea5de84884160229251f37dfcbe52fd7"
sha256: bafff2b38b6f6d331887558ba6e0a01c9c208d9dbb3ad0005234db065122a734
url: "https://pub.dev"
source: hosted
version: "4.2.1"
version: "4.3.0"
bluez:
dependency: transitive
description:
@@ -851,7 +851,7 @@ packages:
description:
path: "."
ref: main
resolved-ref: fb0a92a53b8e1ab23ffca50c2bffe819829843e6
resolved-ref: cea66b5251135c7f9b84f15c0878d4c8af6e88e9
url: "https://github.com/dz0ny/meshcore_client.git"
source: git
version: "0.1.0"

View File

@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 2026.0307.1+14
version: 2026.0307.2+15
environment:
sdk: ^3.9.2