Vis dyplenket tilfluktsrom i lista, selv utenfor topp-3 (hybrid)
Når en dyplenke (eller markørtap) velger et tilfluktsrom som ikke er blant de N nærmeste, blir det nå appendet til bunnpanelets liste med et tydelig "Valgt – utenfor nærområdet"-badge, og lista scroller til den valgte raden. Hvis valget er innenfor topp-N, scrollelementet fortsatt synes — løser begge symptomene som rapporten pekte på. Endringer: - Ny ShelterListItem(swd, isOutsideNearest)-wrapper i adapteren - ShelterListAdapter: viser badge + a11y-suffiks når isOutsideNearest=true - item_shelter.xml: badge-TextView (orange bakgrunn, hvit tekst, gone som default) - MainActivity: rebuildShelterList()-helper bygger top-N + maybe-appended, smoothScrollToPosition(selectedIdx) sikrer synlig markering - Strings i en/nb/nn Forgejo: #13
This commit is contained in:
parent
b31537df2c
commit
1fb9f14ad4
7 changed files with 109 additions and 33 deletions
|
|
@ -44,6 +44,7 @@ import no.naiv.tilfluktsrom.location.ShelterFinder
|
|||
import no.naiv.tilfluktsrom.location.ShelterWithDistance
|
||||
import no.naiv.tilfluktsrom.ui.CivilDefenseInfoDialog
|
||||
import no.naiv.tilfluktsrom.ui.ShelterListAdapter
|
||||
import no.naiv.tilfluktsrom.ui.ShelterListItem
|
||||
import no.naiv.tilfluktsrom.util.DistanceUtils
|
||||
import org.osmdroid.util.GeoPoint
|
||||
import org.osmdroid.views.CustomZoomButtonsController
|
||||
|
|
@ -486,25 +487,60 @@ class MainActivity : AppCompatActivity(), SensorEventListener {
|
|||
allShelters, location.latitude, location.longitude, NEAREST_COUNT
|
||||
)
|
||||
|
||||
// Highlight which nearest-list item matches the current selection
|
||||
val selectedIdx = if (selectedShelter != null) {
|
||||
nearestShelters.indexOfFirst { it.shelter.lokalId == selectedShelter!!.shelter.lokalId }
|
||||
} else -1
|
||||
|
||||
shelterAdapter.submitList(nearestShelters)
|
||||
shelterAdapter.selectPosition(selectedIdx)
|
||||
|
||||
if (userSelectedShelter && selectedShelter != null) {
|
||||
// Recalculate distance/bearing for the user's picked shelter
|
||||
refreshSelectedShelterDistance(location)
|
||||
rebuildShelterList()
|
||||
updateSelectedShelterUI()
|
||||
} else if (nearestShelters.isNotEmpty()) {
|
||||
// Auto-select nearest; selectShelter handles list rebuild + UI
|
||||
selectShelter(nearestShelters[0])
|
||||
} else {
|
||||
// Auto-select nearest
|
||||
if (nearestShelters.isNotEmpty()) {
|
||||
selectShelter(nearestShelters[0])
|
||||
}
|
||||
rebuildShelterList()
|
||||
updateSelectedShelterUI()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild the bottom-sheet list from the current nearest set + selection.
|
||||
*
|
||||
* Hybrid behaviour for Forgejo #13: when a shelter has been explicitly
|
||||
* selected (deep link, marker tap, ...) and is *not* among the N nearest,
|
||||
* append it to the list with an "outside nearest" badge so the user can
|
||||
* see what they selected. The list also auto-scrolls to the selected
|
||||
* row, so a manually-picked nearby entry comes into view too.
|
||||
*/
|
||||
private fun rebuildShelterList() {
|
||||
val items = nearestShelters
|
||||
.map { ShelterListItem(it, isOutsideNearest = false) }
|
||||
.toMutableList()
|
||||
|
||||
val selected = selectedShelter
|
||||
val isSelectedAmongNearest = selected != null &&
|
||||
nearestShelters.any { it.shelter.lokalId == selected.shelter.lokalId }
|
||||
if (selected != null && !isSelectedAmongNearest) {
|
||||
// Only flag as "outside nearest" when there *is* a nearest list to
|
||||
// contrast with - otherwise the selection is just the only entry.
|
||||
items.add(
|
||||
ShelterListItem(
|
||||
selected,
|
||||
isOutsideNearest = nearestShelters.isNotEmpty()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
updateSelectedShelterUI()
|
||||
shelterAdapter.submitList(items)
|
||||
|
||||
val selectedIdx = if (selected != null) {
|
||||
items.indexOfFirst { it.swd.shelter.lokalId == selected.shelter.lokalId }
|
||||
} else -1
|
||||
shelterAdapter.selectPosition(selectedIdx)
|
||||
|
||||
if (selectedIdx >= 0) {
|
||||
binding.shelterList.post {
|
||||
binding.shelterList.smoothScrollToPosition(selectedIdx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -515,10 +551,7 @@ class MainActivity : AppCompatActivity(), SensorEventListener {
|
|||
selectedShelter = swd
|
||||
currentLocation?.let { refreshSelectedShelterDistance(it) }
|
||||
|
||||
// Update list highlight
|
||||
val idx = nearestShelters.indexOfFirst { it.shelter.lokalId == swd.shelter.lokalId }
|
||||
shelterAdapter.selectPosition(idx)
|
||||
|
||||
rebuildShelterList()
|
||||
updateSelectedShelterUI()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package no.naiv.tilfluktsrom.ui
|
|||
|
||||
import android.view.HapticFeedbackConstants
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
|
|
@ -11,12 +12,23 @@ import no.naiv.tilfluktsrom.databinding.ItemShelterBinding
|
|||
import no.naiv.tilfluktsrom.location.ShelterWithDistance
|
||||
import no.naiv.tilfluktsrom.util.DistanceUtils
|
||||
|
||||
/**
|
||||
* One row in the bottom-sheet list. The list normally holds the N nearest
|
||||
* shelters to the user, but a deep-linked / explicitly-selected shelter that
|
||||
* is *not* among them is appended with isOutsideNearest=true so the user can
|
||||
* see what they picked. See Forgejo #13 / beads tilfluktsrom-9sf.
|
||||
*/
|
||||
data class ShelterListItem(
|
||||
val swd: ShelterWithDistance,
|
||||
val isOutsideNearest: Boolean
|
||||
)
|
||||
|
||||
/**
|
||||
* Adapter for the list of nearest shelters shown in the bottom sheet.
|
||||
*/
|
||||
class ShelterListAdapter(
|
||||
private val onShelterSelected: (ShelterWithDistance) -> Unit
|
||||
) : ListAdapter<ShelterWithDistance, ShelterListAdapter.ViewHolder>(DIFF_CALLBACK) {
|
||||
) : ListAdapter<ShelterListItem, ShelterListAdapter.ViewHolder>(DIFF_CALLBACK) {
|
||||
|
||||
private var selectedPosition = 0
|
||||
|
||||
|
|
@ -42,23 +54,34 @@ class ShelterListAdapter(
|
|||
private val binding: ItemShelterBinding
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(item: ShelterWithDistance, isSelected: Boolean) {
|
||||
fun bind(item: ShelterListItem, isSelected: Boolean) {
|
||||
val ctx = binding.root.context
|
||||
binding.shelterAddress.text = item.shelter.adresse
|
||||
binding.shelterDistance.text = DistanceUtils.formatDistance(item.distanceMeters)
|
||||
val swd = item.swd
|
||||
binding.shelterAddress.text = swd.shelter.adresse
|
||||
binding.shelterDistance.text = DistanceUtils.formatDistance(swd.distanceMeters)
|
||||
binding.shelterCapacity.text = ctx.getString(
|
||||
R.string.shelter_capacity, item.shelter.plasser
|
||||
R.string.shelter_capacity, swd.shelter.plasser
|
||||
)
|
||||
binding.shelterRoomNr.text = ctx.getString(
|
||||
R.string.shelter_room_nr, item.shelter.romnr
|
||||
R.string.shelter_room_nr, swd.shelter.romnr
|
||||
)
|
||||
|
||||
binding.root.contentDescription = ctx.getString(
|
||||
binding.outsideNearestBadge.visibility =
|
||||
if (item.isOutsideNearest) View.VISIBLE else View.GONE
|
||||
|
||||
// Build accessible description; suffix the badge text so screen-
|
||||
// reader users learn the same context that sighted users see.
|
||||
val baseDesc = ctx.getString(
|
||||
R.string.content_desc_shelter_item,
|
||||
item.shelter.adresse,
|
||||
DistanceUtils.formatDistance(item.distanceMeters),
|
||||
item.shelter.plasser
|
||||
swd.shelter.adresse,
|
||||
DistanceUtils.formatDistance(swd.distanceMeters),
|
||||
swd.shelter.plasser
|
||||
)
|
||||
binding.root.contentDescription = if (item.isOutsideNearest) {
|
||||
ctx.getString(R.string.shelter_outside_nearest_badge) + ". " + baseDesc
|
||||
} else {
|
||||
baseDesc
|
||||
}
|
||||
|
||||
binding.root.isSelected = isSelected
|
||||
binding.root.alpha = if (isSelected) 1.0f else 0.7f
|
||||
|
|
@ -68,18 +91,18 @@ class ShelterListAdapter(
|
|||
val pos = adapterPosition
|
||||
if (pos != RecyclerView.NO_POSITION) {
|
||||
selectPosition(pos)
|
||||
onShelterSelected(getItem(pos))
|
||||
onShelterSelected(getItem(pos).swd)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<ShelterWithDistance>() {
|
||||
override fun areItemsTheSame(a: ShelterWithDistance, b: ShelterWithDistance) =
|
||||
a.shelter.lokalId == b.shelter.lokalId
|
||||
private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<ShelterListItem>() {
|
||||
override fun areItemsTheSame(a: ShelterListItem, b: ShelterListItem) =
|
||||
a.swd.shelter.lokalId == b.swd.shelter.lokalId
|
||||
|
||||
override fun areContentsTheSame(a: ShelterWithDistance, b: ShelterWithDistance) =
|
||||
override fun areContentsTheSame(a: ShelterListItem, b: ShelterListItem) =
|
||||
a == b
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,21 @@
|
|||
android:paddingHorizontal="12dp"
|
||||
android:paddingVertical="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/outsideNearestBadge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:background="@color/shelter_primary"
|
||||
android:paddingHorizontal="8dp"
|
||||
android:paddingVertical="2dp"
|
||||
android:text="@string/shelter_outside_nearest_badge"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="11sp"
|
||||
android:textStyle="bold"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/shelterAddress"
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@
|
|||
<!-- Tilgjengelighet -->
|
||||
<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="shelter_outside_nearest_badge">Valgt – utenfor nærområdet</string>
|
||||
<string name="compass_accuracy_warning">Upresist kompass - %s</string>
|
||||
<string name="a11y_map">Tilfluktsromkart</string>
|
||||
<string name="a11y_compass">Kompassnavigasjon</string>
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@
|
|||
<!-- Tilgjenge -->
|
||||
<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="shelter_outside_nearest_badge">Vald – utanfor nærområdet</string>
|
||||
<string name="compass_accuracy_warning">Upresis kompass - %s</string>
|
||||
<string name="a11y_map">Tilfluktsromkart</string>
|
||||
<string name="a11y_compass">Kompassnavigasjon</string>
|
||||
|
|
|
|||
|
|
@ -62,6 +62,9 @@
|
|||
<!-- Accessibility -->
|
||||
<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>
|
||||
<!-- Badge shown on a list row that is not among the nearest shelters but
|
||||
was explicitly selected (e.g. via a deep link). Forgejo #13. -->
|
||||
<string name="shelter_outside_nearest_badge">Selected (outside nearest)</string>
|
||||
<string name="compass_accuracy_warning">Low accuracy - %s</string>
|
||||
<string name="a11y_map">Shelter map</string>
|
||||
<string name="a11y_compass">Compass navigation</string>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue