mirror of
https://github.com/zjs81/meshcore-open.git
synced 2026-06-14 22:55:12 +10:00
add selectable LOS obstruction pinning for repeater placement
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"workspace_id": "56872cc9-7375-4423-92d5-6cdebf6564dc",
|
||||
"workspace_name": ".contextstream-global",
|
||||
"project_id": "5b1fe101-ea6b-4fe3-9de5-c87722c38084",
|
||||
"project_name": "meshcore-open",
|
||||
"associated_at": "2026-04-25T12:13:54.086Z"
|
||||
}
|
||||
+41
-1
@@ -2066,5 +2066,45 @@
|
||||
"room_guest": "Информация за сървъра на стаята",
|
||||
"repeater_guest": "Информация за ретранслаторите",
|
||||
"repeater_guestTools": "Инструменти за гости",
|
||||
"settings_multiAck": "Множество потвърждения"
|
||||
"settings_multiAck": "Множество потвърждения",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losSelectedObstructionTitle": "Избрано препятствие",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losBlockedSpotsHint": "Кликнете върху блокираната точка, за да я отбележите на картата.",
|
||||
"losBlockedSpotsTitle": "Ограничени места",
|
||||
"losSelectedObstructionDetails": "Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit})."
|
||||
}
|
||||
|
||||
+41
-1
@@ -2094,5 +2094,45 @@
|
||||
"repeater_guestTools": "Gastwerkzeuge",
|
||||
"chat_sendMessage": "Nachricht senden",
|
||||
"room_guest": "Informationen zum Room Server",
|
||||
"settings_multiAck": "Mehrere Bestätigungen"
|
||||
"settings_multiAck": "Mehrere Bestätigungen",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losBlockedSpotsTitle": "Reservierte Plätze",
|
||||
"losSelectedObstructionTitle": "Ausgewählte Behinderung",
|
||||
"losBlockedSpotChip": "{distance} • {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losBlockedSpotsHint": "Klicken Sie auf einen blockierten Bereich, um ihn auf der Karte hervorzuheben.",
|
||||
"losSelectedObstructionDetails": "Blockiert durch {obstruction} in einer Höhe von {heightUnit}, {distanceFromA} von A und {distanceFromB} von B ({distanceUnit})."
|
||||
}
|
||||
|
||||
@@ -1875,6 +1875,46 @@
|
||||
"losLegendRadioHorizon": "Radio horizon",
|
||||
"losLegendLosBeam": "LOS beam",
|
||||
"losLegendTerrain": "Terrain",
|
||||
"losBlockedSpotsTitle": "Blocked spots",
|
||||
"losBlockedSpotsHint": "Tap a blocked spot to highlight it on the map.",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losSelectedObstructionTitle": "Selected obstruction",
|
||||
"losSelectedObstructionDetails": "Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit}).",
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losFrequencyLabel": "Frequency",
|
||||
"losFrequencyInfoTooltip": "View calculation details",
|
||||
"losFrequencyDialogTitle": "Radio horizon calculation",
|
||||
|
||||
+41
-1
@@ -2094,5 +2094,45 @@
|
||||
"chat_sendMessage": "Enviar mensaje",
|
||||
"repeater_guestTools": "Herramientas para invitados",
|
||||
"room_guest": "Información del servidor",
|
||||
"settings_multiAck": "Múltiples respuestas de confirmación"
|
||||
"settings_multiAck": "Múltiples respuestas de confirmación",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losBlockedSpotsTitle": "Espacios ocupados",
|
||||
"losBlockedSpotsHint": "Seleccione un punto bloqueado para resaltarlo en el mapa.",
|
||||
"losSelectedObstructionTitle": "Obstrucción seleccionada",
|
||||
"losSelectedObstructionDetails": "Bloqueado por {obstruction} a una altura de {heightUnit}, a {distanceFromA} metros de A y a {distanceFromB} metros de B ({distanceUnit}).",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}"
|
||||
}
|
||||
|
||||
+41
-1
@@ -2066,5 +2066,45 @@
|
||||
"chat_sendMessage": "Envoyer un message",
|
||||
"room_guest": "Informations sur le serveur",
|
||||
"repeater_guest": "Informations sur les répéteurs",
|
||||
"settings_multiAck": "Plusieurs accusés de réception"
|
||||
"settings_multiAck": "Plusieurs accusés de réception",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losSelectedObstructionTitle": "Obstruction sélectionnée",
|
||||
"losBlockedSpotsTitle": "Places occupés",
|
||||
"losBlockedSpotsHint": "Sélectionnez un emplacement bloqué pour le mettre en évidence sur la carte.",
|
||||
"losSelectedObstructionDetails": "Bloqué par {obstruction}, à une hauteur de {heightUnit}, à une distance de {distanceFromA} par rapport à A et à une distance de {distanceFromB} par rapport à B ({distanceUnit}).",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}"
|
||||
}
|
||||
|
||||
+41
-1
@@ -2104,5 +2104,45 @@
|
||||
"room_guest": "Szoba szerver információk",
|
||||
"chat_sendMessage": "Üzenet küldése",
|
||||
"repeater_guest": "Adatok a repeaterről",
|
||||
"settings_multiAck": "Többszörös visszaigazolások"
|
||||
"settings_multiAck": "Többszörös visszaigazolások",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losSelectedObstructionTitle": "Kiválasztott akadály",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losBlockedSpotsHint": "A blokkolt területet megjelölve, hogy a térképen kiemeljük.",
|
||||
"losBlockedSpotsTitle": "Foglalhatatlan területek",
|
||||
"losSelectedObstructionDetails": "Elakadt a {obstruction} miatt, {heightUnit} magasságban, {distanceFromA} méterrel A-tól és {distanceFromB} méterrel B-től ({distanceUnit})."
|
||||
}
|
||||
|
||||
+41
-1
@@ -2066,5 +2066,45 @@
|
||||
"repeater_guestTools": "Strumenti per gli ospiti",
|
||||
"chat_sendMessage": "Invia messaggio",
|
||||
"room_guest": "Informazioni sul server",
|
||||
"settings_multiAck": "ACK multipli"
|
||||
"settings_multiAck": "ACK multipli",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losSelectedObstructionTitle": "Ostacolo selezionato",
|
||||
"losBlockedSpotsHint": "Tocca un punto bloccato sulla mappa per evidenziarlo.",
|
||||
"losBlockedSpotsTitle": "Posti occupati",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losSelectedObstructionDetails": "Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit})."
|
||||
}
|
||||
|
||||
+41
-1
@@ -2104,5 +2104,45 @@
|
||||
"chat_sendMessage": "メッセージを送信する",
|
||||
"repeater_guest": "繰り返し送信に関する情報",
|
||||
"repeater_guestTools": "ゲスト向けツール",
|
||||
"settings_multiAck": "複数のACK(応答)"
|
||||
"settings_multiAck": "複数のACK(応答)",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losBlockedSpotsHint": "地図上で、特定された場所を強調するために、該当する場所をタップしてください。",
|
||||
"losSelectedObstructionTitle": "選択された障害",
|
||||
"losBlockedSpotsTitle": "利用できない場所",
|
||||
"losSelectedObstructionDetails": "{obstruction} によって {heightUnit} の高さで、A地点から {distanceFromA}、B地点から {distanceFromB} ({distanceUnit}) の距離で塞がれています。",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}"
|
||||
}
|
||||
|
||||
+41
-1
@@ -2104,5 +2104,45 @@
|
||||
"chat_sendMessage": "메시지를 보내기",
|
||||
"repeater_guest": "반복 장비 정보",
|
||||
"room_guest": "서버 정보",
|
||||
"settings_multiAck": "다중 ACK"
|
||||
"settings_multiAck": "다중 ACK",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losBlockedSpotsHint": "지도에서 특정 위치를 강조하려면 해당 위치를 클릭하세요.",
|
||||
"losBlockedSpotsTitle": "차단된 공간",
|
||||
"losSelectedObstructionTitle": "선택된 장애물",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losSelectedObstructionDetails": "Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit})."
|
||||
}
|
||||
|
||||
@@ -5640,6 +5640,47 @@ abstract class AppLocalizations {
|
||||
/// **'Terrain'**
|
||||
String get losLegendTerrain;
|
||||
|
||||
/// No description provided for @losBlockedSpotsTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Blocked spots'**
|
||||
String get losBlockedSpotsTitle;
|
||||
|
||||
/// No description provided for @losBlockedSpotsHint.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Tap a blocked spot to highlight it on the map.'**
|
||||
String get losBlockedSpotsHint;
|
||||
|
||||
/// No description provided for @losBlockedSpotChip.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{distance} {distanceUnit} • {obstruction} {heightUnit}'**
|
||||
String losBlockedSpotChip(
|
||||
String distance,
|
||||
String distanceUnit,
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
);
|
||||
|
||||
/// No description provided for @losSelectedObstructionTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Selected obstruction'**
|
||||
String get losSelectedObstructionTitle;
|
||||
|
||||
/// No description provided for @losSelectedObstructionDetails.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit}).'**
|
||||
String losSelectedObstructionDetails(
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
String distanceFromA,
|
||||
String distanceUnit,
|
||||
String distanceFromB,
|
||||
);
|
||||
|
||||
/// No description provided for @losFrequencyLabel.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
|
||||
@@ -3236,6 +3236,37 @@ class AppLocalizationsBg extends AppLocalizations {
|
||||
@override
|
||||
String get losLegendTerrain => 'Терен';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsTitle => 'Ограничени места';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsHint =>
|
||||
'Кликнете върху блокираната точка, за да я отбележите на картата.';
|
||||
|
||||
@override
|
||||
String losBlockedSpotChip(
|
||||
String distance,
|
||||
String distanceUnit,
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
) {
|
||||
return '$distance $distanceUnit • $obstruction $heightUnit';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losSelectedObstructionTitle => 'Избрано препятствие';
|
||||
|
||||
@override
|
||||
String losSelectedObstructionDetails(
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
String distanceFromA,
|
||||
String distanceUnit,
|
||||
String distanceFromB,
|
||||
) {
|
||||
return 'Blocked by $obstruction $heightUnit, $distanceFromA from A and $distanceFromB from B ($distanceUnit).';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losFrequencyLabel => 'Честота';
|
||||
|
||||
|
||||
@@ -3241,6 +3241,37 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||
@override
|
||||
String get losLegendTerrain => 'Gelände';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsTitle => 'Reservierte Plätze';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsHint =>
|
||||
'Klicken Sie auf einen blockierten Bereich, um ihn auf der Karte hervorzuheben.';
|
||||
|
||||
@override
|
||||
String losBlockedSpotChip(
|
||||
String distance,
|
||||
String distanceUnit,
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
) {
|
||||
return '$distance • $distanceUnit • $obstruction $heightUnit';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losSelectedObstructionTitle => 'Ausgewählte Behinderung';
|
||||
|
||||
@override
|
||||
String losSelectedObstructionDetails(
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
String distanceFromA,
|
||||
String distanceUnit,
|
||||
String distanceFromB,
|
||||
) {
|
||||
return 'Blockiert durch $obstruction in einer Höhe von $heightUnit, $distanceFromA von A und $distanceFromB von B ($distanceUnit).';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losFrequencyLabel => 'Frequenz';
|
||||
|
||||
|
||||
@@ -3180,6 +3180,37 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
@override
|
||||
String get losLegendTerrain => 'Terrain';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsTitle => 'Blocked spots';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsHint =>
|
||||
'Tap a blocked spot to highlight it on the map.';
|
||||
|
||||
@override
|
||||
String losBlockedSpotChip(
|
||||
String distance,
|
||||
String distanceUnit,
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
) {
|
||||
return '$distance $distanceUnit • $obstruction $heightUnit';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losSelectedObstructionTitle => 'Selected obstruction';
|
||||
|
||||
@override
|
||||
String losSelectedObstructionDetails(
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
String distanceFromA,
|
||||
String distanceUnit,
|
||||
String distanceFromB,
|
||||
) {
|
||||
return 'Blocked by $obstruction $heightUnit, $distanceFromA from A and $distanceFromB from B ($distanceUnit).';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losFrequencyLabel => 'Frequency';
|
||||
|
||||
|
||||
@@ -3235,6 +3235,37 @@ class AppLocalizationsEs extends AppLocalizations {
|
||||
@override
|
||||
String get losLegendTerrain => 'Terreno';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsTitle => 'Espacios ocupados';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsHint =>
|
||||
'Seleccione un punto bloqueado para resaltarlo en el mapa.';
|
||||
|
||||
@override
|
||||
String losBlockedSpotChip(
|
||||
String distance,
|
||||
String distanceUnit,
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
) {
|
||||
return '$distance $distanceUnit • $obstruction $heightUnit';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losSelectedObstructionTitle => 'Obstrucción seleccionada';
|
||||
|
||||
@override
|
||||
String losSelectedObstructionDetails(
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
String distanceFromA,
|
||||
String distanceUnit,
|
||||
String distanceFromB,
|
||||
) {
|
||||
return 'Bloqueado por $obstruction a una altura de $heightUnit, a $distanceFromA metros de A y a $distanceFromB metros de B ($distanceUnit).';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losFrequencyLabel => 'Frecuencia';
|
||||
|
||||
|
||||
@@ -3253,6 +3253,37 @@ class AppLocalizationsFr extends AppLocalizations {
|
||||
@override
|
||||
String get losLegendTerrain => 'Terrain';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsTitle => 'Places occupés';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsHint =>
|
||||
'Sélectionnez un emplacement bloqué pour le mettre en évidence sur la carte.';
|
||||
|
||||
@override
|
||||
String losBlockedSpotChip(
|
||||
String distance,
|
||||
String distanceUnit,
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
) {
|
||||
return '$distance $distanceUnit • $obstruction $heightUnit';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losSelectedObstructionTitle => 'Obstruction sélectionnée';
|
||||
|
||||
@override
|
||||
String losSelectedObstructionDetails(
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
String distanceFromA,
|
||||
String distanceUnit,
|
||||
String distanceFromB,
|
||||
) {
|
||||
return 'Bloqué par $obstruction, à une hauteur de $heightUnit, à une distance de $distanceFromA par rapport à A et à une distance de $distanceFromB par rapport à B ($distanceUnit).';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losFrequencyLabel => 'Fréquence';
|
||||
|
||||
|
||||
@@ -3249,6 +3249,37 @@ class AppLocalizationsHu extends AppLocalizations {
|
||||
@override
|
||||
String get losLegendTerrain => 'Terület';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsTitle => 'Foglalhatatlan területek';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsHint =>
|
||||
'A blokkolt területet megjelölve, hogy a térképen kiemeljük.';
|
||||
|
||||
@override
|
||||
String losBlockedSpotChip(
|
||||
String distance,
|
||||
String distanceUnit,
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
) {
|
||||
return '$distance $distanceUnit • $obstruction $heightUnit';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losSelectedObstructionTitle => 'Kiválasztott akadály';
|
||||
|
||||
@override
|
||||
String losSelectedObstructionDetails(
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
String distanceFromA,
|
||||
String distanceUnit,
|
||||
String distanceFromB,
|
||||
) {
|
||||
return 'Elakadt a $obstruction miatt, $heightUnit magasságban, $distanceFromA méterrel A-tól és $distanceFromB méterrel B-től ($distanceUnit).';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losFrequencyLabel => 'Hatósság';
|
||||
|
||||
|
||||
@@ -3238,6 +3238,37 @@ class AppLocalizationsIt extends AppLocalizations {
|
||||
@override
|
||||
String get losLegendTerrain => 'Terreno';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsTitle => 'Posti occupati';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsHint =>
|
||||
'Tocca un punto bloccato sulla mappa per evidenziarlo.';
|
||||
|
||||
@override
|
||||
String losBlockedSpotChip(
|
||||
String distance,
|
||||
String distanceUnit,
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
) {
|
||||
return '$distance $distanceUnit • $obstruction $heightUnit';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losSelectedObstructionTitle => 'Ostacolo selezionato';
|
||||
|
||||
@override
|
||||
String losSelectedObstructionDetails(
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
String distanceFromA,
|
||||
String distanceUnit,
|
||||
String distanceFromB,
|
||||
) {
|
||||
return 'Blocked by $obstruction $heightUnit, $distanceFromA from A and $distanceFromB from B ($distanceUnit).';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losFrequencyLabel => 'Frequenza';
|
||||
|
||||
|
||||
@@ -3090,6 +3090,36 @@ class AppLocalizationsJa extends AppLocalizations {
|
||||
@override
|
||||
String get losLegendTerrain => '地形';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsTitle => '利用できない場所';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsHint => '地図上で、特定された場所を強調するために、該当する場所をタップしてください。';
|
||||
|
||||
@override
|
||||
String losBlockedSpotChip(
|
||||
String distance,
|
||||
String distanceUnit,
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
) {
|
||||
return '$distance $distanceUnit • $obstruction $heightUnit';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losSelectedObstructionTitle => '選択された障害';
|
||||
|
||||
@override
|
||||
String losSelectedObstructionDetails(
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
String distanceFromA,
|
||||
String distanceUnit,
|
||||
String distanceFromB,
|
||||
) {
|
||||
return '$obstruction によって $heightUnit の高さで、A地点から $distanceFromA、B地点から $distanceFromB ($distanceUnit) の距離で塞がれています。';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losFrequencyLabel => '周波数';
|
||||
|
||||
|
||||
@@ -3090,6 +3090,36 @@ class AppLocalizationsKo extends AppLocalizations {
|
||||
@override
|
||||
String get losLegendTerrain => '지형';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsTitle => '차단된 공간';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsHint => '지도에서 특정 위치를 강조하려면 해당 위치를 클릭하세요.';
|
||||
|
||||
@override
|
||||
String losBlockedSpotChip(
|
||||
String distance,
|
||||
String distanceUnit,
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
) {
|
||||
return '$distance $distanceUnit • $obstruction $heightUnit';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losSelectedObstructionTitle => '선택된 장애물';
|
||||
|
||||
@override
|
||||
String losSelectedObstructionDetails(
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
String distanceFromA,
|
||||
String distanceUnit,
|
||||
String distanceFromB,
|
||||
) {
|
||||
return 'Blocked by $obstruction $heightUnit, $distanceFromA from A and $distanceFromB from B ($distanceUnit).';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losFrequencyLabel => '빈도';
|
||||
|
||||
|
||||
@@ -3220,6 +3220,37 @@ class AppLocalizationsNl extends AppLocalizations {
|
||||
@override
|
||||
String get losLegendTerrain => 'Terrein';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsTitle => 'Geplande plaatsen';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsHint =>
|
||||
'Tik op een geblokkeerd gebied om het op de kaart te markeren.';
|
||||
|
||||
@override
|
||||
String losBlockedSpotChip(
|
||||
String distance,
|
||||
String distanceUnit,
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
) {
|
||||
return '$distance $distanceUnit • $obstruction $heightUnit';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losSelectedObstructionTitle => 'Geselecteerde obstakel';
|
||||
|
||||
@override
|
||||
String losSelectedObstructionDetails(
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
String distanceFromA,
|
||||
String distanceUnit,
|
||||
String distanceFromB,
|
||||
) {
|
||||
return 'Blocked by $obstruction $heightUnit, $distanceFromA from A and $distanceFromB from B ($distanceUnit).';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losFrequencyLabel => 'Frequentie';
|
||||
|
||||
|
||||
@@ -3245,6 +3245,37 @@ class AppLocalizationsPl extends AppLocalizations {
|
||||
@override
|
||||
String get losLegendTerrain => 'Teren';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsTitle => 'Zablokowane miejsca';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsHint =>
|
||||
'Kliknij zablokowane miejsce, aby je zaznaczyć na mapie.';
|
||||
|
||||
@override
|
||||
String losBlockedSpotChip(
|
||||
String distance,
|
||||
String distanceUnit,
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
) {
|
||||
return '$distance $distanceUnit • $obstruction $heightUnit';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losSelectedObstructionTitle => 'Wybór przeszkody';
|
||||
|
||||
@override
|
||||
String losSelectedObstructionDetails(
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
String distanceFromA,
|
||||
String distanceUnit,
|
||||
String distanceFromB,
|
||||
) {
|
||||
return 'Blocked by $obstruction $heightUnit, $distanceFromA from A and $distanceFromB from B ($distanceUnit).';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losFrequencyLabel => 'Częstotliwość';
|
||||
|
||||
|
||||
@@ -3234,6 +3234,37 @@ class AppLocalizationsPt extends AppLocalizations {
|
||||
@override
|
||||
String get losLegendTerrain => 'Terreno';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsTitle => 'Locais ocupados';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsHint =>
|
||||
'Toque em um ponto bloqueado para destacá-lo no mapa.';
|
||||
|
||||
@override
|
||||
String losBlockedSpotChip(
|
||||
String distance,
|
||||
String distanceUnit,
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
) {
|
||||
return '$distance $distanceUnit • $obstruction $heightUnit';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losSelectedObstructionTitle => 'Obstrução selecionada';
|
||||
|
||||
@override
|
||||
String losSelectedObstructionDetails(
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
String distanceFromA,
|
||||
String distanceUnit,
|
||||
String distanceFromB,
|
||||
) {
|
||||
return 'Blocked by $obstruction $heightUnit, $distanceFromA from A and $distanceFromB from B ($distanceUnit).';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losFrequencyLabel => 'Frequência';
|
||||
|
||||
|
||||
@@ -3239,6 +3239,38 @@ class AppLocalizationsRu extends AppLocalizations {
|
||||
@override
|
||||
String get losLegendTerrain => 'Рельеф';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsTitle => 'Зарезервированные места';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsHint =>
|
||||
'Щелкните по заблокированной области, чтобы выделить ее на карте.';
|
||||
|
||||
@override
|
||||
String losBlockedSpotChip(
|
||||
String distance,
|
||||
String distanceUnit,
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
) {
|
||||
return '$distance $distanceUnit • $obstruction $heightUnit';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losSelectedObstructionTitle =>
|
||||
'Выбранный объект, препятствующий движению';
|
||||
|
||||
@override
|
||||
String losSelectedObstructionDetails(
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
String distanceFromA,
|
||||
String distanceUnit,
|
||||
String distanceFromB,
|
||||
) {
|
||||
return 'Blocked by $obstruction $heightUnit, $distanceFromA from A and $distanceFromB from B ($distanceUnit).';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losFrequencyLabel => 'Частота';
|
||||
|
||||
|
||||
@@ -3214,6 +3214,37 @@ class AppLocalizationsSk extends AppLocalizations {
|
||||
@override
|
||||
String get losLegendTerrain => 'Terén';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsTitle => 'Zablokované miesta';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsHint =>
|
||||
'Kliknite na zablokované miesto, aby ste ho zvýraznili na mape.';
|
||||
|
||||
@override
|
||||
String losBlockedSpotChip(
|
||||
String distance,
|
||||
String distanceUnit,
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
) {
|
||||
return '$distance $distanceUnit • $obstruction $heightUnit';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losSelectedObstructionTitle => 'Vybraná prekážka';
|
||||
|
||||
@override
|
||||
String losSelectedObstructionDetails(
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
String distanceFromA,
|
||||
String distanceUnit,
|
||||
String distanceFromB,
|
||||
) {
|
||||
return 'Blocked by $obstruction $heightUnit, $distanceFromA from A and $distanceFromB from B ($distanceUnit).';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losFrequencyLabel => 'Frekvencia';
|
||||
|
||||
|
||||
@@ -3215,6 +3215,37 @@ class AppLocalizationsSl extends AppLocalizations {
|
||||
@override
|
||||
String get losLegendTerrain => 'Teren';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsTitle => 'Zasedena parkirišča';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsHint =>
|
||||
'Dotaknite blokirano točko, da jo označite na zemljeplati.';
|
||||
|
||||
@override
|
||||
String losBlockedSpotChip(
|
||||
String distance,
|
||||
String distanceUnit,
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
) {
|
||||
return '$distance $distanceUnit • $obstruction $heightUnit';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losSelectedObstructionTitle => 'Izbrano ovire';
|
||||
|
||||
@override
|
||||
String losSelectedObstructionDetails(
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
String distanceFromA,
|
||||
String distanceUnit,
|
||||
String distanceFromB,
|
||||
) {
|
||||
return 'Blocked by $obstruction $heightUnit, $distanceFromA from A and $distanceFromB from B ($distanceUnit).';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losFrequencyLabel => 'Frekvenca';
|
||||
|
||||
|
||||
@@ -3197,6 +3197,37 @@ class AppLocalizationsSv extends AppLocalizations {
|
||||
@override
|
||||
String get losLegendTerrain => 'Terräng';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsTitle => 'Reserverade platser';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsHint =>
|
||||
'Klicka på en markerad plats för att framhäva den på kartan.';
|
||||
|
||||
@override
|
||||
String losBlockedSpotChip(
|
||||
String distance,
|
||||
String distanceUnit,
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
) {
|
||||
return '$distance $distanceUnit • $obstruction $heightUnit';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losSelectedObstructionTitle => 'Vald hinder';
|
||||
|
||||
@override
|
||||
String losSelectedObstructionDetails(
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
String distanceFromA,
|
||||
String distanceUnit,
|
||||
String distanceFromB,
|
||||
) {
|
||||
return 'Blocked by $obstruction $heightUnit, $distanceFromA from A and $distanceFromB from B ($distanceUnit).';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losFrequencyLabel => 'Frekvens';
|
||||
|
||||
|
||||
@@ -3242,6 +3242,37 @@ class AppLocalizationsUk extends AppLocalizations {
|
||||
@override
|
||||
String get losLegendTerrain => 'Рельєф';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsTitle => 'Заблоковані місця';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsHint =>
|
||||
'Натисніть на заблоковане місце, щоб виділити його на карті.';
|
||||
|
||||
@override
|
||||
String losBlockedSpotChip(
|
||||
String distance,
|
||||
String distanceUnit,
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
) {
|
||||
return '$distance $distanceUnit • $obstruction $heightUnit';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losSelectedObstructionTitle => 'Вибраний об\'єкт перешкоди';
|
||||
|
||||
@override
|
||||
String losSelectedObstructionDetails(
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
String distanceFromA,
|
||||
String distanceUnit,
|
||||
String distanceFromB,
|
||||
) {
|
||||
return 'Blocked by $obstruction $heightUnit, $distanceFromA from A and $distanceFromB from B ($distanceUnit).';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losFrequencyLabel => 'Частота';
|
||||
|
||||
|
||||
@@ -3014,6 +3014,36 @@ class AppLocalizationsZh extends AppLocalizations {
|
||||
@override
|
||||
String get losLegendTerrain => '地形';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsTitle => '被占用区域';
|
||||
|
||||
@override
|
||||
String get losBlockedSpotsHint => '点击地图上的某个被遮盖的区域,以突出显示该区域。';
|
||||
|
||||
@override
|
||||
String losBlockedSpotChip(
|
||||
String distance,
|
||||
String distanceUnit,
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
) {
|
||||
return '$distance $distanceUnit • $obstruction $heightUnit';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losSelectedObstructionTitle => '选择性阻碍';
|
||||
|
||||
@override
|
||||
String losSelectedObstructionDetails(
|
||||
String obstruction,
|
||||
String heightUnit,
|
||||
String distanceFromA,
|
||||
String distanceUnit,
|
||||
String distanceFromB,
|
||||
) {
|
||||
return 'Blocked by $obstruction $heightUnit, $distanceFromA from A and $distanceFromB from B ($distanceUnit).';
|
||||
}
|
||||
|
||||
@override
|
||||
String get losFrequencyLabel => '频率';
|
||||
|
||||
|
||||
+41
-1
@@ -2066,5 +2066,45 @@
|
||||
"room_guest": "Informatie over de server",
|
||||
"chat_sendMessage": "Verzend bericht",
|
||||
"repeater_guest": "Informatie over herhalingsapparatuur",
|
||||
"settings_multiAck": "Meerdere bevestigingen"
|
||||
"settings_multiAck": "Meerdere bevestigingen",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losSelectedObstructionTitle": "Geselecteerde obstakel",
|
||||
"losBlockedSpotsHint": "Tik op een geblokkeerd gebied om het op de kaart te markeren.",
|
||||
"losBlockedSpotsTitle": "Geplande plaatsen",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losSelectedObstructionDetails": "Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit})."
|
||||
}
|
||||
|
||||
+41
-1
@@ -2104,5 +2104,45 @@
|
||||
"repeater_guestTools": "Narzędzia dla gości",
|
||||
"repeater_guest": "Informacje dotyczące urządzenia powtarzającego",
|
||||
"room_guest": "Informacje o serwerze",
|
||||
"settings_multiAck": "Wielokrotne potwierdzenia odbioru"
|
||||
"settings_multiAck": "Wielokrotne potwierdzenia odbioru",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losSelectedObstructionTitle": "Wybór przeszkody",
|
||||
"losBlockedSpotsTitle": "Zablokowane miejsca",
|
||||
"losBlockedSpotsHint": "Kliknij zablokowane miejsce, aby je zaznaczyć na mapie.",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losSelectedObstructionDetails": "Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit})."
|
||||
}
|
||||
|
||||
+41
-1
@@ -2066,5 +2066,45 @@
|
||||
"room_guest": "Informações do Servidor",
|
||||
"chat_sendMessage": "Enviar mensagem",
|
||||
"repeater_guest": "Informações sobre repetidores",
|
||||
"repeater_guestTools": "Ferramentas para hóspedes"
|
||||
"repeater_guestTools": "Ferramentas para hóspedes",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losBlockedSpotsTitle": "Locais ocupados",
|
||||
"losBlockedSpotsHint": "Toque em um ponto bloqueado para destacá-lo no mapa.",
|
||||
"losSelectedObstructionTitle": "Obstrução selecionada",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losSelectedObstructionDetails": "Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit})."
|
||||
}
|
||||
|
||||
+41
-1
@@ -1306,5 +1306,45 @@
|
||||
"repeater_guest": "Информация о ретрансляторе",
|
||||
"room_guest": "Информация о сервере",
|
||||
"repeater_guestTools": "Инструменты для гостей",
|
||||
"settings_multiAck": "Несколько подтверждений"
|
||||
"settings_multiAck": "Несколько подтверждений",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losBlockedSpotsHint": "Щелкните по заблокированной области, чтобы выделить ее на карте.",
|
||||
"losBlockedSpotsTitle": "Зарезервированные места",
|
||||
"losSelectedObstructionTitle": "Выбранный объект, препятствующий движению",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losSelectedObstructionDetails": "Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit})."
|
||||
}
|
||||
|
||||
+41
-1
@@ -2066,5 +2066,45 @@
|
||||
"chat_sendMessage": "Odoslať správu",
|
||||
"repeater_guest": "Informácie o opakovači",
|
||||
"room_guest": "Informácie o serveri",
|
||||
"repeater_guestTools": "Nástroje pre hostí"
|
||||
"repeater_guestTools": "Nástroje pre hostí",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losBlockedSpotsTitle": "Zablokované miesta",
|
||||
"losBlockedSpotsHint": "Kliknite na zablokované miesto, aby ste ho zvýraznili na mape.",
|
||||
"losSelectedObstructionTitle": "Vybraná prekážka",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losSelectedObstructionDetails": "Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit})."
|
||||
}
|
||||
|
||||
+41
-1
@@ -2066,5 +2066,45 @@
|
||||
"chat_sendMessage": "Pošlji sporočilo",
|
||||
"room_guest": "Informacije o strežniku",
|
||||
"repeater_guestTools": "Naložila za goste",
|
||||
"settings_multiAck": "Več potrdil"
|
||||
"settings_multiAck": "Več potrdil",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losBlockedSpotsHint": "Dotaknite blokirano točko, da jo označite na zemljeplati.",
|
||||
"losSelectedObstructionTitle": "Izbrano ovire",
|
||||
"losBlockedSpotsTitle": "Zasedena parkirišča",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losSelectedObstructionDetails": "Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit})."
|
||||
}
|
||||
|
||||
+41
-1
@@ -2066,5 +2066,45 @@
|
||||
"chat_sendMessage": "Skicka meddelande",
|
||||
"repeater_guestTools": "Gästverktyg",
|
||||
"room_guest": "Information om servern",
|
||||
"settings_multiAck": "Flera bekräftelser"
|
||||
"settings_multiAck": "Flera bekräftelser",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losBlockedSpotsTitle": "Reserverade platser",
|
||||
"losSelectedObstructionTitle": "Vald hinder",
|
||||
"losBlockedSpotsHint": "Klicka på en markerad plats för att framhäva den på kartan.",
|
||||
"losSelectedObstructionDetails": "Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit})."
|
||||
}
|
||||
|
||||
+41
-1
@@ -2066,5 +2066,45 @@
|
||||
"repeater_guest": "Інформація про ретранслятор",
|
||||
"room_guest": "Інформація про сервер кімнати",
|
||||
"chat_sendMessage": "Надіслати повідомлення",
|
||||
"settings_multiAck": "Багато підтверджень"
|
||||
"settings_multiAck": "Багато підтверджень",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losBlockedSpotsHint": "Натисніть на заблоковане місце, щоб виділити його на карті.",
|
||||
"losBlockedSpotsTitle": "Заблоковані місця",
|
||||
"losSelectedObstructionTitle": "Вибраний об'єкт перешкоди",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losSelectedObstructionDetails": "Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit})."
|
||||
}
|
||||
|
||||
+41
-1
@@ -2071,5 +2071,45 @@
|
||||
"repeater_guestTools": "访客工具",
|
||||
"repeater_guest": "重复器信息",
|
||||
"chat_sendMessage": "发送消息",
|
||||
"room_guest": "服务器信息"
|
||||
"room_guest": "服务器信息",
|
||||
"@losBlockedSpotChip": {
|
||||
"placeholders": {
|
||||
"distance": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"@losSelectedObstructionDetails": {
|
||||
"placeholders": {
|
||||
"obstruction": {
|
||||
"type": "String"
|
||||
},
|
||||
"heightUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromA": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceUnit": {
|
||||
"type": "String"
|
||||
},
|
||||
"distanceFromB": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"losBlockedSpotsTitle": "被占用区域",
|
||||
"losBlockedSpotsHint": "点击地图上的某个被遮盖的区域,以突出显示该区域。",
|
||||
"losSelectedObstructionTitle": "选择性阻碍",
|
||||
"losBlockedSpotChip": "{distance} {distanceUnit} • {obstruction} {heightUnit}",
|
||||
"losSelectedObstructionDetails": "Blocked by {obstruction} {heightUnit}, {distanceFromA} from A and {distanceFromB} from B ({distanceUnit})."
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ class _LineOfSightMapScreenState extends State<LineOfSightMapScreen> {
|
||||
bool _loading = false;
|
||||
String? _error;
|
||||
LineOfSightPathResult? _result;
|
||||
LineOfSightObstruction? _selectedObstruction;
|
||||
LineOfSightEndpoint? _start;
|
||||
LineOfSightEndpoint? _end;
|
||||
final List<LineOfSightEndpoint> _customEndpoints = [];
|
||||
@@ -111,6 +112,7 @@ class _LineOfSightMapScreenState extends State<LineOfSightMapScreen> {
|
||||
if (start == null || end == null) {
|
||||
setState(() {
|
||||
_result = null;
|
||||
_selectedObstruction = null;
|
||||
_error = _errorSelectStartEnd;
|
||||
});
|
||||
return;
|
||||
@@ -142,6 +144,7 @@ class _LineOfSightMapScreenState extends State<LineOfSightMapScreen> {
|
||||
}
|
||||
setState(() {
|
||||
_result = result;
|
||||
_selectedObstruction = _defaultObstructionFor(result);
|
||||
});
|
||||
} catch (e) {
|
||||
if (!mounted) return;
|
||||
@@ -156,6 +159,7 @@ class _LineOfSightMapScreenState extends State<LineOfSightMapScreen> {
|
||||
}
|
||||
setState(() {
|
||||
_result = null;
|
||||
_selectedObstruction = null;
|
||||
_error = context.l10n.losRunFailed(e.toString());
|
||||
});
|
||||
} finally {
|
||||
@@ -184,6 +188,7 @@ class _LineOfSightMapScreenState extends State<LineOfSightMapScreen> {
|
||||
void _selectFromMap(LineOfSightEndpoint endpoint) {
|
||||
setState(() {
|
||||
_result = null;
|
||||
_selectedObstruction = null;
|
||||
_error = null;
|
||||
if (_start == null || (_start != null && _end != null)) {
|
||||
_start = endpoint;
|
||||
@@ -241,6 +246,7 @@ class _LineOfSightMapScreenState extends State<LineOfSightMapScreen> {
|
||||
_start = null;
|
||||
_end = null;
|
||||
_result = null;
|
||||
_selectedObstruction = null;
|
||||
_error = _errorSelectStartEnd;
|
||||
});
|
||||
}
|
||||
@@ -251,6 +257,7 @@ class _LineOfSightMapScreenState extends State<LineOfSightMapScreen> {
|
||||
if (identical(_start, endpoint)) _start = null;
|
||||
if (identical(_end, endpoint)) _end = null;
|
||||
_result = null;
|
||||
_selectedObstruction = null;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -377,7 +384,9 @@ class _LineOfSightMapScreenState extends State<LineOfSightMapScreen> {
|
||||
),
|
||||
if (_result != null && _result!.segments.isNotEmpty)
|
||||
PolylineLayer(polylines: _buildSegmentPolylines(_result!)),
|
||||
MarkerLayer(markers: _buildMarkers(endpoints)),
|
||||
MarkerLayer(
|
||||
markers: _buildMarkers(endpoints, _primaryObstructions()),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (_showHud)
|
||||
@@ -445,6 +454,8 @@ class _LineOfSightMapScreenState extends State<LineOfSightMapScreen> {
|
||||
);
|
||||
final displayFrequencyMHz = segment?.frequencyMHz ?? reportedFrequencyMHz;
|
||||
final kFactorUsed = segment?.usedKFactor;
|
||||
final obstructions =
|
||||
segment?.obstructions ?? const <LineOfSightObstruction>[];
|
||||
final endpoints = _visibleEndpoints();
|
||||
final distanceUnit = isImperial ? 'mi' : 'km';
|
||||
final heightUnit = isImperial ? 'ft' : 'm';
|
||||
@@ -463,31 +474,7 @@ class _LineOfSightMapScreenState extends State<LineOfSightMapScreen> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (segment != null)
|
||||
SizedBox(
|
||||
height: 160,
|
||||
width: double.infinity,
|
||||
child: CustomPaint(
|
||||
painter: _LosProfilePainter(
|
||||
samples: segment.samples,
|
||||
distanceUnit: distanceUnit,
|
||||
heightUnit: heightUnit,
|
||||
badgeTextStyle:
|
||||
Theme.of(context).textTheme.labelSmall?.copyWith(
|
||||
color: Colors.white70,
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w600,
|
||||
) ??
|
||||
const TextStyle(
|
||||
color: Colors.white70,
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
terrainLabel: context.l10n.losLegendTerrain,
|
||||
losBeamLabel: context.l10n.losLegendLosBeam,
|
||||
radioHorizonLabel: context.l10n.losLegendRadioHorizon,
|
||||
),
|
||||
),
|
||||
)
|
||||
_buildProfileView(segment, distanceUnit, heightUnit, isImperial)
|
||||
else
|
||||
SizedBox(
|
||||
height: 44,
|
||||
@@ -519,6 +506,96 @@ class _LineOfSightMapScreenState extends State<LineOfSightMapScreen> {
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
if (obstructions.isNotEmpty) ...[
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
context.l10n.losBlockedSpotsTitle,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
context.l10n.losBlockedSpotsHint,
|
||||
style: TextStyle(fontSize: 11, color: Colors.grey[700]),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Wrap(
|
||||
spacing: 6,
|
||||
runSpacing: 6,
|
||||
children: [
|
||||
for (final obstruction in obstructions)
|
||||
ChoiceChip(
|
||||
label: Text(
|
||||
_obstructionChipLabel(obstruction, isImperial),
|
||||
style: const TextStyle(fontSize: 11),
|
||||
),
|
||||
selected:
|
||||
_selectedObstruction?.sampleIndex ==
|
||||
obstruction.sampleIndex,
|
||||
onSelected: (_) => _selectObstruction(obstruction),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (_selectedObstruction != null) ...[
|
||||
const SizedBox(height: 8),
|
||||
DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.orange.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(
|
||||
color: Colors.deepOrangeAccent.withValues(alpha: 0.45),
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
context.l10n.losSelectedObstructionTitle,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
context.l10n.losSelectedObstructionDetails(
|
||||
_formatHeightValue(
|
||||
_selectedObstruction!.obstructionMeters,
|
||||
isImperial,
|
||||
),
|
||||
heightUnit,
|
||||
_formatDistanceValue(
|
||||
_selectedObstruction!.distanceMeters,
|
||||
isImperial,
|
||||
),
|
||||
distanceUnit,
|
||||
_formatDistanceValue(
|
||||
segment!.totalDistanceMeters -
|
||||
_selectedObstruction!.distanceMeters,
|
||||
isImperial,
|
||||
),
|
||||
),
|
||||
style: const TextStyle(fontSize: 11),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'${_selectedObstruction!.point.latitude.toStringAsFixed(5)}, '
|
||||
'${_selectedObstruction!.point.longitude.toStringAsFixed(5)}',
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: Colors.grey[700],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
const SizedBox(height: 4),
|
||||
if (displayFrequencyMHz != null)
|
||||
Padding(
|
||||
@@ -605,6 +682,7 @@ class _LineOfSightMapScreenState extends State<LineOfSightMapScreen> {
|
||||
_showDisplayNodes = value;
|
||||
_sanitizeSelection();
|
||||
_result = null;
|
||||
_selectedObstruction = null;
|
||||
});
|
||||
},
|
||||
),
|
||||
@@ -655,6 +733,7 @@ class _LineOfSightMapScreenState extends State<LineOfSightMapScreen> {
|
||||
setState(() {
|
||||
_start = value;
|
||||
_result = null;
|
||||
_selectedObstruction = null;
|
||||
});
|
||||
if (_start != null && _end != null) {
|
||||
_runLos();
|
||||
@@ -670,6 +749,7 @@ class _LineOfSightMapScreenState extends State<LineOfSightMapScreen> {
|
||||
setState(() {
|
||||
_end = value;
|
||||
_result = null;
|
||||
_selectedObstruction = null;
|
||||
});
|
||||
if (_start != null && _end != null) {
|
||||
_runLos();
|
||||
@@ -769,6 +849,179 @@ class _LineOfSightMapScreenState extends State<LineOfSightMapScreen> {
|
||||
return _result!.segments.first.result;
|
||||
}
|
||||
|
||||
List<LineOfSightObstruction> _primaryObstructions() {
|
||||
return _primarySegmentResult()?.obstructions ?? const [];
|
||||
}
|
||||
|
||||
LineOfSightObstruction? _defaultObstructionFor(
|
||||
LineOfSightPathResult? result,
|
||||
) {
|
||||
if (result == null || result.segments.isEmpty) return null;
|
||||
final obstructions = result.segments.first.result.obstructions;
|
||||
if (obstructions.isEmpty) return null;
|
||||
return obstructions.reduce(
|
||||
(current, next) =>
|
||||
next.obstructionMeters > current.obstructionMeters ? next : current,
|
||||
);
|
||||
}
|
||||
|
||||
void _selectObstruction(LineOfSightObstruction obstruction) {
|
||||
setState(() {
|
||||
_selectedObstruction = obstruction;
|
||||
});
|
||||
}
|
||||
|
||||
String _formatDistanceValue(double meters, bool isImperial) {
|
||||
final value = isImperial ? (meters / 1000.0) * _kmToMiles : meters / 1000.0;
|
||||
return value.toStringAsFixed(2);
|
||||
}
|
||||
|
||||
String _formatHeightValue(double meters, bool isImperial) {
|
||||
final value = isImperial ? meters * _metersToFeet : meters;
|
||||
return value.toStringAsFixed(1);
|
||||
}
|
||||
|
||||
String _obstructionChipLabel(
|
||||
LineOfSightObstruction obstruction,
|
||||
bool isImperial,
|
||||
) {
|
||||
final distanceUnit = isImperial ? 'mi' : 'km';
|
||||
final heightUnit = isImperial ? 'ft' : 'm';
|
||||
return context.l10n.losBlockedSpotChip(
|
||||
_formatDistanceValue(obstruction.distanceMeters, isImperial),
|
||||
distanceUnit,
|
||||
_formatHeightValue(obstruction.obstructionMeters, isImperial),
|
||||
heightUnit,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildProfileView(
|
||||
LineOfSightResult segment,
|
||||
String distanceUnit,
|
||||
String heightUnit,
|
||||
bool isImperial,
|
||||
) {
|
||||
if (segment.samples.length < 2) {
|
||||
return SizedBox(
|
||||
height: 160,
|
||||
width: double.infinity,
|
||||
child: CustomPaint(
|
||||
painter: _LosProfilePainter(
|
||||
samples: segment.samples,
|
||||
distanceUnit: distanceUnit,
|
||||
heightUnit: heightUnit,
|
||||
badgeTextStyle:
|
||||
Theme.of(context).textTheme.labelSmall?.copyWith(
|
||||
color: Colors.white70,
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w600,
|
||||
) ??
|
||||
const TextStyle(
|
||||
color: Colors.white70,
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
terrainLabel: context.l10n.losLegendTerrain,
|
||||
losBeamLabel: context.l10n.losLegendLosBeam,
|
||||
radioHorizonLabel: context.l10n.losLegendRadioHorizon,
|
||||
selectedSampleIndex: _selectedObstruction?.sampleIndex,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return SizedBox(
|
||||
height: 160,
|
||||
width: double.infinity,
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final size = Size(constraints.maxWidth, 160);
|
||||
final geometry = _LosProfileGeometry(
|
||||
samples: segment.samples,
|
||||
size: size,
|
||||
);
|
||||
return Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: CustomPaint(
|
||||
painter: _LosProfilePainter(
|
||||
samples: segment.samples,
|
||||
distanceUnit: distanceUnit,
|
||||
heightUnit: heightUnit,
|
||||
badgeTextStyle:
|
||||
Theme.of(context).textTheme.labelSmall?.copyWith(
|
||||
color: Colors.white70,
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w600,
|
||||
) ??
|
||||
const TextStyle(
|
||||
color: Colors.white70,
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
terrainLabel: context.l10n.losLegendTerrain,
|
||||
losBeamLabel: context.l10n.losLegendLosBeam,
|
||||
radioHorizonLabel: context.l10n.losLegendRadioHorizon,
|
||||
selectedSampleIndex: _selectedObstruction?.sampleIndex,
|
||||
),
|
||||
),
|
||||
),
|
||||
for (final obstruction in segment.obstructions)
|
||||
Builder(
|
||||
builder: (context) {
|
||||
final sample = segment.samples[obstruction.sampleIndex];
|
||||
final position = geometry.mapPoint(
|
||||
sample.distanceMeters,
|
||||
sample.terrainMeters,
|
||||
);
|
||||
final isSelected =
|
||||
_selectedObstruction?.sampleIndex ==
|
||||
obstruction.sampleIndex;
|
||||
final markerSize = isSelected ? 18.0 : 14.0;
|
||||
final left = (position.dx - markerSize / 2)
|
||||
.clamp(0.0, math.max(0.0, size.width - markerSize))
|
||||
.toDouble();
|
||||
final top = (position.dy - markerSize / 2)
|
||||
.clamp(0.0, math.max(0.0, size.height - markerSize))
|
||||
.toDouble();
|
||||
return Positioned(
|
||||
left: left,
|
||||
top: top,
|
||||
child: Tooltip(
|
||||
message: _obstructionChipLabel(obstruction, isImperial),
|
||||
child: GestureDetector(
|
||||
onTap: () => _selectObstruction(obstruction),
|
||||
child: Container(
|
||||
width: markerSize,
|
||||
height: markerSize,
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected
|
||||
? Colors.amberAccent
|
||||
: Colors.deepOrangeAccent,
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: isSelected
|
||||
? Colors.white
|
||||
: Colors.black87,
|
||||
width: isSelected ? 2 : 1.5,
|
||||
),
|
||||
boxShadow: const [
|
||||
BoxShadow(color: Colors.black45, blurRadius: 4),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String _profileStats(LineOfSightResult result, bool isImperial) {
|
||||
final distance = isImperial
|
||||
? (result.totalDistanceMeters / 1000.0) * _kmToMiles
|
||||
@@ -820,8 +1073,51 @@ class _LineOfSightMapScreenState extends State<LineOfSightMapScreen> {
|
||||
return polylines;
|
||||
}
|
||||
|
||||
List<Marker> _buildMarkers(List<LineOfSightEndpoint> endpoints) {
|
||||
List<Marker> _buildMarkers(
|
||||
List<LineOfSightEndpoint> endpoints,
|
||||
List<LineOfSightObstruction> obstructions,
|
||||
) {
|
||||
return [
|
||||
for (final obstruction in obstructions)
|
||||
Marker(
|
||||
point: obstruction.point,
|
||||
width: 52,
|
||||
height: 52,
|
||||
child: GestureDetector(
|
||||
onTap: () => _selectObstruction(obstruction),
|
||||
child: Center(
|
||||
child: Container(
|
||||
width:
|
||||
_selectedObstruction?.sampleIndex == obstruction.sampleIndex
|
||||
? 36
|
||||
: 24,
|
||||
height:
|
||||
_selectedObstruction?.sampleIndex == obstruction.sampleIndex
|
||||
? 36
|
||||
: 24,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Colors.transparent,
|
||||
border: Border.all(
|
||||
color:
|
||||
_selectedObstruction?.sampleIndex ==
|
||||
obstruction.sampleIndex
|
||||
? Colors.amberAccent
|
||||
: Colors.deepOrangeAccent,
|
||||
width:
|
||||
_selectedObstruction?.sampleIndex ==
|
||||
obstruction.sampleIndex
|
||||
? 4
|
||||
: 3,
|
||||
),
|
||||
boxShadow: const [
|
||||
BoxShadow(color: Colors.black26, blurRadius: 6),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
for (final endpoint in endpoints)
|
||||
Marker(
|
||||
point: endpoint.point,
|
||||
@@ -1010,6 +1306,51 @@ class _LineOfSightMapScreenState extends State<LineOfSightMapScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
class _LosProfileGeometry {
|
||||
static const horizontalPadding = 12.0;
|
||||
static const verticalPadding = 12.0;
|
||||
|
||||
final List<LineOfSightSample> samples;
|
||||
final Size size;
|
||||
late final double minY = samples
|
||||
.map(
|
||||
(s) => math.min(
|
||||
math.min(s.terrainMeters, s.lineHeightMeters),
|
||||
s.refractedHeightMeters,
|
||||
),
|
||||
)
|
||||
.reduce(math.min);
|
||||
late final double maxY = samples
|
||||
.map(
|
||||
(s) => math.max(
|
||||
math.max(s.terrainMeters, s.lineHeightMeters),
|
||||
s.refractedHeightMeters,
|
||||
),
|
||||
)
|
||||
.reduce(math.max);
|
||||
late final double ySpan = math.max(1.0, maxY - minY);
|
||||
late final double maxDist = math.max(1.0, samples.last.distanceMeters);
|
||||
late final double chartWidth = math.max(
|
||||
1.0,
|
||||
size.width - horizontalPadding * 2,
|
||||
);
|
||||
late final double chartHeight = math.max(
|
||||
1.0,
|
||||
size.height - verticalPadding * 2,
|
||||
);
|
||||
|
||||
_LosProfileGeometry({required this.samples, required this.size});
|
||||
|
||||
Offset mapPoint(double distanceMeters, double elevationMeters) {
|
||||
final px = horizontalPadding + (distanceMeters / maxDist) * chartWidth;
|
||||
final py =
|
||||
size.height -
|
||||
verticalPadding -
|
||||
((elevationMeters - minY) / ySpan) * chartHeight;
|
||||
return Offset(px, py);
|
||||
}
|
||||
}
|
||||
|
||||
class _LosProfilePainter extends CustomPainter {
|
||||
final List<LineOfSightSample> samples;
|
||||
final String distanceUnit;
|
||||
@@ -1018,6 +1359,7 @@ class _LosProfilePainter extends CustomPainter {
|
||||
final String terrainLabel;
|
||||
final String losBeamLabel;
|
||||
final String radioHorizonLabel;
|
||||
final int? selectedSampleIndex;
|
||||
|
||||
const _LosProfilePainter({
|
||||
required this.samples,
|
||||
@@ -1027,6 +1369,7 @@ class _LosProfilePainter extends CustomPainter {
|
||||
required this.terrainLabel,
|
||||
required this.losBeamLabel,
|
||||
required this.radioHorizonLabel,
|
||||
this.selectedSampleIndex,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -1212,6 +1555,32 @@ class _LosProfilePainter extends CustomPainter {
|
||||
..color = horizonFillColor
|
||||
..style = PaintingStyle.fill,
|
||||
);
|
||||
|
||||
if (selectedSampleIndex != null &&
|
||||
selectedSampleIndex! >= 0 &&
|
||||
selectedSampleIndex! < samples.length) {
|
||||
final selectedSample = samples[selectedSampleIndex!];
|
||||
final selectedPoint = mapPoint(
|
||||
selectedSample.distanceMeters,
|
||||
selectedSample.terrainMeters,
|
||||
);
|
||||
canvas.drawLine(
|
||||
Offset(selectedPoint.dx, verticalPadding),
|
||||
Offset(selectedPoint.dx, size.height - verticalPadding),
|
||||
Paint()
|
||||
..color = Colors.amberAccent.withValues(alpha: 0.7)
|
||||
..strokeWidth = 1.5,
|
||||
);
|
||||
canvas.drawCircle(selectedPoint, 7, Paint()..color = Colors.amberAccent);
|
||||
canvas.drawCircle(
|
||||
selectedPoint,
|
||||
8.5,
|
||||
Paint()
|
||||
..color = Colors.white
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 1.5,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1222,7 +1591,8 @@ class _LosProfilePainter extends CustomPainter {
|
||||
oldDelegate.badgeTextStyle != badgeTextStyle ||
|
||||
oldDelegate.terrainLabel != terrainLabel ||
|
||||
oldDelegate.losBeamLabel != losBeamLabel ||
|
||||
oldDelegate.radioHorizonLabel != radioHorizonLabel;
|
||||
oldDelegate.radioHorizonLabel != radioHorizonLabel ||
|
||||
oldDelegate.selectedSampleIndex != selectedSampleIndex;
|
||||
}
|
||||
|
||||
void _drawUnitBadge(Canvas canvas, Size size) {
|
||||
|
||||
@@ -24,6 +24,26 @@ class LineOfSightSample {
|
||||
});
|
||||
}
|
||||
|
||||
class LineOfSightObstruction {
|
||||
final int sampleIndex;
|
||||
final LatLng point;
|
||||
final double distanceMeters;
|
||||
final double clearanceMeters;
|
||||
final double obstructionMeters;
|
||||
final double terrainMeters;
|
||||
final double lineHeightMeters;
|
||||
|
||||
const LineOfSightObstruction({
|
||||
required this.sampleIndex,
|
||||
required this.point,
|
||||
required this.distanceMeters,
|
||||
required this.clearanceMeters,
|
||||
required this.obstructionMeters,
|
||||
required this.terrainMeters,
|
||||
required this.lineHeightMeters,
|
||||
});
|
||||
}
|
||||
|
||||
class LineOfSightResult {
|
||||
final bool hasData;
|
||||
final bool isClear;
|
||||
@@ -31,6 +51,7 @@ class LineOfSightResult {
|
||||
final double maxObstructionMeters;
|
||||
final double? firstObstructionDistanceMeters;
|
||||
final List<LineOfSightSample> samples;
|
||||
final List<LineOfSightObstruction> obstructions;
|
||||
final String? errorMessage;
|
||||
final double usedKFactor;
|
||||
final double? frequencyMHz;
|
||||
@@ -42,6 +63,7 @@ class LineOfSightResult {
|
||||
required this.maxObstructionMeters,
|
||||
required this.firstObstructionDistanceMeters,
|
||||
required this.samples,
|
||||
required this.obstructions,
|
||||
required this.usedKFactor,
|
||||
this.frequencyMHz,
|
||||
this.errorMessage,
|
||||
@@ -56,7 +78,8 @@ class LineOfSightResult {
|
||||
isClear = false,
|
||||
maxObstructionMeters = 0,
|
||||
firstObstructionDistanceMeters = null,
|
||||
samples = const [];
|
||||
samples = const [],
|
||||
obstructions = const [];
|
||||
}
|
||||
|
||||
class LineOfSightPathSegment {
|
||||
@@ -191,6 +214,7 @@ class LineOfSightService {
|
||||
maxObstructionMeters: 0,
|
||||
firstObstructionDistanceMeters: null,
|
||||
samples: const [],
|
||||
obstructions: const [],
|
||||
usedKFactor: kFactor,
|
||||
frequencyMHz: frequencyMHz,
|
||||
);
|
||||
@@ -249,7 +273,9 @@ class LineOfSightService {
|
||||
var maxObstructionMeters = 0.0;
|
||||
double? firstObstructionDistanceMeters;
|
||||
final samples = <LineOfSightSample>[];
|
||||
final obstructions = <LineOfSightObstruction>[];
|
||||
var isClear = true;
|
||||
LineOfSightObstruction? clusterWorstObstruction;
|
||||
|
||||
for (int i = 0; i < points.length; i++) {
|
||||
final fraction = points.length == 1 ? 0.0 : i / (points.length - 1);
|
||||
@@ -274,6 +300,23 @@ class LineOfSightService {
|
||||
maxObstructionMeters = obstruction;
|
||||
}
|
||||
firstObstructionDistanceMeters ??= distanceFromStart;
|
||||
final candidate = LineOfSightObstruction(
|
||||
sampleIndex: i,
|
||||
point: points[i],
|
||||
distanceMeters: distanceFromStart,
|
||||
clearanceMeters: clearance,
|
||||
obstructionMeters: obstruction,
|
||||
terrainMeters: terrainHeight,
|
||||
lineHeightMeters: lineHeight,
|
||||
);
|
||||
if (clusterWorstObstruction == null ||
|
||||
candidate.obstructionMeters >
|
||||
clusterWorstObstruction.obstructionMeters) {
|
||||
clusterWorstObstruction = candidate;
|
||||
}
|
||||
} else if (clusterWorstObstruction != null) {
|
||||
obstructions.add(clusterWorstObstruction);
|
||||
clusterWorstObstruction = null;
|
||||
}
|
||||
|
||||
samples.add(
|
||||
@@ -286,6 +329,9 @@ class LineOfSightService {
|
||||
),
|
||||
);
|
||||
}
|
||||
if (clusterWorstObstruction != null) {
|
||||
obstructions.add(clusterWorstObstruction);
|
||||
}
|
||||
|
||||
return LineOfSightResult(
|
||||
hasData: true,
|
||||
@@ -294,6 +340,7 @@ class LineOfSightService {
|
||||
maxObstructionMeters: maxObstructionMeters,
|
||||
firstObstructionDistanceMeters: firstObstructionDistanceMeters,
|
||||
samples: samples,
|
||||
obstructions: obstructions,
|
||||
usedKFactor: kFactor,
|
||||
frequencyMHz: frequencyMHz,
|
||||
);
|
||||
|
||||
@@ -23,6 +23,7 @@ void main() {
|
||||
expect(result.isClear, isTrue);
|
||||
expect(result.maxObstructionMeters, equals(0));
|
||||
expect(result.firstObstructionDistanceMeters, isNull);
|
||||
expect(result.obstructions, isEmpty);
|
||||
});
|
||||
|
||||
test(
|
||||
@@ -44,9 +45,32 @@ void main() {
|
||||
expect(result.isClear, isFalse);
|
||||
expect(result.maxObstructionMeters, greaterThan(0));
|
||||
expect(result.firstObstructionDistanceMeters, isNotNull);
|
||||
expect(result.obstructions, hasLength(1));
|
||||
expect(result.obstructions.single.sampleIndex, equals(10));
|
||||
expect(result.obstructions.single.point, equals(points[10]));
|
||||
},
|
||||
);
|
||||
|
||||
test('computeFromElevations groups contiguous blocked samples', () {
|
||||
final points = makePoints(21);
|
||||
final elevations = List<double>.filled(points.length, 100);
|
||||
elevations[9] = 220;
|
||||
elevations[10] = 320;
|
||||
elevations[11] = 240;
|
||||
|
||||
final result = LineOfSightService.computeFromElevations(
|
||||
points: points,
|
||||
elevations: elevations,
|
||||
startAntennaHeightMeters: 1.5,
|
||||
endAntennaHeightMeters: 1.5,
|
||||
kFactor: 4.0 / 3.0,
|
||||
);
|
||||
|
||||
expect(result.obstructions, hasLength(1));
|
||||
expect(result.obstructions.single.sampleIndex, equals(10));
|
||||
expect(result.obstructions.single.obstructionMeters, greaterThan(0));
|
||||
});
|
||||
|
||||
test('analyzePath summarizes clear and blocked segments', () async {
|
||||
final service = LineOfSightService(
|
||||
elevationDataSource: (points) async {
|
||||
|
||||
Reference in New Issue
Block a user