Remove old app icons and update Info.plist version; add radio settings localization and improve device configuration UI
@@ -13,6 +13,9 @@ android {
|
|||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility = JavaVersion.VERSION_11
|
sourceCompatibility = JavaVersion.VERSION_11
|
||||||
targetCompatibility = JavaVersion.VERSION_11
|
targetCompatibility = JavaVersion.VERSION_11
|
||||||
|
// Required by some dependencies (e.g., flutter_local_notifications)
|
||||||
|
// to support Java 8+ APIs on older Android devices.
|
||||||
|
isCoreLibraryDesugaringEnabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
@@ -42,3 +45,8 @@ android {
|
|||||||
flutter {
|
flutter {
|
||||||
source = "../.."
|
source = "../.."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
// Core library desugaring support library
|
||||||
|
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4")
|
||||||
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 24 KiB |
BIN
icon.png
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.0 MiB |
BIN
ios/Runner.ipa
@@ -489,7 +489,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 14;
|
CURRENT_PROJECT_VERSION = 17;
|
||||||
DEVELOPMENT_TEAM = JND55328G8;
|
DEVELOPMENT_TEAM = JND55328G8;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
@@ -511,7 +511,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 14;
|
CURRENT_PROJECT_VERSION = 17;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.meshcore.sar.meshcoreSarApp.RunnerTests;
|
PRODUCT_BUNDLE_IDENTIFIER = com.meshcore.sar.meshcoreSarApp.RunnerTests;
|
||||||
@@ -529,7 +529,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 14;
|
CURRENT_PROJECT_VERSION = 17;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.meshcore.sar.meshcoreSarApp.RunnerTests;
|
PRODUCT_BUNDLE_IDENTIFIER = com.meshcore.sar.meshcoreSarApp.RunnerTests;
|
||||||
@@ -545,7 +545,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 14;
|
CURRENT_PROJECT_VERSION = 17;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.meshcore.sar.meshcoreSarApp.RunnerTests;
|
PRODUCT_BUNDLE_IDENTIFIER = com.meshcore.sar.meshcoreSarApp.RunnerTests;
|
||||||
@@ -676,7 +676,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 14;
|
CURRENT_PROJECT_VERSION = 17;
|
||||||
DEVELOPMENT_TEAM = JND55328G8;
|
DEVELOPMENT_TEAM = JND55328G8;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
@@ -699,7 +699,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 14;
|
CURRENT_PROJECT_VERSION = 17;
|
||||||
DEVELOPMENT_TEAM = JND55328G8;
|
DEVELOPMENT_TEAM = JND55328G8;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 821 KiB |
|
Before Width: | Height: | Size: 861 B After Width: | Height: | Size: 881 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 8.7 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 19 KiB |
@@ -21,7 +21,7 @@
|
|||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>14</string>
|
<string>17</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>UILaunchStoryboardName</key>
|
<key>UILaunchStoryboardName</key>
|
||||||
|
|||||||
@@ -5,22 +5,17 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000206">
|
<testcase classname="fastlane.lanes" name="0: default_platform" time="0.000203">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="1: increment_build_number" time="0.235136">
|
<testcase classname="fastlane.lanes" name="1: increment_build_number" time="0.287931">
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="2: build_app" time="103.133272">
|
<testcase classname="fastlane.lanes" name="2: build_app" time="31.633362">
|
||||||
|
|
||||||
</testcase>
|
|
||||||
|
|
||||||
|
|
||||||
<testcase classname="fastlane.lanes" name="3: upload_to_testflight" time="333.986172">
|
|
||||||
|
|
||||||
</testcase>
|
</testcase>
|
||||||
|
|
||||||
|
|||||||
@@ -1733,5 +1733,48 @@
|
|||||||
"tapToViewOnMap": "Tap to view on map",
|
"tapToViewOnMap": "Tap to view on map",
|
||||||
"@tapToViewOnMap": {
|
"@tapToViewOnMap": {
|
||||||
"description": "Notification action text"
|
"description": "Notification action text"
|
||||||
|
},
|
||||||
|
|
||||||
|
"radioSettings": "Radio Settings",
|
||||||
|
"@radioSettings": {
|
||||||
|
"description": "Section title for radio settings"
|
||||||
|
},
|
||||||
|
|
||||||
|
"frequencyMHz": "Frequency (MHz)",
|
||||||
|
"@frequencyMHz": {
|
||||||
|
"description": "Label for radio frequency field"
|
||||||
|
},
|
||||||
|
|
||||||
|
"frequencyExample": "e.g., 869.618",
|
||||||
|
"@frequencyExample": {
|
||||||
|
"description": "Helper text example for frequency"
|
||||||
|
},
|
||||||
|
|
||||||
|
"bandwidth": "Bandwidth",
|
||||||
|
"@bandwidth": {
|
||||||
|
"description": "Label for bandwidth dropdown"
|
||||||
|
},
|
||||||
|
|
||||||
|
"spreadingFactor": "Spreading Factor",
|
||||||
|
"@spreadingFactor": {
|
||||||
|
"description": "Label for spreading factor dropdown"
|
||||||
|
},
|
||||||
|
|
||||||
|
"codingRate": "Coding Rate",
|
||||||
|
"@codingRate": {
|
||||||
|
"description": "Label for coding rate dropdown"
|
||||||
|
},
|
||||||
|
|
||||||
|
"txPowerDbm": "TX Power (dBm)",
|
||||||
|
"@txPowerDbm": {
|
||||||
|
"description": "Label for TX power field"
|
||||||
|
},
|
||||||
|
|
||||||
|
"maxPowerDbm": "Max: {power} dBm",
|
||||||
|
"@maxPowerDbm": {
|
||||||
|
"description": "Helper text showing maximum TX power",
|
||||||
|
"placeholders": {
|
||||||
|
"power": { "type": "int" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -581,5 +581,14 @@
|
|||||||
|
|
||||||
"coordinates": "Koordinate",
|
"coordinates": "Koordinate",
|
||||||
|
|
||||||
"tapToViewOnMap": "Dodirnite za prikaz na karti"
|
"tapToViewOnMap": "Dodirnite za prikaz na karti",
|
||||||
|
|
||||||
|
"radioSettings": "Postavke radija",
|
||||||
|
"frequencyMHz": "Frekvencija (MHz)",
|
||||||
|
"frequencyExample": "npr. 869.618",
|
||||||
|
"bandwidth": "Širina pojasa",
|
||||||
|
"spreadingFactor": "Faktor širenja",
|
||||||
|
"codingRate": "Omjer kodiranja",
|
||||||
|
"txPowerDbm": "TX snaga (dBm)",
|
||||||
|
"maxPowerDbm": "Maks: {power} dBm"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1850,6 +1850,54 @@ abstract class AppLocalizations {
|
|||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Tap to view on map'**
|
/// **'Tap to view on map'**
|
||||||
String get tapToViewOnMap;
|
String get tapToViewOnMap;
|
||||||
|
|
||||||
|
/// Section title for radio settings
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Radio Settings'**
|
||||||
|
String get radioSettings;
|
||||||
|
|
||||||
|
/// Label for radio frequency field
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Frequency (MHz)'**
|
||||||
|
String get frequencyMHz;
|
||||||
|
|
||||||
|
/// Helper text example for frequency
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'e.g., 869.618'**
|
||||||
|
String get frequencyExample;
|
||||||
|
|
||||||
|
/// Label for bandwidth dropdown
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Bandwidth'**
|
||||||
|
String get bandwidth;
|
||||||
|
|
||||||
|
/// Label for spreading factor dropdown
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Spreading Factor'**
|
||||||
|
String get spreadingFactor;
|
||||||
|
|
||||||
|
/// Label for coding rate dropdown
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Coding Rate'**
|
||||||
|
String get codingRate;
|
||||||
|
|
||||||
|
/// Label for TX power field
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'TX Power (dBm)'**
|
||||||
|
String get txPowerDbm;
|
||||||
|
|
||||||
|
/// Helper text showing maximum TX power
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Max: {power} dBm'**
|
||||||
|
String maxPowerDbm(int power);
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AppLocalizationsDelegate
|
class _AppLocalizationsDelegate
|
||||||
|
|||||||
@@ -1009,4 +1009,30 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get tapToViewOnMap => 'Tap to view on map';
|
String get tapToViewOnMap => 'Tap to view on map';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get radioSettings => 'Radio Settings';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get frequencyMHz => 'Frequency (MHz)';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get frequencyExample => 'e.g., 869.618';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get bandwidth => 'Bandwidth';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get spreadingFactor => 'Spreading Factor';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get codingRate => 'Coding Rate';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get txPowerDbm => 'TX Power (dBm)';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String maxPowerDbm(int power) {
|
||||||
|
return 'Max: $power dBm';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1011,4 +1011,30 @@ class AppLocalizationsHr extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get tapToViewOnMap => 'Dodirnite za prikaz na karti';
|
String get tapToViewOnMap => 'Dodirnite za prikaz na karti';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get radioSettings => 'Postavke radija';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get frequencyMHz => 'Frekvencija (MHz)';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get frequencyExample => 'npr. 869.618';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get bandwidth => 'Širina pojasa';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get spreadingFactor => 'Faktor širenja';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get codingRate => 'Omjer kodiranja';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get txPowerDbm => 'TX snaga (dBm)';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String maxPowerDbm(int power) {
|
||||||
|
return 'Maks: $power dBm';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1011,4 +1011,30 @@ class AppLocalizationsSl extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get tapToViewOnMap => 'Tapnite za prikaz na zemljevidu';
|
String get tapToViewOnMap => 'Tapnite za prikaz na zemljevidu';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get radioSettings => 'Nastavitve radia';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get frequencyMHz => 'Frekvenca (MHz)';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get frequencyExample => 'npr. 869.618';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get bandwidth => 'Pasovna širina';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get spreadingFactor => 'Faktor razširitve';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get codingRate => 'Razmerje kodiranja';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get txPowerDbm => 'Izhodna moč (dBm)';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String maxPowerDbm(int power) {
|
||||||
|
return 'Največ: $power dBm';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -581,5 +581,14 @@
|
|||||||
|
|
||||||
"coordinates": "Koordinate",
|
"coordinates": "Koordinate",
|
||||||
|
|
||||||
"tapToViewOnMap": "Tapnite za prikaz na zemljevidu"
|
"tapToViewOnMap": "Tapnite za prikaz na zemljevidu",
|
||||||
|
|
||||||
|
"radioSettings": "Nastavitve radia",
|
||||||
|
"frequencyMHz": "Frekvenca (MHz)",
|
||||||
|
"frequencyExample": "npr. 869.618",
|
||||||
|
"bandwidth": "Pasovna širina",
|
||||||
|
"spreadingFactor": "Faktor razširitve",
|
||||||
|
"codingRate": "Razmerje kodiranja",
|
||||||
|
"txPowerDbm": "Izhodna moč (dBm)",
|
||||||
|
"maxPowerDbm": "Največ: {power} dBm"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,31 +48,44 @@ class _DeviceConfigScreenState extends State<DeviceConfigScreen> {
|
|||||||
text: deviceInfo.selfName ?? deviceInfo.deviceName ?? '',
|
text: deviceInfo.selfName ?? deviceInfo.deviceName ?? '',
|
||||||
);
|
);
|
||||||
_latController = TextEditingController(
|
_latController = TextEditingController(
|
||||||
text: deviceInfo.advLat != null ? (deviceInfo.advLat! / 1000000).toStringAsFixed(6) : '0.0',
|
text: deviceInfo.advLat != null
|
||||||
|
? (deviceInfo.advLat! / 1000000).toStringAsFixed(6)
|
||||||
|
: '0.0',
|
||||||
);
|
);
|
||||||
_lonController = TextEditingController(
|
_lonController = TextEditingController(
|
||||||
text: deviceInfo.advLon != null ? (deviceInfo.advLon! / 1000000).toStringAsFixed(6) : '0.0',
|
text: deviceInfo.advLon != null
|
||||||
|
? (deviceInfo.advLon! / 1000000).toStringAsFixed(6)
|
||||||
|
: '0.0',
|
||||||
);
|
);
|
||||||
_freqController = TextEditingController(
|
_freqController = TextEditingController(
|
||||||
text: deviceInfo.radioFreq != null ? (deviceInfo.radioFreq! / 1000).toStringAsFixed(3) : '869.618',
|
text: deviceInfo.radioFreq != null
|
||||||
|
? (deviceInfo.radioFreq! / 1000).toStringAsFixed(3)
|
||||||
|
: '869.618',
|
||||||
);
|
);
|
||||||
_txPowerController = TextEditingController(
|
_txPowerController = TextEditingController(
|
||||||
text: deviceInfo.txPower?.toString() ?? '20',
|
text: deviceInfo.txPower?.toString() ?? '20',
|
||||||
);
|
);
|
||||||
|
|
||||||
if (deviceInfo.radioBw != null && deviceInfo.radioBw! >= 0 && deviceInfo.radioBw! <= 9) {
|
if (deviceInfo.radioBw != null &&
|
||||||
|
deviceInfo.radioBw! >= 0 &&
|
||||||
|
deviceInfo.radioBw! <= 9) {
|
||||||
_selectedBandwidth = _bandwidthFromValue(deviceInfo.radioBw!);
|
_selectedBandwidth = _bandwidthFromValue(deviceInfo.radioBw!);
|
||||||
}
|
}
|
||||||
if (deviceInfo.radioSf != null && deviceInfo.radioSf! >= 7 && deviceInfo.radioSf! <= 12) {
|
if (deviceInfo.radioSf != null &&
|
||||||
|
deviceInfo.radioSf! >= 7 &&
|
||||||
|
deviceInfo.radioSf! <= 12) {
|
||||||
_selectedSpreadingFactor = deviceInfo.radioSf!;
|
_selectedSpreadingFactor = deviceInfo.radioSf!;
|
||||||
}
|
}
|
||||||
if (deviceInfo.radioCr != null && deviceInfo.radioCr! >= 5 && deviceInfo.radioCr! <= 8) {
|
if (deviceInfo.radioCr != null &&
|
||||||
|
deviceInfo.radioCr! >= 5 &&
|
||||||
|
deviceInfo.radioCr! <= 8) {
|
||||||
_selectedCodingRate = deviceInfo.radioCr!;
|
_selectedCodingRate = deviceInfo.radioCr!;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if telemetry is enabled (check if lat/lon are set and not zero)
|
// Check if telemetry is enabled (check if lat/lon are set and not zero)
|
||||||
_telemetryEnabled = (deviceInfo.advLat != null && deviceInfo.advLat! != 0) ||
|
_telemetryEnabled =
|
||||||
(deviceInfo.advLon != null && deviceInfo.advLon! != 0);
|
(deviceInfo.advLat != null && deviceInfo.advLat! != 0) ||
|
||||||
|
(deviceInfo.advLon != null && deviceInfo.advLon! != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -87,17 +100,28 @@ class _DeviceConfigScreenState extends State<DeviceConfigScreen> {
|
|||||||
|
|
||||||
String _bandwidthFromValue(int bw) {
|
String _bandwidthFromValue(int bw) {
|
||||||
switch (bw) {
|
switch (bw) {
|
||||||
case 0: return '7.8 kHz';
|
case 0:
|
||||||
case 1: return '10.4 kHz';
|
return '7.8 kHz';
|
||||||
case 2: return '15.6 kHz';
|
case 1:
|
||||||
case 3: return '20.8 kHz';
|
return '10.4 kHz';
|
||||||
case 4: return '31.25 kHz';
|
case 2:
|
||||||
case 5: return '41.7 kHz';
|
return '15.6 kHz';
|
||||||
case 6: return '62.5 kHz';
|
case 3:
|
||||||
case 7: return '125 kHz';
|
return '20.8 kHz';
|
||||||
case 8: return '250 kHz';
|
case 4:
|
||||||
case 9: return '500 kHz';
|
return '31.25 kHz';
|
||||||
default: return '62.5 kHz';
|
case 5:
|
||||||
|
return '41.7 kHz';
|
||||||
|
case 6:
|
||||||
|
return '62.5 kHz';
|
||||||
|
case 7:
|
||||||
|
return '125 kHz';
|
||||||
|
case 8:
|
||||||
|
return '250 kHz';
|
||||||
|
case 9:
|
||||||
|
return '500 kHz';
|
||||||
|
default:
|
||||||
|
return '62.5 kHz';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,10 +183,7 @@ class _DeviceConfigScreenState extends State<DeviceConfigScreen> {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Clear position
|
// Clear position
|
||||||
await connectionProvider.setAdvertLatLon(
|
await connectionProvider.setAdvertLatLon(latitude: 0.0, longitude: 0.0);
|
||||||
latitude: 0.0,
|
|
||||||
longitude: 0.0,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Set telemetry modes to "Deny" (mode 0)
|
// Set telemetry modes to "Deny" (mode 0)
|
||||||
final telemetryModes = 0x00;
|
final telemetryModes = 0x00;
|
||||||
@@ -269,7 +290,11 @@ class _DeviceConfigScreenState extends State<DeviceConfigScreen> {
|
|||||||
if (!serviceEnabled) {
|
if (!serviceEnabled) {
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(content: Text(AppLocalizations.of(context)!.locationServicesDisabled)),
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
AppLocalizations.of(context)!.locationServicesDisabled,
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -281,7 +306,11 @@ class _DeviceConfigScreenState extends State<DeviceConfigScreen> {
|
|||||||
if (permission == LocationPermission.denied) {
|
if (permission == LocationPermission.denied) {
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(content: Text(AppLocalizations.of(context)!.locationPermissionDenied)),
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
AppLocalizations.of(context)!.locationPermissionDenied,
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -291,7 +320,13 @@ class _DeviceConfigScreenState extends State<DeviceConfigScreen> {
|
|||||||
if (permission == LocationPermission.deniedForever) {
|
if (permission == LocationPermission.deniedForever) {
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(content: Text(AppLocalizations.of(context)!.locationPermissionPermanentlyDenied)),
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
AppLocalizations.of(
|
||||||
|
context,
|
||||||
|
)!.locationPermissionPermanentlyDenied,
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -312,19 +347,21 @@ class _DeviceConfigScreenState extends State<DeviceConfigScreen> {
|
|||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text(AppLocalizations.of(context)!.locationBroadcast(
|
content: Text(
|
||||||
position.latitude.toStringAsFixed(6),
|
AppLocalizations.of(context)!.locationBroadcast(
|
||||||
position.longitude.toStringAsFixed(6),
|
position.latitude.toStringAsFixed(6),
|
||||||
)),
|
position.longitude.toStringAsFixed(6),
|
||||||
|
),
|
||||||
|
),
|
||||||
backgroundColor: Colors.green,
|
backgroundColor: Colors.green,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(
|
||||||
SnackBar(content: Text('Failed to get location: $e')),
|
context,
|
||||||
);
|
).showSnackBar(SnackBar(content: Text('Failed to get location: $e')));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -352,11 +389,17 @@ class _DeviceConfigScreenState extends State<DeviceConfigScreen> {
|
|||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
final deviceInfo = connectionProvider.deviceInfo;
|
final deviceInfo = connectionProvider.deviceInfo;
|
||||||
final lat = deviceInfo.advLat != null ? (deviceInfo.advLat! / 1000000).toStringAsFixed(6) : '0.0';
|
final lat = deviceInfo.advLat != null
|
||||||
final lon = deviceInfo.advLon != null ? (deviceInfo.advLon! / 1000000).toStringAsFixed(6) : '0.0';
|
? (deviceInfo.advLat! / 1000000).toStringAsFixed(6)
|
||||||
|
: '0.0';
|
||||||
|
final lon = deviceInfo.advLon != null
|
||||||
|
? (deviceInfo.advLon! / 1000000).toStringAsFixed(6)
|
||||||
|
: '0.0';
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text(AppLocalizations.of(context)!.advertisedAtLocation(lat, lon)),
|
content: Text(
|
||||||
|
AppLocalizations.of(context)!.advertisedAtLocation(lat, lon),
|
||||||
|
),
|
||||||
backgroundColor: Colors.green,
|
backgroundColor: Colors.green,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -365,7 +408,9 @@ class _DeviceConfigScreenState extends State<DeviceConfigScreen> {
|
|||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text(AppLocalizations.of(context)!.failedToAdvertise(e.toString())),
|
content: Text(
|
||||||
|
AppLocalizations.of(context)!.failedToAdvertise(e.toString()),
|
||||||
|
),
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: Colors.red,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -383,9 +428,7 @@ class _DeviceConfigScreenState extends State<DeviceConfigScreen> {
|
|||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(title: Text(AppLocalizations.of(context)!.settings)),
|
||||||
title: Text(AppLocalizations.of(context)!.settings),
|
|
||||||
),
|
|
||||||
body: ListView(
|
body: ListView(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
children: [
|
children: [
|
||||||
@@ -408,11 +451,26 @@ class _DeviceConfigScreenState extends State<DeviceConfigScreen> {
|
|||||||
_InfoRow('Type', _getDeviceTypeString(deviceInfo.deviceType)),
|
_InfoRow('Type', _getDeviceTypeString(deviceInfo.deviceType)),
|
||||||
_InfoRow('Model', deviceInfo.manufacturerModel ?? 'Unknown'),
|
_InfoRow('Model', deviceInfo.manufacturerModel ?? 'Unknown'),
|
||||||
_InfoRow('Version', deviceInfo.semanticVersion ?? 'Unknown'),
|
_InfoRow('Version', deviceInfo.semanticVersion ?? 'Unknown'),
|
||||||
_InfoRow('Build Date', deviceInfo.firmwareBuildDate ?? 'Unknown'),
|
_InfoRow(
|
||||||
_InfoRow('Firmware', 'v${deviceInfo.firmwareVersion?.toString() ?? "?"}'),
|
'Build Date',
|
||||||
_InfoRow('Max Contacts', deviceInfo.maxContacts?.toString() ?? 'Unknown'),
|
deviceInfo.firmwareBuildDate ?? 'Unknown',
|
||||||
_InfoRow('Max Channels', deviceInfo.maxChannels?.toString() ?? 'Unknown'),
|
),
|
||||||
_CopyableInfoRow('Public Key', _getPublicKeyHex(deviceInfo.publicKey)),
|
_InfoRow(
|
||||||
|
'Firmware',
|
||||||
|
'v${deviceInfo.firmwareVersion?.toString() ?? "?"}',
|
||||||
|
),
|
||||||
|
_InfoRow(
|
||||||
|
'Max Contacts',
|
||||||
|
deviceInfo.maxContacts?.toString() ?? 'Unknown',
|
||||||
|
),
|
||||||
|
_InfoRow(
|
||||||
|
'Max Channels',
|
||||||
|
deviceInfo.maxChannels?.toString() ?? 'Unknown',
|
||||||
|
),
|
||||||
|
_CopyableInfoRow(
|
||||||
|
'Public Key',
|
||||||
|
_getPublicKeyHex(deviceInfo.publicKey),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -439,17 +497,6 @@ class _DeviceConfigScreenState extends State<DeviceConfigScreen> {
|
|||||||
Row(
|
Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
IconButton.outlined(
|
|
||||||
onPressed: _isBroadcasting ? null : _broadcastNow,
|
|
||||||
icon: _isBroadcasting
|
|
||||||
? const SizedBox(
|
|
||||||
width: 20,
|
|
||||||
height: 20,
|
|
||||||
child: CircularProgressIndicator(strokeWidth: 2),
|
|
||||||
)
|
|
||||||
: const Icon(Icons.sensors),
|
|
||||||
tooltip: AppLocalizations.of(context)!.settings,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
IconButton.filled(
|
IconButton.filled(
|
||||||
onPressed: _savePublicInfo,
|
onPressed: _savePublicInfo,
|
||||||
@@ -554,7 +601,7 @@ class _DeviceConfigScreenState extends State<DeviceConfigScreen> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Radio Settings',
|
AppLocalizations.of(context)!.radioSettings,
|
||||||
style: theme.textTheme.titleLarge?.copyWith(
|
style: theme.textTheme.titleLarge?.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
@@ -571,21 +618,23 @@ class _DeviceConfigScreenState extends State<DeviceConfigScreen> {
|
|||||||
// LoRa Frequency
|
// LoRa Frequency
|
||||||
TextField(
|
TextField(
|
||||||
controller: _freqController,
|
controller: _freqController,
|
||||||
decoration: const InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: 'Frequency (MHz)',
|
labelText: AppLocalizations.of(context)!.frequencyMHz,
|
||||||
border: OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
helperText: 'e.g., 869.618',
|
helperText: AppLocalizations.of(context)!.frequencyExample,
|
||||||
|
),
|
||||||
|
keyboardType: const TextInputType.numberWithOptions(
|
||||||
|
decimal: true,
|
||||||
),
|
),
|
||||||
keyboardType: const TextInputType.numberWithOptions(decimal: true),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// Bandwidth
|
// Bandwidth
|
||||||
DropdownButtonFormField<String>(
|
DropdownButtonFormField<String>(
|
||||||
value: _selectedBandwidth,
|
value: _selectedBandwidth,
|
||||||
decoration: const InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: 'Bandwidth',
|
labelText: AppLocalizations.of(context)!.bandwidth,
|
||||||
border: OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
),
|
),
|
||||||
items: _bandwidthOptions.map((String value) {
|
items: _bandwidthOptions.map((String value) {
|
||||||
return DropdownMenuItem<String>(
|
return DropdownMenuItem<String>(
|
||||||
@@ -606,11 +655,13 @@ class _DeviceConfigScreenState extends State<DeviceConfigScreen> {
|
|||||||
// Spreading Factor
|
// Spreading Factor
|
||||||
DropdownButtonFormField<int>(
|
DropdownButtonFormField<int>(
|
||||||
value: _selectedSpreadingFactor,
|
value: _selectedSpreadingFactor,
|
||||||
decoration: const InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: 'Spreading Factor',
|
labelText: AppLocalizations.of(context)!.spreadingFactor,
|
||||||
border: OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
),
|
),
|
||||||
items: List.generate(6, (index) => index + 7).map((int value) {
|
items: List.generate(6, (index) => index + 7).map((
|
||||||
|
int value,
|
||||||
|
) {
|
||||||
return DropdownMenuItem<int>(
|
return DropdownMenuItem<int>(
|
||||||
value: value,
|
value: value,
|
||||||
child: Text(value.toString()),
|
child: Text(value.toString()),
|
||||||
@@ -629,11 +680,13 @@ class _DeviceConfigScreenState extends State<DeviceConfigScreen> {
|
|||||||
// Coding Rate
|
// Coding Rate
|
||||||
DropdownButtonFormField<int>(
|
DropdownButtonFormField<int>(
|
||||||
value: _selectedCodingRate,
|
value: _selectedCodingRate,
|
||||||
decoration: const InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: 'Coding Rate',
|
labelText: AppLocalizations.of(context)!.codingRate,
|
||||||
border: OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
),
|
),
|
||||||
items: List.generate(4, (index) => index + 5).map((int value) {
|
items: List.generate(4, (index) => index + 5).map((
|
||||||
|
int value,
|
||||||
|
) {
|
||||||
return DropdownMenuItem<int>(
|
return DropdownMenuItem<int>(
|
||||||
value: value,
|
value: value,
|
||||||
child: Text(value.toString()),
|
child: Text(value.toString()),
|
||||||
@@ -653,9 +706,9 @@ class _DeviceConfigScreenState extends State<DeviceConfigScreen> {
|
|||||||
TextField(
|
TextField(
|
||||||
controller: _txPowerController,
|
controller: _txPowerController,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: 'TX Power (dBm)',
|
labelText: AppLocalizations.of(context)!.txPowerDbm,
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
helperText: 'Max: ${deviceInfo.maxTxPower ?? 22} dBm',
|
helperText: AppLocalizations.of(context)!.maxPowerDbm(deviceInfo.maxTxPower ?? 22),
|
||||||
),
|
),
|
||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
),
|
),
|
||||||
@@ -673,11 +726,16 @@ class _DeviceConfigScreenState extends State<DeviceConfigScreen> {
|
|||||||
String _getDeviceTypeString(int? deviceType) {
|
String _getDeviceTypeString(int? deviceType) {
|
||||||
if (deviceType == null) return 'Unknown';
|
if (deviceType == null) return 'Unknown';
|
||||||
switch (deviceType) {
|
switch (deviceType) {
|
||||||
case 0: return 'None/Unknown';
|
case 0:
|
||||||
case 1: return 'Chat Node';
|
return 'None/Unknown';
|
||||||
case 2: return 'Repeater';
|
case 1:
|
||||||
case 3: return 'Room/Channel';
|
return 'Chat Node';
|
||||||
default: return 'Type $deviceType';
|
case 2:
|
||||||
|
return 'Repeater';
|
||||||
|
case 3:
|
||||||
|
return 'Room/Channel';
|
||||||
|
default:
|
||||||
|
return 'Type $deviceType';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -713,9 +771,7 @@ class _InfoRow extends StatelessWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
value,
|
value,
|
||||||
style: const TextStyle(
|
style: const TextStyle(fontWeight: FontWeight.w600),
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ class _HomeScreenState extends State<HomeScreen>
|
|||||||
|
|
||||||
// Info banner
|
// Info banner
|
||||||
Container(
|
Container(
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 16),
|
margin: const EdgeInsets.only(left: 16, right: 16, top: 16),
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.primaryContainer,
|
color: Theme.of(context).colorScheme.primaryContainer,
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 821 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 642 B After Width: | Height: | Size: 668 B |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 235 KiB After Width: | Height: | Size: 170 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.5 KiB |
BIN
web/favicon.png
|
Before Width: | Height: | Size: 642 B After Width: | Height: | Size: 668 B |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 235 KiB After Width: | Height: | Size: 170 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 235 KiB After Width: | Height: | Size: 170 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.0 KiB |