Compare commits
10 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 12b83993c4 | |||
| e9432756b0 | |||
| 3c1da8adec | |||
| c35ccb91bf | |||
| d4364379ab | |||
| 7ca06948f1 | |||
| 1a72314e30 | |||
| fa4c379176 | |||
| a3728798b8 | |||
| 5fd76678d4 |
47 changed files with 258 additions and 22 deletions
44
F-DROID.md
Normal file
44
F-DROID.md
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
# F-Droid submission notes
|
||||||
|
|
||||||
|
## Anti-features: Play Services dependency
|
||||||
|
|
||||||
|
The app includes `com.google.android.gms:play-services-location:21.3.0` for better location accuracy via `FusedLocationProviderClient`. However, this is **not a hard dependency**:
|
||||||
|
|
||||||
|
- The app checks for Play Services at runtime via `GoogleApiAvailability`
|
||||||
|
- If unavailable, it falls back to `LocationManager` (standard AOSP API)
|
||||||
|
- All core functionality (finding shelters, compass navigation, offline maps) works without Play Services
|
||||||
|
|
||||||
|
This was specifically designed to support degoogled devices (LineageOS, GrapheneOS, /e/OS).
|
||||||
|
|
||||||
|
### F-Droid build options
|
||||||
|
|
||||||
|
**Option A: Accept as-is with `NonFreeDep` anti-feature**
|
||||||
|
The app works fully without Play Services. Mark with `NonFreeDep` anti-feature.
|
||||||
|
|
||||||
|
**Option B: Build flavor without Play Services (recommended)**
|
||||||
|
Create a `fdroid` product flavor that excludes the Play Services dependency entirely. The fallback code paths already handle the absence — only the dependency and the Fused provider code need to be conditionally included.
|
||||||
|
|
||||||
|
## Metadata structure
|
||||||
|
|
||||||
|
```
|
||||||
|
fastlane/metadata/android/
|
||||||
|
├── en-US/ # English (default)
|
||||||
|
├── nb-NO/ # Norwegian Bokmål
|
||||||
|
└── nn-NO/ # Norwegian Nynorsk
|
||||||
|
```
|
||||||
|
|
||||||
|
Each locale contains `title.txt`, `short_description.txt`, `full_description.txt`, and `changelogs/` with per-versionCode files.
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|
Screenshots still need to be added to `images/` directories:
|
||||||
|
- `phoneScreenshots/` — at least 3 phone screenshots
|
||||||
|
- `featureGraphic.png` — 1024x500 feature graphic
|
||||||
|
|
||||||
|
## Build instructions
|
||||||
|
|
||||||
|
Standard Gradle build, no custom steps needed:
|
||||||
|
|
||||||
|
```
|
||||||
|
./gradlew assembleRelease
|
||||||
|
```
|
||||||
|
|
@ -77,9 +77,12 @@ Appen er designet etter «offline-first»-prinsippet:
|
||||||
- Databaseoppdateringer er atomiske (transaksjon) for å unngå datatap
|
- Databaseoppdateringer er atomiske (transaksjon) for å unngå datatap
|
||||||
- Ingen persondata lagres — kun tilfluktsromdata og kartfliser
|
- Ingen persondata lagres — kun tilfluktsromdata og kartfliser
|
||||||
|
|
||||||
|
## Opphavsrett
|
||||||
|
|
||||||
|
Copyright (c) Ole-Morten Duesund <olemd@glemt.net>
|
||||||
|
|
||||||
## Lisens
|
## Lisens
|
||||||
|
|
||||||
Kildekoden er lisensiert under [Mozilla Public License 2.0](LICENSE).
|
Kildekoden er lisensiert under [Mozilla Public License 2.0](LICENSE).
|
||||||
|
|
||||||
Tilfluktsromdata er åpne data fra Geonorge / Direktoratet for samfunnssikkerhet og beredskap (DSB).
|
Appen bruker åpne data og tjenester fra flere kilder. Se [SOURCES.md](SOURCES.md) for en fullstendig oversikt over datakilder, URL-er og lisenser.
|
||||||
Kartfliser fra OpenStreetMap er lisensiert under [ODbL](https://opendatacommons.org/licenses/odbl/).
|
|
||||||
|
|
|
||||||
17
SOURCES.md
Normal file
17
SOURCES.md
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Data Sources
|
||||||
|
|
||||||
|
Centralized list of all external data sources used by the app. This is the authoritative reference for attribution, licensing, and usage context.
|
||||||
|
|
||||||
|
## Sources
|
||||||
|
|
||||||
|
| Source | Provider | URL | Usage | License | Used in |
|
||||||
|
|--------|----------|-----|-------|---------|---------|
|
||||||
|
| Shelter data (GeoJSON) | Geonorge / DSB | [nedlasting.geonorge.no/...](https://nedlasting.geonorge.no/geonorge/Samfunnssikkerhet/TilfluktsromOffentlige/GeoJSON/Samfunnssikkerhet_0000_Norge_25833_TilfluktsromOffentlige_GeoJSON.zip) | Shelter locations, capacity, addresses (~556 shelters) | [NLOD 2.0](https://data.norge.no/nlod/no/2.0) | `app/.../data/ShelterRepository.kt`, `pwa/scripts/fetch-shelters.ts` |
|
||||||
|
| Map tiles | OpenStreetMap | [tile.openstreetmap.org](https://tile.openstreetmap.org) | Offline-capable map display | [ODbL](https://opendatacommons.org/licenses/odbl/) | `app/` via OSMDroid, `pwa/src/ui/map-view.ts` via Leaflet |
|
||||||
|
| Civil defense guidelines | DSB (Direktoratet for samfunnssikkerhet og beredskap) | [dsb.no/sikkerhverdag/egenberedskap](https://www.dsb.no/sikkerhverdag/egenberedskap/) | Emergency instructions shown in the civil defense info dialog | Norwegian public sector information | `app/.../res/values/strings.xml` (civil_defense_* strings) |
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- **Shelter data** is downloaded as a ZIP containing GeoJSON in EPSG:25833 (UTM33N) projection. The app converts coordinates to WGS84 at parse time.
|
||||||
|
- **Map tiles** are cached locally by OSMDroid (Android) and the service worker (PWA) for offline use. OpenStreetMap's [tile usage policy](https://operations.osmfoundation.org/policies/tiles/) applies.
|
||||||
|
- **Civil defense guidelines** are adapted from official DSB recommendations, not quoted verbatim. Content is available in English, Bokmal, and Nynorsk.
|
||||||
|
|
@ -3,6 +3,7 @@ package no.naiv.tilfluktsrom
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.view.HapticFeedbackConstants
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.hardware.Sensor
|
import android.hardware.Sensor
|
||||||
import android.hardware.SensorEvent
|
import android.hardware.SensorEvent
|
||||||
|
|
@ -202,6 +203,7 @@ class MainActivity : AppCompatActivity(), SensorEventListener {
|
||||||
|
|
||||||
private fun setupButtons() {
|
private fun setupButtons() {
|
||||||
binding.toggleViewFab.setOnClickListener {
|
binding.toggleViewFab.setOnClickListener {
|
||||||
|
it.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)
|
||||||
isCompassMode = !isCompassMode
|
isCompassMode = !isCompassMode
|
||||||
if (isCompassMode) {
|
if (isCompassMode) {
|
||||||
binding.mapView.visibility = View.GONE
|
binding.mapView.visibility = View.GONE
|
||||||
|
|
@ -216,24 +218,29 @@ class MainActivity : AppCompatActivity(), SensorEventListener {
|
||||||
|
|
||||||
// Reset to navigation: re-fit map to show user + selected shelter
|
// Reset to navigation: re-fit map to show user + selected shelter
|
||||||
binding.resetNavigationFab.setOnClickListener {
|
binding.resetNavigationFab.setOnClickListener {
|
||||||
|
it.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)
|
||||||
userHasInteractedWithMap = false
|
userHasInteractedWithMap = false
|
||||||
binding.resetNavigationFab.visibility = View.GONE
|
binding.resetNavigationFab.visibility = View.GONE
|
||||||
selectedShelter?.let { highlightShelterOnMap(it) }
|
selectedShelter?.let { highlightShelterOnMap(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.infoButton.setOnClickListener {
|
binding.infoButton.setOnClickListener {
|
||||||
|
it.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)
|
||||||
CivilDefenseInfoDialog().show(supportFragmentManager, CivilDefenseInfoDialog.TAG)
|
CivilDefenseInfoDialog().show(supportFragmentManager, CivilDefenseInfoDialog.TAG)
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.refreshButton.setOnClickListener {
|
binding.refreshButton.setOnClickListener {
|
||||||
|
it.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)
|
||||||
forceRefresh()
|
forceRefresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.shareButton.setOnClickListener {
|
binding.shareButton.setOnClickListener {
|
||||||
|
it.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)
|
||||||
shareShelter()
|
shareShelter()
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.cacheRetryButton.setOnClickListener {
|
binding.cacheRetryButton.setOnClickListener {
|
||||||
|
it.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)
|
||||||
val loc = currentLocation
|
val loc = currentLocation
|
||||||
if (loc == null) {
|
if (loc == null) {
|
||||||
Toast.makeText(this, R.string.status_no_location, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, R.string.status_no_location, Toast.LENGTH_SHORT).show()
|
||||||
|
|
@ -489,7 +496,11 @@ class MainActivity : AppCompatActivity(), SensorEventListener {
|
||||||
/** Update all UI elements for the currently selected shelter. */
|
/** Update all UI elements for the currently selected shelter. */
|
||||||
private fun updateSelectedShelterUI() {
|
private fun updateSelectedShelterUI() {
|
||||||
val selected = selectedShelter ?: return
|
val selected = selectedShelter ?: return
|
||||||
val distanceText = DistanceUtils.formatDistance(selected.distanceMeters)
|
val distanceText = if (selected.distanceMeters.isNaN()) {
|
||||||
|
getString(R.string.status_no_location)
|
||||||
|
} else {
|
||||||
|
DistanceUtils.formatDistance(selected.distanceMeters)
|
||||||
|
}
|
||||||
|
|
||||||
// Update bottom sheet
|
// Update bottom sheet
|
||||||
binding.selectedShelterAddress.text = selected.shelter.adresse
|
binding.selectedShelterAddress.text = selected.shelter.adresse
|
||||||
|
|
@ -829,9 +840,7 @@ class MainActivity : AppCompatActivity(), SensorEventListener {
|
||||||
Log.w(TAG, "Compass accuracy degraded: $accuracy")
|
Log.w(TAG, "Compass accuracy degraded: $accuracy")
|
||||||
binding.compassAddressText.let { tv ->
|
binding.compassAddressText.let { tv ->
|
||||||
val current = selectedShelter?.shelter?.adresse ?: ""
|
val current = selectedShelter?.shelter?.adresse ?: ""
|
||||||
if (!current.contains("⚠")) {
|
tv.text = getString(R.string.compass_accuracy_warning, current)
|
||||||
tv.text = "⚠ $current"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SensorManager.SENSOR_STATUS_ACCURACY_MEDIUM,
|
SensorManager.SENSOR_STATUS_ACCURACY_MEDIUM,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package no.naiv.tilfluktsrom.ui
|
package no.naiv.tilfluktsrom.ui
|
||||||
|
|
||||||
|
import android.view.HapticFeedbackConstants
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
|
@ -52,10 +53,18 @@ class ShelterListAdapter(
|
||||||
R.string.shelter_room_nr, item.shelter.romnr
|
R.string.shelter_room_nr, item.shelter.romnr
|
||||||
)
|
)
|
||||||
|
|
||||||
|
binding.root.contentDescription = ctx.getString(
|
||||||
|
R.string.content_desc_shelter_item,
|
||||||
|
item.shelter.adresse,
|
||||||
|
DistanceUtils.formatDistance(item.distanceMeters),
|
||||||
|
item.shelter.plasser
|
||||||
|
)
|
||||||
|
|
||||||
binding.root.isSelected = isSelected
|
binding.root.isSelected = isSelected
|
||||||
binding.root.alpha = if (isSelected) 1.0f else 0.7f
|
binding.root.alpha = if (isSelected) 1.0f else 0.7f
|
||||||
|
|
||||||
binding.root.setOnClickListener {
|
binding.root.setOnClickListener {
|
||||||
|
it.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)
|
||||||
val pos = adapterPosition
|
val pos = adapterPosition
|
||||||
if (pos != RecyclerView.NO_POSITION) {
|
if (pos != RecyclerView.NO_POSITION) {
|
||||||
selectPosition(pos)
|
selectPosition(pos)
|
||||||
|
|
|
||||||
|
|
@ -221,10 +221,11 @@ class ShelterWidgetProvider : AppWidgetProvider() {
|
||||||
views.setTextViewText(R.id.widgetTimestamp, formatTimestamp(context))
|
views.setTextViewText(R.id.widgetTimestamp, formatTimestamp(context))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Format current time as HH:mm, respecting the user's 12/24h preference. */
|
/** Format current time as "Updated HH:mm", respecting the user's 12/24h preference. */
|
||||||
private fun formatTimestamp(context: Context): String {
|
private fun formatTimestamp(context: Context): String {
|
||||||
val format = DateFormat.getTimeFormat(context)
|
val format = DateFormat.getTimeFormat(context)
|
||||||
return format.format(System.currentTimeMillis())
|
val timeStr = format.format(System.currentTimeMillis())
|
||||||
|
return context.getString(R.string.widget_updated_at, timeStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -114,5 +114,14 @@
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
android:textStyle="italic" />
|
android:textStyle="italic" />
|
||||||
|
|
||||||
|
<!-- Copyright notice -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="@string/app_copyright"
|
||||||
|
android:textColor="@color/text_secondary"
|
||||||
|
android:textSize="11sp" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@
|
||||||
<string name="widget_open_app">\u00c5pne appen for posisjon</string>
|
<string name="widget_open_app">\u00c5pne appen for posisjon</string>
|
||||||
<string name="widget_no_data">Ingen tilfluktsromdata</string>
|
<string name="widget_no_data">Ingen tilfluktsromdata</string>
|
||||||
<string name="widget_no_location">Trykk for \u00e5 oppdatere</string>
|
<string name="widget_no_location">Trykk for \u00e5 oppdatere</string>
|
||||||
|
<string name="widget_updated_at">Oppdatert %s</string>
|
||||||
|
|
||||||
<!-- Dataferskhet -->
|
<!-- Dataferskhet -->
|
||||||
<string name="freshness_fresh">Data er oppdatert</string>
|
<string name="freshness_fresh">Data er oppdatert</string>
|
||||||
|
|
@ -64,10 +65,12 @@
|
||||||
|
|
||||||
<!-- Tilgjengelighet -->
|
<!-- Tilgjengelighet -->
|
||||||
<string name="direction_arrow_description">Retning til tilfluktsrom, %s unna</string>
|
<string name="direction_arrow_description">Retning til tilfluktsrom, %s unna</string>
|
||||||
|
<string name="content_desc_shelter_item">%1$s, %2$s, %3$d plasser</string>
|
||||||
|
<string name="compass_accuracy_warning">Upresist kompass - %s</string>
|
||||||
|
|
||||||
<!-- Sivilforsvar -->
|
<!-- Sivilforsvar -->
|
||||||
<string name="action_civil_defense_info">Sivilforsvarsinformasjon</string>
|
<string name="action_civil_defense_info">Sivilforsvarsinformasjon</string>
|
||||||
<string name="civil_defense_title">Hva du skal gjøre når alarmen går</string>
|
<string name="civil_defense_title">Hva du skal gjøre hvis alarmen går</string>
|
||||||
<string name="civil_defense_step1_title">1. Viktig melding-signalet</string>
|
<string name="civil_defense_step1_title">1. Viktig melding-signalet</string>
|
||||||
<string name="civil_defense_step1_body">Tre serier med korte støt med ett minutts stillhet mellom hver serie. Dette betyr: søk informasjon umiddelbart. Slå på DAB-radio, TV, eller sjekk offisielle kilder på nett.</string>
|
<string name="civil_defense_step1_body">Tre serier med korte støt med ett minutts stillhet mellom hver serie. Dette betyr: søk informasjon umiddelbart. Slå på DAB-radio, TV, eller sjekk offisielle kilder på nett.</string>
|
||||||
<string name="civil_defense_step2_title">2. Flyalarm</string>
|
<string name="civil_defense_step2_title">2. Flyalarm</string>
|
||||||
|
|
@ -79,4 +82,7 @@
|
||||||
<string name="civil_defense_step5_title">5. Faren over</string>
|
<string name="civil_defense_step5_title">5. Faren over</string>
|
||||||
<string name="civil_defense_step5_body">Én sammenhengende tone på omtrent 30 sekunder. Faren eller angrepet er over. Fortsett å følge instruksjoner fra myndighetene.</string>
|
<string name="civil_defense_step5_body">Én sammenhengende tone på omtrent 30 sekunder. Faren eller angrepet er over. Fortsett å følge instruksjoner fra myndighetene.</string>
|
||||||
<string name="civil_defense_source">Kilde: DSB (Direktoratet for samfunnssikkerhet og beredskap)</string>
|
<string name="civil_defense_source">Kilde: DSB (Direktoratet for samfunnssikkerhet og beredskap)</string>
|
||||||
|
|
||||||
|
<!-- Opphavsrett -->
|
||||||
|
<string name="app_copyright">Opphavsrett © Ole-Morten Duesund</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@
|
||||||
<string name="widget_open_app">Opne appen for posisjon</string>
|
<string name="widget_open_app">Opne appen for posisjon</string>
|
||||||
<string name="widget_no_data">Ingen tilfluktsromdata</string>
|
<string name="widget_no_data">Ingen tilfluktsromdata</string>
|
||||||
<string name="widget_no_location">Trykk for \u00e5 oppdatere</string>
|
<string name="widget_no_location">Trykk for \u00e5 oppdatere</string>
|
||||||
|
<string name="widget_updated_at">Oppdatert %s</string>
|
||||||
|
|
||||||
<!-- Dataferskheit -->
|
<!-- Dataferskheit -->
|
||||||
<string name="freshness_fresh">Data er oppdatert</string>
|
<string name="freshness_fresh">Data er oppdatert</string>
|
||||||
|
|
@ -64,10 +65,12 @@
|
||||||
|
|
||||||
<!-- Tilgjenge -->
|
<!-- Tilgjenge -->
|
||||||
<string name="direction_arrow_description">Retning til tilfluktsrom, %s unna</string>
|
<string name="direction_arrow_description">Retning til tilfluktsrom, %s unna</string>
|
||||||
|
<string name="content_desc_shelter_item">%1$s, %2$s, %3$d plassar</string>
|
||||||
|
<string name="compass_accuracy_warning">Upresis kompass - %s</string>
|
||||||
|
|
||||||
<!-- Sivilforsvar -->
|
<!-- Sivilforsvar -->
|
||||||
<string name="action_civil_defense_info">Sivilforsvarsinformasjon</string>
|
<string name="action_civil_defense_info">Sivilforsvarsinformasjon</string>
|
||||||
<string name="civil_defense_title">Kva du skal gjere når alarmen går</string>
|
<string name="civil_defense_title">Kva du skal gjere om alarmen går</string>
|
||||||
<string name="civil_defense_step1_title">1. Viktig melding-signalet</string>
|
<string name="civil_defense_step1_title">1. Viktig melding-signalet</string>
|
||||||
<string name="civil_defense_step1_body">Tre seriar med korte støyt med eitt minutt stille mellom kvar serie. Dette tyder: søk informasjon med ein gong. Slå på DAB-radio, TV, eller sjekk offisielle kjelder på nett.</string>
|
<string name="civil_defense_step1_body">Tre seriar med korte støyt med eitt minutt stille mellom kvar serie. Dette tyder: søk informasjon med ein gong. Slå på DAB-radio, TV, eller sjekk offisielle kjelder på nett.</string>
|
||||||
<string name="civil_defense_step2_title">2. Flyalarm</string>
|
<string name="civil_defense_step2_title">2. Flyalarm</string>
|
||||||
|
|
@ -79,4 +82,7 @@
|
||||||
<string name="civil_defense_step5_title">5. Faren over</string>
|
<string name="civil_defense_step5_title">5. Faren over</string>
|
||||||
<string name="civil_defense_step5_body">Éin samanhengande tone på omtrent 30 sekund. Faren eller åtaket er over. Hald fram med å følgje instruksjonar frå styresmaktene.</string>
|
<string name="civil_defense_step5_body">Éin samanhengande tone på omtrent 30 sekund. Faren eller åtaket er over. Hald fram med å følgje instruksjonar frå styresmaktene.</string>
|
||||||
<string name="civil_defense_source">Kjelde: DSB (Direktoratet for samfunnstryggleik og beredskap)</string>
|
<string name="civil_defense_source">Kjelde: DSB (Direktoratet for samfunnstryggleik og beredskap)</string>
|
||||||
|
|
||||||
|
<!-- Opphavsrett -->
|
||||||
|
<string name="app_copyright">Opphavsrett © Ole-Morten Duesund</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
<color name="background">#1A1A2E</color>
|
<color name="background">#1A1A2E</color>
|
||||||
<color name="status_bar_bg">#16213E</color>
|
<color name="status_bar_bg">#16213E</color>
|
||||||
<color name="status_text">#B0BEC5</color>
|
<color name="status_text">#CFD8DC</color>
|
||||||
<color name="bottom_sheet_bg">#1A1A2E</color>
|
<color name="bottom_sheet_bg">#1A1A2E</color>
|
||||||
<color name="compass_bg">#0F0F23</color>
|
<color name="compass_bg">#0F0F23</color>
|
||||||
<color name="loading_bg">#CC000000</color>
|
<color name="loading_bg">#CC000000</color>
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@
|
||||||
<string name="widget_open_app">Open app for location</string>
|
<string name="widget_open_app">Open app for location</string>
|
||||||
<string name="widget_no_data">No shelter data</string>
|
<string name="widget_no_data">No shelter data</string>
|
||||||
<string name="widget_no_location">Tap to refresh</string>
|
<string name="widget_no_location">Tap to refresh</string>
|
||||||
|
<string name="widget_updated_at">Updated %s</string>
|
||||||
|
|
||||||
<!-- Data freshness -->
|
<!-- Data freshness -->
|
||||||
<string name="freshness_fresh">Data is up to date</string>
|
<string name="freshness_fresh">Data is up to date</string>
|
||||||
|
|
@ -64,10 +65,12 @@
|
||||||
|
|
||||||
<!-- Accessibility -->
|
<!-- Accessibility -->
|
||||||
<string name="direction_arrow_description">Direction to shelter, %s away</string>
|
<string name="direction_arrow_description">Direction to shelter, %s away</string>
|
||||||
|
<string name="content_desc_shelter_item">%1$s, %2$s, %3$d places</string>
|
||||||
|
<string name="compass_accuracy_warning">Low accuracy - %s</string>
|
||||||
|
|
||||||
<!-- Civil defense info -->
|
<!-- Civil defense info -->
|
||||||
<string name="action_civil_defense_info">Civil defense information</string>
|
<string name="action_civil_defense_info">Civil defense information</string>
|
||||||
<string name="civil_defense_title">What to do when the alarm sounds</string>
|
<string name="civil_defense_title">What to do if the alarm sounds</string>
|
||||||
<string name="civil_defense_step1_title">1. Important message signal</string>
|
<string name="civil_defense_step1_title">1. Important message signal</string>
|
||||||
<string name="civil_defense_step1_body">Three series of short blasts with one minute of silence between each series. This means: seek information immediately. Turn on DAB radio, TV, or check official sources online.</string>
|
<string name="civil_defense_step1_body">Three series of short blasts with one minute of silence between each series. This means: seek information immediately. Turn on DAB radio, TV, or check official sources online.</string>
|
||||||
<string name="civil_defense_step2_title">2. Air raid alarm</string>
|
<string name="civil_defense_step2_title">2. Air raid alarm</string>
|
||||||
|
|
@ -79,4 +82,7 @@
|
||||||
<string name="civil_defense_step5_title">5. All clear</string>
|
<string name="civil_defense_step5_title">5. All clear</string>
|
||||||
<string name="civil_defense_step5_body">One continuous tone lasting approximately 30 seconds. The danger or attack is over. Continue to follow instructions from authorities.</string>
|
<string name="civil_defense_step5_body">One continuous tone lasting approximately 30 seconds. The danger or attack is over. Continue to follow instructions from authorities.</string>
|
||||||
<string name="civil_defense_source">Source: DSB (Norwegian Directorate for Civil Protection)</string>
|
<string name="civil_defense_source">Source: DSB (Norwegian Directorate for Civil Protection)</string>
|
||||||
|
|
||||||
|
<!-- Copyright -->
|
||||||
|
<string name="app_copyright">Copyright © Ole-Morten Duesund</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
4
fastlane/metadata/android/en-US/changelogs/3.txt
Normal file
4
fastlane/metadata/android/en-US/changelogs/3.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
• Hybrid location: uses Play Services when available, falls back to standard Android GPS
|
||||||
|
• Data freshness indicator shows when shelter data was last updated
|
||||||
|
• Home screen widget showing nearest shelter with distance
|
||||||
|
• Bundled shelter data for instant offline use on first launch
|
||||||
3
fastlane/metadata/android/en-US/changelogs/4.txt
Normal file
3
fastlane/metadata/android/en-US/changelogs/4.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
• Share shelter location with others via any app
|
||||||
|
• Deep link support — open shared shelters directly in the app
|
||||||
|
• Tap any marker on the map to select and navigate to it
|
||||||
2
fastlane/metadata/android/en-US/changelogs/5.txt
Normal file
2
fastlane/metadata/android/en-US/changelogs/5.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
• Widget now updates automatically every 15 minutes via WorkManager
|
||||||
|
• Fixed widget not showing data without opening the app first
|
||||||
4
fastlane/metadata/android/en-US/changelogs/6.txt
Normal file
4
fastlane/metadata/android/en-US/changelogs/6.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
• Civil defense information: what to do if the alarm sounds (based on DSB guidelines)
|
||||||
|
• Improved accessibility: screen reader labels, better contrast, haptic feedback
|
||||||
|
• Widget shows "Updated 14:32" instead of bare timestamp
|
||||||
|
• Copyright notice added
|
||||||
6
fastlane/metadata/android/en-US/changelogs/7.txt
Normal file
6
fastlane/metadata/android/en-US/changelogs/7.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
• Accessibility: screen reader labels on shelter list, compass, and direction arrows
|
||||||
|
• Improved contrast on status bar text (WCAG AA)
|
||||||
|
• Haptic feedback on all buttons and list items
|
||||||
|
• Widget timestamp now shows "Updated 14:32"
|
||||||
|
• Softer civil defense dialog title
|
||||||
|
• Copyright notice added
|
||||||
15
fastlane/metadata/android/en-US/full_description.txt
Normal file
15
fastlane/metadata/android/en-US/full_description.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
Find the nearest public emergency shelter (tilfluktsrom) in Norway. Built for emergencies — works fully offline after first use.
|
||||||
|
|
||||||
|
Features:
|
||||||
|
• Shows the 3 nearest shelters with distance and capacity
|
||||||
|
• Compass navigation — direction arrow points to the selected shelter
|
||||||
|
• Offline map — map tiles are cached automatically for use without internet
|
||||||
|
• Select any shelter — tap any marker on the map to navigate there
|
||||||
|
• Home screen widget — shows nearest shelter at a glance
|
||||||
|
• Share shelters — send shelter location to others via any app
|
||||||
|
• Civil defense info — what to do if the alarm sounds
|
||||||
|
• Multilingual — English, Bokmål, and Nynorsk
|
||||||
|
|
||||||
|
The app uses open data from Geonorge (Norwegian Mapping Authority) covering approximately 556 public shelters across Norway.
|
||||||
|
|
||||||
|
Works on degoogled devices: the app uses Google Play Services for better location accuracy when available, but falls back to standard Android location APIs on devices without Play Services (LineageOS, GrapheneOS, /e/OS, etc.).
|
||||||
0
fastlane/metadata/android/en-US/images/.gitkeep
Normal file
0
fastlane/metadata/android/en-US/images/.gitkeep
Normal file
1
fastlane/metadata/android/en-US/short_description.txt
Normal file
1
fastlane/metadata/android/en-US/short_description.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Find the nearest public emergency shelter in Norway. Works offline.
|
||||||
1
fastlane/metadata/android/en-US/title.txt
Normal file
1
fastlane/metadata/android/en-US/title.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Tilfluktsrom
|
||||||
4
fastlane/metadata/android/nb-NO/changelogs/3.txt
Normal file
4
fastlane/metadata/android/nb-NO/changelogs/3.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
• Hybrid posisjon: bruker Play Services når tilgjengelig, faller tilbake til standard Android-GPS
|
||||||
|
• Dataferskhetsindikator viser når tilfluktsromdata sist ble oppdatert
|
||||||
|
• Hjemskjerm-widget som viser nærmeste tilfluktsrom med avstand
|
||||||
|
• Medfølgende tilfluktsromdata for umiddelbar frakoblet bruk ved første oppstart
|
||||||
3
fastlane/metadata/android/nb-NO/changelogs/4.txt
Normal file
3
fastlane/metadata/android/nb-NO/changelogs/4.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
• Del tilfluktsrom med andre via en hvilken som helst app
|
||||||
|
• Støtte for dyplenker — åpne delte tilfluktsrom direkte i appen
|
||||||
|
• Trykk på en markør i kartet for å velge og navigere dit
|
||||||
2
fastlane/metadata/android/nb-NO/changelogs/5.txt
Normal file
2
fastlane/metadata/android/nb-NO/changelogs/5.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
• Widget oppdateres nå automatisk hvert 15. minutt via WorkManager
|
||||||
|
• Fikset at widget ikke viste data uten å åpne appen først
|
||||||
4
fastlane/metadata/android/nb-NO/changelogs/6.txt
Normal file
4
fastlane/metadata/android/nb-NO/changelogs/6.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
• Sivilforsvarsinformasjon: hva du skal gjøre hvis alarmen går (basert på DSB-retningslinjer)
|
||||||
|
• Forbedret tilgjengelighet: skjermleseretiketter, bedre kontrast, haptisk tilbakemelding
|
||||||
|
• Widget viser «Oppdatert 14:32» i stedet for bare tidsstempel
|
||||||
|
• Opphavsrettsmelding lagt til
|
||||||
6
fastlane/metadata/android/nb-NO/changelogs/7.txt
Normal file
6
fastlane/metadata/android/nb-NO/changelogs/7.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
• Tilgjengelighet: skjermleseretiketter på tilfluktsromliste, kompass og retningspil
|
||||||
|
• Forbedret kontrast på statuslinjetekst (WCAG AA)
|
||||||
|
• Haptisk tilbakemelding på alle knapper og listeelement
|
||||||
|
• Widget-tidsstempel viser nå «Oppdatert 14:32»
|
||||||
|
• Mildere tittel på sivilforsvarsdialog
|
||||||
|
• Opphavsrettsmelding lagt til
|
||||||
15
fastlane/metadata/android/nb-NO/full_description.txt
Normal file
15
fastlane/metadata/android/nb-NO/full_description.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
Finn nærmeste offentlige tilfluktsrom i Norge. Bygd for nødsituasjoner — fungerer helt uten internett etter første gangs bruk.
|
||||||
|
|
||||||
|
Funksjoner:
|
||||||
|
• Viser de 3 nærmeste tilfluktsrommene med avstand og kapasitet
|
||||||
|
• Kompassnavigasjon — retningspil som peker mot valgt tilfluktsrom
|
||||||
|
• Frakoblet kart — kartfliser lagres automatisk for bruk uten nett
|
||||||
|
• Velg fritt — trykk på en markør i kartet for å navigere dit
|
||||||
|
• Hjemskjerm-widget — viser nærmeste tilfluktsrom med ett blikk
|
||||||
|
• Del tilfluktsrom — send posisjon til andre via en hvilken som helst app
|
||||||
|
• Sivilforsvarsinformasjon — hva du skal gjøre hvis alarmen går
|
||||||
|
• Flerspråklig — engelsk, bokmål og nynorsk
|
||||||
|
|
||||||
|
Appen bruker åpne data fra Geonorge (Kartverket) med ca. 556 offentlige tilfluktsrom i hele Norge.
|
||||||
|
|
||||||
|
Fungerer på de-Google-enheter: appen bruker Google Play Services for bedre posisjonsdata når det er tilgjengelig, men faller tilbake til standard Android-posisjons-API-er på enheter uten Play Services (LineageOS, GrapheneOS, /e/OS osv.).
|
||||||
0
fastlane/metadata/android/nb-NO/images/.gitkeep
Normal file
0
fastlane/metadata/android/nb-NO/images/.gitkeep
Normal file
1
fastlane/metadata/android/nb-NO/short_description.txt
Normal file
1
fastlane/metadata/android/nb-NO/short_description.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Finn nærmeste offentlige tilfluktsrom i Norge. Fungerer uten nett.
|
||||||
1
fastlane/metadata/android/nb-NO/title.txt
Normal file
1
fastlane/metadata/android/nb-NO/title.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Tilfluktsrom
|
||||||
4
fastlane/metadata/android/nn-NO/changelogs/3.txt
Normal file
4
fastlane/metadata/android/nn-NO/changelogs/3.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
• Hybrid posisjon: brukar Play Services når tilgjengeleg, fell tilbake til standard Android-GPS
|
||||||
|
• Dataferskheitsindikator viser når tilfluktsromdata sist vart oppdatert
|
||||||
|
• Heimeskjerm-widget som viser næraste tilfluktsrom med avstand
|
||||||
|
• Medfølgjande tilfluktsromdata for umiddelbar fråkopla bruk ved fyrste oppstart
|
||||||
3
fastlane/metadata/android/nn-NO/changelogs/4.txt
Normal file
3
fastlane/metadata/android/nn-NO/changelogs/4.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
• Del tilfluktsrom med andre via ei kva som helst app
|
||||||
|
• Støtte for djuplenker — opne delte tilfluktsrom direkte i appen
|
||||||
|
• Trykk på ein markør i kartet for å velje og navigere dit
|
||||||
2
fastlane/metadata/android/nn-NO/changelogs/5.txt
Normal file
2
fastlane/metadata/android/nn-NO/changelogs/5.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
• Widget oppdaterast no automatisk kvart 15. minutt via WorkManager
|
||||||
|
• Fiksa at widget ikkje viste data utan å opne appen fyrst
|
||||||
4
fastlane/metadata/android/nn-NO/changelogs/6.txt
Normal file
4
fastlane/metadata/android/nn-NO/changelogs/6.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
• Sivilforsvarsinformasjon: kva du skal gjere om alarmen går (basert på DSB-retningslinjer)
|
||||||
|
• Forbetra tilgjenge: skjermlesar-etiketter, betre kontrast, haptisk tilbakemelding
|
||||||
|
• Widget viser «Oppdatert 14:32» i staden for berre tidsstempel
|
||||||
|
• Opphavsrettsmelding lagt til
|
||||||
6
fastlane/metadata/android/nn-NO/changelogs/7.txt
Normal file
6
fastlane/metadata/android/nn-NO/changelogs/7.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
• Tilgjenge: skjermlesar-etiketter på tilfluktsromliste, kompass og retningspil
|
||||||
|
• Forbetra kontrast på statuslinjetekst (WCAG AA)
|
||||||
|
• Haptisk tilbakemelding på alle knappar og listeelement
|
||||||
|
• Widget-tidsstempel viser no «Oppdatert 14:32»
|
||||||
|
• Mildare tittel på sivilforsvarsdialog
|
||||||
|
• Opphavsrettsmelding lagt til
|
||||||
15
fastlane/metadata/android/nn-NO/full_description.txt
Normal file
15
fastlane/metadata/android/nn-NO/full_description.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
Finn næraste offentlege tilfluktsrom i Noreg. Bygd for nødsituasjonar — fungerer heilt utan internett etter fyrste gongs bruk.
|
||||||
|
|
||||||
|
Funksjonar:
|
||||||
|
• Viser dei 3 næraste tilfluktsromma med avstand og kapasitet
|
||||||
|
• Kompassnavigasjon — retningspil som peikar mot valt tilfluktsrom
|
||||||
|
• Fråkopla kart — kartfliser lagrast automatisk for bruk utan nett
|
||||||
|
• Vel fritt — trykk på ein markør i kartet for å navigere dit
|
||||||
|
• Heimeskjerm-widget — viser næraste tilfluktsrom med eitt blikk
|
||||||
|
• Del tilfluktsrom — send posisjon til andre via ei kva som helst app
|
||||||
|
• Sivilforsvarsinformasjon — kva du skal gjere om alarmen går
|
||||||
|
• Fleirspråkleg — engelsk, bokmål og nynorsk
|
||||||
|
|
||||||
|
Appen brukar opne data frå Geonorge (Kartverket) med ca. 556 offentlege tilfluktsrom i heile Noreg.
|
||||||
|
|
||||||
|
Fungerer på de-Google-einingar: appen brukar Google Play Services for betre posisjonsdata når det er tilgjengeleg, men fell tilbake til standard Android-posisjons-API-ar på einingar utan Play Services (LineageOS, GrapheneOS, /e/OS osb.).
|
||||||
0
fastlane/metadata/android/nn-NO/images/.gitkeep
Normal file
0
fastlane/metadata/android/nn-NO/images/.gitkeep
Normal file
1
fastlane/metadata/android/nn-NO/short_description.txt
Normal file
1
fastlane/metadata/android/nn-NO/short_description.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Finn næraste offentlege tilfluktsrom i Noreg. Fungerer utan nett.
|
||||||
1
fastlane/metadata/android/nn-NO/title.txt
Normal file
1
fastlane/metadata/android/nn-NO/title.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Tilfluktsrom
|
||||||
|
|
@ -43,7 +43,7 @@
|
||||||
<!-- Bottom sheet with shelter info -->
|
<!-- Bottom sheet with shelter info -->
|
||||||
<div id="bottom-sheet">
|
<div id="bottom-sheet">
|
||||||
<div id="selected-shelter">
|
<div id="selected-shelter">
|
||||||
<canvas id="mini-arrow" width="96" height="96"></canvas>
|
<canvas id="mini-arrow" width="96" height="96" role="img" aria-label="Direction to shelter"></canvas>
|
||||||
<div id="selected-shelter-info">
|
<div id="selected-shelter-info">
|
||||||
<div id="selected-shelter-address"></div>
|
<div id="selected-shelter-address"></div>
|
||||||
<div id="selected-shelter-details"></div>
|
<div id="selected-shelter-details"></div>
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ function setupButtons(): void {
|
||||||
// Toggle map/compass
|
// Toggle map/compass
|
||||||
const toggleFab = document.getElementById('toggle-fab')!;
|
const toggleFab = document.getElementById('toggle-fab')!;
|
||||||
toggleFab.addEventListener('click', async () => {
|
toggleFab.addEventListener('click', async () => {
|
||||||
|
navigator.vibrate?.(10);
|
||||||
isCompassMode = !isCompassMode;
|
isCompassMode = !isCompassMode;
|
||||||
|
|
||||||
const mapContainer = document.getElementById('map-container')!;
|
const mapContainer = document.getElementById('map-container')!;
|
||||||
|
|
@ -112,6 +113,7 @@ function setupButtons(): void {
|
||||||
const cacheRetryBtn = document.getElementById('cache-retry-btn')!;
|
const cacheRetryBtn = document.getElementById('cache-retry-btn')!;
|
||||||
cacheRetryBtn.textContent = t('action_cache_now');
|
cacheRetryBtn.textContent = t('action_cache_now');
|
||||||
cacheRetryBtn.addEventListener('click', () => {
|
cacheRetryBtn.addEventListener('click', () => {
|
||||||
|
navigator.vibrate?.(10);
|
||||||
if (currentLocation && navigator.onLine) {
|
if (currentLocation && navigator.onLine) {
|
||||||
startCaching(currentLocation.latitude, currentLocation.longitude);
|
startCaching(currentLocation.latitude, currentLocation.longitude);
|
||||||
}
|
}
|
||||||
|
|
@ -120,6 +122,7 @@ function setupButtons(): void {
|
||||||
// Reset view button
|
// Reset view button
|
||||||
const resetBtn = document.getElementById('reset-view-btn')!;
|
const resetBtn = document.getElementById('reset-view-btn')!;
|
||||||
resetBtn.addEventListener('click', () => {
|
resetBtn.addEventListener('click', () => {
|
||||||
|
navigator.vibrate?.(10);
|
||||||
const selected = nearestShelters[selectedShelterIndex] ?? null;
|
const selected = nearestShelters[selectedShelterIndex] ?? null;
|
||||||
mapView.resetView(selected, currentLocation);
|
mapView.resetView(selected, currentLocation);
|
||||||
resetBtn.classList.remove('visible');
|
resetBtn.classList.remove('visible');
|
||||||
|
|
@ -256,6 +259,8 @@ function updateSelectedShelter(isUserAction: boolean): void {
|
||||||
].join(' \u00B7 ');
|
].join(' \u00B7 ');
|
||||||
|
|
||||||
// Update mini arrow
|
// Update mini arrow
|
||||||
|
const miniArrow = document.getElementById('mini-arrow')!;
|
||||||
|
miniArrow.setAttribute('aria-label', t('direction_arrow_description', dist));
|
||||||
updateMiniArrow(selected.bearingDegrees - deviceHeading);
|
updateMiniArrow(selected.bearingDegrees - deviceHeading);
|
||||||
|
|
||||||
// Update compass view
|
// Update compass view
|
||||||
|
|
|
||||||
|
|
@ -46,4 +46,7 @@ export const en: Record<string, string> = {
|
||||||
'No cached data available. Connect to the internet to download shelter data.',
|
'No cached data available. Connect to the internet to download shelter data.',
|
||||||
update_success: 'Shelter data updated',
|
update_success: 'Shelter data updated',
|
||||||
update_failed: 'Update failed \u2014 using cached data',
|
update_failed: 'Update failed \u2014 using cached data',
|
||||||
|
|
||||||
|
// Accessibility
|
||||||
|
direction_arrow_description: 'Direction to shelter, %s away',
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -41,4 +41,7 @@ export const nb: Record<string, string> = {
|
||||||
'Ingen lagrede data tilgjengelig. Koble til internett for \u00e5 laste ned tilfluktsromdata.',
|
'Ingen lagrede data tilgjengelig. Koble til internett for \u00e5 laste ned tilfluktsromdata.',
|
||||||
update_success: 'Tilfluktsromdata oppdatert',
|
update_success: 'Tilfluktsromdata oppdatert',
|
||||||
update_failed: 'Oppdatering mislyktes \u2014 bruker lagrede data',
|
update_failed: 'Oppdatering mislyktes \u2014 bruker lagrede data',
|
||||||
|
|
||||||
|
// Tilgjengelighet
|
||||||
|
direction_arrow_description: 'Retning til tilfluktsrom, %s unna',
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -41,4 +41,7 @@ export const nn: Record<string, string> = {
|
||||||
'Ingen lagra data tilgjengeleg. Kopla til internett for \u00e5 laste ned tilfluktsromdata.',
|
'Ingen lagra data tilgjengeleg. Kopla til internett for \u00e5 laste ned tilfluktsromdata.',
|
||||||
update_success: 'Tilfluktsromdata oppdatert',
|
update_success: 'Tilfluktsromdata oppdatert',
|
||||||
update_failed: 'Oppdatering mislukkast \u2014 brukar lagra data',
|
update_failed: 'Oppdatering mislukkast \u2014 brukar lagra data',
|
||||||
|
|
||||||
|
// Tilgjenge
|
||||||
|
direction_arrow_description: 'Retning til tilfluktsrom, %s unna',
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ html, body {
|
||||||
|
|
||||||
#status-text {
|
#status-text {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
color: #B0BEC5;
|
color: #CFD8DC;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
@ -50,7 +50,7 @@ html, body {
|
||||||
#refresh-btn {
|
#refresh-btn {
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
color: #B0BEC5;
|
color: #CFD8DC;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
|
|
@ -142,8 +142,8 @@ html, body {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: #16213E;
|
background: #16213E;
|
||||||
border: 2px solid #B0BEC5;
|
border: 2px solid #CFD8DC;
|
||||||
color: #B0BEC5;
|
color: #CFD8DC;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4);
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4);
|
||||||
|
|
@ -356,7 +356,7 @@ html, body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.leaflet-control-attribution a {
|
.leaflet-control-attribution a {
|
||||||
color: #B0BEC5 !important;
|
color: #CFD8DC !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.leaflet-popup-content-wrapper {
|
.leaflet-popup-content-wrapper {
|
||||||
|
|
@ -370,5 +370,5 @@ html, body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.leaflet-popup-close-button {
|
.leaflet-popup-close-button {
|
||||||
color: #B0BEC5 !important;
|
color: #CFD8DC !important;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ export function updateList(
|
||||||
item.appendChild(addressSpan);
|
item.appendChild(addressSpan);
|
||||||
item.appendChild(detailsSpan);
|
item.appendChild(detailsSpan);
|
||||||
item.addEventListener('click', () => {
|
item.addEventListener('click', () => {
|
||||||
|
navigator.vibrate?.(10);
|
||||||
onSelect?.(i);
|
onSelect?.(i);
|
||||||
});
|
});
|
||||||
container!.appendChild(item);
|
container!.appendChild(item);
|
||||||
|
|
|
||||||
|
|
@ -11,5 +11,8 @@ export function setStatus(text: string): void {
|
||||||
/** Set the refresh button click handler. */
|
/** Set the refresh button click handler. */
|
||||||
export function onRefreshClick(handler: () => void): void {
|
export function onRefreshClick(handler: () => void): void {
|
||||||
const btn = document.getElementById('refresh-btn');
|
const btn = document.getElementById('refresh-btn');
|
||||||
if (btn) btn.addEventListener('click', handler);
|
if (btn) btn.addEventListener('click', () => {
|
||||||
|
navigator.vibrate?.(10);
|
||||||
|
handler();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
versionMajor=1
|
versionMajor=1
|
||||||
versionMinor=4
|
versionMinor=4
|
||||||
versionPatch=0
|
versionPatch=1
|
||||||
versionCode=6
|
versionCode=7
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue