Legg til deling av tilfluktsrom og deep link-støtte (v1.3.0)

Del tilfluktsrom via SMS/meldingsapper med adresse, kapasitet,
koordinatar og geo:-URI. Støttar tilfluktsrom://shelter/{id}
deep link for direkte navigering til eit tilfluktsrom.

Closes #3

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Ole-Morten Duesund 2026-03-08 22:23:28 +01:00
commit a813edc0c3
8 changed files with 127 additions and 2 deletions

View file

@ -23,11 +23,20 @@
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:windowSoftInputMode="adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="tilfluktsrom"
android:host="shelter" />
</intent-filter>
</activity>
<receiver

View file

@ -74,6 +74,9 @@ class MainActivity : AppCompatActivity(), SensorEventListener {
// Whether a compass sensor is available on this device
private var hasCompassSensor = false
// Deep link: shelter ID to select once data is loaded
private var pendingDeepLinkShelterId: String? = null
// The currently selected shelter — can be any shelter, not just one from nearestShelters
private var selectedShelter: ShelterWithDistance? = null
// When true, location updates won't auto-select the nearest shelter
@ -127,6 +130,33 @@ class MainActivity : AppCompatActivity(), SensorEventListener {
setupShelterList()
setupButtons()
loadData()
handleDeepLinkIntent(intent)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
handleDeepLinkIntent(intent)
}
/**
* Handle tilfluktsrom://shelter/{lokalId} deep link.
* If shelters are already loaded, select immediately; otherwise store as pending.
*/
private fun handleDeepLinkIntent(intent: Intent?) {
val uri = intent?.data ?: return
if (uri.scheme != "tilfluktsrom" || uri.host != "shelter") return
val lokalId = uri.lastPathSegment ?: return
// Clear intent data so config changes don't re-trigger
intent.data = null
val shelter = allShelters.find { it.lokalId == lokalId }
if (shelter != null) {
selectShelterByData(shelter)
} else {
pendingDeepLinkShelterId = lokalId
}
}
private fun setupMap() {
@ -193,6 +223,10 @@ class MainActivity : AppCompatActivity(), SensorEventListener {
forceRefresh()
}
binding.shareButton.setOnClickListener {
shareShelter()
}
binding.cacheRetryButton.setOnClickListener {
val loc = currentLocation
if (loc == null) {
@ -240,6 +274,17 @@ class MainActivity : AppCompatActivity(), SensorEventListener {
binding.statusText.text = getString(R.string.status_shelters_loaded, shelters.size)
updateFreshnessIndicator()
updateShelterMarkers()
// Process pending deep links now that shelter data is available
pendingDeepLinkShelterId?.let { id ->
pendingDeepLinkShelterId = null
val shelter = shelters.find { it.lokalId == id }
if (shelter != null) {
selectShelterByData(shelter)
} else {
Toast.makeText(this@MainActivity, R.string.error_shelter_not_found, Toast.LENGTH_SHORT).show()
}
}
currentLocation?.let { updateNearestShelters(it) }
}
} catch (e: CancellationException) {
@ -598,6 +643,35 @@ class MainActivity : AppCompatActivity(), SensorEventListener {
}
}
/**
* Share the currently selected shelter via ACTION_SEND.
* Includes address, capacity, geo: URI (for non-app recipients),
* and a tilfluktsrom:// deep link (for app users).
*/
private fun shareShelter() {
val selected = selectedShelter
if (selected == null) {
Toast.makeText(this, R.string.share_no_shelter, Toast.LENGTH_SHORT).show()
return
}
val shelter = selected.shelter
val body = getString(
R.string.share_body,
shelter.adresse,
shelter.plasser,
shelter.latitude,
shelter.longitude
)
val shareIntent = Intent(Intent.ACTION_SEND).apply {
type = "text/plain"
putExtra(Intent.EXTRA_SUBJECT, getString(R.string.share_subject))
putExtra(Intent.EXTRA_TEXT, body)
}
startActivity(Intent.createChooser(shareIntent, getString(R.string.action_share)))
}
/** Update the freshness indicator below the status bar with color-coded age. */
private fun updateFreshnessIndicator() {
val lastUpdate = repository.getLastUpdateMs()

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Material Design share icon -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFF"
android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z" />
</vector>

View file

@ -211,6 +211,16 @@
android:textSize="13sp"
tools:text="1.2 km - 400 plasser - Rom 776" />
</LinearLayout>
<ImageButton
android:id="@+id/shareButton"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginStart="8dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/action_share"
android:src="@drawable/ic_share"
app:tint="@color/text_secondary" />
</LinearLayout>
<!-- Nearest shelters list -->

View file

@ -30,6 +30,7 @@
<string name="action_cache_ok">Lagre kart</string>
<string name="action_cache_now">Lagre nå</string>
<string name="action_reset_navigation">Tilbakestill navigasjonsvisning</string>
<string name="action_share">Del tilfluktsrom</string>
<string name="warning_no_map_cache">Ingen frakoblet kart lagret. Kartet krever internett.</string>
<!-- Tillatelser -->
@ -41,6 +42,7 @@
<string name="error_download_failed">Kunne ikke laste ned tilfluktsromdata. Sjekk internettforbindelsen.</string>
<string name="error_no_data_offline">Ingen lagrede data tilgjengelig. Koble til internett for å laste ned tilfluktsromdata.</string>
<string name="error_no_compass">Kompass er ikke tilgjengelig på denne enheten</string>
<string name="error_shelter_not_found">Fant ikke tilfluktsrommet</string>
<string name="update_success">Tilfluktsromdata oppdatert</string>
<string name="update_failed">Oppdatering mislyktes — bruker lagrede data</string>
@ -55,6 +57,11 @@
<string name="freshness_week">Data er %d dager gammel</string>
<string name="freshness_old">Data er utdatert</string>
<!-- Deling -->
<string name="share_subject">Tilfluktsrom</string>
<string name="share_body">Tilfluktsrom: %1$s\n%2$d plasser\n%3$.6f, %4$.6f\ngeo:%3$.6f,%4$.6f</string>
<string name="share_no_shelter">Ingen tilfluktsrom valgt</string>
<!-- Tilgjengelighet -->
<string name="direction_arrow_description">Retning til tilfluktsrom, %s unna</string>
</resources>

View file

@ -30,6 +30,7 @@
<string name="action_cache_ok">Lagre kart</string>
<string name="action_cache_now">Lagre no</string>
<string name="action_reset_navigation">Tilbakestill navigasjonsvising</string>
<string name="action_share">Del tilfluktsrom</string>
<string name="warning_no_map_cache">Ingen fråkopla kart lagra. Kartet krev internett.</string>
<!-- Løyve -->
@ -41,6 +42,7 @@
<string name="error_download_failed">Kunne ikkje laste ned tilfluktsromdata. Sjekk internettilkoplinga.</string>
<string name="error_no_data_offline">Ingen lagra data tilgjengeleg. Kopla til internett for å laste ned tilfluktsromdata.</string>
<string name="error_no_compass">Kompass er ikkje tilgjengeleg på denne eininga</string>
<string name="error_shelter_not_found">Fann ikkje tilfluktsrommet</string>
<string name="update_success">Tilfluktsromdata oppdatert</string>
<string name="update_failed">Oppdatering mislukkast — brukar lagra data</string>
@ -55,6 +57,11 @@
<string name="freshness_week">Data er %d dagar gammal</string>
<string name="freshness_old">Data er utdatert</string>
<!-- Deling -->
<string name="share_subject">Tilfluktsrom</string>
<string name="share_body">Tilfluktsrom: %1$s\n%2$d plassar\n%3$.6f, %4$.6f\ngeo:%3$.6f,%4$.6f</string>
<string name="share_no_shelter">Ingen tilfluktsrom valt</string>
<!-- Tilgjenge -->
<string name="direction_arrow_description">Retning til tilfluktsrom, %s unna</string>
</resources>

View file

@ -30,6 +30,7 @@
<string name="action_cache_ok">Cache map</string>
<string name="action_cache_now">Cache now</string>
<string name="action_reset_navigation">Reset navigation view</string>
<string name="action_share">Share shelter</string>
<string name="warning_no_map_cache">No offline map cached. Map requires internet.</string>
<!-- Permissions -->
@ -41,6 +42,7 @@
<string name="error_download_failed">Could not download shelter data. Check your internet connection.</string>
<string name="error_no_data_offline">No cached data available. Connect to the internet to download shelter data.</string>
<string name="error_no_compass">Compass not available on this device</string>
<string name="error_shelter_not_found">Shelter not found</string>
<string name="update_success">Shelter data updated</string>
<string name="update_failed">Update failed — using cached data</string>
@ -55,6 +57,11 @@
<string name="freshness_week">Data is %d days old</string>
<string name="freshness_old">Data is outdated</string>
<!-- Sharing -->
<string name="share_subject">Emergency shelter</string>
<string name="share_body">Shelter: %1$s\n%2$d places\n%3$.6f, %4$.6f\ngeo:%3$.6f,%4$.6f</string>
<string name="share_no_shelter">No shelter selected</string>
<!-- Accessibility -->
<string name="direction_arrow_description">Direction to shelter, %s away</string>
</resources>

View file

@ -1,4 +1,4 @@
versionMajor=1
versionMinor=2
versionMinor=3
versionPatch=0
versionCode=3
versionCode=4