mirror of
https://github.com/zjs81/meshcore-open.git
synced 2026-07-28 06:26:39 +10:00
Refactor: move Contact UI labels to l10n extension; rename raw getter to typeLabelRaw
This commit is contained in:
@@ -3997,7 +3997,7 @@ class MeshCoreConnector extends ChangeNotifier {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
appLogger.info(
|
appLogger.info(
|
||||||
"Discovered contact ${contact.name} (type ${contact.typeLabel}) not added due to auto-add settings",
|
"Discovered contact ${contact.name} (type ${contact.typeLabelRaw}) not added due to auto-add settings",
|
||||||
tag: 'Connector',
|
tag: 'Connector',
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
@@ -4019,7 +4019,7 @@ class MeshCoreConnector extends ChangeNotifier {
|
|||||||
if (settings.notificationsEnabled && settings.notifyOnNewAdvert) {
|
if (settings.notificationsEnabled && settings.notifyOnNewAdvert) {
|
||||||
_notificationService.showAdvertNotification(
|
_notificationService.showAdvertNotification(
|
||||||
contactName: contact.name,
|
contactName: contact.name,
|
||||||
contactType: contact.typeLabel,
|
contactType: contact.typeLabelRaw,
|
||||||
contactId: contact.publicKeyHex,
|
contactId: contact.publicKeyHex,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -4094,7 +4094,7 @@ class MeshCoreConnector extends ChangeNotifier {
|
|||||||
if (settings.notificationsEnabled && settings.notifyOnNewAdvert) {
|
if (settings.notificationsEnabled && settings.notifyOnNewAdvert) {
|
||||||
_notificationService.showAdvertNotification(
|
_notificationService.showAdvertNotification(
|
||||||
contactName: contact.name,
|
contactName: contact.name,
|
||||||
contactType: contact.typeLabel,
|
contactType: contact.typeLabelRaw,
|
||||||
contactId: contact.publicKeyHex,
|
contactId: contact.publicKeyHex,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -6025,7 +6025,7 @@ class MeshCoreConnector extends ChangeNotifier {
|
|||||||
if (settings.notificationsEnabled && settings.notifyOnNewAdvert) {
|
if (settings.notificationsEnabled && settings.notifyOnNewAdvert) {
|
||||||
_notificationService.showAdvertNotification(
|
_notificationService.showAdvertNotification(
|
||||||
contactName: contact.name,
|
contactName: contact.name,
|
||||||
contactType: contact.typeLabel,
|
contactType: contact.typeLabelRaw,
|
||||||
contactId: contact.publicKeyHex,
|
contactId: contact.publicKeyHex,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import '../connector/meshcore_protocol.dart';
|
||||||
|
import '../models/contact.dart';
|
||||||
|
import 'app_localizations.dart';
|
||||||
|
|
||||||
|
/// UI-level localization helpers for [Contact].
|
||||||
|
///
|
||||||
|
/// Kept out of the model layer so `Contact` does not depend on
|
||||||
|
/// `AppLocalizations`. Use these from widgets/screens; for logs and
|
||||||
|
/// non-UI export use `Contact.typeLabelRaw`.
|
||||||
|
extension ContactLocalization on Contact {
|
||||||
|
String typeLabel(AppLocalizations l10n) {
|
||||||
|
switch (type) {
|
||||||
|
case advTypeChat:
|
||||||
|
return l10n.contact_typeChat;
|
||||||
|
case advTypeRepeater:
|
||||||
|
return l10n.contact_typeRepeater;
|
||||||
|
case advTypeRoom:
|
||||||
|
return l10n.contact_typeRoom;
|
||||||
|
case advTypeSensor:
|
||||||
|
return l10n.contact_typeSensor;
|
||||||
|
default:
|
||||||
|
return l10n.contact_typeUnknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String pathLabel(AppLocalizations l10n) {
|
||||||
|
if (pathOverride != null) {
|
||||||
|
if (pathOverride! < 0) return l10n.chat_floodForced;
|
||||||
|
if (pathOverride == 0) return l10n.chat_directForced;
|
||||||
|
return l10n.chat_hopsForced(pathOverride!);
|
||||||
|
}
|
||||||
|
if (pathLength < 0) return l10n.channelPath_floodPath;
|
||||||
|
if (pathLength == 0) return l10n.chat_direct;
|
||||||
|
return l10n.chat_hopsCount(pathLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -59,6 +59,9 @@ void main() async {
|
|||||||
final notificationService = NotificationService();
|
final notificationService = NotificationService();
|
||||||
await notificationService.initialize();
|
await notificationService.initialize();
|
||||||
await backgroundService.initialize();
|
await backgroundService.initialize();
|
||||||
|
backgroundService.setLanguageOverrideProvider(
|
||||||
|
() => appSettingsService.settings.languageOverride,
|
||||||
|
);
|
||||||
_registerThirdPartyLicenses();
|
_registerThirdPartyLicenses();
|
||||||
|
|
||||||
await chatTextScaleService.initialize();
|
await chatTextScaleService.initialize();
|
||||||
|
|||||||
+4
-28
@@ -2,7 +2,6 @@ import 'dart:typed_data';
|
|||||||
import 'package:meshcore_open/utils/app_logger.dart';
|
import 'package:meshcore_open/utils/app_logger.dart';
|
||||||
|
|
||||||
import '../connector/meshcore_protocol.dart';
|
import '../connector/meshcore_protocol.dart';
|
||||||
import '../l10n/app_localizations.dart';
|
|
||||||
|
|
||||||
class Contact {
|
class Contact {
|
||||||
final Uint8List publicKey;
|
final Uint8List publicKey;
|
||||||
@@ -42,7 +41,10 @@ class Contact {
|
|||||||
|
|
||||||
String get publicKeyHex => pubKeyToHex(publicKey);
|
String get publicKeyHex => pubKeyToHex(publicKey);
|
||||||
|
|
||||||
String get typeLabel {
|
/// Non-localized type label, intended for logs and non-UI exports
|
||||||
|
/// (e.g. GPX). For UI use the `typeLabel(l10n)` extension in
|
||||||
|
/// `lib/l10n/contact_localization.dart`.
|
||||||
|
String get typeLabelRaw {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case advTypeChat:
|
case advTypeChat:
|
||||||
return 'Chat';
|
return 'Chat';
|
||||||
@@ -57,32 +59,6 @@ class Contact {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String typeLabelLocalized(AppLocalizations l10n) {
|
|
||||||
switch (type) {
|
|
||||||
case advTypeChat:
|
|
||||||
return l10n.contact_typeChat;
|
|
||||||
case advTypeRepeater:
|
|
||||||
return l10n.contact_typeRepeater;
|
|
||||||
case advTypeRoom:
|
|
||||||
return l10n.contact_typeRoom;
|
|
||||||
case advTypeSensor:
|
|
||||||
return l10n.contact_typeSensor;
|
|
||||||
default:
|
|
||||||
return l10n.contact_typeUnknown;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String pathLabel(AppLocalizations l10n) {
|
|
||||||
if (pathOverride != null) {
|
|
||||||
if (pathOverride! < 0) return l10n.chat_floodForced;
|
|
||||||
if (pathOverride == 0) return l10n.chat_directForced;
|
|
||||||
return l10n.chat_hopsForced(pathOverride!);
|
|
||||||
}
|
|
||||||
if (pathLength < 0) return l10n.channelPath_floodPath;
|
|
||||||
if (pathLength == 0) return l10n.chat_direct;
|
|
||||||
return l10n.chat_hopsCount(pathLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get hasLocation {
|
bool get hasLocation {
|
||||||
const double epsilon = 1e-6;
|
const double epsilon = 1e-6;
|
||||||
final lat = latitude ?? 0.0;
|
final lat = latitude ?? 0.0;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import '../helpers/gif_helper.dart';
|
|||||||
import '../helpers/path_helper.dart';
|
import '../helpers/path_helper.dart';
|
||||||
import '../models/channel_message.dart';
|
import '../models/channel_message.dart';
|
||||||
import '../models/contact.dart';
|
import '../models/contact.dart';
|
||||||
|
import '../l10n/contact_localization.dart';
|
||||||
import '../models/message.dart';
|
import '../models/message.dart';
|
||||||
import '../models/path_history.dart';
|
import '../models/path_history.dart';
|
||||||
import '../models/translation_support.dart';
|
import '../models/translation_support.dart';
|
||||||
@@ -1168,7 +1169,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
_buildInfoRow(context.l10n.chat_type, contact.typeLabelLocalized(context.l10n)),
|
_buildInfoRow(context.l10n.chat_type, contact.typeLabel(context.l10n)),
|
||||||
_buildInfoRow(context.l10n.chat_path, contact.pathLabel(context.l10n)),
|
_buildInfoRow(context.l10n.chat_path, contact.pathLabel(context.l10n)),
|
||||||
_buildInfoRow(
|
_buildInfoRow(
|
||||||
context.l10n.contact_lastSeen,
|
context.l10n.contact_lastSeen,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import '../connector/meshcore_connector.dart';
|
|||||||
import '../l10n/l10n.dart';
|
import '../l10n/l10n.dart';
|
||||||
import '../connector/meshcore_protocol.dart';
|
import '../connector/meshcore_protocol.dart';
|
||||||
import '../models/contact.dart';
|
import '../models/contact.dart';
|
||||||
|
import '../l10n/contact_localization.dart';
|
||||||
import '../models/contact_group.dart';
|
import '../models/contact_group.dart';
|
||||||
import '../services/ui_view_state_service.dart';
|
import '../services/ui_view_state_service.dart';
|
||||||
import '../utils/contact_search.dart';
|
import '../utils/contact_search.dart';
|
||||||
@@ -1123,7 +1124,7 @@ class _ContactsScreenState extends State<ContactsScreen>
|
|||||||
value: isSelected,
|
value: isSelected,
|
||||||
title: Text(contact.name),
|
title: Text(contact.name),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
contact.typeLabelLocalized(context.l10n),
|
contact.typeLabel(context.l10n),
|
||||||
),
|
),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
setDialogState(() {
|
setDialogState(() {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import '../connector/meshcore_protocol.dart';
|
|||||||
import '../models/app_settings.dart';
|
import '../models/app_settings.dart';
|
||||||
import '../models/channel.dart';
|
import '../models/channel.dart';
|
||||||
import '../models/contact.dart';
|
import '../models/contact.dart';
|
||||||
|
import '../l10n/contact_localization.dart';
|
||||||
import '../services/app_settings_service.dart';
|
import '../services/app_settings_service.dart';
|
||||||
import '../services/path_history_service.dart';
|
import '../services/path_history_service.dart';
|
||||||
import '../services/map_marker_service.dart';
|
import '../services/map_marker_service.dart';
|
||||||
@@ -1425,7 +1426,7 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
_buildInfoRow(context.l10n.map_type, contact.typeLabelLocalized(context.l10n)),
|
_buildInfoRow(context.l10n.map_type, contact.typeLabel(context.l10n)),
|
||||||
_buildInfoRow(context.l10n.map_path, contact.pathLabel(context.l10n)),
|
_buildInfoRow(context.l10n.map_path, contact.pathLabel(context.l10n)),
|
||||||
if (contact.hasLocation)
|
if (contact.hasLocation)
|
||||||
_buildInfoRow(
|
_buildInfoRow(
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'package:meshcore_open/connector/meshcore_protocol.dart';
|
|||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import '../l10n/l10n.dart';
|
import '../l10n/l10n.dart';
|
||||||
import '../models/contact.dart';
|
import '../models/contact.dart';
|
||||||
|
import '../l10n/contact_localization.dart';
|
||||||
import '../services/app_settings_service.dart';
|
import '../services/app_settings_service.dart';
|
||||||
import 'repeater_status_screen.dart';
|
import 'repeater_status_screen.dart';
|
||||||
import 'repeater_cli_screen.dart';
|
import 'repeater_cli_screen.dart';
|
||||||
|
|||||||
@@ -6,6 +6,14 @@ import '../utils/platform_info.dart';
|
|||||||
|
|
||||||
class BackgroundService {
|
class BackgroundService {
|
||||||
bool _initialized = false;
|
bool _initialized = false;
|
||||||
|
String? Function()? _languageOverrideProvider;
|
||||||
|
|
||||||
|
/// Allows the app to expose its current language override (e.g. from
|
||||||
|
/// AppSettingsService) so the foreground notification matches the app UI
|
||||||
|
/// language instead of only the system locale.
|
||||||
|
void setLanguageOverrideProvider(String? Function()? provider) {
|
||||||
|
_languageOverrideProvider = provider;
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> initialize() async {
|
Future<void> initialize() async {
|
||||||
if (!PlatformInfo.isAndroid || _initialized) return;
|
if (!PlatformInfo.isAndroid || _initialized) return;
|
||||||
@@ -47,6 +55,10 @@ class BackgroundService {
|
|||||||
|
|
||||||
Future<AppLocalizations> _loadLocalizations() async {
|
Future<AppLocalizations> _loadLocalizations() async {
|
||||||
final supported = AppLocalizations.supportedLocales;
|
final supported = AppLocalizations.supportedLocales;
|
||||||
|
final override = _languageOverrideProvider?.call();
|
||||||
|
if (override != null && override.isNotEmpty) {
|
||||||
|
return AppLocalizations.delegate.load(Locale(override));
|
||||||
|
}
|
||||||
final system =
|
final system =
|
||||||
WidgetsBinding.instance.platformDispatcher.locale;
|
WidgetsBinding.instance.platformDispatcher.locale;
|
||||||
final match = basicLocaleListResolution(
|
final match = basicLocaleListResolution(
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ class GpxExport {
|
|||||||
contact.name,
|
contact.name,
|
||||||
contact.latitude!,
|
contact.latitude!,
|
||||||
contact.longitude!,
|
contact.longitude!,
|
||||||
"Type: ${contact.typeLabel}\nPublic Key: ${contact.publicKeyHex}",
|
"Type: ${contact.typeLabelRaw}\nPublic Key: ${contact.publicKeyHex}",
|
||||||
url,
|
url,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -91,7 +91,7 @@ class GpxExport {
|
|||||||
contact.name,
|
contact.name,
|
||||||
contact.latitude!,
|
contact.latitude!,
|
||||||
contact.longitude!,
|
contact.longitude!,
|
||||||
"Type: ${contact.typeLabel}\nPublic Key: ${contact.publicKeyHex}",
|
"Type: ${contact.typeLabelRaw}\nPublic Key: ${contact.publicKeyHex}",
|
||||||
url,
|
url,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -110,7 +110,7 @@ class GpxExport {
|
|||||||
contact.name,
|
contact.name,
|
||||||
contact.latitude ?? 0.0,
|
contact.latitude ?? 0.0,
|
||||||
contact.longitude ?? 0.0,
|
contact.longitude ?? 0.0,
|
||||||
"Type: ${contact.typeLabel}\nPublic Key: ${contact.publicKeyHex}",
|
"Type: ${contact.typeLabelRaw}\nPublic Key: ${contact.publicKeyHex}",
|
||||||
url,
|
url,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import 'package:provider/provider.dart';
|
|||||||
import '../connector/meshcore_connector.dart';
|
import '../connector/meshcore_connector.dart';
|
||||||
import '../l10n/l10n.dart';
|
import '../l10n/l10n.dart';
|
||||||
import '../models/contact.dart';
|
import '../models/contact.dart';
|
||||||
|
import '../l10n/contact_localization.dart';
|
||||||
import '../helpers/path_helper.dart';
|
import '../helpers/path_helper.dart';
|
||||||
import '../services/path_history_service.dart';
|
import '../services/path_history_service.dart';
|
||||||
import '../helpers/snack_bar_builder.dart';
|
import '../helpers/snack_bar_builder.dart';
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:meshcore_open/connector/meshcore_protocol.dart';
|
import 'package:meshcore_open/connector/meshcore_protocol.dart';
|
||||||
import '../l10n/l10n.dart';
|
import '../l10n/l10n.dart';
|
||||||
import '../models/contact.dart';
|
import '../models/contact.dart';
|
||||||
|
import '../l10n/contact_localization.dart';
|
||||||
import '../helpers/snack_bar_builder.dart';
|
import '../helpers/snack_bar_builder.dart';
|
||||||
|
|
||||||
class PathSelectionDialog extends StatefulWidget {
|
class PathSelectionDialog extends StatefulWidget {
|
||||||
@@ -311,7 +312,7 @@ class _PathSelectionDialogState extends State<PathSelectionDialog> {
|
|||||||
style: const TextStyle(fontSize: 14),
|
style: const TextStyle(fontSize: 14),
|
||||||
),
|
),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
'${contact.typeLabelLocalized(l10n)} • ${contact.publicKeyHex.substring(0, 2)}',
|
'${contact.typeLabel(l10n)} • ${contact.publicKeyHex.substring(0, 2)}',
|
||||||
style: const TextStyle(fontSize: 10),
|
style: const TextStyle(fontSize: 10),
|
||||||
),
|
),
|
||||||
trailing: isSelected
|
trailing: isSelected
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import '../l10n/l10n.dart';
|
import '../l10n/l10n.dart';
|
||||||
import '../models/contact.dart';
|
import '../models/contact.dart';
|
||||||
|
import '../l10n/contact_localization.dart';
|
||||||
import '../services/storage_service.dart';
|
import '../services/storage_service.dart';
|
||||||
import '../connector/meshcore_connector.dart';
|
import '../connector/meshcore_connector.dart';
|
||||||
import '../connector/meshcore_protocol.dart';
|
import '../connector/meshcore_protocol.dart';
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import '../l10n/l10n.dart';
|
import '../l10n/l10n.dart';
|
||||||
import '../models/contact.dart';
|
import '../models/contact.dart';
|
||||||
|
import '../l10n/contact_localization.dart';
|
||||||
import '../services/storage_service.dart';
|
import '../services/storage_service.dart';
|
||||||
import '../connector/meshcore_connector.dart';
|
import '../connector/meshcore_connector.dart';
|
||||||
import '../connector/meshcore_protocol.dart';
|
import '../connector/meshcore_protocol.dart';
|
||||||
|
|||||||
Reference in New Issue
Block a user