Merge remote-tracking branch 'origin/main' into dev-pathtrace

This commit is contained in:
Zach
2026-01-28 21:43:07 -07:00
32 changed files with 9713 additions and 587 deletions
File diff suppressed because one or more lines are too long
+1
View File
@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig" #include "Generated.xcconfig"
+1
View File
@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig" #include "Generated.xcconfig"
+152
View File
@@ -0,0 +1,152 @@
PODS:
- Flutter (1.0.0)
- flutter_blue_plus_darwin (0.0.2):
- Flutter
- FlutterMacOS
- flutter_foreground_task (0.0.1):
- Flutter
- flutter_local_notifications (0.0.1):
- Flutter
- GoogleDataTransport (10.1.0):
- nanopb (~> 3.30910.0)
- PromisesObjC (~> 2.4)
- GoogleMLKit/BarcodeScanning (7.0.0):
- GoogleMLKit/MLKitCore
- MLKitBarcodeScanning (~> 6.0.0)
- GoogleMLKit/MLKitCore (7.0.0):
- MLKitCommon (~> 12.0.0)
- GoogleToolboxForMac/Defines (4.2.1)
- GoogleToolboxForMac/Logger (4.2.1):
- GoogleToolboxForMac/Defines (= 4.2.1)
- "GoogleToolboxForMac/NSData+zlib (4.2.1)":
- GoogleToolboxForMac/Defines (= 4.2.1)
- GoogleUtilities/Environment (8.1.0):
- GoogleUtilities/Privacy
- GoogleUtilities/Logger (8.1.0):
- GoogleUtilities/Environment
- GoogleUtilities/Privacy
- GoogleUtilities/Privacy (8.1.0)
- GoogleUtilities/UserDefaults (8.1.0):
- GoogleUtilities/Logger
- GoogleUtilities/Privacy
- GTMSessionFetcher/Core (3.5.0)
- MLImage (1.0.0-beta6)
- MLKitBarcodeScanning (6.0.0):
- MLKitCommon (~> 12.0)
- MLKitVision (~> 8.0)
- MLKitCommon (12.0.0):
- GoogleDataTransport (~> 10.0)
- GoogleToolboxForMac/Logger (< 5.0, >= 4.2.1)
- "GoogleToolboxForMac/NSData+zlib (< 5.0, >= 4.2.1)"
- GoogleUtilities/Logger (~> 8.0)
- GoogleUtilities/UserDefaults (~> 8.0)
- GTMSessionFetcher/Core (< 4.0, >= 3.3.2)
- MLKitVision (8.0.0):
- GoogleToolboxForMac/Logger (< 5.0, >= 4.2.1)
- "GoogleToolboxForMac/NSData+zlib (< 5.0, >= 4.2.1)"
- GTMSessionFetcher/Core (< 4.0, >= 3.3.2)
- MLImage (= 1.0.0-beta6)
- MLKitCommon (~> 12.0)
- mobile_scanner (6.0.2):
- Flutter
- GoogleMLKit/BarcodeScanning (~> 7.0.0)
- nanopb (3.30910.0):
- nanopb/decode (= 3.30910.0)
- nanopb/encode (= 3.30910.0)
- nanopb/decode (3.30910.0)
- nanopb/encode (3.30910.0)
- package_info_plus (0.4.5):
- Flutter
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- PromisesObjC (2.4.0)
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- sqflite_darwin (0.0.4):
- Flutter
- FlutterMacOS
- url_launcher_ios (0.0.1):
- Flutter
- wakelock_plus (0.0.1):
- Flutter
DEPENDENCIES:
- Flutter (from `Flutter`)
- flutter_blue_plus_darwin (from `.symlinks/plugins/flutter_blue_plus_darwin/darwin`)
- flutter_foreground_task (from `.symlinks/plugins/flutter_foreground_task/ios`)
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
- mobile_scanner (from `.symlinks/plugins/mobile_scanner/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
SPEC REPOS:
trunk:
- GoogleDataTransport
- GoogleMLKit
- GoogleToolboxForMac
- GoogleUtilities
- GTMSessionFetcher
- MLImage
- MLKitBarcodeScanning
- MLKitCommon
- MLKitVision
- nanopb
- PromisesObjC
EXTERNAL SOURCES:
Flutter:
:path: Flutter
flutter_blue_plus_darwin:
:path: ".symlinks/plugins/flutter_blue_plus_darwin/darwin"
flutter_foreground_task:
:path: ".symlinks/plugins/flutter_foreground_task/ios"
flutter_local_notifications:
:path: ".symlinks/plugins/flutter_local_notifications/ios"
mobile_scanner:
:path: ".symlinks/plugins/mobile_scanner/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
sqflite_darwin:
:path: ".symlinks/plugins/sqflite_darwin/darwin"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
wakelock_plus:
:path: ".symlinks/plugins/wakelock_plus/ios"
SPEC CHECKSUMS:
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
flutter_blue_plus_darwin: 20a08bfeaa0f7804d524858d3d8744bcc1b6dbc3
flutter_foreground_task: a159d2c2173b33699ddb3e6c2a067045d7cebb89
flutter_local_notifications: 395056b3175ba4f08480a7c5de30cd36d69827e4
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
GoogleMLKit: eff9e23ec1d90ea4157a1ee2e32a4f610c5b3318
GoogleToolboxForMac: d1a2cbf009c453f4d6ded37c105e2f67a32206d8
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6
MLImage: 0ad1c5f50edd027672d8b26b0fee78a8b4a0fc56
MLKitBarcodeScanning: 0a3064da0a7f49ac24ceb3cb46a5bc67496facd2
MLKitCommon: 07c2c33ae5640e5380beaaa6e4b9c249a205542d
MLKitVision: 45e79d68845a2de77e2dd4d7f07947f0ed157b0e
mobile_scanner: af8f71879eaba2bbcb4d86c6a462c3c0e7f23036
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
PODFILE CHECKSUM: 570da2a631486c6bd6496bed1e605e63e2471be5
COCOAPODS: 1.16.2
+74 -6
View File
@@ -14,6 +14,7 @@
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
9A698254711B63C3940A64CB /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4268181FCF3E12817B700E9C /* libPods-Runner.a */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@@ -42,9 +43,13 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
24A76623340E493BD4C25C5C /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; }; 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
40AC50CE3E1D4278E82498CF /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
4268181FCF3E12817B700E9C /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
718BC7DCCFC5C370705C12E5 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
@@ -62,6 +67,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
9A698254711B63C3940A64CB /* libPods-Runner.a in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -94,6 +100,8 @@
97C146F01CF9000F007C117D /* Runner */, 97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */, 97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */, 331C8082294A63A400263BE5 /* RunnerTests */,
DEE6F094D3B70E76087722E1 /* Pods */,
DAE613E34DF694C2E33B64C7 /* Frameworks */,
); );
sourceTree = "<group>"; sourceTree = "<group>";
}; };
@@ -121,6 +129,25 @@
path = Runner; path = Runner;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
DAE613E34DF694C2E33B64C7 /* Frameworks */ = {
isa = PBXGroup;
children = (
4268181FCF3E12817B700E9C /* libPods-Runner.a */,
);
name = Frameworks;
sourceTree = "<group>";
};
DEE6F094D3B70E76087722E1 /* Pods */ = {
isa = PBXGroup;
children = (
40AC50CE3E1D4278E82498CF /* Pods-Runner.debug.xcconfig */,
24A76623340E493BD4C25C5C /* Pods-Runner.release.xcconfig */,
718BC7DCCFC5C370705C12E5 /* Pods-Runner.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
@@ -145,12 +172,14 @@
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = ( buildPhases = (
DE3B2E091393835C0B38492E /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */, 9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */, 97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */, 97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */, 97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */, 9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
B788CEDB957A87EE8AC593BB /* [CP] Copy Pods Resources */,
); );
buildRules = ( buildRules = (
); );
@@ -253,6 +282,45 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
}; };
B788CEDB957A87EE8AC593BB /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
DE3B2E091393835C0B38492E /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
@@ -368,7 +436,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.meshcore.meshcoreOpen; PRODUCT_BUNDLE_IDENTIFIER = com.monitormx.meshcoreopen;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
@@ -384,7 +452,7 @@
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.meshcore.meshcoreOpen.RunnerTests; PRODUCT_BUNDLE_IDENTIFIER = com.monitormx.meshcoreopen.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -401,7 +469,7 @@
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.meshcore.meshcoreOpen.RunnerTests; PRODUCT_BUNDLE_IDENTIFIER = com.monitormx.meshcoreopen.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@@ -416,7 +484,7 @@
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.meshcore.meshcoreOpen.RunnerTests; PRODUCT_BUNDLE_IDENTIFIER = com.monitormx.meshcoreopen.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@@ -547,7 +615,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.meshcore.meshcoreOpen; PRODUCT_BUNDLE_IDENTIFIER = com.monitormx.meshcoreopen;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -569,7 +637,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.meshcore.meshcoreOpen; PRODUCT_BUNDLE_IDENTIFIER = com.monitormx.meshcoreopen;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
+3
View File
@@ -4,4 +4,7 @@
<FileRef <FileRef
location = "group:Runner.xcodeproj"> location = "group:Runner.xcodeproj">
</FileRef> </FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace> </Workspace>
+37 -1
View File
@@ -146,6 +146,7 @@ class MeshCoreConnector extends ChangeNotifier {
final Set<String> _knownContactKeys = {}; final Set<String> _knownContactKeys = {};
final Map<String, int> _contactLastReadMs = {}; final Map<String, int> _contactLastReadMs = {};
final Map<int, int> _channelLastReadMs = {}; final Map<int, int> _channelLastReadMs = {};
bool _unreadStateLoaded = false;
final Map<String, _RepeaterAckContext> _pendingRepeaterAcks = {}; final Map<String, _RepeaterAckContext> _pendingRepeaterAcks = {};
String? _activeContactKey; String? _activeContactKey;
int? _activeChannelIndex; int? _activeChannelIndex;
@@ -317,6 +318,7 @@ class MeshCoreConnector extends ChangeNotifier {
} }
int getUnreadCountForContactKey(String contactKeyHex) { int getUnreadCountForContactKey(String contactKeyHex) {
if (!_unreadStateLoaded) return 0;
if (!_shouldTrackUnreadForContactKey(contactKeyHex)) return 0; if (!_shouldTrackUnreadForContactKey(contactKeyHex)) return 0;
final messages = _conversations[contactKeyHex]; final messages = _conversations[contactKeyHex];
if (messages == null || messages.isEmpty) return 0; if (messages == null || messages.isEmpty) return 0;
@@ -336,6 +338,7 @@ class MeshCoreConnector extends ChangeNotifier {
} }
int getUnreadCountForChannelIndex(int channelIndex) { int getUnreadCountForChannelIndex(int channelIndex) {
if (!_unreadStateLoaded) return 0;
final messages = _channelMessages[channelIndex]; final messages = _channelMessages[channelIndex];
if (messages == null || messages.isEmpty) return 0; if (messages == null || messages.isEmpty) return 0;
final lastReadMs = _channelLastReadMs[channelIndex] ?? 0; final lastReadMs = _channelLastReadMs[channelIndex] ?? 0;
@@ -350,6 +353,7 @@ class MeshCoreConnector extends ChangeNotifier {
} }
int getTotalUnreadCount() { int getTotalUnreadCount() {
if (!_unreadStateLoaded) return 0;
var total = 0; var total = 0;
// Count unread contact messages // Count unread contact messages
for (final contact in _contacts) { for (final contact in _contacts) {
@@ -381,6 +385,7 @@ class MeshCoreConnector extends ChangeNotifier {
_channelLastReadMs _channelLastReadMs
..clear() ..clear()
..addAll(await _unreadStore.loadChannelLastRead()); ..addAll(await _unreadStore.loadChannelLastRead());
_unreadStateLoaded = true;
notifyListeners(); notifyListeners();
} }
@@ -620,6 +625,32 @@ class MeshCoreConnector extends ChangeNotifier {
_scanResults.clear(); _scanResults.clear();
_setState(MeshCoreConnectionState.scanning); _setState(MeshCoreConnectionState.scanning);
// Ensure any previous scan is fully stopped
await FlutterBluePlus.stopScan();
await _scanSubscription?.cancel();
// On iOS/macOS, wait for Bluetooth to be powered on before scanning
if (defaultTargetPlatform == TargetPlatform.iOS ||
defaultTargetPlatform == TargetPlatform.macOS) {
// Wait for adapter state to be powered on
final adapterState = await FlutterBluePlus.adapterState.first;
if (adapterState != BluetoothAdapterState.on) {
// Wait for the adapter to turn on, with timeout
await FlutterBluePlus.adapterState
.firstWhere((state) => state == BluetoothAdapterState.on)
.timeout(
const Duration(seconds: 5),
onTimeout: () {
_setState(MeshCoreConnectionState.disconnected);
throw Exception('Bluetooth adapter not available');
},
);
}
// Add a small delay to allow BLE stack to fully initialize
await Future.delayed(const Duration(milliseconds: 300));
}
_scanSubscription = FlutterBluePlus.scanResults.listen((results) { _scanSubscription = FlutterBluePlus.scanResults.listen((results) {
_scanResults.clear(); _scanResults.clear();
for (var result in results) { for (var result in results) {
@@ -928,7 +959,12 @@ class MeshCoreConnector extends ChangeNotifier {
if (!isConnected) return; if (!isConnected) return;
if (_batteryRequested && !force) return; if (_batteryRequested && !force) return;
_batteryRequested = true; _batteryRequested = true;
await sendFrame(buildGetBattAndStorageFrame()); try {
await sendFrame(buildGetBattAndStorageFrame());
} catch (e) {
// Connection likely lost - trigger disconnection handling
_handleDisconnection();
}
} }
void _startBatteryPolling() { void _startBatteryPolling() {
+68
View File
@@ -0,0 +1,68 @@
import 'package:flutter/material.dart';
class ChatScrollController extends ScrollController {
final ValueNotifier<bool> showJumpToBottom = ValueNotifier(false);
VoidCallback? onScrollNearTop;
static const _bottomThreshold = 100.0;
static const _topThreshold = 50.0;
ChatScrollController() {
addListener(_handleScroll);
}
void _handleScroll() {
if (!hasClients) return;
final pos = position;
// With reverse: true, position 0 is bottom, maxScrollExtent is top
// Show jump button when scrolled away from bottom (position > threshold)
final isAtBottom = pos.pixels <= _bottomThreshold;
if (showJumpToBottom.value == isAtBottom) {
showJumpToBottom.value = !isAtBottom;
}
// Pagination trigger when scrolled near top (maxScrollExtent)
if (pos.pixels >= pos.maxScrollExtent - _topThreshold) {
onScrollNearTop?.call();
}
}
void jumpToBottom() {
if (hasClients && position.maxScrollExtent > 0) {
animateTo(
0, // With reverse: true, position 0 is bottom
duration: const Duration(milliseconds: 300),
curve: Curves.easeOut,
);
}
}
void handleKeyboardOpen() {
// Simple: just scroll to bottom when keyboard opens
if (hasClients) {
animateTo(
0, // With reverse: true, position 0 is bottom
duration: const Duration(milliseconds: 200),
curve: Curves.easeOut,
);
}
}
void scrollToBottomIfAtBottom() {
// Only scroll if jump button is NOT showing (i.e., already at bottom)
if (!showJumpToBottom.value && hasClients && position.maxScrollExtent > 0) {
animateTo(
0, // With reverse: true, position 0 is bottom
duration: const Duration(milliseconds: 200),
curve: Curves.easeOut,
);
}
}
@override
void dispose() {
showJumpToBottom.dispose();
super.dispose();
}
}
+26 -26
View File
@@ -104,7 +104,7 @@
"settings_timeSynchronized": "Synchronisation temporelle", "settings_timeSynchronized": "Synchronisation temporelle",
"settings_refreshContacts": "Rafraîchir les Contacts", "settings_refreshContacts": "Rafraîchir les Contacts",
"settings_refreshContactsSubtitle": "Recharger la liste des contacts depuis l'appareil", "settings_refreshContactsSubtitle": "Recharger la liste des contacts depuis l'appareil",
"settings_rebootDevice": "Réinitialiser l'appareil", "settings_rebootDevice": "Redémarrer l'appareil",
"settings_rebootDeviceSubtitle": "Redémarrer l'appareil MeshCore", "settings_rebootDeviceSubtitle": "Redémarrer l'appareil MeshCore",
"settings_rebootDeviceConfirm": "Êtes-vous sûr de vouloir redémarrer l'appareil ? Vous serez déconnecté.", "settings_rebootDeviceConfirm": "Êtes-vous sûr de vouloir redémarrer l'appareil ? Vous serez déconnecté.",
"settings_debug": "Déboguer", "settings_debug": "Déboguer",
@@ -279,7 +279,7 @@
} }
} }
}, },
"contacts_newGroup": "Nouvelle Groupe", "contacts_newGroup": "Nouveau Groupe",
"contacts_groupName": "Nom du groupe", "contacts_groupName": "Nom du groupe",
"contacts_groupNameRequired": "Le nom du groupe est obligatoire.", "contacts_groupNameRequired": "Le nom du groupe est obligatoire.",
"contacts_groupAlreadyExists": "Le groupe \"{name}\" existe déjà.", "contacts_groupAlreadyExists": "Le groupe \"{name}\" existe déjà.",
@@ -293,8 +293,8 @@
"contacts_filterContacts": "Filtrer les contacts...", "contacts_filterContacts": "Filtrer les contacts...",
"contacts_noContactsMatchFilter": "Aucun contact ne correspond à votre filtre.", "contacts_noContactsMatchFilter": "Aucun contact ne correspond à votre filtre.",
"contacts_noMembers": "Aucun membre", "contacts_noMembers": "Aucun membre",
"contacts_lastSeenNow": "Dernière fois vu maintenant", "contacts_lastSeenNow": "Vu maintenant",
"contacts_lastSeenMinsAgo": "Dernière fois vu il y a {minutes} minutes.", "contacts_lastSeenMinsAgo": "Vu il y a {minutes} minutes",
"@contacts_lastSeenMinsAgo": { "@contacts_lastSeenMinsAgo": {
"placeholders": { "placeholders": {
"minutes": { "minutes": {
@@ -302,8 +302,8 @@
} }
} }
}, },
"contacts_lastSeenHourAgo": "Dernière fois vu il y a 1 heure.", "contacts_lastSeenHourAgo": "Vu il y a 1 heure",
"contacts_lastSeenHoursAgo": "Dernière fois vu il y a {hours} heures.", "contacts_lastSeenHoursAgo": "Vu il y a {hours} heures",
"@contacts_lastSeenHoursAgo": { "@contacts_lastSeenHoursAgo": {
"placeholders": { "placeholders": {
"hours": { "hours": {
@@ -311,8 +311,8 @@
} }
} }
}, },
"contacts_lastSeenDayAgo": "Dernière fois vu il y a 1 jour", "contacts_lastSeenDayAgo": "Vu il y a 1 jour",
"contacts_lastSeenDaysAgo": "Dernière activité il y a {days} jours", "contacts_lastSeenDaysAgo": "Vu il y a {days} jours",
"@contacts_lastSeenDaysAgo": { "@contacts_lastSeenDaysAgo": {
"placeholders": { "placeholders": {
"days": { "days": {
@@ -394,7 +394,7 @@
"channels_sortBy": "Trier par", "channels_sortBy": "Trier par",
"channels_sortManual": "Manuel", "channels_sortManual": "Manuel",
"channels_sortAZ": "A à Z", "channels_sortAZ": "A à Z",
"channels_sortLatestMessages": "Dernières messages", "channels_sortLatestMessages": "Derniers messages",
"channels_sortUnread": "Non lu", "channels_sortUnread": "Non lu",
"chat_noMessages": "Aucun message pour le moment.", "chat_noMessages": "Aucun message pour le moment.",
"chat_sendMessageToStart": "Envoyer un message pour commencer", "chat_sendMessageToStart": "Envoyer un message pour commencer",
@@ -436,7 +436,7 @@
"chat_messageCopied": "Message copié", "chat_messageCopied": "Message copié",
"chat_messageDeleted": "Message supprimé", "chat_messageDeleted": "Message supprimé",
"chat_retryingMessage": "Tentative de récupération.", "chat_retryingMessage": "Tentative de récupération.",
"chat_retryCount": "Réessayer {current}/{max}", "chat_retryCount": "Essai {current}/{max}",
"@chat_retryCount": { "@chat_retryCount": {
"placeholders": { "placeholders": {
"current": { "current": {
@@ -699,7 +699,7 @@
} }
} }
}, },
"mapCache_cachedTilesWithFailed": "Tiles mis en cache ({downloaded}) ({failed} ratés)", "mapCache_cachedTilesWithFailed": "Tuiles mis en cache ({downloaded}) ({failed} ratés)",
"@mapCache_cachedTilesWithFailed": { "@mapCache_cachedTilesWithFailed": {
"placeholders": { "placeholders": {
"downloaded": { "downloaded": {
@@ -746,7 +746,7 @@
} }
} }
}, },
"mapCache_boundsLabel": "N {north}, S {south}, E {east}, W {west}", "mapCache_boundsLabel": "N {north}, S {south}, E {east}, O {west}",
"@mapCache_boundsLabel": { "@mapCache_boundsLabel": {
"placeholders": { "placeholders": {
"north": { "north": {
@@ -763,7 +763,7 @@
} }
} }
}, },
"time_justNow": "Il y a tout juste maintenant", "time_justNow": "Maintenant",
"time_minutesAgo": "{minutes} minutes auparavant", "time_minutesAgo": "{minutes} minutes auparavant",
"@time_minutesAgo": { "@time_minutesAgo": {
"placeholders": { "placeholders": {
@@ -911,7 +911,7 @@
"repeater_packetStatistics": "Statistiques des paquets", "repeater_packetStatistics": "Statistiques des paquets",
"repeater_sent": "Envoyé", "repeater_sent": "Envoyé",
"repeater_received": "Reçu", "repeater_received": "Reçu",
"repeater_duplicates": "Dupliques", "repeater_duplicates": "Doublons",
"repeater_daysHoursMinsSecs": "{days} jours {hours}h {minutes}m {seconds}s", "repeater_daysHoursMinsSecs": "{days} jours {hours}h {minutes}m {seconds}s",
"@repeater_daysHoursMinsSecs": { "@repeater_daysHoursMinsSecs": {
"placeholders": { "placeholders": {
@@ -1024,7 +1024,7 @@
} }
}, },
"repeater_encryptedAdvertInterval": "Intervalle d'annonces cryptées", "repeater_encryptedAdvertInterval": "Intervalle d'annonces cryptées",
"repeater_dangerZone": "Zone d'alerte", "repeater_dangerZone": "Zone dangereuse",
"repeater_rebootRepeater": "Redémarrer Répéteur", "repeater_rebootRepeater": "Redémarrer Répéteur",
"repeater_rebootRepeaterSubtitle": "Réinitialiser l'appareil répétiteur", "repeater_rebootRepeaterSubtitle": "Réinitialiser l'appareil répétiteur",
"repeater_rebootRepeaterConfirm": "Êtes-vous sûr de vouloir redémarrer ce répétiteur ?", "repeater_rebootRepeaterConfirm": "Êtes-vous sûr de vouloir redémarrer ce répétiteur ?",
@@ -1120,7 +1120,7 @@
"repeater_cliHelpSetAf": "Définit le facteur de temps d'air.", "repeater_cliHelpSetAf": "Définit le facteur de temps d'air.",
"repeater_cliHelpSetTx": "Définit la puissance de transmission LoRa en dBm (réinitialisation requise pour appliquer).", "repeater_cliHelpSetTx": "Définit la puissance de transmission LoRa en dBm (réinitialisation requise pour appliquer).",
"repeater_cliHelpSetRepeat": "Active ou désactive le rôle du répétiteur pour ce nœud.", "repeater_cliHelpSetRepeat": "Active ou désactive le rôle du répétiteur pour ce nœud.",
"repeater_cliHelpSetAllowReadOnly": "(Serveur de pièce) Si \"activé\", alors un mot de passe vide permettra la connexion, mais ne permettra pas de publier dans la pièce. (lecture seule uniquement)", "repeater_cliHelpSetAllowReadOnly": "(Room server) Si \"activé\", alors un mot de passe vide permettra la connexion, mais ne permettra pas de publier dans la pièce. (lecture seule uniquement)",
"repeater_cliHelpSetFloodMax": "Définit le nombre maximal de sauts pour les paquets de balayage entrants (si >= max, le paquet n'est pas acheminé).", "repeater_cliHelpSetFloodMax": "Définit le nombre maximal de sauts pour les paquets de balayage entrants (si >= max, le paquet n'est pas acheminé).",
"repeater_cliHelpSetIntThresh": "Définit le seuil d'interférence (en dB). La valeur par défaut est de 14. Définir sur 0 désactive la détection des interférences de canal.", "repeater_cliHelpSetIntThresh": "Définit le seuil d'interférence (en dB). La valeur par défaut est de 14. Définir sur 0 désactive la détection des interférences de canal.",
"repeater_cliHelpSetAgcResetInterval": "Définit l'intervalle pour réinitialiser le contrôleur de gain automatique. Mettez à 0 pour désactiver.", "repeater_cliHelpSetAgcResetInterval": "Définit l'intervalle pour réinitialiser le contrôleur de gain automatique. Mettez à 0 pour désactiver.",
@@ -1339,16 +1339,16 @@
"channelPath_unknownRepeater": "Répéteur Inconnu", "channelPath_unknownRepeater": "Répéteur Inconnu",
"listFilter_tooltip": "Filtrer et trier", "listFilter_tooltip": "Filtrer et trier",
"listFilter_sortBy": "Trier par", "listFilter_sortBy": "Trier par",
"listFilter_latestMessages": "Dernières messages", "listFilter_latestMessages": "Derniers messages",
"listFilter_heardRecently": "Écoute récemment", "listFilter_heardRecently": "Écoute récemment",
"listFilter_az": "A à Z", "listFilter_az": "A à Z",
"listFilter_filters": "Filtres", "listFilter_filters": "Filtres",
"listFilter_all": "Tout", "listFilter_all": "Tout",
"listFilter_users": "Utilisateurs", "listFilter_users": "Utilisateurs",
"listFilter_repeaters": "Répéteurs", "listFilter_repeaters": "Répéteurs",
"listFilter_roomServers": "Serveurs de pièce", "listFilter_roomServers": "Room servers",
"listFilter_unreadOnly": "Messages non lus seulement", "listFilter_unreadOnly": "Messages non lus seulement",
"listFilter_newGroup": "Nouvelle groupe", "listFilter_newGroup": "Nouveau groupe",
"@neighbors_errorLoading": { "@neighbors_errorLoading": {
"placeholders": { "placeholders": {
"error": { "error": {
@@ -1374,7 +1374,7 @@
"channels_scanQrCode": "Scanner un code QR", "channels_scanQrCode": "Scanner un code QR",
"channels_scanQrCodeComingSoon": "Bientôt disponible", "channels_scanQrCodeComingSoon": "Bientôt disponible",
"channels_enterHashtag": "Entrez le hashtag", "channels_enterHashtag": "Entrez le hashtag",
"channels_hashtagHint": "ex. #équipe", "channels_hashtagHint": "ex. #equipe",
"@neighbors_unknownContact": { "@neighbors_unknownContact": {
"placeholders": { "placeholders": {
"pubkey": { "pubkey": {
@@ -1391,11 +1391,11 @@
}, },
"neighbors_unknownContact": "Clé publique inconnue {pubkey}", "neighbors_unknownContact": "Clé publique inconnue {pubkey}",
"neighbors_heardAgo": "Écouté : {time} auparavant", "neighbors_heardAgo": "Écouté : {time} auparavant",
"settings_locationGPSEnable": "Habilita GPS", "settings_locationGPSEnable": "Activer le GPS",
"settings_locationGPSEnableSubtitle": "Habilita la actualización automática de la ubicación mediante GPS.", "settings_locationGPSEnableSubtitle": "Activer la mise à jour automatique de la position via GPS",
"settings_locationIntervalSec": "Intervalo pour GPS (Segundos)", "settings_locationIntervalSec": "Intervalle de mise-à-jour du GPS (Secondes)",
"settings_locationIntervalInvalid": "El intervalo debe ser de al menos 60 segundos y menor que 86400 segundos.", "settings_locationIntervalInvalid": "L'intervalle doit être compris entre 60 et 86400 secondes.",
"contacts_manageRoom": "Gestionar Servidor de Habitación", "contacts_manageRoom": "Gérer le Room Server",
"room_management": "Administración del Servidor de Habitación", "room_management": "Administración del Servidor de Habitación",
"@community_joinConfirmation": { "@community_joinConfirmation": {
"placeholders": { "placeholders": {
@@ -1492,7 +1492,7 @@
}, },
"community_deleted": "Communauté \"{name}\" quittée", "community_deleted": "Communauté \"{name}\" quittée",
"community_addHashtagChannel": "Ajouter un Hashtag Communauté", "community_addHashtagChannel": "Ajouter un Hashtag Communauté",
"community_addHashtagChannelDesc": "Ajouter un canal hachage pour cette communauté", "community_addHashtagChannelDesc": "Ajouter un canal hashtag pour cette communauté",
"community_selectCommunity": "Sélectionner Communauté", "community_selectCommunity": "Sélectionner Communauté",
"community_regularHashtag": "Hashtag régulier", "community_regularHashtag": "Hashtag régulier",
"community_regularHashtagDesc": "Hashtag public (tout le monde peut rejoindre)", "community_regularHashtagDesc": "Hashtag public (tout le monde peut rejoindre)",
+10
View File
@@ -14,9 +14,11 @@ import 'app_localizations_it.dart';
import 'app_localizations_nl.dart'; import 'app_localizations_nl.dart';
import 'app_localizations_pl.dart'; import 'app_localizations_pl.dart';
import 'app_localizations_pt.dart'; import 'app_localizations_pt.dart';
import 'app_localizations_ru.dart';
import 'app_localizations_sk.dart'; import 'app_localizations_sk.dart';
import 'app_localizations_sl.dart'; import 'app_localizations_sl.dart';
import 'app_localizations_sv.dart'; import 'app_localizations_sv.dart';
import 'app_localizations_uk.dart';
import 'app_localizations_zh.dart'; import 'app_localizations_zh.dart';
// ignore_for_file: type=lint // ignore_for_file: type=lint
@@ -114,9 +116,11 @@ abstract class AppLocalizations {
Locale('nl'), Locale('nl'),
Locale('pl'), Locale('pl'),
Locale('pt'), Locale('pt'),
Locale('ru'),
Locale('sk'), Locale('sk'),
Locale('sl'), Locale('sl'),
Locale('sv'), Locale('sv'),
Locale('uk'),
Locale('zh'), Locale('zh'),
]; ];
@@ -4705,9 +4709,11 @@ class _AppLocalizationsDelegate
'nl', 'nl',
'pl', 'pl',
'pt', 'pt',
'ru',
'sk', 'sk',
'sl', 'sl',
'sv', 'sv',
'uk',
'zh', 'zh',
].contains(locale.languageCode); ].contains(locale.languageCode);
@@ -4736,12 +4742,16 @@ AppLocalizations lookupAppLocalizations(Locale locale) {
return AppLocalizationsPl(); return AppLocalizationsPl();
case 'pt': case 'pt':
return AppLocalizationsPt(); return AppLocalizationsPt();
case 'ru':
return AppLocalizationsRu();
case 'sk': case 'sk':
return AppLocalizationsSk(); return AppLocalizationsSk();
case 'sl': case 'sl':
return AppLocalizationsSl(); return AppLocalizationsSl();
case 'sv': case 'sv':
return AppLocalizationsSv(); return AppLocalizationsSv();
case 'uk':
return AppLocalizationsUk();
case 'zh': case 'zh':
return AppLocalizationsZh(); return AppLocalizationsZh();
} }
+27 -26
View File
@@ -204,18 +204,19 @@ class AppLocalizationsFr extends AppLocalizations {
String get settings_locationInvalid => 'Latitude ou longitude invalide.'; String get settings_locationInvalid => 'Latitude ou longitude invalide.';
@override @override
String get settings_locationGPSEnable => 'Habilita GPS'; String get settings_locationGPSEnable => 'Activer le GPS';
@override @override
String get settings_locationGPSEnableSubtitle => String get settings_locationGPSEnableSubtitle =>
'Habilita la actualización automática de la ubicación mediante GPS.'; 'Activer la mise à jour automatique de la position via GPS';
@override @override
String get settings_locationIntervalSec => 'Intervalo pour GPS (Segundos)'; String get settings_locationIntervalSec =>
'Intervalle de mise-à-jour du GPS (Secondes)';
@override @override
String get settings_locationIntervalInvalid => String get settings_locationIntervalInvalid =>
'El intervalo debe ser de al menos 60 segundos y menor que 86400 segundos.'; 'L\'intervalle doit être compris entre 60 et 86400 secondes.';
@override @override
String get settings_latitude => 'Latitude'; String get settings_latitude => 'Latitude';
@@ -272,7 +273,7 @@ class AppLocalizationsFr extends AppLocalizations {
'Recharger la liste des contacts depuis l\'appareil'; 'Recharger la liste des contacts depuis l\'appareil';
@override @override
String get settings_rebootDevice => 'Réinitialiser l\'appareil'; String get settings_rebootDevice => 'Redémarrer l\'appareil';
@override @override
String get settings_rebootDeviceSubtitle => 'Redémarrer l\'appareil MeshCore'; String get settings_rebootDeviceSubtitle => 'Redémarrer l\'appareil MeshCore';
@@ -667,7 +668,7 @@ class AppLocalizationsFr extends AppLocalizations {
String get contacts_manageRepeater => 'Gérer le répétiteur'; String get contacts_manageRepeater => 'Gérer le répétiteur';
@override @override
String get contacts_manageRoom => 'Gestionar Servidor de Habitación'; String get contacts_manageRoom => 'Gérer le Room Server';
@override @override
String get contacts_roomLogin => 'Connexion Salle'; String get contacts_roomLogin => 'Connexion Salle';
@@ -687,7 +688,7 @@ class AppLocalizationsFr extends AppLocalizations {
} }
@override @override
String get contacts_newGroup => 'Nouvelle Groupe'; String get contacts_newGroup => 'Nouveau Groupe';
@override @override
String get contacts_groupName => 'Nom du groupe'; String get contacts_groupName => 'Nom du groupe';
@@ -711,27 +712,27 @@ class AppLocalizationsFr extends AppLocalizations {
String get contacts_noMembers => 'Aucun membre'; String get contacts_noMembers => 'Aucun membre';
@override @override
String get contacts_lastSeenNow => 'Dernière fois vu maintenant'; String get contacts_lastSeenNow => 'Vu maintenant';
@override @override
String contacts_lastSeenMinsAgo(int minutes) { String contacts_lastSeenMinsAgo(int minutes) {
return 'Dernière fois vu il y a $minutes minutes.'; return 'Vu il y a $minutes minutes';
} }
@override @override
String get contacts_lastSeenHourAgo => 'Dernière fois vu il y a 1 heure.'; String get contacts_lastSeenHourAgo => 'Vu il y a 1 heure';
@override @override
String contacts_lastSeenHoursAgo(int hours) { String contacts_lastSeenHoursAgo(int hours) {
return 'Dernière fois vu il y a $hours heures.'; return 'Vu il y a $hours heures';
} }
@override @override
String get contacts_lastSeenDayAgo => 'Dernière fois vu il y a 1 jour'; String get contacts_lastSeenDayAgo => 'Vu il y a 1 jour';
@override @override
String contacts_lastSeenDaysAgo(int days) { String contacts_lastSeenDaysAgo(int days) {
return 'Dernière activité il y a $days jours'; return 'Vu il y a $days jours';
} }
@override @override
@@ -845,7 +846,7 @@ class AppLocalizationsFr extends AppLocalizations {
String get channels_sortAZ => 'A à Z'; String get channels_sortAZ => 'A à Z';
@override @override
String get channels_sortLatestMessages => 'Dernières messages'; String get channels_sortLatestMessages => 'Derniers messages';
@override @override
String get channels_sortUnread => 'Non lu'; String get channels_sortUnread => 'Non lu';
@@ -888,7 +889,7 @@ class AppLocalizationsFr extends AppLocalizations {
String get channels_enterHashtag => 'Entrez le hashtag'; String get channels_enterHashtag => 'Entrez le hashtag';
@override @override
String get channels_hashtagHint => 'ex. #équipe'; String get channels_hashtagHint => 'ex. #equipe';
@override @override
String get chat_noMessages => 'Aucun message pour le moment.'; String get chat_noMessages => 'Aucun message pour le moment.';
@@ -936,7 +937,7 @@ class AppLocalizationsFr extends AppLocalizations {
@override @override
String chat_retryCount(int current, int max) { String chat_retryCount(int current, int max) {
return 'Réessayer $current/$max'; return 'Essai $current/$max';
} }
@override @override
@@ -1389,7 +1390,7 @@ class AppLocalizationsFr extends AppLocalizations {
@override @override
String mapCache_cachedTilesWithFailed(int downloaded, int failed) { String mapCache_cachedTilesWithFailed(int downloaded, int failed) {
return 'Tiles mis en cache ($downloaded) ($failed ratés)'; return 'Tuiles mis en cache ($downloaded) ($failed ratés)';
} }
@override @override
@@ -1443,11 +1444,11 @@ class AppLocalizationsFr extends AppLocalizations {
String east, String east,
String west, String west,
) { ) {
return 'N $north, S $south, E $east, W $west'; return 'N $north, S $south, E $east, O $west';
} }
@override @override
String get time_justNow => 'Il y a tout juste maintenant'; String get time_justNow => 'Maintenant';
@override @override
String time_minutesAgo(int minutes) { String time_minutesAgo(int minutes) {
@@ -1743,7 +1744,7 @@ class AppLocalizationsFr extends AppLocalizations {
String get repeater_received => 'Reçu'; String get repeater_received => 'Reçu';
@override @override
String get repeater_duplicates => 'Dupliques'; String get repeater_duplicates => 'Doublons';
@override @override
String repeater_daysHoursMinsSecs( String repeater_daysHoursMinsSecs(
@@ -1891,7 +1892,7 @@ class AppLocalizationsFr extends AppLocalizations {
'Intervalle d\'annonces cryptées'; 'Intervalle d\'annonces cryptées';
@override @override
String get repeater_dangerZone => 'Zone d\'alerte'; String get repeater_dangerZone => 'Zone dangereuse';
@override @override
String get repeater_rebootRepeater => 'Redémarrer Répéteur'; String get repeater_rebootRepeater => 'Redémarrer Répéteur';
@@ -2088,7 +2089,7 @@ class AppLocalizationsFr extends AppLocalizations {
@override @override
String get repeater_cliHelpSetAllowReadOnly => String get repeater_cliHelpSetAllowReadOnly =>
'(Serveur de pièce) Si \"activé\", alors un mot de passe vide permettra la connexion, mais ne permettra pas de publier dans la pièce. (lecture seule uniquement)'; '(Room server) Si \"activé\", alors un mot de passe vide permettra la connexion, mais ne permettra pas de publier dans la pièce. (lecture seule uniquement)';
@override @override
String get repeater_cliHelpSetFloodMax => String get repeater_cliHelpSetFloodMax =>
@@ -2632,7 +2633,7 @@ class AppLocalizationsFr extends AppLocalizations {
@override @override
String get community_addHashtagChannelDesc => String get community_addHashtagChannelDesc =>
'Ajouter un canal hachage pour cette communauté'; 'Ajouter un canal hashtag pour cette communauté';
@override @override
String get community_selectCommunity => 'Sélectionner Communauté'; String get community_selectCommunity => 'Sélectionner Communauté';
@@ -2663,7 +2664,7 @@ class AppLocalizationsFr extends AppLocalizations {
String get listFilter_sortBy => 'Trier par'; String get listFilter_sortBy => 'Trier par';
@override @override
String get listFilter_latestMessages => 'Dernières messages'; String get listFilter_latestMessages => 'Derniers messages';
@override @override
String get listFilter_heardRecently => 'Écoute récemment'; String get listFilter_heardRecently => 'Écoute récemment';
@@ -2684,11 +2685,11 @@ class AppLocalizationsFr extends AppLocalizations {
String get listFilter_repeaters => 'Répéteurs'; String get listFilter_repeaters => 'Répéteurs';
@override @override
String get listFilter_roomServers => 'Serveurs de pièce'; String get listFilter_roomServers => 'Room servers';
@override @override
String get listFilter_unreadOnly => 'Messages non lus seulement'; String get listFilter_unreadOnly => 'Messages non lus seulement';
@override @override
String get listFilter_newGroup => 'Nouvelle groupe'; String get listFilter_newGroup => 'Nouveau groupe';
} }
File diff suppressed because it is too large Load Diff
+170 -170
View File
@@ -12,7 +12,7 @@ class AppLocalizationsSl extends AppLocalizations {
String get appTitle => 'MeshCore Open'; String get appTitle => 'MeshCore Open';
@override @override
String get nav_contacts => 'Kontakti'; String get nav_contacts => 'Stiki';
@override @override
String get nav_channels => 'Kanali'; String get nav_channels => 'Kanali';
@@ -30,13 +30,13 @@ class AppLocalizationsSl extends AppLocalizations {
String get common_connect => 'Poveži se'; String get common_connect => 'Poveži se';
@override @override
String get common_unknownDevice => 'Nepoznano naprave'; String get common_unknownDevice => 'Nepoznane naprave';
@override @override
String get common_save => 'Shrani'; String get common_save => 'Shrani';
@override @override
String get common_delete => 'Izbrisati'; String get common_delete => 'Izbriši';
@override @override
String get common_close => 'Zapri'; String get common_close => 'Zapri';
@@ -51,7 +51,7 @@ class AppLocalizationsSl extends AppLocalizations {
String get common_settings => 'Nastavitve'; String get common_settings => 'Nastavitve';
@override @override
String get common_disconnect => 'Odklopiti'; String get common_disconnect => 'Odklopi';
@override @override
String get common_connected => 'Povezano'; String get common_connected => 'Povezano';
@@ -66,31 +66,31 @@ class AppLocalizationsSl extends AppLocalizations {
String get common_continue => 'Poudarki'; String get common_continue => 'Poudarki';
@override @override
String get common_share => 'Deliti'; String get common_share => 'Deli';
@override @override
String get common_copy => 'Kopiraj'; String get common_copy => 'Kopiraj';
@override @override
String get common_retry => 'Ponoviti'; String get common_retry => 'Ponovi';
@override @override
String get common_hide => 'Skrita'; String get common_hide => 'Skrita';
@override @override
String get common_remove => 'Izbrisati'; String get common_remove => 'Izbriši';
@override @override
String get common_enable => 'Omogoči'; String get common_enable => 'Omogoči';
@override @override
String get common_disable => 'Izklopiti'; String get common_disable => 'Izklopi';
@override @override
String get common_reboot => 'Ponoviti'; String get common_reboot => 'Ponovno zaženi';
@override @override
String get common_loading => 'Naložanje...'; String get common_loading => 'Nalaganje...';
@override @override
String get common_notAvailable => ''; String get common_notAvailable => '';
@@ -109,7 +109,7 @@ class AppLocalizationsSl extends AppLocalizations {
String get scanner_title => 'MeshCore Open'; String get scanner_title => 'MeshCore Open';
@override @override
String get scanner_scanning => 'Skeniram za naprave...'; String get scanner_scanning => 'Iščem naprave...';
@override @override
String get scanner_connecting => 'Povezujem se...'; String get scanner_connecting => 'Povezujem se...';
@@ -118,7 +118,7 @@ class AppLocalizationsSl extends AppLocalizations {
String get scanner_disconnecting => 'Odklapljam se...'; String get scanner_disconnecting => 'Odklapljam se...';
@override @override
String get scanner_notConnected => 'Nezavezan'; String get scanner_notConnected => 'Ni povezave';
@override @override
String scanner_connectedTo(String deviceName) { String scanner_connectedTo(String deviceName) {
@@ -134,7 +134,7 @@ class AppLocalizationsSl extends AppLocalizations {
@override @override
String scanner_connectionFailed(String error) { String scanner_connectionFailed(String error) {
return 'Pošlo je z povezavo: $error'; return 'Napaka pri povezavi: $error';
} }
@override @override
@@ -144,7 +144,7 @@ class AppLocalizationsSl extends AppLocalizations {
String get scanner_scan => 'Skeniraj'; String get scanner_scan => 'Skeniraj';
@override @override
String get device_quickSwitch => 'Hitro preklopiti'; String get device_quickSwitch => 'Hitri preklop';
@override @override
String get device_meshcore => 'MeshCore'; String get device_meshcore => 'MeshCore';
@@ -153,7 +153,7 @@ class AppLocalizationsSl extends AppLocalizations {
String get settings_title => 'Nastavitve'; String get settings_title => 'Nastavitve';
@override @override
String get settings_deviceInfo => 'Informacije o napravei'; String get settings_deviceInfo => 'Informacije o napravi';
@override @override
String get settings_appSettings => 'Nastavitve aplikacije'; String get settings_appSettings => 'Nastavitve aplikacije';
@@ -163,16 +163,16 @@ class AppLocalizationsSl extends AppLocalizations {
'Obveščanja, sporoščanje in zemljevidi.'; 'Obveščanja, sporoščanje in zemljevidi.';
@override @override
String get settings_nodeSettings => 'Nastavitve časa'; String get settings_nodeSettings => 'Nastavitev časa';
@override @override
String get settings_nodeName => 'Ime omrežno mesto'; String get settings_nodeName => 'Ime node-a';
@override @override
String get settings_nodeNameNotSet => 'Nezavedeno'; String get settings_nodeNameNotSet => 'Ni nastavljeno';
@override @override
String get settings_nodeNameHint => 'Vnesite ime časa'; String get settings_nodeNameHint => 'Vnesite ime node-a';
@override @override
String get settings_nodeNameUpdated => 'Ime posodobljeno'; String get settings_nodeNameUpdated => 'Ime posodobljeno';
@@ -182,7 +182,7 @@ class AppLocalizationsSl extends AppLocalizations {
@override @override
String get settings_radioSettingsSubtitle => String get settings_radioSettingsSubtitle =>
'Frekvenca, moč, razširni faktor'; 'Frekvenca, moč, razširitveni faktor';
@override @override
String get settings_radioSettingsUpdated => 'Radio nastavitve posodobljene'; String get settings_radioSettingsUpdated => 'Radio nastavitve posodobljene';
@@ -201,21 +201,21 @@ class AppLocalizationsSl extends AppLocalizations {
@override @override
String get settings_locationInvalid => String get settings_locationInvalid =>
'Neveljna zemeljska širina ali dolžina.'; 'Neveljavna zemeljska širina ali dolžina.';
@override @override
String get settings_locationGPSEnable => 'Omogoči GPS'; String get settings_locationGPSEnable => 'Omogoči GPS';
@override @override
String get settings_locationGPSEnableSubtitle => String get settings_locationGPSEnableSubtitle =>
'Omogoči samodejno posodabljanje lokacije z GPS-jem.'; 'Omogoči samodejno posodabljanje lokacije z GPS-om.';
@override @override
String get settings_locationIntervalSec => 'Interval za GPS (Sekunde)'; String get settings_locationIntervalSec => 'Interval za GPS (sekunde)';
@override @override
String get settings_locationIntervalInvalid => String get settings_locationIntervalInvalid =>
'Intervallo mora biti vsaj 60 sekund in manj kot 86400 sekund.'; 'Interval mora biti med 60 in 86400 sekund.';
@override @override
String get settings_latitude => 'Širina'; String get settings_latitude => 'Širina';
@@ -224,7 +224,7 @@ class AppLocalizationsSl extends AppLocalizations {
String get settings_longitude => 'Dolžina'; String get settings_longitude => 'Dolžina';
@override @override
String get settings_privacyMode => 'Mod podjetja'; String get settings_privacyMode => 'Zasebnost';
@override @override
String get settings_privacyModeSubtitle => 'Skrita imena/lokacije v oglasih'; String get settings_privacyModeSubtitle => 'Skrita imena/lokacije v oglasih';
@@ -234,16 +234,16 @@ class AppLocalizationsSl extends AppLocalizations {
'Omogoči način zasebnosti, da skrijemo tvoje ime in lokacijo v oglasih.'; 'Omogoči način zasebnosti, da skrijemo tvoje ime in lokacijo v oglasih.';
@override @override
String get settings_privacyModeEnabled => 'Privatni režim je omogočen.'; String get settings_privacyModeEnabled => 'Privatni način je omogočen.';
@override @override
String get settings_privacyModeDisabled => 'Privatni režim je onemogočen.'; String get settings_privacyModeDisabled => 'Privatni način je onemogočen.';
@override @override
String get settings_actions => 'Akcije'; String get settings_actions => 'Akcije';
@override @override
String get settings_sendAdvertisement => 'Pošlji Oglas'; String get settings_sendAdvertisement => 'Pošlji oglas';
@override @override
String get settings_sendAdvertisementSubtitle => String get settings_sendAdvertisementSubtitle =>
@@ -253,50 +253,50 @@ class AppLocalizationsSl extends AppLocalizations {
String get settings_advertisementSent => 'Oglas poslan'; String get settings_advertisementSent => 'Oglas poslan';
@override @override
String get settings_syncTime => 'Ugasniti čas'; String get settings_syncTime => 'Nastavi uro';
@override @override
String get settings_syncTimeSubtitle => 'Nastavi uro naprave v čas telefona'; String get settings_syncTimeSubtitle => 'Nastavi uro naprave na čas telefona';
@override @override
String get settings_timeSynchronized => 'Sinhronizirano po času'; String get settings_timeSynchronized => 'Ura sinhronizirana';
@override @override
String get settings_refreshContacts => 'Ponovno obišči kontakte'; String get settings_refreshContacts => 'Osveži stike';
@override @override
String get settings_refreshContactsSubtitle => String get settings_refreshContactsSubtitle =>
'Ponovno naloži seznam kontaktov iz naprave'; 'Ponovno naloži seznam stikov v napravi';
@override @override
String get settings_rebootDevice => 'Restart Naprave'; String get settings_rebootDevice => 'Ponovni zagon naprave';
@override @override
String get settings_rebootDeviceSubtitle => String get settings_rebootDeviceSubtitle =>
'Ponovite zažetek naprave MeshCore'; 'Ponovno zaženi MeshCore napravo';
@override @override
String get settings_rebootDeviceConfirm => String get settings_rebootDeviceConfirm =>
'Ste prepričani, da želite ponovno zagon napravke? Boste odvisni od omrežja.'; 'Ste prepričani, da želite ponovno zagnati napravo? Povezava bo prekinjena.';
@override @override
String get settings_debug => 'Napravi popravek'; String get settings_debug => 'Debug';
@override @override
String get settings_bleDebugLog => 'Logarjev zapis BLE'; String get settings_bleDebugLog => 'BLE debug log (razhroščevanje)';
@override @override
String get settings_bleDebugLogSubtitle => String get settings_bleDebugLogSubtitle =>
'Navodila BLE, odgovori in surovo podatkovno'; 'BLE ukazi, odgovori in surovi podatki';
@override @override
String get settings_appDebugLog => 'Log zapiske aplikacije'; String get settings_appDebugLog => 'Logi aplikacije';
@override @override
String get settings_appDebugLogSubtitle => 'Prijavni sporočila aplikacije'; String get settings_appDebugLogSubtitle => 'Debug sporočila aplikacije';
@override @override
String get settings_about => 'Oglejte si'; String get settings_about => 'O aplikaciji';
@override @override
String settings_aboutVersion(String version) { String settings_aboutVersion(String version) {
@@ -304,11 +304,11 @@ class AppLocalizationsSl extends AppLocalizations {
} }
@override @override
String get settings_aboutLegalese => 'MeshCore Odprtokodni Projekt 2024'; String get settings_aboutLegalese => 'Odprtokodni projekt MeshCore 2024';
@override @override
String get settings_aboutDescription => String get settings_aboutDescription =>
'Odprtokodni Flutter kličnik za naprave za LoRa mrežo MeshCore.'; 'Odprtokodni Flutter klient za naprave za LoRa omrežje MeshCore.';
@override @override
String get settings_infoName => 'Ime'; String get settings_infoName => 'Ime';
@@ -323,10 +323,10 @@ class AppLocalizationsSl extends AppLocalizations {
String get settings_infoBattery => 'Baterija'; String get settings_infoBattery => 'Baterija';
@override @override
String get settings_infoPublicKey => 'Ključ javnega tipa'; String get settings_infoPublicKey => 'Javni ključ';
@override @override
String get settings_infoContactsCount => 'Število kontaktov'; String get settings_infoContactsCount => 'Število stikov';
@override @override
String get settings_infoChannelCount => 'Število kanalov'; String get settings_infoChannelCount => 'Število kanalov';
@@ -350,7 +350,7 @@ class AppLocalizationsSl extends AppLocalizations {
String get settings_frequencyHelper => '300,00 - 2500,00'; String get settings_frequencyHelper => '300,00 - 2500,00';
@override @override
String get settings_frequencyInvalid => 'Neveljčna frekvenca (300-2500 MHz)'; String get settings_frequencyInvalid => 'Neveljavna frekvenca (300-2500 MHz)';
@override @override
String get settings_bandwidth => 'Pasovna širina'; String get settings_bandwidth => 'Pasovna širina';
@@ -359,7 +359,7 @@ class AppLocalizationsSl extends AppLocalizations {
String get settings_spreadingFactor => 'Razširitveni faktor'; String get settings_spreadingFactor => 'Razširitveni faktor';
@override @override
String get settings_codingRate => 'Programska hitrost'; String get settings_codingRate => 'Programska hitrost (CR)';
@override @override
String get settings_txPower => 'TX Moč (dBm)'; String get settings_txPower => 'TX Moč (dBm)';
@@ -368,13 +368,13 @@ class AppLocalizationsSl extends AppLocalizations {
String get settings_txPowerHelper => '0 - 22'; String get settings_txPowerHelper => '0 - 22';
@override @override
String get settings_txPowerInvalid => 'Neveljaven TX moč (0-22 dBm)'; String get settings_txPowerInvalid => 'Neveljavna TX moč (0-22 dBm)';
@override @override
String get settings_longRange => 'Dolenje območje'; String get settings_longRange => 'Dolg doseg';
@override @override
String get settings_fastSpeed => 'Hitra hitrost'; String get settings_fastSpeed => 'Visoka hitrost';
@override @override
String settings_error(String message) { String settings_error(String message) {
@@ -391,10 +391,10 @@ class AppLocalizationsSl extends AppLocalizations {
String get appSettings_theme => 'Tema'; String get appSettings_theme => 'Tema';
@override @override
String get appSettings_themeSystem => 'Predpomnilnik sistema'; String get appSettings_themeSystem => 'Sistemska tema';
@override @override
String get appSettings_themeLight => 'Luč'; String get appSettings_themeLight => 'Svetlo';
@override @override
String get appSettings_themeDark => 'Temno'; String get appSettings_themeDark => 'Temno';
@@ -445,10 +445,10 @@ class AppLocalizationsSl extends AppLocalizations {
String get appSettings_languageBg => 'Български'; String get appSettings_languageBg => 'Български';
@override @override
String get appSettings_notifications => 'Obveščanja'; String get appSettings_notifications => 'Obvestila';
@override @override
String get appSettings_enableNotifications => 'Omogoči obveščanje'; String get appSettings_enableNotifications => 'Omogoči obvestila';
@override @override
String get appSettings_enableNotificationsSubtitle => String get appSettings_enableNotificationsSubtitle =>
@@ -484,7 +484,7 @@ class AppLocalizationsSl extends AppLocalizations {
@override @override
String get appSettings_advertisementNotificationsSubtitle => String get appSettings_advertisementNotificationsSubtitle =>
'Pokaži obvestilo, ko so novi vozlišči odkrivljeni.'; 'Pokaži obvestilo, ko so najdene nove naprave.';
@override @override
String get appSettings_messaging => 'Komuniciranje'; String get appSettings_messaging => 'Komuniciranje';
@@ -499,18 +499,18 @@ class AppLocalizationsSl extends AppLocalizations {
@override @override
String get appSettings_pathsWillBeCleared => String get appSettings_pathsWillBeCleared =>
'Potnice bodo očiščene po 5 neuspešnih poskusih.'; 'Počisti pot po 5 neuspešnih poskusih.';
@override @override
String get appSettings_pathsWillNotBeCleared => String get appSettings_pathsWillNotBeCleared =>
'Potniški poti ne bodo samodejno čiščeni.'; 'Poti ne bodo samodejno čiščene.';
@override @override
String get appSettings_autoRouteRotation => 'Avtomatsko Občutke in Rotacije'; String get appSettings_autoRouteRotation => 'Avtomatsko rotacija prenosne poti';
@override @override
String get appSettings_autoRouteRotationSubtitle => String get appSettings_autoRouteRotationSubtitle =>
'Med spreminjanjem med najboljšimi potmi in plovilnim načinom'; 'Menjaj med boljšo potjo in flood načinom';
@override @override
String get appSettings_autoRouteRotationEnabled => String get appSettings_autoRouteRotationEnabled =>
@@ -524,16 +524,16 @@ class AppLocalizationsSl extends AppLocalizations {
String get appSettings_battery => 'Baterija'; String get appSettings_battery => 'Baterija';
@override @override
String get appSettings_batteryChemistry => 'Razem z možnostmi'; String get appSettings_batteryChemistry => 'Kemija baterije';
@override @override
String appSettings_batteryChemistryPerDevice(String deviceName) { String appSettings_batteryChemistryPerDevice(String deviceName) {
return 'Nastavitve za naprave ($deviceName)'; return 'Nastavitev za napravo ($deviceName)';
} }
@override @override
String get appSettings_batteryChemistryConnectFirst => String get appSettings_batteryChemistryConnectFirst =>
'Povežite se z napravo za izbiro'; 'Za izbiro se poveži z napravo';
@override @override
String get appSettings_batteryNmc => '18650 NMC (3,0-4,2V)'; String get appSettings_batteryNmc => '18650 NMC (3,0-4,2V)';
@@ -545,52 +545,52 @@ class AppLocalizationsSl extends AppLocalizations {
String get appSettings_batteryLipo => 'LiPo (3,0-4,2V)'; String get appSettings_batteryLipo => 'LiPo (3,0-4,2V)';
@override @override
String get appSettings_mapDisplay => 'Prikaz zemljevide'; String get appSettings_mapDisplay => 'Prikaz zemljevida';
@override @override
String get appSettings_showRepeaters => 'Prikaži ponovitve'; String get appSettings_showRepeaters => 'Prikaži repetitorje';
@override @override
String get appSettings_showRepeatersSubtitle => String get appSettings_showRepeatersSubtitle =>
'Prikaži ponovljalne notranjosti na zemljeploscu'; 'Prikaži repetitorje na mapi';
@override @override
String get appSettings_showChatNodes => 'Prikaži čakalne notranjosti'; String get appSettings_showChatNodes => 'Prikaži naprave za klepet';
@override @override
String get appSettings_showChatNodesSubtitle => String get appSettings_showChatNodesSubtitle =>
'Prikaži pogovorni pike na zemljeploscu'; 'Prikaži naprave na zemljevidu';
@override @override
String get appSettings_showOtherNodes => 'Pokaži druge vozlišča'; String get appSettings_showOtherNodes => 'Pokaži druge naprave';
@override @override
String get appSettings_showOtherNodesSubtitle => String get appSettings_showOtherNodesSubtitle =>
'Pokaži druge vrste notranjih elementov na zemljevalu.'; 'Pokaži druge vrste naprav na zemljevidu.';
@override @override
String get appSettings_timeFilter => 'Filtri po času'; String get appSettings_timeFilter => 'Filter po času';
@override @override
String get appSettings_timeFilterShowAll => 'Pokaži vse notranje elemente'; String get appSettings_timeFilterShowAll => 'Pokaži vse naprave';
@override @override
String appSettings_timeFilterShowLast(int hours) { String appSettings_timeFilterShowLast(int hours) {
return 'Pokaži notranjosti iz zadnjih $hours ur'; return 'Pokaži naprave v zadnjih $hours urah';
} }
@override @override
String get appSettings_mapTimeFilter => 'Filtri časa zemljevida'; String get appSettings_mapTimeFilter => 'Filter časa na zemljevidu';
@override @override
String get appSettings_showNodesDiscoveredWithin => String get appSettings_showNodesDiscoveredWithin =>
'Pokaži notranje čepke, odkrivene v:'; 'Pokaži naprave odkrite v:';
@override @override
String get appSettings_allTime => 'Vse čase'; String get appSettings_allTime => 'Brez omejitev';
@override @override
String get appSettings_lastHour => 'Minuto nazaj'; String get appSettings_lastHour => 'V zadnji uri';
@override @override
String get appSettings_last6Hours => 'Zadnjih 6 ur'; String get appSettings_last6Hours => 'Zadnjih 6 ur';
@@ -599,13 +599,13 @@ class AppLocalizationsSl extends AppLocalizations {
String get appSettings_last24Hours => 'Zadnjih 24 ur'; String get appSettings_last24Hours => 'Zadnjih 24 ur';
@override @override
String get appSettings_lastWeek => 'Lepošno'; String get appSettings_lastWeek => 'Prejšnji teden';
@override @override
String get appSettings_offlineMapCache => 'Omrezni Poudni Arhiv'; String get appSettings_offlineMapCache => 'Shramba zemljevidov brez povezave';
@override @override
String get appSettings_noAreaSelected => 'Nizkana označena površina'; String get appSettings_noAreaSelected => 'Območje ni izbrano';
@override @override
String appSettings_areaSelectedZoom(int minZoom, int maxZoom) { String appSettings_areaSelectedZoom(int minZoom, int maxZoom) {
@@ -613,79 +613,79 @@ class AppLocalizationsSl extends AppLocalizations {
} }
@override @override
String get appSettings_debugCard => 'Napravi popravek'; String get appSettings_debugCard => 'Razhroščevanje';
@override @override
String get appSettings_appDebugLogging => 'Programski Log'; String get appSettings_appDebugLogging => 'Programski dnevnik';
@override @override
String get appSettings_appDebugLoggingSubtitle => String get appSettings_appDebugLoggingSubtitle =>
'Log aplikacijske debug sporočila za odpravljanje težav'; 'Dnevnik debug sporočil za odpravljanje težav';
@override @override
String get appSettings_appDebugLoggingEnabled => String get appSettings_appDebugLoggingEnabled =>
'Omogočeno zaznamovanje napak v aplikaciji'; 'Beleženje napak v aplikaciji omogočeno';
@override @override
String get appSettings_appDebugLoggingDisabled => String get appSettings_appDebugLoggingDisabled =>
'Programski logi aplikacije so onemogočeni.'; 'Beleženje napak v aplikacije onemogočeno.';
@override @override
String get contacts_title => 'Kontakti'; String get contacts_title => 'Stiki';
@override @override
String get contacts_noContacts => 'Še ni kontaktov.'; String get contacts_noContacts => 'Ni stikov.';
@override @override
String get contacts_contactsWillAppear => String get contacts_contactsWillAppear =>
'Kontakti se bodo prikazali, ko naprave oglasijo.'; 'Stiki se bodo prikazali takoj, ko se naprave oglasijo.';
@override @override
String get contacts_searchContacts => 'Iskanje kontaktov...'; String get contacts_searchContacts => 'Iskanje stikov...';
@override @override
String get contacts_noUnreadContacts => 'Nerešeno kontaktov.'; String get contacts_noUnreadContacts => 'Ne prebrani stiki.';
@override @override
String get contacts_noContactsFound => String get contacts_noContactsFound =>
'Niti ena oseba ali skupine ni najdena.'; 'Stiki niso najdeni.';
@override @override
String get contacts_deleteContact => 'Izbrisati Kontakt'; String get contacts_deleteContact => 'Izbriši stik';
@override @override
String contacts_removeConfirm(String contactName) { String contacts_removeConfirm(String contactName) {
return 'Izbrisati $contactName iz kontaktov?'; return 'Izbrišem $contactName iz stikov?';
} }
@override @override
String get contacts_manageRepeater => 'Upravljajte Ponovitve'; String get contacts_manageRepeater => 'Upravljanje repetitorjev';
@override @override
String get contacts_manageRoom => 'Upravljajte strežnik sobe'; String get contacts_manageRoom => 'Upravljanje strežniške sobe';
@override @override
String get contacts_roomLogin => 'Vnos v sobo'; String get contacts_roomLogin => 'Prijava v sobo';
@override @override
String get contacts_openChat => 'Odprta kleta'; String get contacts_openChat => 'Odpri klepet';
@override @override
String get contacts_editGroup => 'Uredi Skupino'; String get contacts_editGroup => 'Uredi skupino';
@override @override
String get contacts_deleteGroup => 'Izbrisati Skupino'; String get contacts_deleteGroup => 'Izbriši skupino';
@override @override
String contacts_deleteGroupConfirm(String groupName) { String contacts_deleteGroupConfirm(String groupName) {
return 'Odpovedati $groupName?'; return 'Izbriši $groupName?';
} }
@override @override
String get contacts_newGroup => 'Novo skupino'; String get contacts_newGroup => 'Nova skupina';
@override @override
String get contacts_groupName => 'Skupina imena'; String get contacts_groupName => 'Ime skupine';
@override @override
String get contacts_groupNameRequired => 'Ime skupine je obvezno.'; String get contacts_groupNameRequired => 'Ime skupine je obvezno.';
@@ -696,53 +696,53 @@ class AppLocalizationsSl extends AppLocalizations {
} }
@override @override
String get contacts_filterContacts => 'Filtri kontakt\\,...'; String get contacts_filterContacts => 'Filtriraj stik\\,...';
@override @override
String get contacts_noContactsMatchFilter => String get contacts_noContactsMatchFilter =>
'Niti ena oseba ne ustreza vašemu kriteriju.'; 'Noben stik ne ustreza vašemu kriteriju.';
@override @override
String get contacts_noMembers => 'Nič članov.'; String get contacts_noMembers => 'Ni članov.';
@override @override
String get contacts_lastSeenNow => 'Datum zadnjega vpisa zdaj'; String get contacts_lastSeenNow => 'Nazadnje viden zdaj';
@override @override
String contacts_lastSeenMinsAgo(int minutes) { String contacts_lastSeenMinsAgo(int minutes) {
return 'Zadnjič videti $minutes minut nazaj'; return 'Zadnjič viden pred $minutes minutami';
} }
@override @override
String get contacts_lastSeenHourAgo => 'Zadnjič ogledan pred 1 uro.'; String get contacts_lastSeenHourAgo => 'Zadnjič viden pred 1 uro.';
@override @override
String contacts_lastSeenHoursAgo(int hours) { String contacts_lastSeenHoursAgo(int hours) {
return 'Zadnjič videti $hours ur nazaj'; return 'Zadnjič viden pred $hours urami';
} }
@override @override
String get contacts_lastSeenDayAgo => 'Zadnjič ogledan pred 1 dnem'; String get contacts_lastSeenDayAgo => 'Zadnjič viden pred 1 dnem';
@override @override
String contacts_lastSeenDaysAgo(int days) { String contacts_lastSeenDaysAgo(int days) {
return 'Zadnjič videti $days dni nazaj'; return 'Zadnjič viden pred $days dnem';
} }
@override @override
String get channels_title => 'Kanali'; String get channels_title => 'Kanali';
@override @override
String get channels_noChannelsConfigured => 'Nekonfigurirane kanale'; String get channels_noChannelsConfigured => 'Kanali še niso konfigurirani';
@override @override
String get channels_addPublicChannel => 'Dodaj Objavni Kanal'; String get channels_addPublicChannel => 'Dodaj javni kanal';
@override @override
String get channels_searchChannels => 'Poišči kanale...'; String get channels_searchChannels => 'Poišči kanale...';
@override @override
String get channels_noChannelsFound => 'Niti kanalov najti ni.'; String get channels_noChannelsFound => 'Ne najdem kanalov.';
@override @override
String channels_channelIndex(int index) { String channels_channelIndex(int index) {
@@ -753,16 +753,16 @@ class AppLocalizationsSl extends AppLocalizations {
String get channels_hashtagChannel => 'Hashtag kanal'; String get channels_hashtagChannel => 'Hashtag kanal';
@override @override
String get channels_public => 'javno'; String get channels_public => 'Javni';
@override @override
String get channels_private => 'Zasebno'; String get channels_private => 'Zasebni';
@override @override
String get channels_publicChannel => 'Ogljišna skupina'; String get channels_publicChannel => 'Javni kanal';
@override @override
String get channels_privateChannel => 'Zatemniščen kanal'; String get channels_privateChannel => 'Zasebni kanal';
@override @override
String get channels_editChannel => 'Uredi kanal'; String get channels_editChannel => 'Uredi kanal';
@@ -772,7 +772,7 @@ class AppLocalizationsSl extends AppLocalizations {
@override @override
String channels_deleteChannelConfirm(String name) { String channels_deleteChannelConfirm(String name) {
return 'Izbrisati \"$name\"? To se ne da povrniti.'; return 'Izbrišem \"$name\"? To se ne da povrniti.';
} }
@override @override
@@ -862,20 +862,20 @@ class AppLocalizationsSl extends AppLocalizations {
@override @override
String get channels_joinPublicChannelDesc => String get channels_joinPublicChannelDesc =>
'Kdor karkoli je, lahko se pridruži tej skupini.'; 'Kdorkoli se lahko pridruži tej skupini.';
@override @override
String get channels_joinHashtagChannel => 'Pridružite se Kanalu z Hashtagom'; String get channels_joinHashtagChannel => 'Pridružite se kanalu s hashtagom';
@override @override
String get channels_joinHashtagChannelDesc => String get channels_joinHashtagChannelDesc =>
'Kdor karkoli, lahko se pridruži hashtag kanalom.'; 'Kdorkoli se lahko pridruži hashtag kanalom.';
@override @override
String get channels_scanQrCode => 'Skeniraj QR kodo'; String get channels_scanQrCode => 'Skeniraj QR kodo';
@override @override
String get channels_scanQrCodeComingSoon => 'Prihajajoča'; String get channels_scanQrCodeComingSoon => 'Prihaja kmalu';
@override @override
String get channels_enterHashtag => 'Vnesite hashtag'; String get channels_enterHashtag => 'Vnesite hashtag';
@@ -895,7 +895,7 @@ class AppLocalizationsSl extends AppLocalizations {
@override @override
String chat_replyingTo(String name) { String chat_replyingTo(String name) {
return 'Odgovarjanje $name'; return 'Odgovori $name';
} }
@override @override
@@ -912,35 +912,35 @@ class AppLocalizationsSl extends AppLocalizations {
} }
@override @override
String get chat_typeMessage => 'Vnesite sporočilo...'; String get chat_typeMessage => 'Vnesi sporočilo...';
@override @override
String chat_messageTooLong(int maxBytes) { String chat_messageTooLong(int maxBytes) {
return 'Pošiljanje sporočila je onemogočeno, saj je preveliko (maksimalno $maxBytes bajt).'; return 'Pošiljanje sporočila je onemogočeno, saj je preveliko (maksimalno $maxBytes byte-ov).';
} }
@override @override
String get chat_messageCopied => 'Pošljeno sporočilo'; String get chat_messageCopied => 'Sporočilo poslano';
@override @override
String get chat_messageDeleted => 'Pošiljanje sporočila izbrisano'; String get chat_messageDeleted => 'Sporočilo izbrisano';
@override @override
String get chat_retryingMessage => 'Ponovna poskus.'; String get chat_retryingMessage => 'Ponovni poskus.';
@override @override
String chat_retryCount(int current, int max) { String chat_retryCount(int current, int max) {
return 'Ponovit $current/$max'; return 'Ponovitev $current/$max';
} }
@override @override
String get chat_sendGif => 'Pošlji GIF'; String get chat_sendGif => 'Pošlji GIF';
@override @override
String get chat_reply => 'Odpošlji'; String get chat_reply => 'Odgovori';
@override @override
String get chat_addReaction => 'Dodaj Reakcijo'; String get chat_addReaction => 'Dodaj reakcijo';
@override @override
String get chat_me => 'jaz'; String get chat_me => 'jaz';
@@ -961,19 +961,19 @@ class AppLocalizationsSl extends AppLocalizations {
String get gifPicker_title => 'Izberi GIF'; String get gifPicker_title => 'Izberi GIF';
@override @override
String get gifPicker_searchHint => 'Iskalite GIF-e...'; String get gifPicker_searchHint => 'Išči GIF-e...';
@override @override
String get gifPicker_poweredBy => 'Naprodno z GIPHY'; String get gifPicker_poweredBy => 'Napredno z GIPHY';
@override @override
String get gifPicker_noGifsFound => 'Niti GIF-jev najti ni.'; String get gifPicker_noGifsFound => 'Ne najdem GIF-ov.';
@override @override
String get gifPicker_failedLoad => 'Neuspešno je naložilo GIF-e'; String get gifPicker_failedLoad => 'Neuspešno nalaganje GIF-a';
@override @override
String get gifPicker_failedSearch => 'Posodobit neuspešno.'; String get gifPicker_failedSearch => 'Iskanje neuspešno.';
@override @override
String get gifPicker_noInternet => 'Ni internetne povezave'; String get gifPicker_noInternet => 'Ni internetne povezave';
@@ -982,35 +982,35 @@ class AppLocalizationsSl extends AppLocalizations {
String get debugLog_appTitle => 'Log zapiske aplikacije'; String get debugLog_appTitle => 'Log zapiske aplikacije';
@override @override
String get debugLog_bleTitle => 'Logarjev zapis BLE'; String get debugLog_bleTitle => 'Log zapis BLE';
@override @override
String get debugLog_copyLog => 'Kopiraj zapiske'; String get debugLog_copyLog => 'Kopiraj dnevnik';
@override @override
String get debugLog_clearLog => 'Pasters log'; String get debugLog_clearLog => 'Briši log';
@override @override
String get debugLog_copied => 'Kopirana belež poteka.'; String get debugLog_copied => 'Beležka kopirana.';
@override @override
String get debugLog_bleCopied => 'Kopirana beležke iz BLE'; String get debugLog_bleCopied => 'Kopirana beležka iz BLE';
@override @override
String get debugLog_noEntries => 'Še ni ustvarjenih debug zapisov.'; String get debugLog_noEntries => 'Ni debug zapisov.';
@override @override
String get debugLog_enableInSettings => String get debugLog_enableInSettings =>
'Omogoči beleženje napak v aplikaciji v nastavitvah'; 'Omogoči beleženje napak v nastavitvah aplikacije';
@override @override
String get debugLog_frames => 'Okna'; String get debugLog_frames => 'Okvirji';
@override @override
String get debugLog_rawLogRx => 'Svež Log-RX'; String get debugLog_rawLogRx => 'Svež Log-RX';
@override @override
String get debugLog_noBleActivity => 'Šele začnite z aktivnostjo BLE.'; String get debugLog_noBleActivity => 'Ni BLE aktivnosti.';
@override @override
String debugFrame_length(int count) { String debugFrame_length(int count) {
@@ -1019,7 +1019,7 @@ class AppLocalizationsSl extends AppLocalizations {
@override @override
String debugFrame_command(String value) { String debugFrame_command(String value) {
return 'Navodilo: 0x$value'; return 'Ukaz: 0x$value';
} }
@override @override
@@ -1079,10 +1079,10 @@ class AppLocalizationsSl extends AppLocalizations {
'Zapiske o poti so popolni. Izbriši vnose, da dodaš nove.'; 'Zapiske o poti so popolni. Izbriši vnose, da dodaš nove.';
@override @override
String get chat_hopSingular => 'skoč'; String get chat_hopSingular => 'skok';
@override @override
String get chat_hopPlural => 'škrabec'; String get chat_hopPlural => 'skokov';
@override @override
String chat_hopsCount(int count) { String chat_hopsCount(int count) {
@@ -1103,7 +1103,7 @@ class AppLocalizationsSl extends AppLocalizations {
@override @override
String get chat_noPathHistoryYet => String get chat_noPathHistoryYet =>
'Še ni shranjenih poti.\nPošlji sporočilo za odkrivanje poti.'; 'Ni shranjenih poti.\nPošlji sporočilo za odkrivanje poti.';
@override @override
String get chat_pathActions => 'Potni ukazi:'; String get chat_pathActions => 'Potni ukazi:';
@@ -1115,7 +1115,7 @@ class AppLocalizationsSl extends AppLocalizations {
String get chat_setCustomPathSubtitle => 'Ročno določite potniško pot.'; String get chat_setCustomPathSubtitle => 'Ročno določite potniško pot.';
@override @override
String get chat_clearPath => 'Čista pot'; String get chat_clearPath => 'Počisti pot';
@override @override
String get chat_clearPathSubtitle => 'Ob naslednji pošiljanju znova zbrati.'; String get chat_clearPathSubtitle => 'Ob naslednji pošiljanju znova zbrati.';
@@ -1133,7 +1133,7 @@ class AppLocalizationsSl extends AppLocalizations {
'Narejena je bila omrežna modaliteta. Vklopi jo znova preko ikone v meniju aplikacije.'; 'Narejena je bila omrežna modaliteta. Vklopi jo znova preko ikone v meniju aplikacije.';
@override @override
String get chat_fullPath => 'Polni pot'; String get chat_fullPath => 'Polna pot';
@override @override
String get chat_pathDetailsNotAvailable => String get chat_pathDetailsNotAvailable =>
@@ -1152,7 +1152,7 @@ class AppLocalizationsSl extends AppLocalizations {
@override @override
String get chat_pathSavedLocally => String get chat_pathSavedLocally =>
'Shrano lokalno. Povežite se za sinhronizacijo.'; 'Shranjeno lokalno. Povežite se za sinhronizacijo.';
@override @override
String get chat_pathDeviceConfirmed => 'Naprave potrjeno.'; String get chat_pathDeviceConfirmed => 'Naprave potrjeno.';
@@ -2012,13 +2012,13 @@ class AppLocalizationsSl extends AppLocalizations {
} }
@override @override
String get repeater_cliQuickGetName => 'Dobiti ime'; String get repeater_cliQuickGetName => 'Pridobi ime';
@override @override
String get repeater_cliQuickGetRadio => 'Dobiti Radiopravo'; String get repeater_cliQuickGetRadio => 'Dobiti Radiopravo';
@override @override
String get repeater_cliQuickGetTx => 'Dobiti TX'; String get repeater_cliQuickGetTx => 'Pridobi TX';
@override @override
String get repeater_cliQuickNeighbors => 'Sosedi'; String get repeater_cliQuickNeighbors => 'Sosedi';
@@ -2030,7 +2030,7 @@ class AppLocalizationsSl extends AppLocalizations {
String get repeater_cliQuickAdvertise => 'Oglasite'; String get repeater_cliQuickAdvertise => 'Oglasite';
@override @override
String get repeater_cliQuickClock => 'Urnik'; String get repeater_cliQuickClock => 'Ura';
@override @override
String get repeater_cliHelpAdvert => 'Pošlje paket oglasov'; String get repeater_cliHelpAdvert => 'Pošlje paket oglasov';
@@ -2153,7 +2153,7 @@ class AppLocalizationsSl extends AppLocalizations {
@override @override
String get repeater_cliHelpSetPerm => String get repeater_cliHelpSetPerm =>
'Modificira ACL. Odstrani ustreznu vnos (po predponi pubkeyja), če je \"permissions\" enako nič. Dodaja nov vnos, če je pubkey-hex v celoti in trenutno ni v ACL. Posodobi vnos po ustreznem predponi pubkeyja. Bitje dovoljenj se razlikuje glede na firmware vlogo, vendar so prvi dve bitki: 0 (Gost), 1 (Lezenje samo), 2 (Lezenje in pisanje), 3 (Administrator).'; 'Modificira ACL. Odstrani ustrezen vnos (po predponi pubkeyja), če je \"permissions\" enako nič. Dodaja nov vnos, če je pubkey-hex v celoti in trenutno ni v ACL. Posodobi vnos po ustreznem predponi pubkeyja. Bitje dovoljenj se razlikuje glede na firmware vlogo, vendar so prvi dve bitki: 0 (Gost), 1 (Lezenje samo), 2 (Lezenje in pisanje), 3 (Administrator).';
@override @override
String get repeater_cliHelpGetBridgeType => String get repeater_cliHelpGetBridgeType =>
@@ -2261,11 +2261,11 @@ class AppLocalizationsSl extends AppLocalizations {
String get repeater_logging => 'Logiranje'; String get repeater_logging => 'Logiranje';
@override @override
String get repeater_neighborsRepeaterOnly => 'Sosedi (le za ponovitelja)'; String get repeater_neighborsRepeaterOnly => 'Sosedi (le za repetitorje)';
@override @override
String get repeater_regionManagementRepeaterOnly => String get repeater_regionManagementRepeaterOnly =>
'Upravljanje regij (zgolj za ponovitve)'; 'Upravljanje regij (zgolj za repetitorje)';
@override @override
String get repeater_regionNote => String get repeater_regionNote =>
@@ -2380,13 +2380,13 @@ class AppLocalizationsSl extends AppLocalizations {
String get channelPath_messageDetails => 'Podrobnosti sporočila'; String get channelPath_messageDetails => 'Podrobnosti sporočila';
@override @override
String get channelPath_senderLabel => 'Pošiljalec'; String get channelPath_senderLabel => 'Pošiljatelj';
@override @override
String get channelPath_timeLabel => 'Čas'; String get channelPath_timeLabel => 'Ura';
@override @override
String get channelPath_repeatsLabel => 'Ponovi'; String get channelPath_repeatsLabel => 'Ponovitve';
@override @override
String channelPath_pathLabel(int index) { String channelPath_pathLabel(int index) {
@@ -2551,10 +2551,10 @@ class AppLocalizationsSl extends AppLocalizations {
@override @override
String get community_scanOrCreate => String get community_scanOrCreate =>
'Skenirajte QR kodo ali ustvarite skupnost za začetek.'; 'Skeniraj QR kodo ali ustvari skupnost za začetek.';
@override @override
String get community_manageCommunities => 'Upravljajte skupnosti'; String get community_manageCommunities => 'Upravljanje skupnosti';
@override @override
String get community_delete => 'Opusti skupnost'; String get community_delete => 'Opusti skupnost';
@@ -2604,7 +2604,7 @@ class AppLocalizationsSl extends AppLocalizations {
} }
@override @override
String get community_addHashtagChannel => 'Dodaj Oznako Obštnine'; String get community_addHashtagChannel => 'Dodaj hashtag kanal';
@override @override
String get community_addHashtagChannelDesc => String get community_addHashtagChannelDesc =>
@@ -2618,7 +2618,7 @@ class AppLocalizationsSl extends AppLocalizations {
@override @override
String get community_regularHashtagDesc => String get community_regularHashtagDesc =>
'javna oznaka (kateri koli lahko sodelujejo)'; 'javna oznaka (kdorkoli lahko sodelujeje)';
@override @override
String get community_communityHashtag => 'Skupnostni hashtag'; String get community_communityHashtag => 'Skupnostni hashtag';
@@ -2633,7 +2633,7 @@ class AppLocalizationsSl extends AppLocalizations {
} }
@override @override
String get listFilter_tooltip => 'Filtri in vrstiči'; String get listFilter_tooltip => 'Filtri in sortiranje';
@override @override
String get listFilter_sortBy => 'Sortiraj po'; String get listFilter_sortBy => 'Sortiraj po';
@@ -2657,13 +2657,13 @@ class AppLocalizationsSl extends AppLocalizations {
String get listFilter_users => 'Uporabniki'; String get listFilter_users => 'Uporabniki';
@override @override
String get listFilter_repeaters => 'Ponovitve'; String get listFilter_repeaters => 'Samo repetirorji';
@override @override
String get listFilter_roomServers => 'Smeti za prostore'; String get listFilter_roomServers => 'Samo room serverji';
@override @override
String get listFilter_unreadOnly => 'Nezbrani samo'; String get listFilter_unreadOnly => 'Samo neprebrani';
@override @override
String get listFilter_newGroup => 'Nova skupina'; String get listFilter_newGroup => 'Nova skupina';
File diff suppressed because it is too large Load Diff
+778
View File
@@ -0,0 +1,778 @@
{
"@@locale": "ru",
"appTitle": "MeshCore Open",
"nav_contacts": "Контакты",
"nav_channels": "Каналы",
"nav_map": "Карта",
"common_cancel": "Отмена",
"common_ok": "OK",
"common_connect": "Коннект",
"common_unknownDevice": "Неизвестное устройство",
"common_save": "Сохранить",
"common_delete": "Удалить",
"common_close": "Закрыть",
"common_edit": "Изменить",
"common_add": "Добавить",
"common_settings": "Настройки",
"common_disconnect": "Отключить",
"common_connected": "Подключено",
"common_disconnected": "Отключено",
"common_create": "Создать",
"common_continue": "Продолжить",
"common_share": "Поделиться",
"common_copy": "Копировать",
"common_retry": "Повторить",
"common_hide": "Скрыть",
"common_remove": "Убрать",
"common_enable": "Включить",
"common_disable": "Выключить",
"common_reboot": "Перезагрузить",
"common_loading": "Загрузка...",
"common_notAvailable": "—",
"common_voltageValue": "{volts} В",
"common_percentValue": "{percent}%",
"scanner_title": "MeshCore Open",
"scanner_scanning": "Поиск устройств...",
"scanner_connecting": "Подключение...",
"scanner_disconnecting": "Отключение...",
"scanner_notConnected": "Не подключено",
"scanner_connectedTo": "Подключено к {deviceName}",
"scanner_searchingDevices": "Поиск устройств MeshCore...",
"scanner_tapToScan": "Нажмите для поиска MeshCore устройств",
"scanner_connectionFailed": "Подключение не удалось: {error}",
"scanner_stop": "Стоп",
"scanner_scan": "Сканирование",
"device_quickSwitch": "Быстрое переключение",
"device_meshcore": "MeshCore",
"settings_title": "Настройки",
"settings_deviceInfo": "Информация об устройстве",
"settings_appSettings": "Настройки приложения",
"settings_appSettingsSubtitle": "Уведомления, сообщения и настройки карты",
"settings_nodeSettings": "Настройки ноды",
"settings_nodeName": "Имя ноды",
"settings_nodeNameNotSet": "Не установлено",
"settings_nodeNameHint": "Введите имя ноды",
"settings_nodeNameUpdated": "Имя обновлено",
"settings_radioSettings": "Настройки радио",
"settings_radioSettingsSubtitle": "Частота, мощность и коэффициент распространения",
"settings_radioSettingsUpdated": "Настройки радио обновлены",
"settings_location": "Позиция",
"settings_locationSubtitle": "Координаты GPS",
"settings_locationUpdated": "Позиция и настройки GPS обновлены",
"settings_locationBothRequired": "Введите широту и долготу.",
"settings_locationInvalid": "Неверная широта или долгота.",
"settings_locationGPSEnable": "Включить GPS",
"settings_locationGPSEnableSubtitle": "Включение GPS для автоматического обновления позиции.",
"settings_locationIntervalSec": "Интервал для позиционирования GPS (секунды)",
"settings_locationIntervalInvalid": "Интервал должен составлять не менее 60 секунд и не более 86400 секунд.",
"settings_latitude": "Широта",
"settings_longitude": "Долгота",
"settings_privacyMode": "Режим конфиденциальности",
"settings_privacyModeSubtitle": "Скрыть имя/позицию в анонсировании",
"settings_privacyModeToggle": "Включите режим конфиденциальности, чтобы скрыть свое имя и местоположение в анонсировании.",
"settings_privacyModeEnabled": "Режим конфиденциальности включен",
"settings_privacyModeDisabled": "Режим конфиденциальности выключен",
"settings_actions": "Действия",
"settings_sendAdvertisement": "Отправить анонсирование",
"settings_sendAdvertisementSubtitle": "Отправить анонсирование о присутствии сейчас",
"settings_advertisementSent": "Анонсирование отправлено",
"settings_syncTime": "Синхронизация времени",
"settings_syncTimeSubtitle": "Синхронизировать время с телефоном",
"settings_timeSynchronized": "Время синхронизировано",
"settings_refreshContacts": "Обновить контакты",
"settings_refreshContactsSubtitle": "Перезагрузить список контактов с устройства",
"settings_rebootDevice": "Перезагрузить устройство",
"settings_rebootDeviceSubtitle": "Перезапустить устройство MeshCore",
"settings_rebootDeviceConfirm": "Вы уверены, что хотите перезагрузить устройство? Вы будете отключены.",
"settings_debug": "Отладка",
"settings_bleDebugLog": "Журнал отладки BLE",
"settings_bleDebugLogSubtitle": "Команды BLE, ответы и сырые данные",
"settings_appDebugLog": "Журнал отладки приложения",
"settings_appDebugLogSubtitle": "Сообщения отладки приложения",
"settings_about": "О программе",
"settings_aboutVersion": "MeshCore Open v{version}",
"settings_aboutLegalese": "2026 MeshCore Open Source Project",
"settings_aboutDescription": "Открытое клиентское приложение на Flutter для устройств MeshCore с LoRa-сетями.",
"settings_infoName": "Имя",
"settings_infoId": "ID",
"settings_infoStatus": "Статус",
"settings_infoBattery": "Батарея",
"settings_infoPublicKey": "Публичный ключ",
"settings_infoContactsCount": "Количество контактов",
"settings_infoChannelCount": "Количество каналов",
"settings_presets": "Пресеты",
"settings_preset915Mhz": "915 МГц",
"settings_preset868Mhz": "868 МГц",
"settings_preset433Mhz": "433 МГц",
"settings_frequency": "Частота (МГц)",
"settings_frequencyHelper": "300.0 2500.0",
"settings_frequencyInvalid": "Недопустимая частота (300–2500 МГц)",
"settings_bandwidth": "Полоса пропускания",
"settings_spreadingFactor": "Коэффициент расширения",
"settings_codingRate": "Коэффициент кодирования",
"settings_txPower": "Мощность передачи (дБм)",
"settings_txPowerHelper": "0 22",
"settings_txPowerInvalid": "Недопустимая мощность передачи (0–22 дБм)",
"settings_longRange": "Дальний радиус",
"settings_fastSpeed": "Высокая скорость",
"settings_error": "Ошибка: {message}",
"appSettings_title": "Настройки приложения",
"appSettings_appearance": "Внешний вид",
"appSettings_theme": "Тема",
"appSettings_themeSystem": "Как в системе",
"appSettings_themeLight": "Светлая",
"appSettings_themeDark": "Тёмная",
"appSettings_language": "Язык",
"appSettings_languageSystem": "Как в системе",
"appSettings_languageEn": "Английский",
"appSettings_languageFr": "Французский",
"appSettings_languageEs": "Испанский",
"appSettings_languageDe": "Немецкий",
"appSettings_languagePl": "Польский",
"appSettings_languageSl": "Словенский",
"appSettings_languagePt": "Португальский",
"appSettings_languageIt": "Итальянский",
"appSettings_languageZh": "Китайский",
"appSettings_languageSv": "Шведский",
"appSettings_languageNl": "Нидерландский",
"appSettings_languageSk": "Словацкий",
"appSettings_languageBg": "Болгарский",
"appSettings_languageRu": "Русский",
"appSettings_notifications": "Уведомления",
"appSettings_enableNotifications": "Включить уведомления",
"appSettings_enableNotificationsSubtitle": "Получать уведомления о сообщениях и оповещениях",
"appSettings_notificationPermissionDenied": "Разрешение на уведомления отклонено",
"appSettings_notificationsEnabled": "Уведомления включены",
"appSettings_notificationsDisabled": "Уведомления отключены",
"appSettings_messageNotifications": "Уведомления о сообщениях",
"appSettings_messageNotificationsSubtitle": "Показывать уведомление при получении новых сообщений",
"appSettings_channelMessageNotifications": "Уведомления о сообщениях в каналах",
"appSettings_channelMessageNotificationsSubtitle": "Показывать уведомление при получении сообщений в каналах",
"appSettings_advertisementNotifications": "Уведомления об анонсированиях",
"appSettings_advertisementNotificationsSubtitle": "Показывать уведомление при обнаружении новых нод",
"appSettings_messaging": "Обмен сообщениями",
"appSettings_clearPathOnMaxRetry": "Сбросить маршрут после максимального числа попыток",
"appSettings_clearPathOnMaxRetrySubtitle": "Сбросить маршрут контакта после 5 неудачных попыток отправки",
"appSettings_pathsWillBeCleared": "Маршруты будут сброшены после 5 неудачных попыток",
"appSettings_pathsWillNotBeCleared": "Маршруты не будут автоматически сбрасываться",
"appSettings_autoRouteRotation": "Автоматическое переключение маршрутов",
"appSettings_autoRouteRotationSubtitle": "Циклически переключаться между лучшими маршрутами и режимом рассылки",
"appSettings_autoRouteRotationEnabled": "Автоматическое переключение маршрутов включено",
"appSettings_autoRouteRotationDisabled": "Автоматическое переключение маршрутов отключено",
"appSettings_battery": "Батарея",
"appSettings_batteryChemistry": "Химия батареи",
"appSettings_batteryChemistryPerDevice": "Установить для устройства ({deviceName})",
"appSettings_batteryChemistryConnectFirst": "Подключитесь к устройству, чтобы выбрать",
"appSettings_batteryNmc": "18650 NMC (3.04.2 В)",
"appSettings_batteryLifepo4": "LiFePO4 (2.63.65 В)",
"appSettings_batteryLipo": "LiPo (3.04.2 В)",
"appSettings_mapDisplay": "Отображение карты",
"appSettings_showRepeaters": "Показывать репитеры",
"appSettings_showRepeatersSubtitle": "Отображать репитеры на карте",
"appSettings_showChatNodes": "Показывать чат-ноды",
"appSettings_showChatNodesSubtitle": "Отображать чат-ноды на карте",
"appSettings_showOtherNodes": "Показывать другие ноды",
"appSettings_showOtherNodesSubtitle": "Отображать другие типы нод на карте",
"appSettings_timeFilter": "Фильтр по времени",
"appSettings_timeFilterShowAll": "Показывать все ноды",
"appSettings_timeFilterShowLast": "Показывать ноды за последние {hours} ч",
"appSettings_mapTimeFilter": "Временной фильтр карты",
"appSettings_showNodesDiscoveredWithin": "Показывать ноды, обнаруженные за:",
"appSettings_allTime": "Всё время",
"appSettings_lastHour": "Последний час",
"appSettings_last6Hours": "Последние 6 часов",
"appSettings_last24Hours": "Последние 24 часа",
"appSettings_lastWeek": "Последнюю неделю",
"appSettings_offlineMapCache": "Кэш офлайн-карты",
"appSettings_noAreaSelected": "Область не выбрана",
"appSettings_areaSelectedZoom": "Область выбрана (масштаб {minZoom}{maxZoom})",
"appSettings_debugCard": "Отладка",
"appSettings_appDebugLogging": "Журнал отладки приложения",
"appSettings_appDebugLoggingSubtitle": "Записывать отладочные сообщения приложения для диагностики",
"appSettings_appDebugLoggingEnabled": "Журнал отладки приложения включён",
"appSettings_appDebugLoggingDisabled": "Журнал отладки приложения отключён",
"contacts_title": "Контакты",
"contacts_noContacts": "Контактов пока нет",
"contacts_contactsWillAppear": "Контакты появятся, когда устройства начнут рассылать оповещения",
"contacts_searchContacts": "Поиск контактов...",
"contacts_noUnreadContacts": "Нет непрочитанных контактов",
"contacts_noContactsFound": "Контакты или группы не найдены",
"contacts_deleteContact": "Удалить контакт",
"contacts_removeConfirm": "Удалить {contactName} из контактов?",
"contacts_manageRepeater": "Управление репитером",
"contacts_manageRoom": "Управление сервером комнат",
"contacts_roomLogin": "Вход на сервер комнат",
"contacts_openChat": "Открыть чат",
"contacts_editGroup": "Изменить группу",
"contacts_deleteGroup": "Удалить группу",
"contacts_deleteGroupConfirm": "Удалить \"{groupName}\"?",
"contacts_newGroup": "Новая группа",
"contacts_groupName": "Имя группы",
"contacts_groupNameRequired": "Имя группы обязательно",
"contacts_groupAlreadyExists": "Группа \"{name}\" уже существует",
"contacts_filterContacts": "Фильтр контактов...",
"contacts_noContactsMatchFilter": "Нет контактов, соответствующих фильтру",
"contacts_noMembers": "Нет участников",
"contacts_lastSeenNow": "Видели только что",
"contacts_lastSeenMinsAgo": "Видели {minutes} мин назад",
"contacts_lastSeenHourAgo": "Видели 1 час назад",
"contacts_lastSeenHoursAgo": "Видели {hours} ч назад",
"contacts_lastSeenDayAgo": "Видели 1 день назад",
"contacts_lastSeenDaysAgo": "Видели {days} дн. назад",
"channels_title": "Каналы",
"channels_noChannelsConfigured": "Каналы не настроены",
"channels_addPublicChannel": "Добавить публичный канал",
"channels_searchChannels": "Поиск каналов...",
"channels_noChannelsFound": "Каналы не найдены",
"channels_channelIndex": "Канал {index}",
"channels_hashtagChannel": "Хэштег-канал",
"channels_public": "Публичный",
"channels_private": "Приватный",
"channels_publicChannel": "Публичный канал",
"channels_privateChannel": "Приватный канал",
"channels_editChannel": "Изменить канал",
"channels_deleteChannel": "Удалить канал",
"channels_deleteChannelConfirm": "Удалить \"{name}\"? Это действие нельзя отменить.",
"channels_channelDeleted": "Канал \"{name}\" удалён",
"channels_addChannel": "Добавить канал",
"channels_channelIndexLabel": "Индекс канала",
"channels_channelName": "Имя канала",
"channels_usePublicChannel": "Использовать публичный канал",
"channels_standardPublicPsk": "Стандартный публичный PSK",
"channels_pskHex": "PSK (Hex)",
"channels_generateRandomPsk": "Сгенерировать случайный PSK",
"channels_enterChannelName": "Введите имя канала",
"channels_pskMustBe32Hex": "PSK должен содержать 32 шестнадцатеричных символа",
"channels_channelAdded": "Канал \"{name}\" добавлен",
"channels_editChannelTitle": "Изменить канал {index}",
"channels_smazCompression": "Сжатие SMAZ",
"channels_channelUpdated": "Канал \"{name}\" обновлён",
"channels_publicChannelAdded": "Публичный канал добавлен",
"channels_sortBy": "Сортировка",
"channels_sortManual": "Вручную",
"channels_sortAZ": "По алфавиту",
"channels_sortLatestMessages": "По последним сообщениям",
"channels_sortUnread": "По непрочитанным",
"channels_createPrivateChannel": "Создать приватный канал",
"channels_createPrivateChannelDesc": "Защищён секретным ключом.",
"channels_joinPrivateChannel": "Присоединиться к приватному каналу",
"channels_joinPrivateChannelDesc": "Введите секретный ключ вручную.",
"channels_joinPublicChannel": "Присоединиться к публичному каналу",
"channels_joinPublicChannelDesc": "К этому каналу может присоединиться любой.",
"channels_joinHashtagChannel": "Присоединиться к хэштег-каналу",
"channels_joinHashtagChannelDesc": "К хэштег-каналам может присоединиться любой.",
"channels_scanQrCode": "Сканировать QR-код",
"channels_scanQrCodeComingSoon": "Скоро будет",
"channels_enterHashtag": "Введите хэштег",
"channels_hashtagHint": "например, #команда",
"chat_noMessages": "Сообщений пока нет",
"chat_sendMessageToStart": "Отправьте сообщение, чтобы начать",
"chat_originalMessageNotFound": "Исходное сообщение не найдено",
"chat_replyingTo": "Ответ для {name}",
"chat_replyTo": "Ответить {name}",
"chat_location": "Местоположение",
"chat_sendMessageTo": "Отправить сообщение {contactName}",
"chat_typeMessage": "Напишите сообщение...",
"chat_messageTooLong": "Сообщение слишком длинное (макс. {maxBytes} байт).",
"chat_messageCopied": "Сообщение скопировано",
"chat_messageDeleted": "Сообщение удалено",
"chat_retryingMessage": "Повтор отправки сообщения",
"chat_retryCount": "Попытка {current}/{max}",
"chat_sendGif": "Отправить GIF",
"chat_reply": "Ответить",
"chat_addReaction": "Добавить реакцию",
"chat_me": "Я",
"emojiCategorySmileys": "Смайлы",
"emojiCategoryGestures": "Жесты",
"emojiCategoryHearts": "Сердечки",
"emojiCategoryObjects": "Предметы",
"gifPicker_title": "Выберите GIF",
"gifPicker_searchHint": "Поиск GIF...",
"gifPicker_poweredBy": "Работает на GIPHY",
"gifPicker_noGifsFound": "GIF не найдены",
"gifPicker_failedLoad": "Не удалось загрузить GIF",
"gifPicker_failedSearch": "Не удалось выполнить поиск GIF",
"gifPicker_noInternet": "Нет подключения к интернету",
"debugLog_appTitle": "Журнал отладки приложения",
"debugLog_bleTitle": "Журнал отладки BLE",
"debugLog_copyLog": "Копировать журнал",
"debugLog_clearLog": "Очистить журнал",
"debugLog_copied": "Журнал отладки скопирован",
"debugLog_bleCopied": "Журнал BLE скопирован",
"debugLog_noEntries": "Журнал отладки пока пуст",
"debugLog_enableInSettings": "Включите запись журнала отладки в настройках",
"debugLog_frames": "Фреймы",
"debugLog_rawLogRx": "Сырой журнал приёма",
"debugLog_noBleActivity": "Активность BLE пока отсутствует",
"debugFrame_length": "Длина фрейма: {count} байт",
"debugFrame_command": "Команда: 0x{value}",
"debugFrame_textMessageHeader": "Фрейм текстового сообщения:",
"debugFrame_destinationPubKey": "- Публичный ключ получателя: {pubKey}",
"debugFrame_timestamp": "- Временная метка: {timestamp}",
"debugFrame_flags": "- Флаги: 0x{value}",
"debugFrame_textType": "- Тип текста: {type} ({label})",
"debugFrame_textTypeCli": "CLI",
"debugFrame_textTypePlain": "Обычный",
"debugFrame_text": "- Текст: \"{text}\"",
"debugFrame_hexDump": "Шестнадцатеричный дамп:",
"chat_pathManagement": "Управление маршрутами",
"chat_routingMode": "Режим маршрутизации",
"chat_autoUseSavedPath": "Авто (использовать сохранённый маршрут)",
"chat_forceFloodMode": "Принудительный режим рассылки",
"chat_recentAckPaths": "Недавние подтверждённые маршруты (нажмите, чтобы использовать):",
"chat_pathHistoryFull": "История маршрутов заполнена. Удалите записи, чтобы добавить новые.",
"chat_hopSingular": "хоп",
"chat_hopPlural": "хопов",
"chat_hopsCount": "{count} {count, plural, one{хоп} few{хопа} many{хопов} other{хопов}}",
"chat_successes": "успешно",
"chat_removePath": "Удалить маршрут",
"chat_noPathHistoryYet": "История маршрутов пока пуста.\nОтправьте сообщение, чтобы обнаружить маршруты.",
"chat_pathActions": "Действия с маршрутом:",
"chat_setCustomPath": "Указать маршрут вручную",
"chat_setCustomPathSubtitle": "Вручную задать маршрут передачи",
"chat_clearPath": "Очистить маршрут",
"chat_clearPathSubtitle": "Принудительно обновить маршрут при следующей отправке",
"chat_pathCleared": "Маршрут очищен. Следующее сообщение обновит маршрут.",
"chat_floodModeSubtitle": "Используйте переключатель маршрутизации в панели приложения",
"chat_floodModeEnabled": "Режим рассылки включён. Отключите через значок маршрутизации в панели приложения.",
"chat_fullPath": "Полный маршрут",
"chat_pathDetailsNotAvailable": "Детали маршрута ещё недоступны. Попробуйте отправить сообщение для обновления.",
"chat_pathSetHops": "Маршрут установлен: {hopCount} {hopCount, plural, one{хоп} few{хопа} many{хопов} other{хопов}} — {status}",
"chat_pathSavedLocally": "Сохранено локально. Подключитесь для синхронизации.",
"chat_pathDeviceConfirmed": "Подтверждено устройством.",
"chat_pathDeviceNotConfirmed": "Ещё не подтверждено устройством.",
"chat_type": "Тип",
"chat_path": "Маршрут",
"chat_publicKey": "Публичный ключ",
"chat_compressOutgoingMessages": "Сжимать исходящие сообщения",
"chat_floodForced": "Рассылка (принудительно)",
"chat_directForced": "Прямой (принудительно)",
"chat_hopsForced": "{count} хоп(ов) (принудительно)",
"chat_floodAuto": "Рассылка (авто)",
"chat_direct": "Прямой",
"chat_poiShared": "Точка интереса отправлена",
"chat_unread": "Непрочитанных: {count}",
"map_title": "Карта нод",
"map_noNodesWithLocation": "Нет нод с данными о местоположении",
"map_nodesNeedGps": "Ноды должны передавать свои GPS-координаты, чтобы отображаться на карте",
"map_nodesCount": "Нод: {count}",
"map_pinsCount": "Меток: {count}",
"map_chat": "Чат",
"map_repeater": "Репитер",
"map_room": "Комната",
"map_sensor": "Сенсор",
"map_pinDm": "Метка (ЛС)",
"map_pinPrivate": "Метка (Приватная)",
"map_pinPublic": "Метка (Публичная)",
"map_lastSeen": "Последнее появление",
"map_disconnectConfirm": "Вы уверены, что хотите отключиться от этого устройства?",
"map_from": "От",
"map_source": "Источник",
"map_flags": "Флаги",
"map_shareMarkerHere": "Поделиться меткой здесь",
"map_pinLabel": "Метка",
"map_label": "Подпись",
"map_pointOfInterest": "Точка интереса",
"map_sendToContact": "Отправить контакту",
"map_sendToChannel": "Отправить в канал",
"map_noChannelsAvailable": "Нет доступных каналов",
"map_publicLocationShare": "Публичная передача местоположения",
"map_publicLocationShareConfirm": "Вы собираетесь поделиться местоположением в {channelLabel}. Этот канал публичный, и любой, у кого есть PSK, сможет его увидеть.",
"map_connectToShareMarkers": "Подключитесь к устройству, чтобы делиться метками",
"map_filterNodes": "Фильтр нод",
"map_nodeTypes": "Типы нод",
"map_chatNodes": "Чат-ноды",
"map_repeaters": "Репитеры",
"map_otherNodes": "Другие ноды",
"map_keyPrefix": "Префикс ключа",
"map_filterByKeyPrefix": "Фильтр по префиксу ключа",
"map_publicKeyPrefix": "Префикс публичного ключа",
"map_markers": "Метки",
"map_showSharedMarkers": "Показывать общие метки",
"map_lastSeenTime": "Время последнего появления",
"map_sharedPin": "Общая метка",
"map_joinRoom": "Присоединиться к комнате",
"map_manageRepeater": "Управление репитером",
"mapCache_title": "Кэш офлайн-карты",
"mapCache_selectAreaFirst": "Сначала выберите область для кэширования",
"mapCache_noTilesToDownload": "Нет плиток для загрузки в этой области",
"mapCache_downloadTilesTitle": "Загрузить плитки",
"mapCache_downloadTilesPrompt": "Загрузить {count} плиток для офлайн-использования?",
"mapCache_downloadAction": "Загрузить",
"mapCache_cachedTiles": "Закэшировано {count} плиток",
"mapCache_cachedTilesWithFailed": "Закэшировано {downloaded} плиток ({failed} не загружено)",
"mapCache_clearOfflineCacheTitle": "Очистить офлайн-кэш",
"mapCache_clearOfflineCachePrompt": "Удалить все закэшированные плитки карты?",
"mapCache_offlineCacheCleared": "Офлайн-кэш очищен",
"mapCache_noAreaSelected": "Область не выбрана",
"mapCache_cacheArea": "Область кэширования",
"mapCache_useCurrentView": "Использовать текущий вид",
"mapCache_zoomRange": "Диапазон масштаба",
"mapCache_estimatedTiles": "Оценочное количество плиток: {count}",
"mapCache_downloadedTiles": "Загружено {completed} из {total}",
"mapCache_downloadTilesButton": "Загрузить плитки",
"mapCache_clearCacheButton": "Очистить кэш",
"mapCache_failedDownloads": "Неудачных загрузок: {count}",
"mapCache_boundsLabel": "С {north}, Ю {south}, В {east}, З {west}",
"time_justNow": "Только что",
"time_minutesAgo": "{minutes} мин назад",
"time_hoursAgo": "{hours} ч назад",
"time_daysAgo": "{days} дн. назад",
"time_hour": "час",
"time_hours": "часов",
"time_day": "день",
"time_days": "дней",
"time_week": "неделя",
"time_weeks": "недель",
"time_month": "месяц",
"time_months": "месяцев",
"time_minutes": "минут",
"time_allTime": "Всё время",
"dialog_disconnect": "Отключиться",
"dialog_disconnectConfirm": "Вы уверены, что хотите отключиться от этого устройства?",
"login_repeaterLogin": "Вход в репитер",
"login_roomLogin": "Вход на сервер комнат",
"login_password": "Пароль",
"login_enterPassword": "Введите пароль",
"login_savePassword": "Сохранить пароль",
"login_savePasswordSubtitle": "Пароль будет надёжно сохранён на этом устройстве",
"login_repeaterDescription": "Введите пароль репитера для доступа к настройкам и статусу.",
"login_roomDescription": "Введите пароль комнаты для доступа к настройкам и статусу.",
"login_routing": "Маршрутизация",
"login_routingMode": "Режим маршрутизации",
"login_autoUseSavedPath": "Авто (использовать сохранённый маршрут)",
"login_forceFloodMode": "Принудительный режим рассылки",
"login_managePaths": "Управление маршрутами",
"login_login": "Войти",
"login_attempt": "Попытка {current}/{max}",
"login_failed": "Ошибка входа: {error}",
"login_failedMessage": "Не удалось войти. Либо пароль неверен, либо репитер недоступен.",
"common_reload": "Обновить",
"common_clear": "Очистить",
"path_currentPath": "Текущий маршрут: {path}",
"path_usingHopsPath": "Используется маршрут из {count} {count, plural, one{хоп} few{хопа} many{хопов} other{хопов}}",
"path_enterCustomPath": "Введите маршрут вручную",
"path_currentPathLabel": "Текущий маршрут",
"path_hexPrefixInstructions": "Введите 2-символьные шестнадцатеричные префиксы для каждого хопа, разделённые запятыми.",
"path_hexPrefixExample": "Пример: A1,F2,3C (каждый узел использует первый байт своего публичного ключа)",
"path_labelHexPrefixes": "Маршрут (шестнадцатеричные префиксы)",
"path_helperMaxHops": "Максимум 64 хопа. Каждый префикс — 2 шестнадцатеричных символа (1 байт)",
"path_selectFromContacts": "Или выберите из контактов:",
"path_noRepeatersFound": "Репитеры или серверы комнат не найдены.",
"path_customPathsRequire": "Пользовательские маршруты требуют промежуточных узлов, способных ретранслировать сообщения.",
"path_invalidHexPrefixes": "Недопустимые шестнадцатеричные префиксы: {prefixes}",
"path_tooLong": "Маршрут слишком длинный. Максимум 64 хопа.",
"path_setPath": "Установить маршрут",
"repeater_management": "Управление репитером",
"room_management": "Управление сервером комнат",
"repeater_managementTools": "Инструменты управления",
"repeater_status": "Статус",
"repeater_statusSubtitle": "Просмотр статуса, статистики и соседей репитера",
"repeater_telemetry": "Телеметрия",
"repeater_telemetrySubtitle": "Просмотр телеметрии датчиков и системной статистики",
"repeater_cli": "CLI",
"repeater_cliSubtitle": "Отправка команд репитеру",
"repeater_neighbours": "Соседи",
"repeater_neighboursSubtitle": "Просмотр соседей на нулевом хопе.",
"repeater_settings": "Настройки",
"repeater_settingsSubtitle": "Настройка параметров репитера",
"repeater_statusTitle": "Статус репитера",
"repeater_routingMode": "Режим маршрутизации",
"repeater_autoUseSavedPath": "Авто (использовать сохранённый маршрут)",
"repeater_forceFloodMode": "Принудительный режим рассылки",
"repeater_pathManagement": "Управление маршрутами",
"repeater_refresh": "Обновить",
"repeater_statusRequestTimeout": "Время ожидания статуса истекло.",
"repeater_errorLoadingStatus": "Ошибка загрузки статуса: {error}",
"repeater_systemInformation": "Системная информация",
"repeater_battery": "Батарея",
"repeater_clockAtLogin": "Время (при входе)",
"repeater_uptime": "Время работы",
"repeater_queueLength": "Длина очереди",
"repeater_debugFlags": "Флаги отладки",
"repeater_radioStatistics": "Радиостатистика",
"repeater_lastRssi": "Последний RSSI",
"repeater_lastSnr": "Последний SNR",
"repeater_noiseFloor": "Уровень шума",
"repeater_txAirtime": "Время эфира (передача)",
"repeater_rxAirtime": "Время эфира (приём)",
"repeater_packetStatistics": "Статистика пакетов",
"repeater_sent": "Отправлено",
"repeater_received": "Получено",
"repeater_duplicates": "Дубликаты",
"repeater_daysHoursMinsSecs": "{days} дн. {hours}ч {minutes}м {seconds}с",
"repeater_packetTxTotal": "Всего: {total}, Рассылка: {flood}, Прямые: {direct}",
"repeater_packetRxTotal": "Всего: {total}, Рассылка: {flood}, Прямые: {direct}",
"repeater_duplicatesFloodDirect": "Рассылка: {flood}, Прямые: {direct}",
"repeater_duplicatesTotal": "Всего: {total}",
"repeater_settingsTitle": "Настройки репитера",
"repeater_basicSettings": "Основные настройки",
"repeater_repeaterName": "Имя репитера",
"repeater_repeaterNameHelper": "Отображаемое имя этого репитера",
"repeater_adminPassword": "Пароль администратора",
"repeater_adminPasswordHelper": "Пароль с полным доступом",
"repeater_guestPassword": "Гостевой пароль",
"repeater_guestPasswordHelper": "Пароль для доступа только для чтения",
"repeater_radioSettings": "Настройки радио",
"repeater_frequencyMhz": "Частота (МГц)",
"repeater_frequencyHelper": "3002500 МГц",
"repeater_txPower": "Мощность передачи",
"repeater_txPowerHelper": "130 дБм",
"repeater_bandwidth": "Полоса пропускания",
"repeater_spreadingFactor": "Коэффициент расширения",
"repeater_codingRate": "Коэффициент кодирования",
"repeater_locationSettings": "Настройки местоположения",
"repeater_latitude": "Широта",
"repeater_latitudeHelper": "В десятичных градусах (напр., 37.7749)",
"repeater_longitude": "Долгота",
"repeater_longitudeHelper": "В десятичных градусах (напр., -122.4194)",
"repeater_features": "Функции",
"repeater_packetForwarding": "Пересылка пакетов",
"repeater_packetForwardingSubtitle": "Разрешить репитеру пересылать пакеты",
"repeater_guestAccess": "Гостевой доступ",
"repeater_guestAccessSubtitle": "Разрешить гостевой доступ только для чтения",
"repeater_privacyMode": "Режим конфиденциальности",
"repeater_privacyModeSubtitle": "Скрывать имя/местоположение в оповещениях",
"repeater_advertisementSettings": "Настройки анонсирования",
"repeater_localAdvertInterval": "Интервал локальных анонсирований",
"repeater_localAdvertIntervalMinutes": "{minutes} минут",
"repeater_floodAdvertInterval": "Интервал анонсирований рассылкой (flood)",
"repeater_floodAdvertIntervalHours": "{hours} часов",
"repeater_encryptedAdvertInterval": "Интервал зашифрованных анонсирований",
"repeater_dangerZone": "Опасная зона",
"repeater_rebootRepeater": "Перезагрузить репитер",
"repeater_rebootRepeaterSubtitle": "Перезапустить устройство репитера",
"repeater_rebootRepeaterConfirm": "Вы уверены, что хотите перезагрузить этот репитер?",
"repeater_regenerateIdentityKey": "Пересоздать ключ идентификации",
"repeater_regenerateIdentityKeySubtitle": "Сгенерировать новую пару публичного/приватного ключей",
"repeater_regenerateIdentityKeyConfirm": "Это создаст новую идентичность для репитера. Продолжить?",
"repeater_eraseFileSystem": "Стереть файловую систему",
"repeater_eraseFileSystemSubtitle": "Отформатировать файловую систему репитера",
"repeater_eraseFileSystemConfirm": "ВНИМАНИЕ: это удалит все данные на репитере. Действие нельзя отменить!",
"repeater_eraseSerialOnly": "Очистка доступна только через последовательную консоль.",
"repeater_commandSent": "Команда отправлена: {command}",
"repeater_errorSendingCommand": "Ошибка отправки команды: {error}",
"repeater_confirm": "Подтвердить",
"repeater_settingsSaved": "Настройки успешно сохранены",
"repeater_errorSavingSettings": "Ошибка сохранения настроек: {error}",
"repeater_refreshBasicSettings": "Обновить основные настройки",
"repeater_refreshRadioSettings": "Обновить настройки радио",
"repeater_refreshTxPower": "Обновить мощность передачи",
"repeater_refreshLocationSettings": "Обновить настройки местоположения",
"repeater_refreshPacketForwarding": "Обновить пересылку пакетов",
"repeater_refreshGuestAccess": "Обновить гостевой доступ",
"repeater_refreshPrivacyMode": "Обновить режим конфиденциальности",
"repeater_refreshAdvertisementSettings": "Обновить настройки анонсирований",
"repeater_refreshed": "{label} обновлён",
"repeater_errorRefreshing": "Ошибка обновления {label}",
"repeater_cliTitle": "CLI репитера",
"repeater_debugNextCommand": "Отладка следующей команды",
"repeater_commandHelp": "Справка по командам",
"repeater_clearHistory": "Очистить историю",
"repeater_noCommandsSent": "Команды ещё не отправлялись",
"repeater_typeCommandOrUseQuick": "Введите команду ниже или используйте быстрые команды",
"repeater_enterCommandHint": "Введите команду...",
"repeater_previousCommand": "Предыдущая команда",
"repeater_nextCommand": "Следующая команда",
"repeater_enterCommandFirst": "Сначала введите команду",
"repeater_cliCommandFrameTitle": "Фрейм CLI-команды",
"repeater_cliCommandError": "Ошибка: {error}",
"repeater_cliQuickGetName": "Получить имя",
"repeater_cliQuickGetRadio": "Получить радио",
"repeater_cliQuickGetTx": "Получить TX",
"repeater_cliQuickNeighbors": "Соседи",
"repeater_cliQuickVersion": "Версия",
"repeater_cliQuickAdvertise": "Анонсировать",
"repeater_cliQuickClock": "Время",
"repeater_cliHelpAdvert": "Отправляет пакет анонсирования",
"repeater_cliHelpReboot": "Перезагружает устройство. (обычно вы получите «Тайм-аут» — это нормально)",
"repeater_cliHelpClock": "Показывает текущее время по часам устройства.",
"repeater_cliHelpPassword": "Устанавливает новый пароль администратора для устройства.",
"repeater_cliHelpVersion": "Показывает версию устройства и дату сборки прошивки.",
"repeater_cliHelpClearStats": "Сбрасывает различные счётчики статистики в ноль.",
"repeater_cliHelpSetAf": "Устанавливает коэффициент времени в эфире.",
"repeater_cliHelpSetTx": "Устанавливает мощность передачи LoRa в дБм. (требуется перезагрузка)",
"repeater_cliHelpSetRepeat": "Включает или отключает роль репитера для этой ноды.",
"repeater_cliHelpSetAllowReadOnly": "(Сервер комнат) Если «on», то вход без пароля разрешён, но публиковать в комнату нельзя (только чтение)",
"repeater_cliHelpSetFloodMax": "Устанавливает максимальное число хопов для входящих пакетов в режиме рассылки (если >= макс., пакет не пересылается)",
"repeater_cliHelpSetIntThresh": "Устанавливает порог интерференции (в дБ). По умолчанию 14. Установите 0, чтобы отключить обнаружение помех.",
"repeater_cliHelpSetAgcResetInterval": "Устанавливает интервал сброса автоматической регулировки усиления. Установите 0, чтобы отключить.",
"repeater_cliHelpSetMultiAcks": "Включает или отключает функцию «двойных ACK».",
"repeater_cliHelpSetAdvertInterval": "Устанавливает интервал (в минутах) отправки локального (нулевой хоп) анонсирования. Установите 0, чтобы отключить.",
"repeater_cliHelpSetFloodAdvertInterval": "Устанавливает интервал (в часах) отправки анонсирований рассылкой. Установите 0, чтобы отключить.",
"repeater_cliHelpSetGuestPassword": "Устанавливает/обновляет гостевой пароль. (для репитеров гости могут отправлять запрос «Get Stats»)",
"repeater_cliHelpSetName": "Устанавливает имя в оповещениях.",
"repeater_cliHelpSetLat": "Устанавливает широту для карты в оповещениях. (десятичные градусы)",
"repeater_cliHelpSetLon": "Устанавливает долготу для карты в оповещениях. (десятичные градусы)",
"repeater_cliHelpSetRadio": "Устанавливает полностью новые параметры радио и сохраняет их в настройки. Требуется команда «reboot» для применения.",
"repeater_cliHelpSetRxDelay": "Устанавливает (экспериментально) базовую задержку (>1 для эффекта) для принятых пакетов на основе качества сигнала. Установите 0, чтобы отключить.",
"repeater_cliHelpSetTxDelay": "Устанавливает множитель времени в эфире для пакета в режиме рассылки и применяет случайную задержку перед пересылкой (чтобы уменьшить коллизии).",
"repeater_cliHelpSetDirectTxDelay": "То же, что txdelay, но для случайной задержки пересылки пакетов в прямом режиме.",
"repeater_cliHelpSetBridgeEnabled": "Включить/выключить мост.",
"repeater_cliHelpSetBridgeDelay": "Установить задержку перед ретрансляцией пакетов.",
"repeater_cliHelpSetBridgeSource": "Выбрать, будет ли мост ретранслировать полученные или отправленные пакеты.",
"repeater_cliHelpSetBridgeBaud": "Установить скорость последовательного соединения для мостов RS232.",
"repeater_cliHelpSetBridgeSecret": "Установить секрет моста для мостов ESP-NOW.",
"repeater_cliHelpSetAdcMultiplier": "Устанавливает пользовательский коэффициент коррекции напряжения батареи (поддерживается только на некоторых платах).",
"repeater_cliHelpTempRadio": "Устанавливает временные параметры радио на заданное число минут, затем возвращает исходные. (НЕ сохраняется в настройки).",
"repeater_cliHelpSetPerm": "Изменяет ACL. Удаляет запись (по префиксу публичного ключа), если «permissions» равен нулю. Добавляет новую запись, если указан полный ключ и он отсутствует в ACL. Обновляет запись по совпадению префикса. Биты прав зависят от роли прошивки, но младшие 2 бита: 0 (Гость), 1 (Только чтение), 2 (Чтение/запись), 3 (Админ)",
"repeater_cliHelpGetBridgeType": "Получает тип моста: none, rs232, espnow",
"repeater_cliHelpLogStart": "Начинает запись пакетов в файловую систему.",
"repeater_cliHelpLogStop": "Останавливает запись пакетов в файловую систему.",
"repeater_cliHelpLogErase": "Удаляет журналы пакетов из файловой системы.",
"repeater_cliHelpNeighbors": "Показывает список других репитеров, услышанных через оповещения нулевого хопа. Каждая строка: префикс-id-в-hex:временная-метка:snr×4",
"repeater_cliHelpNeighborRemove": "Удаляет первую подходящую запись (по префиксу публичного ключа в hex) из списка соседей.",
"repeater_cliHelpRegion": "(только через последовательный порт) Показывает все определённые регионы и текущие права на рассылку.",
"repeater_cliHelpRegionLoad": "ПРИМЕЧАНИЕ: это специальная многострочная команда. Каждая следующая строка — имя региона (с отступом пробелами для указания иерархии, минимум один пробел). Завершается пустой строкой.",
"repeater_cliHelpRegionGet": "Ищет регион по префиксу имени (или «*» для глобальной области). Отвечает: «-> имя-региона (родитель) 'F'»",
"repeater_cliHelpRegionPut": "Добавляет или обновляет определение региона с заданным именем.",
"repeater_cliHelpRegionRemove": "Удаляет определение региона с заданным именем. (должно точно совпадать и не иметь дочерних регионов)",
"repeater_cliHelpRegionAllowf": "Разрешает рассылку («F»lood) для заданного региона. («*» для глобальной/устаревшей области)",
"repeater_cliHelpRegionDenyf": "Запрещает рассылку («F»lood) для заданного региона. (НЕ рекомендуется для глобальной области!)",
"repeater_cliHelpRegionHome": "Показывает текущий «домашний» регион. (Пока не используется, зарезервировано на будущее)",
"repeater_cliHelpRegionHomeSet": "Устанавливает «домашний» регион.",
"repeater_cliHelpRegionSave": "Сохраняет список/карту регионов в память.",
"repeater_cliHelpGps": "Показывает статус GPS. Если GPS выключен — отвечает только «off». Если включён — показывает статус, фиксацию, количество спутников.",
"repeater_cliHelpGpsOnOff": "Переключает состояние питания GPS.",
"repeater_cliHelpGpsSync": "Синхронизирует время ноды с часами GPS.",
"repeater_cliHelpGpsSetLoc": "Устанавливает позицию ноды по координатам GPS и сохраняет в настройки.",
"repeater_cliHelpGpsAdvert": "Показывает конфигурацию передачи местоположения в анонсированиях:\n- none: не включать местоположение\n- share: передавать GPS-координаты (из SensorManager)\n- prefs: передавать координаты из настроек",
"repeater_cliHelpGpsAdvertSet": "Устанавливает конфигурацию передачи местоположения.",
"repeater_commandsListTitle": "Список команд",
"repeater_commandsListNote": "ПРИМЕЧАНИЕ: для большинства команд «set ...» существуют соответствующие команды «get ...».",
"repeater_general": "Общие",
"repeater_settingsCategory": "Настройки",
"repeater_bridge": "Мост",
"repeater_logging": "Журналирование",
"repeater_neighborsRepeaterOnly": "Соседи (только для репитеров)",
"repeater_regionManagementRepeaterOnly": "Управление регионами (только для репитеров)",
"repeater_regionNote": "Команды регионов введены для управления определениями регионов и правами доступа.",
"repeater_gpsManagement": "Управление GPS",
"repeater_gpsNote": "Команда gps введена для управления параметрами, связанными с местоположением.",
"telemetry_receivedData": "Полученные телеметрические данные",
"telemetry_requestTimeout": "Время ожидания телеметрии истекло.",
"telemetry_errorLoading": "Ошибка загрузки телеметрии: {error}",
"telemetry_noData": "Данные телеметрии недоступны.",
"telemetry_channelTitle": "Канал {channel}",
"telemetry_batteryLabel": "Батарея",
"telemetry_voltageLabel": "Напряжение",
"telemetry_mcuTemperatureLabel": "Температура МК",
"telemetry_temperatureLabel": "Температура",
"telemetry_currentLabel": "Ток",
"telemetry_batteryValue": "{percent}% / {volts}В",
"telemetry_voltageValue": "{volts}В",
"telemetry_currentValue": "{amps}А",
"telemetry_temperatureValue": "{celsius}°C / {fahrenheit}°F",
"neighbors_receivedData": "Полученные данные о соседях",
"neighbors_requestTimedOut": "Время ожидания данных о соседях истекло.",
"neighbors_errorLoading": "Ошибка загрузки соседей: {error}",
"neighbors_repeatersNeighbours": "Соседи репитеров",
"neighbors_noData": "Данные о соседях недоступны.",
"neighbors_unknownContact": "Неизвестный {pubkey}",
"neighbors_heardA ago": "Слышали: {time} назад",
"channelPath_title": "Путь пакета",
"channelPath_viewMap": "Посмотреть на карте",
"channelPath_otherObservedPaths": "Другие наблюдаемые пути",
"channelPath_repeaterHops": "Хопы через репитеры",
"channelPath_noHopDetails": "Детали хопов для этого пакета не предоставлены.",
"channelPath_messageDetails": "Детали сообщения",
"channelPath_senderLabel": "Отправитель",
"channelPath_timeLabel": "Время",
"channelPath_repeatsLabel": "Повторы",
"channelPath_pathLabel": "Путь {index}",
"channelPath_observedLabel": "Наблюдаемый",
"channelPath_observedPathTitle": "Наблюдаемый путь {index} • {hops}",
"channelPath_noLocationData": "Нет данных о местоположении",
"channelPath_timeWithDate": "{day}/{month} {time}",
"channelPath_timeOnly": "{time}",
"channelPath_unknownPath": "Неизвестный",
"channelPath_floodPath": "Рассылка",
"channelPath_directPath": "Прямой",
"channelPath_observedZeroOf": "0 из {total} хопов",
"channelPath_observedSomeOf": "{observed} из {total} хопов",
"channelPath_mapTitle": "Карта пути",
"channelPath_noRepeaterLocations": "Нет данных о местоположении репитеров для этого пути.",
"channelPath_primaryPath": "Путь {index} (Основной)",
"channelPath_pathLabelTitle": "Путь",
"channelPath_observedPathHeader": "Наблюдаемый путь",
"channelPath_selectedPathLabel": "{label} • {prefixes}",
"channelPath_noHopDetailsAvailable": "Детали хопов для этого пакета недоступны.",
"channelPath_unknownRepeater": "Неизвестный репитер",
"community_title": "Сообщество",
"community_create": "Создать сообщество",
"community_createDesc": "Создать новое сообщество и поделиться через QR-код.",
"community_join": "Присоединиться",
"community_joinTitle": "Присоединиться к сообществу",
"community_joinConfirmation": "Вы хотите присоединиться к сообществу \"{name}\"?",
"community_scanQr": "Сканировать QR-код сообщества",
"community_scanInstructions": "Наведите камеру на QR-код сообщества",
"community_showQr": "Показать QR-код",
"community_publicChannel": "Публичный канал сообщества",
"community_hashtagChannel": "Хэштег-канал сообщества",
"community_name": "Имя сообщества",
"community_enterName": "Введите имя сообщества",
"community_created": "Сообщество \"{name}\" создано",
"community_joined": "Присоединились к сообществу \"{name}\"",
"community_qrTitle": "Поделиться сообществом",
"community_qrInstructions": "Отсканируйте этот QR-код, чтобы присоединиться к \"{name}\"",
"community_hashtagPrivacyHint": "Хэштег-каналы сообщества доступны только его участникам",
"community_invalidQrCode": "Недопустимый QR-код сообщества",
"community_alreadyMember": "Уже участник",
"community_alreadyMemberMessage": "Вы уже участник сообщества \"{name}\".",
"community_addPublicChannel": "Добавить публичный канал сообщества",
"community_addPublicChannelHint": "Автоматически добавить публичный канал для этого сообщества",
"community_noCommunities": "Вы ещё не присоединились ни к одному сообществу",
"community_scanOrCreate": "Отсканируйте QR-код или создайте сообщество, чтобы начать",
"community_manageCommunities": "Управление сообществами",
"community_delete": "Покинуть сообщество",
"community_deleteConfirm": "Покинуть \"{name}\"?",
"community_deleteChannelsWarning": "Это также удалит {count} канал(ов) и их сообщения.",
"community_deleted": "Покинули сообщество \"{name}\"",
"community_regenerateSecret": "Пересоздать секрет",
"community_regenerateSecretConfirm": "Пересоздать секретный ключ для \"{name}\"? Все участники должны будут отсканировать новый QR-код для продолжения общения.",
"community_regenerate": "Пересоздать",
"community_secretRegenerated": "Секрет пересоздан для \"{name}\"",
"community_updateSecret": "Обновить секрет",
"community_secretUpdated": "Секрет обновлён для \"{name}\"",
"community_scanToUpdateSecret": "Отсканируйте новый QR-код, чтобы обновить секрет для \"{name}\"",
"community_addHashtagChannel": "Добавить хэштег-канал сообщества",
"community_addHashtagChannelDesc": "Добавить хэштег-канал для этого сообщества",
"community_selectCommunity": "Выбрать сообщество",
"community_regularHashtag": "Обычный хэштег",
"community_regularHashtagDesc": "Публичный хэштег (любой может присоединиться)",
"community_communityHashtag": "Хэштег сообщества",
"community_communityHashtagDesc": "Доступен только участникам сообщества",
"community_forCommunity": "Для {name}",
"listFilter_tooltip": "Фильтр и сортировка",
"listFilter_sortBy": "Сортировка по",
"listFilter_latestMessages": "Последние сообщения",
"listFilter_heardRecently": "Слышали недавно",
"listFilter_az": "По алфавиту",
"listFilter_filters": "Фильтры",
"listFilter_all": "Все",
"listFilter_users": "Пользователи",
"listFilter_repeaters": "Репитеры",
"listFilter_roomServers": "Серверы комнат",
"listFilter_unreadOnly": "Только непрочитанные",
"listFilter_newGroup": "Новая группа",
"@chat_couldNotOpenLink": {
"placeholders": {
"url": {
"type": "String"
}
}
},
"@neighbors_heardAgo": {
"placeholders": {
"time": {
"type": "String"
}
}
},
"chat_open": "Открыть",
"chat_couldNotOpenLink": "Не удалось открыть ссылку: {url}",
"chat_openLink": "Открыть ссылку?",
"chat_openLinkConfirmation": "Хотите открыть эту ссылку в вашем браузере?",
"neighbors_heardAgo": "Слушал(а): {time} назад",
"chat_invalidLink": "Неправильный формат ссылки"
}
+142 -142
View File
@@ -1,7 +1,7 @@
{ {
"@@locale": "sl", "@@locale": "sl",
"appTitle": "MeshCore Open", "appTitle": "MeshCore Open",
"nav_contacts": "Kontakti", "nav_contacts": "Stiki",
"nav_channels": "Kanali", "nav_channels": "Kanali",
"nav_map": "Karta", "nav_map": "Karta",
"common_cancel": "Prekliči", "common_cancel": "Prekliči",
@@ -69,49 +69,49 @@
}, },
"scanner_stop": "Prekliči", "scanner_stop": "Prekliči",
"scanner_scan": "Skeniraj", "scanner_scan": "Skeniraj",
"device_quickSwitch": "Hitro preklopiti", "device_quickSwitch": "Hitro preklop",
"device_meshcore": "MeshCore", "device_meshcore": "MeshCore",
"settings_title": "Nastavitve", "settings_title": "Nastavitve",
"settings_deviceInfo": "Informacije o napravei", "settings_deviceInfo": "Informacije o napravei",
"settings_appSettings": "Nastavitve aplikacije", "settings_appSettings": "Nastavitve aplikacije",
"settings_appSettingsSubtitle": "Obveščanja, sporoščanje in zemljevidi.", "settings_appSettingsSubtitle": "Obveščanja, sporoščanje in zemljevidi.",
"settings_nodeSettings": "Nastavitve časa", "settings_nodeSettings": "Nastavitev časa",
"settings_nodeName": "Ime omrežno mesto", "settings_nodeName": "Ime node-a",
"settings_nodeNameNotSet": "Nezavedeno", "settings_nodeNameNotSet": "Ni nastavljeno",
"settings_nodeNameHint": "Vnesite ime časa", "settings_nodeNameHint": "Vnesite ime node-a",
"settings_nodeNameUpdated": "Ime posodobljeno", "settings_nodeNameUpdated": "Ime posodobljeno",
"settings_radioSettings": "Nastavitve radija", "settings_radioSettings": "Nastavitve radija",
"settings_radioSettingsSubtitle": "Frekvenca, moč, razširni faktor", "settings_radioSettingsSubtitle": "Frekvenca, moč, razširitveni faktor",
"settings_radioSettingsUpdated": "Radio nastavitve posodobljene", "settings_radioSettingsUpdated": "Radio nastavitve posodobljene",
"settings_location": "Lokacija", "settings_location": "Lokacija",
"settings_locationSubtitle": "GPS koordinate", "settings_locationSubtitle": "GPS koordinate",
"settings_locationUpdated": "Lokacija posodobljena", "settings_locationUpdated": "Lokacija posodobljena",
"settings_locationBothRequired": "Vnesite širino in dolžino.", "settings_locationBothRequired": "Vnesite širino in dolžino.",
"settings_locationInvalid": "Neveljna zemeljska širina ali dolžina.", "settings_locationInvalid": "Neveljavna zemeljska širina ali dolžina.",
"settings_latitude": "Širina", "settings_latitude": "Širina",
"settings_longitude": "Dolžina", "settings_longitude": "Dolžina",
"settings_privacyMode": "Mod podjetja", "settings_privacyMode": "Zasebnost",
"settings_privacyModeSubtitle": "Skrita imena/lokacije v oglasih", "settings_privacyModeSubtitle": "Skrita imena/lokacije v oglasih",
"settings_privacyModeToggle": "Omogoči način zasebnosti, da skrijemo tvoje ime in lokacijo v oglasih.", "settings_privacyModeToggle": "Omogoči način zasebnosti, da skrijemo tvoje ime in lokacijo v oglasih.",
"settings_privacyModeEnabled": "Privatni režim je omogočen.", "settings_privacyModeEnabled": "Privatni način je omogočen.",
"settings_privacyModeDisabled": "Privatni režim je onemogočen.", "settings_privacyModeDisabled": "Privatni način je onemogočen.",
"settings_actions": "Akcije", "settings_actions": "Akcije",
"settings_sendAdvertisement": "Pošlji Oglas", "settings_sendAdvertisement": "Pošlji Oglas",
"settings_sendAdvertisementSubtitle": "Trenutna prisotnost v oddajah", "settings_sendAdvertisementSubtitle": "Trenutna prisotnost v oddajah",
"settings_advertisementSent": "Oglas poslan", "settings_advertisementSent": "Oglas poslan",
"settings_syncTime": "Ugasniti čas", "settings_syncTime": "Nastavi uro",
"settings_syncTimeSubtitle": "Nastavi uro naprave v čas telefona", "settings_syncTimeSubtitle": "Nastavi uro naprave na čas telefona",
"settings_timeSynchronized": "Sinhronizirano po času", "settings_timeSynchronized": "Ura sinhronizirana",
"settings_refreshContacts": "Ponovno obišči kontakte", "settings_refreshContacts": "Ponovno obišči kontakte",
"settings_refreshContactsSubtitle": "Ponovno naloži seznam kontaktov iz naprave", "settings_refreshContactsSubtitle": "Ponovno naloži seznam stikov v napravi",
"settings_rebootDevice": "Restart Naprave", "settings_rebootDevice": "Ponovni zagon naprave",
"settings_rebootDeviceSubtitle": "Ponovite zažetek naprave MeshCore", "settings_rebootDeviceSubtitle": "Ponovno zaženi MeshCore napravo",
"settings_rebootDeviceConfirm": "Ste prepričani, da želite ponovno zagon napravke? Boste odvisni od omrežja.", "settings_rebootDeviceConfirm": "Ste prepričani, da želite ponovno zagnati napravo? Povezava bo prekinjena.",
"settings_debug": "Napravi popravek", "settings_debug": "Debug",
"settings_bleDebugLog": "Logarjev zapis BLE", "settings_bleDebugLog": "BLE debug log (razhroščevanje)",
"settings_bleDebugLogSubtitle": "Navodila BLE, odgovori in surovo podatkovno", "settings_bleDebugLogSubtitle": "BLE ukazi, odgovori in surovi podatki",
"settings_appDebugLog": "Log zapiske aplikacije", "settings_appDebugLog": "Logi aplikacije",
"settings_appDebugLogSubtitle": "Prijavni sporočila aplikacije", "settings_appDebugLogSubtitle": "Debug sporočila aplikacije",
"settings_about": "Oglejte si", "settings_about": "Oglejte si",
"settings_aboutVersion": "MeshCore Open v{version}", "settings_aboutVersion": "MeshCore Open v{version}",
"@settings_aboutVersion": { "@settings_aboutVersion": {
@@ -121,14 +121,14 @@
} }
} }
}, },
"settings_aboutLegalese": "MeshCore Odprtokodni Projekt 2024", "settings_aboutLegalese": "Odprtokodni projekt MeshCore 2024",
"settings_aboutDescription": "Odprtokodni Flutter kličnik za naprave za LoRa mrežo MeshCore.", "settings_aboutDescription": "Odprtokodni Flutter klient za naprave za LoRa omrežje MeshCore.",
"settings_infoName": "Ime", "settings_infoName": "Ime",
"settings_infoId": "ID", "settings_infoId": "ID",
"settings_infoStatus": "Status", "settings_infoStatus": "Status",
"settings_infoBattery": "Baterija", "settings_infoBattery": "Baterija",
"settings_infoPublicKey": "Ključ javnega tipa", "settings_infoPublicKey": "Javni ključ",
"settings_infoContactsCount": "Število kontaktov", "settings_infoContactsCount": "Število stikov",
"settings_infoChannelCount": "Število kanalov", "settings_infoChannelCount": "Število kanalov",
"settings_presets": "Prednastavitve", "settings_presets": "Prednastavitve",
"settings_preset915Mhz": "915 MHz", "settings_preset915Mhz": "915 MHz",
@@ -136,15 +136,15 @@
"settings_preset433Mhz": "433 MHz", "settings_preset433Mhz": "433 MHz",
"settings_frequency": "Frekvenca (MHz)", "settings_frequency": "Frekvenca (MHz)",
"settings_frequencyHelper": "300,00 - 2500,00", "settings_frequencyHelper": "300,00 - 2500,00",
"settings_frequencyInvalid": "Neveljčna frekvenca (300-2500 MHz)", "settings_frequencyInvalid": "Neveljavna frekvenca (300-2500 MHz)",
"settings_bandwidth": "Pasovna širina", "settings_bandwidth": "Pasovna širina",
"settings_spreadingFactor": "Razširitveni faktor", "settings_spreadingFactor": "Razširitveni faktor",
"settings_codingRate": "Programska hitrost", "settings_codingRate": "Programska hitrost",
"settings_txPower": "TX Moč (dBm)", "settings_txPower": "TX Moč (dBm)",
"settings_txPowerHelper": "0 - 22", "settings_txPowerHelper": "0 - 22",
"settings_txPowerInvalid": "Neveljaven TX moč (0-22 dBm)", "settings_txPowerInvalid": "Neveljavna TX moč (0-22 dBm)",
"settings_longRange": "Dolenje območje", "settings_longRange": "DDolg doseg",
"settings_fastSpeed": "Hitra hitrost", "settings_fastSpeed": "Visoka hitrost",
"settings_error": "Napaka: {message}", "settings_error": "Napaka: {message}",
"@settings_error": { "@settings_error": {
"placeholders": { "placeholders": {
@@ -156,8 +156,8 @@
"appSettings_title": "Nastavitve aplikacije", "appSettings_title": "Nastavitve aplikacije",
"appSettings_appearance": "Prikaži", "appSettings_appearance": "Prikaži",
"appSettings_theme": "Tema", "appSettings_theme": "Tema",
"appSettings_themeSystem": "Predpomnilnik sistema", "appSettings_themeSystem": "Sistemska tema",
"appSettings_themeLight": "Luč", "appSettings_themeLight": "Svetlo",
"appSettings_themeDark": "Temno", "appSettings_themeDark": "Temno",
"appSettings_language": "Jezik", "appSettings_language": "Jezik",
"appSettings_languageSystem": "Sistemska privzeta vrednost", "appSettings_languageSystem": "Sistemska privzeta vrednost",
@@ -174,8 +174,8 @@
"appSettings_languageNl": "Nederlands", "appSettings_languageNl": "Nederlands",
"appSettings_languageSk": "Slovenčina", "appSettings_languageSk": "Slovenčina",
"appSettings_languageBg": "Български", "appSettings_languageBg": "Български",
"appSettings_notifications": "Obveščanja", "appSettings_notifications": "Obvestila",
"appSettings_enableNotifications": "Omogoči obveščanje", "appSettings_enableNotifications": "Omogoči obvestila",
"appSettings_enableNotificationsSubtitle": "Prejmite obvestila o sporočilih in oglasih", "appSettings_enableNotificationsSubtitle": "Prejmite obvestila o sporočilih in oglasih",
"appSettings_notificationPermissionDenied": "Odobritev obvestila zavrnjena", "appSettings_notificationPermissionDenied": "Odobritev obvestila zavrnjena",
"appSettings_notificationsEnabled": "Obvestila omogočena", "appSettings_notificationsEnabled": "Obvestila omogočena",
@@ -185,19 +185,19 @@
"appSettings_channelMessageNotifications": "Obvestila o sporočilih kanala", "appSettings_channelMessageNotifications": "Obvestila o sporočilih kanala",
"appSettings_channelMessageNotificationsSubtitle": "Pokaži obvestilo ob prejemanju sporočil kanala", "appSettings_channelMessageNotificationsSubtitle": "Pokaži obvestilo ob prejemanju sporočil kanala",
"appSettings_advertisementNotifications": "Opozorila o oglasih", "appSettings_advertisementNotifications": "Opozorila o oglasih",
"appSettings_advertisementNotificationsSubtitle": "Pokaži obvestilo, ko so novi vozlišči odkrivljeni.", "appSettings_advertisementNotificationsSubtitle": "Pokaži obvestilo, ko so najdene nove naprave.",
"appSettings_messaging": "Komuniciranje", "appSettings_messaging": "Komuniciranje",
"appSettings_clearPathOnMaxRetry": "Ponovite pot do cilja na največjem štetju", "appSettings_clearPathOnMaxRetry": "Ponovite pot do cilja na največjem štetju",
"appSettings_clearPathOnMaxRetrySubtitle": "Ponovi pot zimske obveščevalne poti po 5 neuspešnih poskusih pošiljanja", "appSettings_clearPathOnMaxRetrySubtitle": "Ponovi pot zimske obveščevalne poti po 5 neuspešnih poskusih pošiljanja",
"appSettings_pathsWillBeCleared": "Potnice bodo očiščene po 5 neuspešnih poskusih.", "appSettings_pathsWillBeCleared": "Počisti pot po 5 neuspešnih poskusih.",
"appSettings_pathsWillNotBeCleared": "Potniški poti ne bodo samodejno čiščeni.", "appSettings_pathsWillNotBeCleared": "Poti ne bodo samodejno čiščene.",
"appSettings_autoRouteRotation": "Avtomatsko Občutke in Rotacije", "appSettings_autoRouteRotation": "Avtomatsko rotacija prenosne poti",
"appSettings_autoRouteRotationSubtitle": "Med spreminjanjem med najboljšimi potmi in plovilnim načinom", "appSettings_autoRouteRotationSubtitle": "Menjaj med boljšo potjo in flood načinom",
"appSettings_autoRouteRotationEnabled": "Samodejno krmilno rotiranje omogočeno", "appSettings_autoRouteRotationEnabled": "Samodejno krmilno rotiranje omogočeno",
"appSettings_autoRouteRotationDisabled": "Samodejno krmilno rotiranje je onemogočeno", "appSettings_autoRouteRotationDisabled": "Samodejno krmilno rotiranje je onemogočeno",
"appSettings_battery": "Baterija", "appSettings_battery": "Baterija",
"appSettings_batteryChemistry": "Razem z možnostmi", "appSettings_batteryChemistry": "Kemija baterije",
"appSettings_batteryChemistryPerDevice": "Nastavitve za naprave ({deviceName})", "appSettings_batteryChemistryPerDevice": "Nastavitev za napravo ({deviceName})",
"@appSettings_batteryChemistryPerDevice": { "@appSettings_batteryChemistryPerDevice": {
"placeholders": { "placeholders": {
"deviceName": { "deviceName": {
@@ -205,20 +205,20 @@
} }
} }
}, },
"appSettings_batteryChemistryConnectFirst": "Povežite se z napravo za izbiro", "appSettings_batteryChemistryConnectFirst": "Za izbiro se poveži z napravo",
"appSettings_batteryNmc": "18650 NMC (3,0-4,2V)", "appSettings_batteryNmc": "18650 NMC (3,0-4,2V)",
"appSettings_batteryLifepo4": "LiFePO4 (2,63,65 V)", "appSettings_batteryLifepo4": "LiFePO4 (2,63,65 V)",
"appSettings_batteryLipo": "LiPo (3,0-4,2V)", "appSettings_batteryLipo": "LiPo (3,0-4,2V)",
"appSettings_mapDisplay": "Prikaz zemljevide", "appSettings_mapDisplay": "Prikaz zemljevida",
"appSettings_showRepeaters": "Prikaži ponovitve", "appSettings_showRepeaters": "Prikaži repetitorje",
"appSettings_showRepeatersSubtitle": "Prikaži ponovljalne notranjosti na zemljeploscu", "appSettings_showRepeatersSubtitle": "Prikaži repetitorje na mapi",
"appSettings_showChatNodes": "Prikaži čakalne notranjosti", "appSettings_showChatNodes": "Prikaži naprave za klepet",
"appSettings_showChatNodesSubtitle": "Prikaži pogovorni pike na zemljeploscu", "appSettings_showChatNodesSubtitle": "Prikaži naprave na zemljevidu",
"appSettings_showOtherNodes": "Pokaži druge vozlišča", "appSettings_showOtherNodes": "Pokaži druge naprave",
"appSettings_showOtherNodesSubtitle": "Pokaži druge vrste notranjih elementov na zemljevalu.", "appSettings_showOtherNodesSubtitle": "Pokaži druge vrste naprav na zemljevidu.",
"appSettings_timeFilter": "Filtri po času", "appSettings_timeFilter": "Filter po času",
"appSettings_timeFilterShowAll": "Pokaži vse notranje elemente", "appSettings_timeFilterShowAll": "Pokaži vse naprave",
"appSettings_timeFilterShowLast": "Pokaži notranjosti iz zadnjih {hours} ur", "appSettings_timeFilterShowLast": "Pokaži naprave v zadnjih {hours} urah",
"@appSettings_timeFilterShowLast": { "@appSettings_timeFilterShowLast": {
"placeholders": { "placeholders": {
"hours": { "hours": {
@@ -226,15 +226,15 @@
} }
} }
}, },
"appSettings_mapTimeFilter": "Filtri časa zemljevida", "appSettings_mapTimeFilter": "Filter časa na zemljevidu",
"appSettings_showNodesDiscoveredWithin": "Pokaži notranje čepke, odkrivene v:", "appSettings_showNodesDiscoveredWithin": "Pokaži naprave odkrite v:",
"appSettings_allTime": "Vse čase", "appSettings_allTime": "Brez omejitev",
"appSettings_lastHour": "Minuto nazaj", "appSettings_lastHour": "V zadnji uri",
"appSettings_last6Hours": "Zadnjih 6 ur", "appSettings_last6Hours": "Zadnjih 6 ur",
"appSettings_last24Hours": "Zadnjih 24 ur", "appSettings_last24Hours": "Zadnjih 24 ur",
"appSettings_lastWeek": "Lepošno", "appSettings_lastWeek": "Prejšnji teden",
"appSettings_offlineMapCache": "Omrezni Poudni Arhiv", "appSettings_offlineMapCache": "Shramba zemljevidov brez povezave",
"appSettings_noAreaSelected": "Nizkana označena površina", "appSettings_noAreaSelected": "Območje ni izbrano",
"appSettings_areaSelectedZoom": "Izbrano območje (povečava {minZoom}-{maxZoom})", "appSettings_areaSelectedZoom": "Izbrano območje (povečava {minZoom}-{maxZoom})",
"@appSettings_areaSelectedZoom": { "@appSettings_areaSelectedZoom": {
"placeholders": { "placeholders": {
@@ -246,19 +246,19 @@
} }
} }
}, },
"appSettings_debugCard": "Napravi popravek", "appSettings_debugCard": "Razhroščevanje",
"appSettings_appDebugLogging": "Programski Log", "appSettings_appDebugLogging": "Programski dnevnik",
"appSettings_appDebugLoggingSubtitle": "Log aplikacijske debug sporočila za odpravljanje težav", "appSettings_appDebugLoggingSubtitle": "Dnevnik debug sporočil za odpravljanje težav",
"appSettings_appDebugLoggingEnabled": "Omogočeno zaznamovanje napak v aplikaciji", "appSettings_appDebugLoggingEnabled": "Beleženje napak v aplikaciji omogočeno",
"appSettings_appDebugLoggingDisabled": "Programski logi aplikacije so onemogočeni.", "appSettings_appDebugLoggingDisabled": "Beleženje napak v aplikacije onemogočeno.",
"contacts_title": "Kontakti", "contacts_title": "Stiki",
"contacts_noContacts": "Še ni kontaktov.", "contacts_noContacts": "Ni stikov.",
"contacts_contactsWillAppear": "Kontakti se bodo prikazali, ko naprave oglasijo.", "contacts_contactsWillAppear": "Stiki se bodo prikazali, ko se naprave oglasijo.",
"contacts_searchContacts": "Iskanje kontaktov...", "contacts_searchContacts": "Iskanje stikov...",
"contacts_noUnreadContacts": "Nerešeno kontaktov.", "contacts_noUnreadContacts": "Ne prebrani stiki.",
"contacts_noContactsFound": "Niti ena oseba ali skupine ni najdena.", "contacts_noContactsFound": "Stiki niso najdeni.",
"contacts_deleteContact": "Izbrisati Kontakt", "contacts_deleteContact": "Izbriši stik",
"contacts_removeConfirm": "Izbrisati {contactName} iz kontaktov?", "contacts_removeConfirm": "Izbrišem {contactName} iz stikov?",
"@contacts_removeConfirm": { "@contacts_removeConfirm": {
"placeholders": { "placeholders": {
"contactName": { "contactName": {
@@ -266,12 +266,12 @@
} }
} }
}, },
"contacts_manageRepeater": "Upravljajte Ponovitve", "contacts_manageRepeater": "Upravljaj Ponovitve",
"contacts_roomLogin": "Vnos v sobo", "contacts_roomLogin": "Prijava v sobo",
"contacts_openChat": "Odprta kleta", "contacts_openChat": "Odpri klepet",
"contacts_editGroup": "Uredi Skupino", "contacts_editGroup": "Uredi skupino",
"contacts_deleteGroup": "Izbrisati Skupino", "contacts_deleteGroup": "Izbriši skupino",
"contacts_deleteGroupConfirm": "Odpovedati {groupName}?", "contacts_deleteGroupConfirm": "Izbriši {groupName}?",
"@contacts_deleteGroupConfirm": { "@contacts_deleteGroupConfirm": {
"placeholders": { "placeholders": {
"groupName": { "groupName": {
@@ -279,8 +279,8 @@
} }
} }
}, },
"contacts_newGroup": "Novo skupino", "contacts_newGroup": "Nova skupina",
"contacts_groupName": "Skupina imena", "contacts_groupName": "Ime skupine",
"contacts_groupNameRequired": "Ime skupine je obvezno.", "contacts_groupNameRequired": "Ime skupine je obvezno.",
"contacts_groupAlreadyExists": "Skupina \"{name}\" že obstaja", "contacts_groupAlreadyExists": "Skupina \"{name}\" že obstaja",
"@contacts_groupAlreadyExists": { "@contacts_groupAlreadyExists": {
@@ -290,11 +290,11 @@
} }
} }
}, },
"contacts_filterContacts": "Filtri kontakt\\,...", "contacts_filterContacts": "Filtriraj stik\\,...",
"contacts_noContactsMatchFilter": "Niti ena oseba ne ustreza vašemu kriteriju.", "contacts_noContactsMatchFilter": "Noben stik ne ustreza vašemu kriteriju.",
"contacts_noMembers": "Nič članov.", "contacts_noMembers": "Ni članov.",
"contacts_lastSeenNow": "Datum zadnjega vpisa zdaj", "contacts_lastSeenNow": "Nazadnje viden zdaj",
"contacts_lastSeenMinsAgo": "Zadnjič videti {minutes} minut nazaj", "contacts_lastSeenMinsAgo": "Zadnjič viden pred {minutes} minutami",
"@contacts_lastSeenMinsAgo": { "@contacts_lastSeenMinsAgo": {
"placeholders": { "placeholders": {
"minutes": { "minutes": {
@@ -302,8 +302,8 @@
} }
} }
}, },
"contacts_lastSeenHourAgo": "Zadnjič ogledan pred 1 uro.", "contacts_lastSeenHourAgo": "Zadnjič viden pred 1 uro.",
"contacts_lastSeenHoursAgo": "Zadnjič videti {hours} ur nazaj", "contacts_lastSeenHoursAgo": "Zadnjič viden pred {hours} urami",
"@contacts_lastSeenHoursAgo": { "@contacts_lastSeenHoursAgo": {
"placeholders": { "placeholders": {
"hours": { "hours": {
@@ -311,8 +311,8 @@
} }
} }
}, },
"contacts_lastSeenDayAgo": "Zadnjič ogledan pred 1 dnem", "contacts_lastSeenDayAgo": "Zadnjič viden pred 1 dnem",
"contacts_lastSeenDaysAgo": "Zadnjič videti {days} dni nazaj", "contacts_lastSeenDaysAgo": "Zadnjič viden pred {days} dnem",
"@contacts_lastSeenDaysAgo": { "@contacts_lastSeenDaysAgo": {
"placeholders": { "placeholders": {
"days": { "days": {
@@ -321,10 +321,10 @@
} }
}, },
"channels_title": "Kanali", "channels_title": "Kanali",
"channels_noChannelsConfigured": "Nekonfigurirane kanale", "channels_noChannelsConfigured": "Kanali še niso konfigurirani",
"channels_addPublicChannel": "Dodaj Objavni Kanal", "channels_addPublicChannel": "Dodaj javni kanal",
"channels_searchChannels": "Poišči kanale...", "channels_searchChannels": "Poišči kanale...",
"channels_noChannelsFound": "Niti kanalov najti ni.", "channels_noChannelsFound": "Ne najdem kanalov.",
"channels_channelIndex": "Kanal {index}", "channels_channelIndex": "Kanal {index}",
"@channels_channelIndex": { "@channels_channelIndex": {
"placeholders": { "placeholders": {
@@ -334,13 +334,13 @@
} }
}, },
"channels_hashtagChannel": "Hashtag kanal", "channels_hashtagChannel": "Hashtag kanal",
"channels_public": "javno", "channels_public": "Javni",
"channels_private": "Zasebno", "channels_private": "Zasebni",
"channels_publicChannel": "Ogljišna skupina", "channels_publicChannel": "Javni kanal",
"channels_privateChannel": "Zatemniščen kanal", "channels_privateChannel": "Zasebni kanal",
"channels_editChannel": "Uredi kanal", "channels_editChannel": "Uredi kanal",
"channels_deleteChannel": "Pošlji kanal", "channels_deleteChannel": "Pošlji kanal",
"channels_deleteChannelConfirm": "Izbrisati \"{name}\"? To se ne da povrniti.", "channels_deleteChannelConfirm": "Izbrišem \"{name}\"? To se ne da povrniti.",
"@channels_deleteChannelConfirm": { "@channels_deleteChannelConfirm": {
"placeholders": { "placeholders": {
"name": { "name": {
@@ -424,8 +424,8 @@
} }
} }
}, },
"chat_typeMessage": "Vnesite sporočilo...", "chat_typeMessage": "Vnesi sporočilo...",
"chat_messageTooLong": "Pošiljanje sporočila je onemogočeno, saj je preveliko (maksimalno {maxBytes} bajt).", "chat_messageTooLong": "Pošiljanje sporočila je onemogočeno, saj je preveliko (maksimalno {maxBytes} byte-ov).",
"@chat_messageTooLong": { "@chat_messageTooLong": {
"placeholders": { "placeholders": {
"maxBytes": { "maxBytes": {
@@ -433,9 +433,9 @@
} }
} }
}, },
"chat_messageCopied": "Pošljeno sporočilo", "chat_messageCopied": "Sporočilo poslano",
"chat_messageDeleted": "Pošiljanje sporočila izbrisano", "chat_messageDeleted": "Sporočilo izbrisano",
"chat_retryingMessage": "Ponovna poskus.", "chat_retryingMessage": "Ponovni poskus.",
"chat_retryCount": "Ponovit {current}/{max}", "chat_retryCount": "Ponovit {current}/{max}",
"@chat_retryCount": { "@chat_retryCount": {
"placeholders": { "placeholders": {
@@ -448,31 +448,31 @@
} }
}, },
"chat_sendGif": "Pošlji GIF", "chat_sendGif": "Pošlji GIF",
"chat_reply": "Odpošlji", "chat_reply": "Odgovori",
"chat_addReaction": "Dodaj Reakcijo", "chat_addReaction": "Dodaj reakcijo",
"chat_me": "jaz", "chat_me": "jaz",
"emojiCategorySmileys": "Emoji", "emojiCategorySmileys": "Emoji",
"emojiCategoryGestures": "Gestikulacije", "emojiCategoryGestures": "Gestikulacije",
"emojiCategoryHearts": "Srce", "emojiCategoryHearts": "Srce",
"emojiCategoryObjects": "Predmeti", "emojiCategoryObjects": "Predmeti",
"gifPicker_title": "Izberi GIF", "gifPicker_title": "Izberi GIF",
"gifPicker_searchHint": "Iskalite GIF-e...", "gifPicker_searchHint": "Išči GIF-e...",
"gifPicker_poweredBy": "Naprodno z GIPHY", "gifPicker_poweredBy": "Napredno z GIPHY",
"gifPicker_noGifsFound": "Niti GIF-jev najti ni.", "gifPicker_noGifsFound": "Ne najdem GIF-ov.",
"gifPicker_failedLoad": "Neuspešno je naložilo GIF-e", "gifPicker_failedLoad": "Neuspešno nalaganje GIF-a",
"gifPicker_failedSearch": "Posodobit neuspešno.", "gifPicker_failedSearch": "Iskanje neuspešno.",
"gifPicker_noInternet": "Ni internetne povezave", "gifPicker_noInternet": "Ni internetne povezave",
"debugLog_appTitle": "Log zapiske aplikacije", "debugLog_appTitle": "Log zapiske aplikacije",
"debugLog_bleTitle": "Logarjev zapis BLE", "debugLog_bleTitle": "Log zapis BLE",
"debugLog_copyLog": "Kopiraj zapiske", "debugLog_copyLog": "Kopiraj dnevnik",
"debugLog_clearLog": "Pasters log", "debugLog_clearLog": "Briši log",
"debugLog_copied": "Kopirana belež poteka.", "debugLog_copied": "Beležka kopirana.",
"debugLog_bleCopied": "Kopirana beležke iz BLE", "debugLog_bleCopied": "Kopirana beležka iz BLE",
"debugLog_noEntries": "Še ni ustvarjenih debug zapisov.", "debugLog_noEntries": "Ni ustvarjenih debug zapisov.",
"debugLog_enableInSettings": "Omogoči beleženje napak v aplikaciji v nastavitvah", "debugLog_enableInSettings": "Omogoči beleženje napak v nastavitvah aplikacije",
"debugLog_frames": "Okna", "debugLog_frames": "Okvirji",
"debugLog_rawLogRx": "Svež Log-RX", "debugLog_rawLogRx": "Svež Log-RX",
"debugLog_noBleActivity": "Šele začnite z aktivnostjo BLE.", "debugLog_noBleActivity": "Ni BLE aktivnosti.",
"debugFrame_length": "Izhodni rob: {count} bajtov", "debugFrame_length": "Izhodni rob: {count} bajtov",
"@debugFrame_length": { "@debugFrame_length": {
"placeholders": { "placeholders": {
@@ -542,8 +542,8 @@
"chat_forceFloodMode": "Nasilje obvezati v način", "chat_forceFloodMode": "Nasilje obvezati v način",
"chat_recentAckPaths": "Nedavni poti ACK (tap za uporabo):", "chat_recentAckPaths": "Nedavni poti ACK (tap za uporabo):",
"chat_pathHistoryFull": "Zapiske o poti so popolni. Izbriši vnose, da dodaš nove.", "chat_pathHistoryFull": "Zapiske o poti so popolni. Izbriši vnose, da dodaš nove.",
"chat_hopSingular": "skoč", "chat_hopSingular": "skok",
"chat_hopPlural": "škrabec", "chat_hopPlural": "skokov",
"chat_hopsCount": "{count} {count, plural, =1{hop} other{hops}}", "chat_hopsCount": "{count} {count, plural, =1{hop} other{hops}}",
"@chat_hopsCount": { "@chat_hopsCount": {
"placeholders": { "placeholders": {
@@ -554,16 +554,16 @@
}, },
"chat_successes": "Uspešni", "chat_successes": "Uspešni",
"chat_removePath": "Izbriši pot", "chat_removePath": "Izbriši pot",
"chat_noPathHistoryYet": "Še ni shranjenih poti.\nPošlji sporočilo za odkrivanje poti.", "chat_noPathHistoryYet": "Ni shranjenih poti.\nPošlji sporočilo za odkrivanje poti.",
"chat_pathActions": "Potni ukazi:", "chat_pathActions": "Potni ukazi:",
"chat_setCustomPath": "Nastavi Prilozeno Pot", "chat_setCustomPath": "Nastavi Prilozeno Pot",
"chat_setCustomPathSubtitle": "Ročno določite potniško pot.", "chat_setCustomPathSubtitle": "Ročno določite potniško pot.",
"chat_clearPath": "Čista pot", "chat_clearPath": "Počisti pot",
"chat_clearPathSubtitle": "Ob naslednji pošiljanju znova zbrati.", "chat_clearPathSubtitle": "Ob naslednji pošiljanju znova zbrati.",
"chat_pathCleared": "Pot je očiščena. Naslednje sporočilo bo ponovno odkril pot.", "chat_pathCleared": "Pot je očiščena. Naslednje sporočilo bo ponovno odkril pot.",
"chat_floodModeSubtitle": "Uporabi tipko usmerjevanja v meniju aplikacije.", "chat_floodModeSubtitle": "Uporabi tipko usmerjevanja v meniju aplikacije.",
"chat_floodModeEnabled": "Narejena je bila omrežna modaliteta. Vklopi jo znova preko ikone v meniju aplikacije.", "chat_floodModeEnabled": "Narejena je bila omrežna modaliteta. Vklopi jo znova preko ikone v meniju aplikacije.",
"chat_fullPath": "Polni pot", "chat_fullPath": "Polna pot",
"chat_pathDetailsNotAvailable": "Podrobnosti poti zaenkrat niso na voljo. Poskusite poslati sporočilo za osvežitev.", "chat_pathDetailsNotAvailable": "Podrobnosti poti zaenkrat niso na voljo. Poskusite poslati sporočilo za osvežitev.",
"chat_pathSetHops": "Pot nastavljen: {hopCount} {hopCount, plural, =1{hop} other{hops}} - {status}", "chat_pathSetHops": "Pot nastavljen: {hopCount} {hopCount, plural, =1{hop} other{hops}} - {status}",
"@chat_pathSetHops": { "@chat_pathSetHops": {
@@ -1104,13 +1104,13 @@
} }
} }
}, },
"repeater_cliQuickGetName": "Dobiti ime", "repeater_cliQuickGetName": "Pridobi ime",
"repeater_cliQuickGetRadio": "Dobiti Radiopravo", "repeater_cliQuickGetRadio": "Dobiti Radiopravo",
"repeater_cliQuickGetTx": "Dobiti TX", "repeater_cliQuickGetTx": "Pridobi TX",
"repeater_cliQuickNeighbors": "Sosedi", "repeater_cliQuickNeighbors": "Sosedi",
"repeater_cliQuickVersion": "Različica", "repeater_cliQuickVersion": "Različica",
"repeater_cliQuickAdvertise": "Oglasite", "repeater_cliQuickAdvertise": "Oglasite",
"repeater_cliQuickClock": "Urnik", "repeater_cliQuickClock": "Ura",
"repeater_cliHelpAdvert": "Pošlje paket oglasov", "repeater_cliHelpAdvert": "Pošlje paket oglasov",
"repeater_cliHelpReboot": "Ponastavi naprave. (Opomba, lahko pride do 'Timeouta', kar je normalno)", "repeater_cliHelpReboot": "Ponastavi naprave. (Opomba, lahko pride do 'Timeouta', kar je normalno)",
"repeater_cliHelpClock": "Prikaže trenutno uro po uri naprave.", "repeater_cliHelpClock": "Prikaže trenutno uro po uri naprave.",
@@ -1142,7 +1142,7 @@
"repeater_cliHelpSetBridgeSecret": "Nastavi skrivni dostop za mostove ESPNOW.", "repeater_cliHelpSetBridgeSecret": "Nastavi skrivni dostop za mostove ESPNOW.",
"repeater_cliHelpSetAdcMultiplier": "Nastavi prilagoditev faktorja za prilagoditev poravnalnega napetosti baterije (podprt le na izbranih ploščah).", "repeater_cliHelpSetAdcMultiplier": "Nastavi prilagoditev faktorja za prilagoditev poravnalnega napetosti baterije (podprt le na izbranih ploščah).",
"repeater_cliHelpTempRadio": "Nastavi začasne radio parametre za določeno časovno obdobje, kar po preteku časa vrne originalne radio parametre. (ne shranjuje v preferencije).", "repeater_cliHelpTempRadio": "Nastavi začasne radio parametre za določeno časovno obdobje, kar po preteku časa vrne originalne radio parametre. (ne shranjuje v preferencije).",
"repeater_cliHelpSetPerm": "Modificira ACL. Odstrani ustreznu vnos (po predponi pubkeyja), če je \"permissions\" enako nič. Dodaja nov vnos, če je pubkey-hex v celoti in trenutno ni v ACL. Posodobi vnos po ustreznem predponi pubkeyja. Bitje dovoljenj se razlikuje glede na firmware vlogo, vendar so prvi dve bitki: 0 (Gost), 1 (Lezenje samo), 2 (Lezenje in pisanje), 3 (Administrator).", "repeater_cliHelpSetPerm": "Modificira ACL. Odstrani ustrezen vnos (po predponi pubkeyja), če je \"permissions\" enako nič. Dodaja nov vnos, če je pubkey-hex v celoti in trenutno ni v ACL. Posodobi vnos po ustreznem predponi pubkeyja. Bitje dovoljenj se razlikuje glede na firmware vlogo, vendar so prvi dve bitki: 0 (Gost), 1 (Lezenje samo), 2 (Lezenje in pisanje), 3 (Administrator).",
"repeater_cliHelpGetBridgeType": "Dobrodošli pri izbiri vrste mostu: brez, rs232, espnow", "repeater_cliHelpGetBridgeType": "Dobrodošli pri izbiri vrste mostu: brez, rs232, espnow",
"repeater_cliHelpLogStart": "Začnete beleženje paketov v datotekovni sistem.", "repeater_cliHelpLogStart": "Začnete beleženje paketov v datotekovni sistem.",
"repeater_cliHelpLogStop": "Ustavite beleženje paketov v datotečno sistem.", "repeater_cliHelpLogStop": "Ustavite beleženje paketov v datotečno sistem.",
@@ -1171,8 +1171,8 @@
"repeater_settingsCategory": "Nastavitve", "repeater_settingsCategory": "Nastavitve",
"repeater_bridge": "Most", "repeater_bridge": "Most",
"repeater_logging": "Logiranje", "repeater_logging": "Logiranje",
"repeater_neighborsRepeaterOnly": "Sosedi (le za ponovitelja)", "repeater_neighborsRepeaterOnly": "Sosedi (le za repetitorje)",
"repeater_regionManagementRepeaterOnly": "Upravljanje regij (zgolj za ponovitve)", "repeater_regionManagementRepeaterOnly": "Upravljanje regij (zgolj za repetitorje)",
"repeater_regionNote": "Regionske ukazi so bili uvedeni za upravljanje z regijskimi definicijami in dovolili.", "repeater_regionNote": "Regionske ukazi so bili uvedeni za upravljanje z regijskimi definicijami in dovolili.",
"repeater_gpsManagement": "Upravljanje GPS", "repeater_gpsManagement": "Upravljanje GPS",
"repeater_gpsNote": "GPS ukaz je bil uveden za upravljanje z vprašanji, povezanimi z lokacijo.", "repeater_gpsNote": "GPS ukaz je bil uveden za upravljanje z vprašanji, povezanimi z lokacijo.",
@@ -1244,9 +1244,9 @@
"channelPath_repeaterHops": "Skoki ponovitelja", "channelPath_repeaterHops": "Skoki ponovitelja",
"channelPath_noHopDetails": "Podrobnosti o paketu za dostavo niso navedene.", "channelPath_noHopDetails": "Podrobnosti o paketu za dostavo niso navedene.",
"channelPath_messageDetails": "Podrobnosti sporočila", "channelPath_messageDetails": "Podrobnosti sporočila",
"channelPath_senderLabel": "Pošiljalec", "channelPath_senderLabel": "Pošiljatelj",
"channelPath_timeLabel": "Čas", "channelPath_timeLabel": "Ura",
"channelPath_repeatsLabel": "Ponovi", "channelPath_repeatsLabel": "Ponovitve",
"channelPath_pathLabel": "Pot {index}", "channelPath_pathLabel": "Pot {index}",
"channelPath_observedLabel": "Opazovani", "channelPath_observedLabel": "Opazovani",
"channelPath_observedPathTitle": "Opazovana pot {index} • {hops}", "channelPath_observedPathTitle": "Opazovana pot {index} • {hops}",
@@ -1478,10 +1478,10 @@
"community_addPublicChannel": "Dodaj Objavni Kanal Komunitarja", "community_addPublicChannel": "Dodaj Objavni Kanal Komunitarja",
"community_addPublicChannelHint": "Samodejno dodaj javni kanal za to skupnost.", "community_addPublicChannelHint": "Samodejno dodaj javni kanal za to skupnost.",
"community_noCommunities": "Še nobena skupnost se ni pridružila.", "community_noCommunities": "Še nobena skupnost se ni pridružila.",
"community_scanOrCreate": "Skenirajte QR kodo ali ustvarite skupnost za začetek.", "community_scanOrCreate": "Skeniraj QR kodo ali ustvari skupnost za začetek.",
"community_manageCommunities": "Upravljajte skupnosti", "community_manageCommunities": "Upravljanje skupnosti",
"community_delete": "Opusti skupnost", "community_delete": "Opusti skupnost",
"community_deleteConfirm": "Zapustiti \"{name}\"?", "community_deleteConfirm": "Zapusti \"{name}\"?",
"community_deleteChannelsWarning": "To bo izbrisalo tudi {count} kanal/kanalov in njihova sporočila.", "community_deleteChannelsWarning": "To bo izbrisalo tudi {count} kanal/kanalov in njihova sporočila.",
"@community_deleteChannelsWarning": { "@community_deleteChannelsWarning": {
"placeholders": { "placeholders": {
@@ -1491,11 +1491,11 @@
} }
}, },
"community_deleted": "Zapustil skupnost \"{name}\"", "community_deleted": "Zapustil skupnost \"{name}\"",
"community_addHashtagChannel": "Dodaj Oznako Obštnine", "community_addHashtagChannel": "Dodaj hashtag kanal",
"community_addHashtagChannelDesc": "Dodajte hashtag kanal za to skupnost.", "community_addHashtagChannelDesc": "Dodajte hashtag kanal za to skupnost.",
"community_selectCommunity": "Izberi skupnost", "community_selectCommunity": "Izberi skupnost",
"community_regularHashtag": "Oznaka s hashtagom", "community_regularHashtag": "Oznaka s hashtagom",
"community_regularHashtagDesc": "javna oznaka (kateri koli lahko sodelujejo)", "community_regularHashtagDesc": "javna oznaka (kdorkoli lahko sodeluje)",
"community_communityHashtag": "Skupnostni hashtag", "community_communityHashtag": "Skupnostni hashtag",
"community_communityHashtagDesc": "Izključeno za uporabnike skupnosti", "community_communityHashtagDesc": "Izključeno za uporabnike skupnosti",
"community_forCommunity": "Za {name}", "community_forCommunity": "Za {name}",
@@ -1527,11 +1527,11 @@
} }
} }
}, },
"community_secretRegenerated": "Tajna za \"{name}\" ponovno ustvarjena", "community_secretRegenerated": "Geslo za \"{name}\" ponovno ustvarjeno",
"community_regenerateSecret": "Preberi nov tajni kôd", "community_regenerateSecret": "Ponovno ustvari geslo",
"community_regenerateSecretConfirm": "Preberite novo tajno geslo za \"{name}\"? Vsi članici morajo prebrati novo QR kodo, da lahko nadaljujejo s komunikacijo.", "community_regenerateSecretConfirm": "Preberite novo tajno geslo za \"{name}\"? Vsi članici morajo prebrati novo QR kodo, da lahko nadaljujejo s komunikacijo.",
"community_regenerate": "Preberi znova", "community_regenerate": "Preberi znova",
"community_scanToUpdateSecret": "Skeniraj nov kôd QR za posodabljanje tajne za {name}", "community_scanToUpdateSecret": "Skeniraj novo QR kodo za posodabljanje ključa za {name}",
"community_updateSecret": "Ažurniraj tajno", "community_updateSecret": "Ažuriraj ključ",
"community_secretUpdated": "Skrivnostno spremembo za \"{name}\"" "community_secretUpdated": "Skrivnostno spremembo za \"{name}\""
} }
+1538
View File
File diff suppressed because it is too large Load Diff
+152 -92
View File
@@ -8,6 +8,7 @@ import 'package:latlong2/latlong.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../connector/meshcore_connector.dart'; import '../connector/meshcore_connector.dart';
import '../helpers/chat_scroll_controller.dart';
import '../connector/meshcore_protocol.dart'; import '../connector/meshcore_protocol.dart';
import '../helpers/link_handler.dart'; import '../helpers/link_handler.dart';
import '../helpers/utf8_length_limiter.dart'; import '../helpers/utf8_length_limiter.dart';
@@ -17,6 +18,7 @@ import '../models/channel_message.dart';
import '../utils/emoji_utils.dart'; import '../utils/emoji_utils.dart';
import '../widgets/emoji_picker.dart'; import '../widgets/emoji_picker.dart';
import '../widgets/gif_message.dart'; import '../widgets/gif_message.dart';
import '../widgets/jump_to_bottom_button.dart';
import '../widgets/gif_picker.dart'; import '../widgets/gif_picker.dart';
import 'channel_message_path_screen.dart'; import 'channel_message_path_screen.dart';
import 'map_screen.dart'; import 'map_screen.dart';
@@ -35,42 +37,51 @@ class ChannelChatScreen extends StatefulWidget {
class _ChannelChatScreenState extends State<ChannelChatScreen> { class _ChannelChatScreenState extends State<ChannelChatScreen> {
final TextEditingController _textController = TextEditingController(); final TextEditingController _textController = TextEditingController();
final ScrollController _scrollController = ScrollController(); final ChatScrollController _scrollController = ChatScrollController();
final FocusNode _textFieldFocusNode = FocusNode();
ChannelMessage? _replyingToMessage; ChannelMessage? _replyingToMessage;
final Map<String, GlobalKey> _messageKeys = {}; final Map<String, GlobalKey> _messageKeys = {};
bool _isLoadingOlder = false;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_textFieldFocusNode.addListener(_onTextFieldFocusChange);
_scrollController.onScrollNearTop = _loadOlderMessages;
SchedulerBinding.instance.addPostFrameCallback((_) { SchedulerBinding.instance.addPostFrameCallback((_) {
if (!mounted) return; if (!mounted) return;
context.read<MeshCoreConnector>().setActiveChannel(widget.channel.index); context.read<MeshCoreConnector>().setActiveChannel(widget.channel.index);
// Scroll to bottom when opening channel chat - use SchedulerBinding for next frame
if (_scrollController.hasClients) {
_scrollController.jumpTo(_scrollController.position.maxScrollExtent);
}
}); });
} }
void _onTextFieldFocusChange() {
if (_textFieldFocusNode.hasFocus && mounted) {
_scrollController.handleKeyboardOpen();
}
}
Future<void> _loadOlderMessages() async {
if (_isLoadingOlder) return;
setState(() => _isLoadingOlder = true);
final connector = context.read<MeshCoreConnector>();
await connector.loadOlderChannelMessages(widget.channel.index);
if (mounted) {
setState(() => _isLoadingOlder = false);
}
}
@override @override
void dispose() { void dispose() {
context.read<MeshCoreConnector>().setActiveChannel(null); context.read<MeshCoreConnector>().setActiveChannel(null);
_textFieldFocusNode.removeListener(_onTextFieldFocusChange);
_textFieldFocusNode.dispose();
_textController.dispose(); _textController.dispose();
_scrollController.dispose(); _scrollController.dispose();
super.dispose(); super.dispose();
} }
void _scrollToBottom() {
if (_scrollController.hasClients) {
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
duration: const Duration(milliseconds: 300),
curve: Curves.easeOut,
);
}
}
void _setReplyingTo(ChannelMessage message) { void _setReplyingTo(ChannelMessage message) {
setState(() { setState(() {
_replyingToMessage = message; _replyingToMessage = message;
@@ -155,10 +166,6 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
builder: (context, connector, child) { builder: (context, connector, child) {
final messages = connector.getChannelMessages(widget.channel); final messages = connector.getChannelMessages(widget.channel);
SchedulerBinding.instance.addPostFrameCallback((_) {
_scrollToBottom();
});
if (messages.isEmpty) { if (messages.isEmpty) {
return Center( return Center(
child: Column( child: Column(
@@ -192,20 +199,51 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
); );
} }
return ListView.builder( // Reverse messages so newest appear at bottom with reverse: true
controller: _scrollController, final reversedMessages = messages.reversed.toList();
padding: const EdgeInsets.all(8), final itemCount = reversedMessages.length + (_isLoadingOlder ? 1 : 0);
itemCount: messages.length,
itemBuilder: (context, index) { // Auto-scroll to bottom if user is already at bottom
final message = messages[index]; WidgetsBinding.instance.addPostFrameCallback((_) {
if (!_messageKeys.containsKey(message.messageId)) { _scrollController.scrollToBottomIfAtBottom();
_messageKeys[message.messageId] = GlobalKey(); });
}
return Container( return Stack(
key: _messageKeys[message.messageId]!, children: [
child: _buildMessageBubble(message), ListView.builder(
); reverse: true, // List grows from bottom up
}, controller: _scrollController,
padding: const EdgeInsets.all(8),
itemCount: itemCount,
itemBuilder: (context, index) {
// Loading indicator now appears at end (bottom) of reversed list
if (_isLoadingOlder && index == itemCount - 1) {
return const Padding(
padding: EdgeInsets.symmetric(vertical: 16),
child: Center(
child: SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(strokeWidth: 2),
),
),
);
}
final messageIndex = index;
final message = reversedMessages[messageIndex];
if (!_messageKeys.containsKey(message.messageId)) {
_messageKeys[message.messageId] = GlobalKey();
}
return Container(
key: _messageKeys[message.messageId]!,
child: _buildMessageBubble(message),
);
},
),
JumpToBottomButton(
scrollController: _scrollController,
),
],
); );
}, },
), ),
@@ -243,7 +281,9 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
onTap: () => _showMessagePathInfo(message), onTap: () => _showMessagePathInfo(message),
onLongPress: () => _showMessageActions(message), onLongPress: () => _showMessageActions(message),
child: Container( child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), padding: gifId != null
? const EdgeInsets.all(4)
: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
constraints: BoxConstraints( constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * 0.65, maxWidth: MediaQuery.of(context).size.width * 0.65,
), ),
@@ -257,15 +297,20 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (!isOutgoing) ...[ if (!isOutgoing) ...[
Text( Padding(
message.senderName, padding: gifId != null
style: TextStyle( ? const EdgeInsets.only(left: 8, top: 4, bottom: 4)
fontSize: 12, : EdgeInsets.zero,
fontWeight: FontWeight.bold, child: Text(
color: Theme.of(context).colorScheme.primary, message.senderName,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.primary,
),
), ),
), ),
const SizedBox(height: 4), if (gifId == null) const SizedBox(height: 4),
], ],
if (message.replyToMessageId != null) ...[ if (message.replyToMessageId != null) ...[
_buildReplyPreview(message), _buildReplyPreview(message),
@@ -274,12 +319,15 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
if (poi != null) if (poi != null)
_buildPoiMessage(context, poi, isOutgoing) _buildPoiMessage(context, poi, isOutgoing)
else if (gifId != null) else if (gifId != null)
GifMessage( ClipRRect(
url: 'https://media.giphy.com/media/$gifId/giphy.gif', borderRadius: BorderRadius.circular(8),
backgroundColor: Theme.of(context).colorScheme.surfaceContainerHighest, child: GifMessage(
fallbackTextColor: isOutgoing url: 'https://media.giphy.com/media/$gifId/giphy.gif',
? Theme.of(context).colorScheme.onPrimaryContainer.withValues(alpha: 0.7) backgroundColor: Colors.transparent,
: Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.6), fallbackTextColor: isOutgoing
? Theme.of(context).colorScheme.onPrimaryContainer.withValues(alpha: 0.7)
: Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.6),
),
) )
else else
Linkify( Linkify(
@@ -299,46 +347,56 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
), ),
if (displayPath.isNotEmpty) ...[ if (displayPath.isNotEmpty) ...[
const SizedBox(height: 4), const SizedBox(height: 4),
Text( Padding(
'via ${_formatPathPrefixes(displayPath)}', padding: gifId != null
style: TextStyle(fontSize: 11, color: Colors.grey[600]), ? const EdgeInsets.symmetric(horizontal: 8)
: EdgeInsets.zero,
child: Text(
'via ${_formatPathPrefixes(displayPath)}',
style: TextStyle(fontSize: 11, color: Colors.grey[600]),
),
), ),
], ],
const SizedBox(height: 4), const SizedBox(height: 4),
Row( Padding(
mainAxisSize: MainAxisSize.min, padding: gifId != null
children: [ ? const EdgeInsets.only(left: 8, right: 8, bottom: 4)
Text( : EdgeInsets.zero,
_formatTime(message.timestamp), child: Row(
style: TextStyle( mainAxisSize: MainAxisSize.min,
fontSize: 11, children: [
color: Colors.grey[600],
),
),
if (message.repeatCount > 0) ...[
const SizedBox(width: 6),
Icon(Icons.repeat, size: 12, color: Colors.grey[600]),
const SizedBox(width: 2),
Text( Text(
'${message.repeatCount}', _formatTime(message.timestamp),
style: TextStyle(fontSize: 11, color: Colors.grey[600]), style: TextStyle(
fontSize: 11,
color: Colors.grey[600],
),
), ),
if (message.repeatCount > 0) ...[
const SizedBox(width: 6),
Icon(Icons.repeat, size: 12, color: Colors.grey[600]),
const SizedBox(width: 2),
Text(
'${message.repeatCount}',
style: TextStyle(fontSize: 11, color: Colors.grey[600]),
),
],
if (isOutgoing) ...[
const SizedBox(width: 4),
Icon(
message.status == ChannelMessageStatus.sent
? Icons.check
: message.status == ChannelMessageStatus.pending
? Icons.schedule
: Icons.error_outline,
size: 14,
color: message.status == ChannelMessageStatus.failed
? Colors.red
: Colors.grey[600],
),
],
], ],
if (isOutgoing) ...[ ),
const SizedBox(width: 4),
Icon(
message.status == ChannelMessageStatus.sent
? Icons.check
: message.status == ChannelMessageStatus.pending
? Icons.schedule
: Icons.error_outline,
size: 14,
color: message.status == ChannelMessageStatus.failed
? Colors.red
: Colors.grey[600],
),
],
],
), ),
], ],
), ),
@@ -377,8 +435,7 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
url: 'https://media.giphy.com/media/$gifId/giphy.gif', url: 'https://media.giphy.com/media/$gifId/giphy.gif',
backgroundColor: colorScheme.surfaceContainerHighest, backgroundColor: colorScheme.surfaceContainerHighest,
fallbackTextColor: previewTextColor, fallbackTextColor: previewTextColor,
width: 120, maxSize: 80,
height: 80,
), ),
); );
} else if (poi != null) { } else if (poi != null) {
@@ -703,14 +760,16 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
return Row( return Row(
children: [ children: [
Expanded( Expanded(
child: GifMessage( child: ClipRRect(
url: 'https://media.giphy.com/media/$gifId/giphy.gif', borderRadius: BorderRadius.circular(12),
backgroundColor: child: GifMessage(
Theme.of(context).colorScheme.surfaceContainerHighest, url: 'https://media.giphy.com/media/$gifId/giphy.gif',
fallbackTextColor: backgroundColor:
Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.6), Theme.of(context).colorScheme.surfaceContainerHighest,
width: 160, fallbackTextColor:
height: 110, Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.6),
maxSize: 160,
),
), ),
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
@@ -724,6 +783,7 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
return TextField( return TextField(
controller: _textController, controller: _textController,
focusNode: _textFieldFocusNode,
inputFormatters: [ inputFormatters: [
Utf8LengthLimitingTextInputFormatter(maxBytes), Utf8LengthLimitingTextInputFormatter(maxBytes),
], ],
+1
View File
@@ -312,6 +312,7 @@ class _ChannelsScreenState extends State<ChannelsScreen>
), ),
floatingActionButton: FloatingActionButton( floatingActionButton: FloatingActionButton(
onPressed: () => _showAddChannelDialog(context), onPressed: () => _showAddChannelDialog(context),
tooltip: context.l10n.channels_addChannel,
child: const Icon(Icons.add), child: const Icon(Icons.add),
), ),
bottomNavigationBar: SafeArea( bottomNavigationBar: SafeArea(
+138 -73
View File
@@ -11,6 +11,7 @@ import 'package:latlong2/latlong.dart';
import '../connector/meshcore_connector.dart'; import '../connector/meshcore_connector.dart';
import '../connector/meshcore_protocol.dart'; import '../connector/meshcore_protocol.dart';
import '../helpers/chat_scroll_controller.dart';
import '../helpers/link_handler.dart'; import '../helpers/link_handler.dart';
import '../helpers/utf8_length_limiter.dart'; import '../helpers/utf8_length_limiter.dart';
import '../models/channel_message.dart'; import '../models/channel_message.dart';
@@ -22,6 +23,7 @@ import 'map_screen.dart';
import '../utils/emoji_utils.dart'; import '../utils/emoji_utils.dart';
import '../widgets/emoji_picker.dart'; import '../widgets/emoji_picker.dart';
import '../widgets/gif_message.dart'; import '../widgets/gif_message.dart';
import '../widgets/jump_to_bottom_button.dart';
import '../widgets/gif_picker.dart'; import '../widgets/gif_picker.dart';
import '../widgets/path_selection_dialog.dart'; import '../widgets/path_selection_dialog.dart';
import '../utils/app_logger.dart'; import '../utils/app_logger.dart';
@@ -38,25 +40,44 @@ class ChatScreen extends StatefulWidget {
class _ChatScreenState extends State<ChatScreen> { class _ChatScreenState extends State<ChatScreen> {
final _textController = TextEditingController(); final _textController = TextEditingController();
final _scrollController = ScrollController(); final _scrollController = ChatScrollController();
final _textFieldFocusNode = FocusNode();
bool _isLoadingOlder = false;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_textFieldFocusNode.addListener(_onTextFieldFocusChange);
_scrollController.onScrollNearTop = _loadOlderMessages;
SchedulerBinding.instance.addPostFrameCallback((_) { SchedulerBinding.instance.addPostFrameCallback((_) {
if (!mounted) return; if (!mounted) return;
context.read<MeshCoreConnector>().setActiveContact(widget.contact.publicKeyHex); context.read<MeshCoreConnector>().setActiveContact(widget.contact.publicKeyHex);
// Scroll to bottom when opening chat use SchedulerBinding for next frame
if (_scrollController.hasClients) {
_scrollController.jumpTo(_scrollController.position.maxScrollExtent);
}
}); });
} }
void _onTextFieldFocusChange() {
if (_textFieldFocusNode.hasFocus && mounted) {
_scrollController.handleKeyboardOpen();
}
}
Future<void> _loadOlderMessages() async {
if (_isLoadingOlder) return;
setState(() => _isLoadingOlder = true);
final connector = context.read<MeshCoreConnector>();
await connector.loadOlderMessages(widget.contact.publicKeyHex);
if (mounted) {
setState(() => _isLoadingOlder = false);
}
}
@override @override
void dispose() { void dispose() {
context.read<MeshCoreConnector>().setActiveContact(null); context.read<MeshCoreConnector>().setActiveContact(null);
_textFieldFocusNode.removeListener(_onTextFieldFocusChange);
_textFieldFocusNode.dispose();
_textController.dispose(); _textController.dispose();
_scrollController.dispose(); _scrollController.dispose();
super.dispose(); super.dispose();
@@ -169,9 +190,16 @@ class _ChatScreenState extends State<ChatScreen> {
return Column( return Column(
children: [ children: [
Expanded( Expanded(
child: messages.isEmpty child: Stack(
? _buildEmptyState() children: [
: _buildMessageList(messages, connector), messages.isEmpty
? _buildEmptyState()
: _buildMessageList(messages, connector),
JumpToBottomButton(
scrollController: _scrollController,
),
],
),
), ),
_buildInputBar(connector), _buildInputBar(connector),
], ],
@@ -203,13 +231,37 @@ class _ChatScreenState extends State<ChatScreen> {
} }
Widget _buildMessageList(List<Message> messages, MeshCoreConnector connector) { Widget _buildMessageList(List<Message> messages, MeshCoreConnector connector) {
// Reverse messages so newest appear at bottom with reverse: true
final reversedMessages = messages.reversed.toList();
final itemCount = reversedMessages.length + (_isLoadingOlder ? 1 : 0);
// Auto-scroll to bottom if user is already at bottom
WidgetsBinding.instance.addPostFrameCallback((_) {
_scrollController.scrollToBottomIfAtBottom();
});
return ListView.builder( return ListView.builder(
reverse: true, // List grows from bottom up
controller: _scrollController, controller: _scrollController,
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 16),
itemCount: messages.length, itemCount: itemCount,
itemBuilder: (context, index) { itemBuilder: (context, index) {
// Loading indicator now appears at end (bottom) of reversed list
if (_isLoadingOlder && index == itemCount - 1) {
return const Padding(
padding: EdgeInsets.symmetric(vertical: 16),
child: Center(
child: SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(strokeWidth: 2),
),
),
);
}
final messageIndex = index;
Contact contact = widget.contact; Contact contact = widget.contact;
final message = messages[index]; final message = reversedMessages[messageIndex];
String fourByteHex = ''; String fourByteHex = '';
if (widget.contact.type == advTypeRoom) { if (widget.contact.type == advTypeRoom) {
contact = _resolveContactFrom4Bytes( contact = _resolveContactFrom4Bytes(
@@ -258,13 +310,15 @@ class _ChatScreenState extends State<ChatScreen> {
return Row( return Row(
children: [ children: [
Expanded( Expanded(
child: GifMessage( child: ClipRRect(
url: 'https://media.giphy.com/media/$gifId/giphy.gif', borderRadius: BorderRadius.circular(12),
backgroundColor: colorScheme.surfaceContainerHighest, child: GifMessage(
fallbackTextColor: url: 'https://media.giphy.com/media/$gifId/giphy.gif',
colorScheme.onSurface.withValues(alpha: 0.6), backgroundColor: colorScheme.surfaceContainerHighest,
width: 160, fallbackTextColor:
height: 110, colorScheme.onSurface.withValues(alpha: 0.6),
maxSize: 160,
),
), ),
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
@@ -278,6 +332,7 @@ class _ChatScreenState extends State<ChatScreen> {
return TextField( return TextField(
controller: _textController, controller: _textController,
focusNode: _textFieldFocusNode,
inputFormatters: [ inputFormatters: [
Utf8LengthLimitingTextInputFormatter(maxBytes), Utf8LengthLimitingTextInputFormatter(maxBytes),
], ],
@@ -339,16 +394,6 @@ class _ChatScreenState extends State<ChatScreen> {
text, text,
); );
_textController.clear(); _textController.clear();
Future.delayed(const Duration(milliseconds: 100), () {
if (_scrollController.hasClients) {
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
duration: const Duration(milliseconds: 200),
curve: Curves.easeOut,
);
}
});
} }
@@ -960,7 +1005,9 @@ class _MessageBubble extends StatelessWidget {
], ],
Flexible( Flexible(
child: Container( child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), padding: gifId != null
? const EdgeInsets.all(4)
: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
constraints: BoxConstraints( constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * 0.65, maxWidth: MediaQuery.of(context).size.width * 0.65,
), ),
@@ -972,23 +1019,31 @@ class _MessageBubble extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
if (!isOutgoing) ...[ if (!isOutgoing) ...[
Text( Padding(
senderName, padding: gifId != null
style: TextStyle( ? const EdgeInsets.only(left: 8, top: 4, bottom: 4)
fontSize: 12, : EdgeInsets.zero,
fontWeight: FontWeight.bold, child: Text(
color: colorScheme.primary, senderName,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: colorScheme.primary,
),
), ),
), ),
const SizedBox(height: 4), if (gifId == null) const SizedBox(height: 4),
], ],
if (poi != null) if (poi != null)
_buildPoiMessage(context, poi, textColor, metaColor) _buildPoiMessage(context, poi, textColor, metaColor)
else if (gifId != null) else if (gifId != null)
GifMessage( ClipRRect(
url: 'https://media.giphy.com/media/$gifId/giphy.gif', borderRadius: BorderRadius.circular(12),
backgroundColor: bubbleColor, child: GifMessage(
fallbackTextColor: textColor.withValues(alpha: 0.7), url: 'https://media.giphy.com/media/$gifId/giphy.gif',
backgroundColor: Colors.transparent,
fallbackTextColor: textColor.withValues(alpha: 0.7),
),
) )
else else
Linkify( Linkify(
@@ -1009,48 +1064,58 @@ class _MessageBubble extends StatelessWidget {
), ),
if (isOutgoing && message.retryCount > 0) ...[ if (isOutgoing && message.retryCount > 0) ...[
const SizedBox(height: 4), const SizedBox(height: 4),
Text( Padding(
context.l10n.chat_retryCount(message.retryCount, 4), padding: gifId != null
style: TextStyle( ? const EdgeInsets.symmetric(horizontal: 8)
fontSize: 10, : EdgeInsets.zero,
color: metaColor, child: Text(
fontWeight: FontWeight.w500, context.l10n.chat_retryCount(message.retryCount, 4),
style: TextStyle(
fontSize: 10,
color: metaColor,
fontWeight: FontWeight.w500,
),
), ),
), ),
], ],
const SizedBox(height: 4), const SizedBox(height: 4),
Wrap( Padding(
spacing: 4, padding: gifId != null
crossAxisAlignment: WrapCrossAlignment.center, ? const EdgeInsets.only(left: 8, right: 8, bottom: 4)
children: [ : EdgeInsets.zero,
Text( child: Wrap(
_formatTime(message.timestamp), spacing: 4,
style: TextStyle( crossAxisAlignment: WrapCrossAlignment.center,
fontSize: 10, children: [
color: metaColor,
),
),
if (isOutgoing) ...[
const SizedBox(width: 4),
_buildStatusIcon(metaColor),
],
if (message.tripTimeMs != null &&
message.status == MessageStatus.delivered) ...[
const SizedBox(width: 4),
Icon(
Icons.speed,
size: 10,
color: isOutgoing ? metaColor : Colors.green[700],
),
Text( Text(
'${(message.tripTimeMs! / 1000).toStringAsFixed(1)}s', _formatTime(message.timestamp),
style: TextStyle( style: TextStyle(
fontSize: 9, fontSize: 10,
color: isOutgoing ? metaColor : Colors.green[700], color: metaColor,
), ),
), ),
if (isOutgoing) ...[
const SizedBox(width: 4),
_buildStatusIcon(metaColor),
],
if (message.tripTimeMs != null &&
message.status == MessageStatus.delivered) ...[
const SizedBox(width: 4),
Icon(
Icons.speed,
size: 10,
color: isOutgoing ? metaColor : Colors.green[700],
),
Text(
'${(message.tripTimeMs! / 1000).toStringAsFixed(1)}s',
style: TextStyle(
fontSize: 9,
color: isOutgoing ? metaColor : Colors.green[700],
),
),
],
], ],
], ),
), ),
], ],
), ),
+31 -14
View File
@@ -315,6 +315,14 @@ class _ContactsScreenState extends State<ContactsScreen>
return matchesContactQuery(contact, _searchQuery); return matchesContactQuery(contact, _searchQuery);
}).toList(); }).toList();
// Filter out own node from the list
if (connector.selfPublicKey != null) {
final selfPubKeyHex = pubKeyToHex(connector.selfPublicKey!);
filtered = filtered.where((contact) {
return contact.publicKeyHex != selfPubKeyHex;
}).toList();
}
if (_typeFilter != ContactTypeFilter.all) { if (_typeFilter != ContactTypeFilter.all) {
filtered = filtered.where(_matchesTypeFilter).toList(); filtered = filtered.where(_matchesTypeFilter).toList();
} }
@@ -901,21 +909,30 @@ class _ContactTile extends StatelessWidget {
subtitle: Text( subtitle: Text(
'${contact.typeLabel}${contact.pathLabel} ${contact.shortPubKeyHex}', '${contact.typeLabel}${contact.pathLabel} ${contact.shortPubKeyHex}',
), ),
trailing: Column( // Clamp text scaling in trailing section to prevent overflow while
mainAxisAlignment: MainAxisAlignment.center, // maintaining accessibility. Primary content (title/subtitle) scales normally.
crossAxisAlignment: CrossAxisAlignment.end, trailing: MediaQuery(
children: [ data: MediaQuery.of(context).copyWith(
if (unreadCount > 0) ...[ textScaler: TextScaler.linear(
UnreadBadge(count: unreadCount), MediaQuery.textScalerOf(context).scale(1.0).clamp(1.0, 1.3),
const SizedBox(height: 4),
],
Text(
_formatLastSeen(context, lastSeen),
style: TextStyle(fontSize: 12, color: Colors.grey[600]),
), ),
if (contact.hasLocation) ),
Icon(Icons.location_on, size: 14, color: Colors.grey[400]), child: Column(
], mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
if (unreadCount > 0) ...[
UnreadBadge(count: unreadCount),
const SizedBox(height: 4),
],
Text(
_formatLastSeen(context, lastSeen),
style: TextStyle(fontSize: 12, color: Colors.grey[600]),
),
if (contact.hasLocation)
Icon(Icons.location_on, size: 14, color: Colors.grey[400]),
],
),
), ),
onTap: onTap, onTap: onTap,
onLongPress: onLongPress, onLongPress: onLongPress,
+1
View File
@@ -354,6 +354,7 @@ class _MapScreenState extends State<MapScreen> {
), ),
floatingActionButton: FloatingActionButton( floatingActionButton: FloatingActionButton(
onPressed: () => _showFilterDialog(context, settingsService), onPressed: () => _showFilterDialog(context, settingsService),
tooltip: context.l10n.map_filterNodes,
child: const Icon(Icons.filter_list), child: const Icon(Icons.filter_list),
), ),
), ),
+39 -10
View File
@@ -8,9 +8,47 @@ import '../widgets/device_tile.dart';
import 'contacts_screen.dart'; import 'contacts_screen.dart';
/// Screen for scanning and connecting to MeshCore devices /// Screen for scanning and connecting to MeshCore devices
class ScannerScreen extends StatelessWidget { class ScannerScreen extends StatefulWidget {
const ScannerScreen({super.key}); const ScannerScreen({super.key});
@override
State<ScannerScreen> createState() => _ScannerScreenState();
}
class _ScannerScreenState extends State<ScannerScreen> {
bool _changedNavigation = false;
late final VoidCallback _connectionListener;
@override
void initState() {
super.initState();
final connector = Provider.of<MeshCoreConnector>(context, listen: false);
_connectionListener = () {
if (connector.state == MeshCoreConnectionState.disconnected) {
_changedNavigation = false;
} else if (connector.state == MeshCoreConnectionState.connected && !_changedNavigation) {
_changedNavigation = true;
if (mounted) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const ContactsScreen(),
),
);
}
}
};
connector.addListener(_connectionListener);
}
@override
void dispose() {
final connector = Provider.of<MeshCoreConnector>(context, listen: false);
connector.removeListener(_connectionListener);
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@@ -161,15 +199,6 @@ final l10n = context.l10n;
? result.device.platformName ? result.device.platformName
: result.advertisementData.advName; : result.advertisementData.advName;
await connector.connect(result.device, displayName: name); await connector.connect(result.device, displayName: name);
if (context.mounted && connector.isConnected) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const ContactsScreen(),
),
);
}
} catch (e) { } catch (e) {
if (context.mounted) { if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
+42 -25
View File
@@ -6,16 +6,14 @@ class GifMessage extends StatefulWidget {
final String url; final String url;
final Color backgroundColor; final Color backgroundColor;
final Color fallbackTextColor; final Color fallbackTextColor;
final double width; final double maxSize;
final double height;
const GifMessage({ const GifMessage({
super.key, super.key,
required this.url, required this.url,
required this.backgroundColor, required this.backgroundColor,
required this.fallbackTextColor, required this.fallbackTextColor,
this.width = 200, this.maxSize = 200,
this.height = 140,
}); });
@override @override
@@ -122,6 +120,28 @@ class _GifMessageState extends State<GifMessage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// Calculate display size based on image aspect ratio
// Use 4:3 placeholder aspect ratio during loading to minimize layout shifts
double displayWidth = widget.maxSize;
double displayHeight = widget.maxSize * 0.75;
if (_image != null) {
final imageWidth = _image!.width.toDouble();
final imageHeight = _image!.height.toDouble();
final aspectRatio = imageWidth / imageHeight;
// Fit within maxSize, calculating dimensions from aspect ratio
if (aspectRatio >= 1) {
// Wider than tall: constrain by width
displayWidth = widget.maxSize;
displayHeight = displayWidth / aspectRatio;
} else {
// Taller than wide: constrain by height
displayHeight = widget.maxSize;
displayWidth = displayHeight * aspectRatio;
}
}
Widget content; Widget content;
if (_error != null) { if (_error != null) {
@@ -151,33 +171,30 @@ class _GifMessageState extends State<GifMessage> {
} else { } else {
content = RawImage( content = RawImage(
image: _image, image: _image,
fit: BoxFit.cover, fit: BoxFit.contain,
width: widget.width, width: displayWidth,
height: widget.height, height: displayHeight,
); );
} }
return GestureDetector( return GestureDetector(
onTap: _togglePause, onTap: _togglePause,
child: ClipRRect( child: Container(
borderRadius: BorderRadius.circular(10), color: widget.backgroundColor,
child: Container( width: displayWidth,
color: widget.backgroundColor, height: displayHeight,
width: widget.width, child: Stack(
height: widget.height, fit: StackFit.expand,
child: Stack( children: [
fit: StackFit.expand, content,
children: [ if (_isPaused && _image != null)
content, Container(
if (_isPaused && _image != null) color: Colors.black.withValues(alpha: 0.2),
Container( child: const Center(
color: Colors.black.withValues(alpha: 0.2), child: Icon(Icons.pause, color: Colors.white70, size: 28),
child: const Center(
child: Icon(Icons.pause, color: Colors.white70, size: 28),
),
), ),
], ),
), ],
), ),
), ),
); );
+29
View File
@@ -0,0 +1,29 @@
import 'package:flutter/material.dart';
import '../helpers/chat_scroll_controller.dart';
class JumpToBottomButton extends StatelessWidget {
final ChatScrollController scrollController;
const JumpToBottomButton({
super.key,
required this.scrollController,
});
@override
Widget build(BuildContext context) {
return ValueListenableBuilder<bool>(
valueListenable: scrollController.showJumpToBottom,
builder: (context, show, _) {
if (!show) return const SizedBox.shrink();
return Positioned(
right: 16,
bottom: 16,
child: FloatingActionButton.small(
onPressed: scrollController.jumpToBottom,
child: const Icon(Icons.keyboard_arrow_down),
),
);
},
);
}
}
+1
View File
@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig"
+1
View File
@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig"
+42
View File
@@ -0,0 +1,42 @@
platform :osx, '10.15'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\""
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_macos_podfile_setup
target 'Runner' do
use_frameworks!
flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_macos_build_settings(target)
end
end
+74
View File
@@ -0,0 +1,74 @@
PODS:
- flutter_blue_plus_darwin (0.0.2):
- Flutter
- FlutterMacOS
- flutter_local_notifications (0.0.1):
- FlutterMacOS
- FlutterMacOS (1.0.0)
- mobile_scanner (6.0.2):
- FlutterMacOS
- package_info_plus (0.0.1):
- FlutterMacOS
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- sqflite_darwin (0.0.4):
- Flutter
- FlutterMacOS
- url_launcher_macos (0.0.1):
- FlutterMacOS
- wakelock_plus (0.0.1):
- FlutterMacOS
DEPENDENCIES:
- flutter_blue_plus_darwin (from `Flutter/ephemeral/.symlinks/plugins/flutter_blue_plus_darwin/darwin`)
- flutter_local_notifications (from `Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos`)
- FlutterMacOS (from `Flutter/ephemeral`)
- mobile_scanner (from `Flutter/ephemeral/.symlinks/plugins/mobile_scanner/macos`)
- package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`)
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite_darwin (from `Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin`)
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
- wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`)
EXTERNAL SOURCES:
flutter_blue_plus_darwin:
:path: Flutter/ephemeral/.symlinks/plugins/flutter_blue_plus_darwin/darwin
flutter_local_notifications:
:path: Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos
FlutterMacOS:
:path: Flutter/ephemeral
mobile_scanner:
:path: Flutter/ephemeral/.symlinks/plugins/mobile_scanner/macos
package_info_plus:
:path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos
path_provider_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
shared_preferences_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
sqflite_darwin:
:path: Flutter/ephemeral/.symlinks/plugins/sqflite_darwin/darwin
url_launcher_macos:
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
wakelock_plus:
:path: Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos
SPEC CHECKSUMS:
flutter_blue_plus_darwin: 20a08bfeaa0f7804d524858d3d8744bcc1b6dbc3
flutter_local_notifications: 13862b132e32eb858dea558a86d45d08daeacfe7
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
mobile_scanner: 0e365ed56cad24f28c0fd858ca04edefb40dfac3
package_info_plus: f0052d280d17aa382b932f399edf32507174e870
path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
url_launcher_macos: f87a979182d112f911de6820aefddaf56ee9fbfd
wakelock_plus: 917609be14d812ddd9e9528876538b2263aaa03b
PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009
COCOAPODS: 1.16.2
+97 -1
View File
@@ -27,6 +27,8 @@
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
99C5B380294D2DE19A818101 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B665683D805EE21638F484F2 /* Pods_RunnerTests.framework */; };
D7DDCBD47F2955423D77927D /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0F985DDB6BE5BEB6B545DE9A /* Pods_Runner.framework */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@@ -60,11 +62,13 @@
/* End PBXCopyFilesBuildPhase section */ /* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
00F1FE94A1827B8A00BD3DB9 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
0F985DDB6BE5BEB6B545DE9A /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; }; 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
33CC10ED2044A3C60003C045 /* meshcore_open.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "meshcore_open.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10ED2044A3C60003C045 /* meshcore_open.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = meshcore_open.app; sourceTree = BUILT_PRODUCTS_DIR; };
33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
@@ -76,8 +80,14 @@
33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; }; 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
4172BCCDFD1E1404F7155426 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
96DE804777D5630B2C6952B5 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
B665683D805EE21638F484F2 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
BEFF4DDC60AFB628205F8E82 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
D99E941424F19B7B9AA1B968 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
EA5A89F8C49904B995EFAA24 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@@ -85,6 +95,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
99C5B380294D2DE19A818101 /* Pods_RunnerTests.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -92,6 +103,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
D7DDCBD47F2955423D77927D /* Pods_Runner.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -125,6 +137,7 @@
331C80D6294CF71000263BE5 /* RunnerTests */, 331C80D6294CF71000263BE5 /* RunnerTests */,
33CC10EE2044A3C60003C045 /* Products */, 33CC10EE2044A3C60003C045 /* Products */,
D73912EC22F37F3D000D13A0 /* Frameworks */, D73912EC22F37F3D000D13A0 /* Frameworks */,
73DBB8BFF247FD65EEC878CC /* Pods */,
); );
sourceTree = "<group>"; sourceTree = "<group>";
}; };
@@ -172,9 +185,25 @@
path = Runner; path = Runner;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
73DBB8BFF247FD65EEC878CC /* Pods */ = {
isa = PBXGroup;
children = (
BEFF4DDC60AFB628205F8E82 /* Pods-Runner.debug.xcconfig */,
4172BCCDFD1E1404F7155426 /* Pods-Runner.release.xcconfig */,
00F1FE94A1827B8A00BD3DB9 /* Pods-Runner.profile.xcconfig */,
96DE804777D5630B2C6952B5 /* Pods-RunnerTests.debug.xcconfig */,
EA5A89F8C49904B995EFAA24 /* Pods-RunnerTests.release.xcconfig */,
D99E941424F19B7B9AA1B968 /* Pods-RunnerTests.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
D73912EC22F37F3D000D13A0 /* Frameworks */ = { D73912EC22F37F3D000D13A0 /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
0F985DDB6BE5BEB6B545DE9A /* Pods_Runner.framework */,
B665683D805EE21638F484F2 /* Pods_RunnerTests.framework */,
); );
name = Frameworks; name = Frameworks;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -186,6 +215,7 @@
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = ( buildPhases = (
7DEC542F9A4811B2EEDCB8C1 /* [CP] Check Pods Manifest.lock */,
331C80D1294CF70F00263BE5 /* Sources */, 331C80D1294CF70F00263BE5 /* Sources */,
331C80D2294CF70F00263BE5 /* Frameworks */, 331C80D2294CF70F00263BE5 /* Frameworks */,
331C80D3294CF70F00263BE5 /* Resources */, 331C80D3294CF70F00263BE5 /* Resources */,
@@ -204,11 +234,13 @@
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = ( buildPhases = (
79D67F01E273245A9C69C0B6 /* [CP] Check Pods Manifest.lock */,
33CC10E92044A3C60003C045 /* Sources */, 33CC10E92044A3C60003C045 /* Sources */,
33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EA2044A3C60003C045 /* Frameworks */,
33CC10EB2044A3C60003C045 /* Resources */, 33CC10EB2044A3C60003C045 /* Resources */,
33CC110E2044A8840003C045 /* Bundle Framework */, 33CC110E2044A8840003C045 /* Bundle Framework */,
3399D490228B24CF009A79C7 /* ShellScript */, 3399D490228B24CF009A79C7 /* ShellScript */,
306490712F2EAA29CA421662 /* [CP] Embed Pods Frameworks */,
); );
buildRules = ( buildRules = (
); );
@@ -291,6 +323,23 @@
/* End PBXResourcesBuildPhase section */ /* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */
306490712F2EAA29CA421662 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
3399D490228B24CF009A79C7 /* ShellScript */ = { 3399D490228B24CF009A79C7 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1; alwaysOutOfDate = 1;
@@ -329,6 +378,50 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
}; };
79D67F01E273245A9C69C0B6 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
7DEC542F9A4811B2EEDCB8C1 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
@@ -380,6 +473,7 @@
/* Begin XCBuildConfiguration section */ /* Begin XCBuildConfiguration section */
331C80DB294CF71000263BE5 /* Debug */ = { 331C80DB294CF71000263BE5 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 96DE804777D5630B2C6952B5 /* Pods-RunnerTests.debug.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
@@ -394,6 +488,7 @@
}; };
331C80DC294CF71000263BE5 /* Release */ = { 331C80DC294CF71000263BE5 /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = EA5A89F8C49904B995EFAA24 /* Pods-RunnerTests.release.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
@@ -408,6 +503,7 @@
}; };
331C80DD294CF71000263BE5 /* Profile */ = { 331C80DD294CF71000263BE5 /* Profile */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = D99E941424F19B7B9AA1B968 /* Pods-RunnerTests.profile.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
+3
View File
@@ -4,4 +4,7 @@
<FileRef <FileRef
location = "group:Runner.xcodeproj"> location = "group:Runner.xcodeproj">
</FileRef> </FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace> </Workspace>
+1 -1
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 # 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 # 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. # of the product and file versions while build-number is used as the build suffix.
version: 0.4.0+4 version: 5.0.0+5
environment: environment:
sdk: ^3.9.2 sdk: ^3.9.2