Skip to content

Commit

Permalink
Extract cell signal list item mappers
Browse files Browse the repository at this point in the history
Signed-off-by: Kyle Corry <kylecorry31@gmail.com>
  • Loading branch information
kylecorry31 committed Feb 15, 2025
1 parent 2a90cbe commit fd0f38f
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 94 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import com.kylecorry.andromeda.sense.location.IGPS
import com.kylecorry.andromeda.signal.ICellSignalSensor
import com.kylecorry.luna.coroutines.CoroutineQueueRunner
import com.kylecorry.sol.units.Coordinate
import com.kylecorry.trail_sense.shared.hooks.HookTriggers
import com.kylecorry.trail_sense.shared.sensors.SensorService
import java.time.Duration

Expand All @@ -16,12 +15,6 @@ fun ReactiveComponent.useCoroutineQueue(): CoroutineQueueRunner {
}
}

fun ReactiveComponent.useTriggers(): HookTriggers {
return useMemo {
HookTriggers()
}
}

// Sensors

fun ReactiveComponent.useGPSSensor(frequency: Duration = Duration.ofMillis(20)): IGPS {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import android.view.View
import android.view.ViewGroup
import androidx.annotation.IdRes
import androidx.annotation.LayoutRes
import androidx.navigation.NavController
import androidx.navigation.fragment.findNavController
import com.kylecorry.andromeda.fragments.AndromedaFragment
import com.kylecorry.sol.units.Coordinate
import com.kylecorry.sol.units.Distance
Expand Down Expand Up @@ -70,5 +72,9 @@ abstract class TrailSenseReactiveFragment(@LayoutRes private val layoutId: Int)
update()
}

fun useNavController(): NavController {
return useMemo(useRootView()) { findNavController() }
}

abstract fun update()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.kylecorry.trail_sense.tools.signal_finder.ui

import android.content.Context
import com.kylecorry.andromeda.signal.CellSignal
import com.kylecorry.andromeda.views.list.ListItem
import com.kylecorry.andromeda.views.list.ListItemMapper
import com.kylecorry.andromeda.views.list.ResourceListIcon
import com.kylecorry.trail_sense.R
import com.kylecorry.trail_sense.shared.CustomUiUtils
import com.kylecorry.trail_sense.shared.FormatService
import com.kylecorry.trail_sense.shared.extensions.AppServiceRegistry
import com.kylecorry.trail_sense.shared.sensors.CellSignalUtils

class CellSignalListItemMapper(private val context: Context) : ListItemMapper<CellSignal> {

private val formatter = AppServiceRegistry.get<FormatService>()

override fun map(value: CellSignal): ListItem {
return ListItem(
value.id.hashCode().toLong(),
formatter.formatCellNetwork(value.network),
formatter.join(
formatter.formatPercentage(value.strength),
formatter.formatTime(value.time),
if (value.isRegistered) {
context.getString(R.string.full_service)
} else {
context.getString(R.string.emergency_calls_only)
},
separator = FormatService.Separator.Dot
),
icon = ResourceListIcon(
CellSignalUtils.getCellQualityImage(value.quality),
CustomUiUtils.getQualityColor(value.quality)
)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.kylecorry.trail_sense.tools.signal_finder.ui

import android.content.Context
import com.kylecorry.andromeda.core.system.Resources
import com.kylecorry.andromeda.signal.CellNetwork
import com.kylecorry.andromeda.views.list.ListItem
import com.kylecorry.andromeda.views.list.ListItemMapper
import com.kylecorry.andromeda.views.list.ListMenuItem
import com.kylecorry.andromeda.views.list.ResourceListIcon
import com.kylecorry.sol.units.Coordinate
import com.kylecorry.sol.units.Distance
import com.kylecorry.trail_sense.R
import com.kylecorry.trail_sense.shared.FormatService
import com.kylecorry.trail_sense.shared.Units
import com.kylecorry.trail_sense.shared.UserPreferences
import com.kylecorry.trail_sense.shared.extensions.AppServiceRegistry
import com.kylecorry.trail_sense.shared.toRelativeDistance

enum class CellTowerListItemAction {
Navigate,
CreateBeacon
}

class CellTowerListItemMapper(
private val context: Context,
private val location: Coordinate,
private val onAction: (Pair<Coordinate, CellNetwork>, CellTowerListItemAction) -> Unit
) :
ListItemMapper<Pair<Coordinate, CellNetwork>> {

private val formatter = AppServiceRegistry.get<FormatService>()
private val prefs = AppServiceRegistry.get<UserPreferences>()

override fun map(value: Pair<Coordinate, CellNetwork>): ListItem {
val towerLocation = value.first
val network = value.second
val distance =
Distance.meters(location.distanceTo(towerLocation))
.convertTo(prefs.baseDistanceUnits).toRelativeDistance()
val direction = location.bearingTo(towerLocation)
val formattedDistance =
formatter.formatDistance(distance, Units.getDecimalPlaces(distance.units))
val formattedBearing = formatter.formatDegrees(direction.value, replace360 = true)
val formattedDirection = formatter.formatDirection(direction.direction)
return ListItem(
value.hashCode().toLong(),
formatter.formatCellNetwork(network),
formatter.join(
context.getString(R.string.cell_tower),
formattedDistance,
"$formattedBearing $formattedDirection",
separator = FormatService.Separator.Dot
),
icon = ResourceListIcon(
R.drawable.cell_tower,
Resources.androidTextColorSecondary(context)
),
menu = listOf(
ListMenuItem(context.getString(R.string.navigate)) {
onAction(value, CellTowerListItemAction.Navigate)
},
ListMenuItem(context.getString(R.string.create_beacon)) {
onAction(value, CellTowerListItemAction.CreateBeacon)
}
)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,24 @@ package com.kylecorry.trail_sense.tools.signal_finder.ui
import android.widget.TextView
import androidx.core.os.bundleOf
import androidx.core.text.method.LinkMovementMethodCompat
import androidx.navigation.fragment.findNavController
import com.kylecorry.andromeda.core.system.GeoUri
import com.kylecorry.andromeda.core.system.Resources
import com.kylecorry.andromeda.fragments.inBackground
import com.kylecorry.andromeda.fragments.useBackgroundEffect
import com.kylecorry.andromeda.markdown.MarkdownService
import com.kylecorry.andromeda.signal.CellNetwork
import com.kylecorry.andromeda.signal.CellSignal
import com.kylecorry.andromeda.views.list.AndromedaListView
import com.kylecorry.andromeda.views.list.ListItem
import com.kylecorry.andromeda.views.list.ListMenuItem
import com.kylecorry.andromeda.views.list.ResourceListIcon
import com.kylecorry.andromeda.views.toolbar.Toolbar
import com.kylecorry.sol.science.geology.Geofence
import com.kylecorry.sol.units.Coordinate
import com.kylecorry.sol.units.Distance
import com.kylecorry.trail_sense.R
import com.kylecorry.trail_sense.shared.CustomUiUtils
import com.kylecorry.trail_sense.shared.FormatService
import com.kylecorry.trail_sense.shared.Units
import com.kylecorry.trail_sense.shared.UserPreferences
import com.kylecorry.trail_sense.shared.extensions.TrailSenseReactiveFragment
import com.kylecorry.trail_sense.shared.extensions.useCellSignalSensor
import com.kylecorry.trail_sense.shared.extensions.useCoroutineQueue
import com.kylecorry.trail_sense.shared.extensions.useLocation
import com.kylecorry.trail_sense.shared.extensions.useService
import com.kylecorry.trail_sense.shared.extensions.useTopic
import com.kylecorry.trail_sense.shared.extensions.useTriggers
import com.kylecorry.trail_sense.shared.openTool
import com.kylecorry.trail_sense.shared.sensors.CellSignalUtils
import com.kylecorry.trail_sense.shared.toRelativeDistance
import com.kylecorry.trail_sense.tools.navigation.infrastructure.Navigator
import com.kylecorry.trail_sense.tools.signal_finder.infrastructure.CellTowerModel
import com.kylecorry.trail_sense.tools.tools.infrastructure.Tools
Expand All @@ -41,21 +29,21 @@ import java.time.Duration
class ToolSignalFinderFragment : TrailSenseReactiveFragment(R.layout.fragment_signal_finder) {

override fun update() {
val context = useAndroidContext()

// Views
val list = useView2<AndromedaListView>(R.id.list)
val disclaimer = useView2<TextView>(R.id.disclaimer)
val emptyText = useView2<TextView>(R.id.empty_text)
val title = useView2<Toolbar>(R.id.title)
val navController = useNavController()

// Services
val formatter = useService<FormatService>()
val prefs = useService<UserPreferences>()
val markdown = useService<MarkdownService>()
val navigator = useService<Navigator>()

// Other objects
val queue = useCoroutineQueue()
val triggers = useTriggers()

// Sensor readings
val signals = useCellSignals()
Expand All @@ -76,88 +64,47 @@ class ToolSignalFinderFragment : TrailSenseReactiveFragment(R.layout.fragment_si
// List items
useEffect(
list,
navController,
signals,
nearby,
distance(location, Distance.meters(100f))
) {

val signalItems = signals.mapIndexed { index, signal ->
ListItem(
index.toLong(),
formatter.formatCellNetwork(signal.network),
formatter.join(
formatter.formatPercentage(signal.strength),
formatter.formatTime(signal.time),
if (signal.isRegistered) {
getString(R.string.full_service)
} else {
getString(R.string.emergency_calls_only)
},
separator = FormatService.Separator.Dot
),
icon = ResourceListIcon(
CellSignalUtils.getCellQualityImage(signal.quality),
CustomUiUtils.getQualityColor(signal.quality)
)
)
}

val nearbyItems = nearby.flatMapIndexed { index, (towerLocation, networks) ->
val distance =
Distance.meters((location ?: Coordinate.zero).distanceTo(towerLocation))
.convertTo(prefs.baseDistanceUnits).toRelativeDistance()
val direction = (location ?: Coordinate.zero).bearingTo(towerLocation)
val formattedDistance =
formatter.formatDistance(distance, Units.getDecimalPlaces(distance.units))
val formattedBearing = formatter.formatDegrees(direction.value, replace360 = true)
val formattedDirection = formatter.formatDirection(direction.direction)
networks.mapIndexed { networkIndex, network ->
ListItem(
(index * 1000 + networkIndex).toLong(),
formatter.formatCellNetwork(network),
formatter.join(
getString(R.string.cell_tower),
formattedDistance,
"$formattedBearing $formattedDirection",
separator = FormatService.Separator.Dot
),
icon = ResourceListIcon(
R.drawable.cell_tower,
Resources.androidTextColorSecondary(requireContext())
),
menu = listOf(
ListMenuItem(getString(R.string.navigate)) {
navigator.navigateTo(towerLocation, getString(R.string.cell_tower))
findNavController().openTool(Tools.NAVIGATION)
},
ListMenuItem(getString(R.string.create_beacon)) {
val bundle = bundleOf(
"initial_location" to GeoUri(towerLocation)
)
findNavController().navigate(R.id.placeBeaconFragment, bundle)
}
)
)
val signalMapper = CellSignalListItemMapper(context)
val signalItems = signals.map { signalMapper.map(it) }

val towerMapper =
CellTowerListItemMapper(context, location) { (towerLocation, _), action ->
when (action) {
CellTowerListItemAction.Navigate -> {
navigator.navigateTo(towerLocation, getString(R.string.cell_tower))
navController.openTool(Tools.NAVIGATION)
}

CellTowerListItemAction.CreateBeacon -> {
val bundle = bundleOf(
"initial_location" to GeoUri(towerLocation)
)
navController.navigate(R.id.placeBeaconFragment, bundle)
}
}
}
val nearbyItems = nearby.flatMap { (towerLocation, networks) ->
networks.map { towerMapper.map(towerLocation to it) }
}

list.setItems(signalItems + nearbyItems)
}

// Cell tower updating
useEffect(
distance(location, Distance.meters(100f))
) {
inBackground {
setLoading(true)
queue.replace {
setNearby(CellTowerModel.getTowers(
requireContext(),
Geofence(location, Distance.kilometers(20f)),
5
).sortedBy { location.distanceTo(it.first) })
setLoading(false)
}
useBackgroundEffect(distance(location, Distance.meters(100f))) {
setLoading(true)
queue.replace {
setNearby(CellTowerModel.getTowers(
requireContext(),
Geofence(location, Distance.kilometers(20f)),
5
).sortedBy { location.distanceTo(it.first) })
setLoading(false)
}
}

Expand Down

0 comments on commit fd0f38f

Please sign in to comment.