fix: correct incorrect rendering and status of map marker points

This commit is contained in:
undef-i
2025-08-03 16:29:06 +08:00
parent 59e9987d7f
commit 4278de2a8d
35 changed files with 201 additions and 115 deletions

4
.gitignore vendored
View File

@@ -13,10 +13,10 @@ captures
.externalNativeBuild .externalNativeBuild
.cxx .cxx
local.properties local.properties
local.properties
*.ps1 *.ps1
.*.bat .*.bat
*.jks *.jks
*.keystore *.keystore
*.base64 *.base64
docs docs
gradle.properties

0
Task Normal file
View File

View File

@@ -13,8 +13,8 @@ android {
applicationId = "org.noxylva.lbjconsole" applicationId = "org.noxylva.lbjconsole"
minSdk = 29 minSdk = 29
targetSdk = 35 targetSdk = 35
versionCode = 9 versionCode = 10
versionName = "0.1.0" versionName = "0.1.1"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }
@@ -60,6 +60,7 @@ android {
} }
lint { lint {
disable += "NullSafeMutableLiveData" disable += "NullSafeMutableLiveData"
warning += "MissingPermission"
} }
} }

View File

@@ -14,6 +14,7 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/> <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

View File

@@ -62,6 +62,7 @@ import org.noxylva.lbjconsole.ui.screens.HistoryScreen
import org.noxylva.lbjconsole.ui.screens.MapScreen import org.noxylva.lbjconsole.ui.screens.MapScreen
import org.noxylva.lbjconsole.ui.screens.SettingsScreen import org.noxylva.lbjconsole.ui.screens.SettingsScreen
import org.noxylva.lbjconsole.ui.screens.CardMapView
import org.noxylva.lbjconsole.ui.theme.LBJConsoleTheme import org.noxylva.lbjconsole.ui.theme.LBJConsoleTheme
import org.noxylva.lbjconsole.util.LocoInfoUtil import org.noxylva.lbjconsole.util.LocoInfoUtil
@@ -108,6 +109,7 @@ class MainActivity : ComponentActivity() {
private var historyExpandedStates by mutableStateOf<Map<String, Boolean>>(emptyMap()) private var historyExpandedStates by mutableStateOf<Map<String, Boolean>>(emptyMap())
private var historyScrollPosition by mutableStateOf(0) private var historyScrollPosition by mutableStateOf(0)
private var historyScrollOffset by mutableStateOf(0) private var historyScrollOffset by mutableStateOf(0)
private var historyCardMapStates by mutableStateOf<Map<String, CardMapView>>(emptyMap())
private var mapCenterPosition by mutableStateOf<Pair<Double, Double>?>(null) private var mapCenterPosition by mutableStateOf<Pair<Double, Double>?>(null)
private var mapZoomLevel by mutableStateOf(10.0) private var mapZoomLevel by mutableStateOf(10.0)
private var mapRailwayLayerVisible by mutableStateOf(true) private var mapRailwayLayerVisible by mutableStateOf(true)
@@ -365,12 +367,14 @@ class MainActivity : ComponentActivity() {
historyEditMode = historyEditMode, historyEditMode = historyEditMode,
historySelectedRecords = historySelectedRecords, historySelectedRecords = historySelectedRecords,
historyExpandedStates = historyExpandedStates, historyExpandedStates = historyExpandedStates,
historyMapViewStates = historyCardMapStates,
historyScrollPosition = historyScrollPosition, historyScrollPosition = historyScrollPosition,
historyScrollOffset = historyScrollOffset, historyScrollOffset = historyScrollOffset,
onHistoryStateChange = { editMode, selectedRecords, expandedStates, scrollPosition, scrollOffset -> onHistoryStateChange = { editMode, selectedRecords, expandedStates, mapStates, scrollPosition, scrollOffset ->
historyEditMode = editMode historyEditMode = editMode
historySelectedRecords = selectedRecords historySelectedRecords = selectedRecords
historyExpandedStates = expandedStates historyExpandedStates = expandedStates
historyCardMapStates = mapStates
historyScrollPosition = scrollPosition historyScrollPosition = scrollPosition
historyScrollOffset = scrollOffset historyScrollOffset = scrollOffset
saveSettings() saveSettings()
@@ -932,9 +936,10 @@ fun MainContent(
historyEditMode: Boolean, historyEditMode: Boolean,
historySelectedRecords: Set<String>, historySelectedRecords: Set<String>,
historyExpandedStates: Map<String, Boolean>, historyExpandedStates: Map<String, Boolean>,
historyMapViewStates: Map<String, CardMapView>,
historyScrollPosition: Int, historyScrollPosition: Int,
historyScrollOffset: Int, historyScrollOffset: Int,
onHistoryStateChange: (Boolean, Set<String>, Map<String, Boolean>, Int, Int) -> Unit, onHistoryStateChange: (Boolean, Set<String>, Map<String, Boolean>, Map<String, CardMapView>, Int, Int) -> Unit,
settingsScrollPosition: Int, settingsScrollPosition: Int,
@@ -1040,7 +1045,7 @@ fun MainContent(
}, },
navigationIcon = { navigationIcon = {
IconButton(onClick = { IconButton(onClick = {
onHistoryStateChange(false, emptySet(), historyExpandedStates, historyScrollPosition, historyScrollOffset) onHistoryStateChange(false, emptySet(), historyExpandedStates, historyMapViewStates, historyScrollPosition, historyScrollOffset)
}) { }) {
Icon( Icon(
imageVector = Icons.Default.Close, imageVector = Icons.Default.Close,
@@ -1086,7 +1091,7 @@ fun MainContent(
} }
onDeleteRecords(recordsToDelete.toList()) onDeleteRecords(recordsToDelete.toList())
onHistoryStateChange(false, emptySet(), historyExpandedStates, historyScrollPosition, historyScrollOffset) onHistoryStateChange(false, emptySet(), historyExpandedStates, historyMapViewStates, historyScrollPosition, historyScrollOffset)
} }
} }
) { ) {
@@ -1151,6 +1156,7 @@ fun MainContent(
editMode = historyEditMode, editMode = historyEditMode,
selectedRecords = historySelectedRecords, selectedRecords = historySelectedRecords,
expandedStates = historyExpandedStates, expandedStates = historyExpandedStates,
mapViewStates = historyMapViewStates,
scrollPosition = historyScrollPosition, scrollPosition = historyScrollPosition,
scrollOffset = historyScrollOffset, scrollOffset = historyScrollOffset,
onStateChange = onHistoryStateChange onStateChange = onHistoryStateChange

View File

@@ -43,8 +43,14 @@ import org.noxylva.lbjconsole.model.MergeSettings
import org.noxylva.lbjconsole.model.GroupBy import org.noxylva.lbjconsole.model.GroupBy
import org.noxylva.lbjconsole.util.LocoInfoUtil import org.noxylva.lbjconsole.util.LocoInfoUtil
import org.noxylva.lbjconsole.util.TrainTypeUtil import org.noxylva.lbjconsole.util.TrainTypeUtil
import org.osmdroid.util.BoundingBox
import org.osmdroid.util.GeoPoint
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
import androidx.compose.ui.platform.LocalContext
data class CardMapView(val center: GeoPoint, val zoom: Double)
@OptIn(ExperimentalFoundationApi::class) @OptIn(ExperimentalFoundationApi::class)
@Composable @Composable
@@ -328,6 +334,7 @@ fun TrainRecordItem(
controller.setZoom(10.0) controller.setZoom(10.0)
controller.setCenter(coordinates) controller.setCenter(coordinates)
this.isTilesScaledToDpi = true this.isTilesScaledToDpi = true
tilesScaleFactor = context.resources.displayMetrics.density * 0.2f
this.setUseDataConnection(true) this.setUseDataConnection(true)
try { try {
@@ -409,6 +416,8 @@ fun MergedTrainRecordItem(
mergeSettings: MergeSettings? = null, mergeSettings: MergeSettings? = null,
isInEditMode: Boolean = false, isInEditMode: Boolean = false,
selectedRecords: List<TrainRecord> = emptyList(), selectedRecords: List<TrainRecord> = emptyList(),
mapViewState: CardMapView?,
onMapViewStateChange: (CardMapView) -> Unit,
onToggleSelection: (TrainRecord) -> Unit = {}, onToggleSelection: (TrainRecord) -> Unit = {},
onLongClick: (TrainRecord) -> Unit = {}, onLongClick: (TrainRecord) -> Unit = {},
modifier: Modifier = Modifier modifier: Modifier = Modifier
@@ -659,93 +668,152 @@ fun MergedTrainRecordItem(
exit = shrinkVertically(animationSpec = spring(dampingRatio = Spring.DampingRatioNoBouncy, stiffness = Spring.StiffnessMediumLow)) + fadeOut(animationSpec = spring(dampingRatio = Spring.DampingRatioNoBouncy, stiffness = Spring.StiffnessMediumLow)) exit = shrinkVertically(animationSpec = spring(dampingRatio = Spring.DampingRatioNoBouncy, stiffness = Spring.StiffnessMediumLow)) + fadeOut(animationSpec = spring(dampingRatio = Spring.DampingRatioNoBouncy, stiffness = Spring.StiffnessMediumLow))
) { ) {
Column { Column {
val coordinates = remember { latestRecord.getCoordinates() } val allValidCoordinates = remember {
mergedRecord.records
.mapNotNull { it.getCoordinates() }
.filter { it.latitude != 0.0 || it.longitude != 0.0 }
}
if (allValidCoordinates.isNotEmpty()) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(220.dp)
.padding(vertical = 4.dp)
.clip(RoundedCornerShape(8.dp)),
contentAlignment = Alignment.Center
) {
AndroidView(
modifier = Modifier.clickable(
indication = null,
interactionSource = remember { MutableInteractionSource() }
) {},
factory = { context ->
MapView(context).apply {
setTileSource(TileSourceFactory.MAPNIK)
setMultiTouchControls(true)
zoomController.setVisibility(org.osmdroid.views.CustomZoomButtonsController.Visibility.NEVER)
isHorizontalMapRepetitionEnabled = false
isVerticalMapRepetitionEnabled = false
setHasTransientState(true)
setOnTouchListener { v, event ->
v.parent?.requestDisallowInterceptTouchEvent(true)
false
}
this.isTilesScaledToDpi = true
tilesScaleFactor = context.resources.displayMetrics.density * 0.2f
this.setUseDataConnection(true)
addMapListener(object : org.osmdroid.events.MapListener {
override fun onScroll(event: org.osmdroid.events.ScrollEvent?): Boolean {
val center = mapCenter
val zoom = zoomLevelDouble
onMapViewStateChange(CardMapView(center as GeoPoint, zoom))
return true
}
if (coordinates != null) { override fun onZoom(event: org.osmdroid.events.ZoomEvent?): Boolean {
Box( val center = mapCenter
modifier = Modifier val zoom = zoomLevelDouble
.fillMaxWidth() onMapViewStateChange(CardMapView(center as GeoPoint, zoom))
.height(220.dp) return true
.padding(vertical = 4.dp) }
.clip(RoundedCornerShape(8.dp)), })
contentAlignment = Alignment.Center
) {
AndroidView(
modifier = Modifier.clickable(
indication = null,
interactionSource = remember { MutableInteractionSource() }
) {},
factory = { context ->
MapView(context).apply {
setTileSource(TileSourceFactory.MAPNIK)
setMultiTouchControls(true)
zoomController.setVisibility(org.osmdroid.views.CustomZoomButtonsController.Visibility.NEVER)
isHorizontalMapRepetitionEnabled = false
isVerticalMapRepetitionEnabled = false
setHasTransientState(true)
setOnTouchListener { v, event ->
v.parent?.requestDisallowInterceptTouchEvent(true)
false
}
controller.setZoom(10.0)
controller.setCenter(coordinates)
this.isTilesScaledToDpi = true
this.setUseDataConnection(true)
try { try {
val railwayTileSource = XYTileSource( val railwayTileSource = XYTileSource(
"OpenRailwayMap", 8, 16, 256, ".png", "OpenRailwayMap", 8, 16, 256, ".png",
arrayOf( arrayOf(
"https://a.tiles.openrailwayMap.org/standard/", "https://a.tiles.openrailwaymap.org/standard/",
"https://b.tiles.openrailwaymap.org/standard/", "https://b.tiles.openrailwaymap.org/standard/",
"https://c.tiles.openrailwaymap.org/standard/" "https://c.tiles.openrailwaymap.org/standard/"
), ),
"© OpenRailwayMap contributors, © OpenStreetMap contributors" "© OpenRailwayMap contributors, © OpenStreetMap contributors"
) )
val railwayProvider = MapTileProviderBasic(context) val railwayProvider = MapTileProviderBasic(context)
railwayProvider.tileSource = railwayTileSource railwayProvider.tileSource = railwayTileSource
val railwayOverlay = TilesOverlay(railwayProvider, context) val railwayOverlay = TilesOverlay(railwayProvider, context)
railwayOverlay.loadingBackgroundColor = android.graphics.Color.TRANSPARENT railwayOverlay.loadingBackgroundColor = android.graphics.Color.TRANSPARENT
railwayOverlay.loadingLineColor = android.graphics.Color.TRANSPARENT railwayOverlay.loadingLineColor = android.graphics.Color.TRANSPARENT
overlays.add(railwayOverlay) overlays.add(railwayOverlay)
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
}
try {
val locationProvider = GpsMyLocationProvider(context).apply {
locationUpdateMinDistance = 10f
locationUpdateMinTime = 1000
} }
MyLocationNewOverlay(locationProvider, this).apply { try {
enableMyLocation() val locationProvider = GpsMyLocationProvider(context).apply {
}.also { overlays.add(it) } locationUpdateMinDistance = 10f
} catch (e: Exception) { locationUpdateMinTime = 1000
e.printStackTrace() }
MyLocationNewOverlay(locationProvider, this).apply {
enableMyLocation()
}.also { overlays.add(it) }
} catch (e: Exception) {
e.printStackTrace()
}
mergedRecord.records.forEach { record ->
record.getCoordinates()?.let { coordinates ->
if (coordinates.latitude != 0.0 || coordinates.longitude != 0.0) {
val recordMap = record.toMap()
val marker = Marker(this)
marker.position = coordinates
val latStr = String.format("%.4f", coordinates.latitude)
val lonStr = String.format("%.4f", coordinates.longitude)
val coordStr = "${latStr}°N, ${lonStr}°E"
marker.title = recordMap["train"]?.toString() ?: "列车"
marker.snippet = coordStr
marker.setInfoWindowAnchor(Marker.ANCHOR_CENTER, 0f)
overlays.add(marker)
if (record == latestRecord) {
marker.showInfoWindow()
}
}
}
}
if (mapViewState != null) {
controller.setZoom(mapViewState.zoom)
controller.setCenter(mapViewState.center)
} else if (allValidCoordinates.size > 1) {
val boundingBox = BoundingBox.fromGeoPoints(allValidCoordinates)
val layoutListener = object : android.view.View.OnLayoutChangeListener {
override fun onLayoutChange(v: android.view.View?, left: Int, top: Int, right: Int, bottom: Int, oldLeft: Int, oldTop: Int, oldRight: Int, oldBottom: Int) {
if (width > 0 && height > 0) {
val zoomLevel = org.osmdroid.views.MapView.getTileSystem().getBoundingBoxZoom(boundingBox, width, height)
val latSpan = boundingBox.latitudeSpan
val adjustedCenter = org.osmdroid.util.GeoPoint(
boundingBox.center.latitude + latSpan * 0.25, // Shift center UP (north) to create top padding
boundingBox.center.longitude
)
val newZoom = zoomLevel - 1.0
controller.setZoom(newZoom)
controller.setCenter(adjustedCenter)
onMapViewStateChange(CardMapView(adjustedCenter, newZoom))
removeOnLayoutChangeListener(this)
}
}
}
addOnLayoutChangeListener(layoutListener)
} else if (allValidCoordinates.isNotEmpty()) {
val center = allValidCoordinates.first()
val zoom = 14.0
controller.setZoom(zoom)
controller.setCenter(center)
onMapViewStateChange(CardMapView(center, zoom))
}
} }
},
val marker = Marker(this) update = { mapView -> mapView.invalidate() }
marker.position = coordinates )
val latStr = String.format("%.4f", coordinates.latitude)
val lonStr = String.format("%.4f", coordinates.longitude)
val coordStr = "${latStr}°N, ${lonStr}°E"
marker.title = recordMap["train"]?.toString() ?: "列车"
marker.snippet = coordStr
marker.setInfoWindowAnchor(Marker.ANCHOR_CENTER, 0f)
overlays.add(marker)
marker.showInfoWindow()
}
},
update = { mapView -> mapView.invalidate() }
)
} }
} }
if (recordMap.containsKey("position_info")) { if (recordMap.containsKey("position_info")) {
@@ -903,9 +971,10 @@ fun HistoryScreen(
editMode: Boolean = false, editMode: Boolean = false,
selectedRecords: Set<String> = emptySet(), selectedRecords: Set<String> = emptySet(),
expandedStates: Map<String, Boolean> = emptyMap(), expandedStates: Map<String, Boolean> = emptyMap(),
mapViewStates: Map<String, CardMapView> = emptyMap(),
scrollPosition: Int = 0, scrollPosition: Int = 0,
scrollOffset: Int = 0, scrollOffset: Int = 0,
onStateChange: (Boolean, Set<String>, Map<String, Boolean>, Int, Int) -> Unit = { _, _, _, _, _ -> } onStateChange: (Boolean, Set<String>, Map<String, Boolean>, Map<String, CardMapView>, Int, Int) -> Unit = { _, _, _, _, _, _ -> }
) { ) {
val refreshKey = latestRecord?.timestamp?.time ?: 0 val refreshKey = latestRecord?.timestamp?.time ?: 0
@@ -935,6 +1004,9 @@ fun HistoryScreen(
val expandedStatesMap = remember(expandedStates) { val expandedStatesMap = remember(expandedStates) {
mutableStateMapOf<String, Boolean>().apply { putAll(expandedStates) } mutableStateMapOf<String, Boolean>().apply { putAll(expandedStates) }
} }
val mapViewStatesMap = remember(mapViewStates) {
mutableStateMapOf<String, CardMapView>().apply { putAll(mapViewStates) }
}
val listState = rememberLazyListState( val listState = rememberLazyListState(
initialFirstVisibleItemIndex = scrollPosition, initialFirstVisibleItemIndex = scrollPosition,
@@ -965,28 +1037,28 @@ fun HistoryScreen(
LaunchedEffect(isInEditMode, selectedRecordsList.size) { LaunchedEffect(isInEditMode, selectedRecordsList.size) {
val selectedIds = selectedRecordsList.map { it.uniqueId }.toSet() val selectedIds = selectedRecordsList.map { it.uniqueId }.toSet()
onStateChange(isInEditMode, selectedIds, expandedStatesMap.toMap(), listState.firstVisibleItemIndex, listState.firstVisibleItemScrollOffset) onStateChange(isInEditMode, selectedIds, expandedStatesMap.toMap(), mapViewStatesMap.toMap(), listState.firstVisibleItemIndex, listState.firstVisibleItemScrollOffset)
} }
LaunchedEffect(expandedStatesMap.toMap()) { LaunchedEffect(expandedStatesMap.toMap()) {
if (!isInEditMode) { if (!isInEditMode) {
val selectedIds = selectedRecordsList.map { it.uniqueId }.toSet() val selectedIds = selectedRecordsList.map { it.uniqueId }.toSet()
delay(50) delay(50)
onStateChange(isInEditMode, selectedIds, expandedStatesMap.toMap(), listState.firstVisibleItemIndex, listState.firstVisibleItemScrollOffset) onStateChange(isInEditMode, selectedIds, expandedStatesMap.toMap(), mapViewStatesMap.toMap(), listState.firstVisibleItemIndex, listState.firstVisibleItemScrollOffset)
} }
} }
LaunchedEffect(listState.firstVisibleItemIndex, listState.firstVisibleItemScrollOffset) { LaunchedEffect(listState.firstVisibleItemIndex, listState.firstVisibleItemScrollOffset) {
if (!isInEditMode) { if (!isInEditMode) {
val selectedIds = selectedRecordsList.map { it.uniqueId }.toSet() val selectedIds = selectedRecordsList.map { it.uniqueId }.toSet()
onStateChange(isInEditMode, selectedIds, expandedStatesMap.toMap(), listState.firstVisibleItemIndex, listState.firstVisibleItemScrollOffset) onStateChange(isInEditMode, selectedIds, expandedStatesMap.toMap(), mapViewStatesMap.toMap(), listState.firstVisibleItemIndex, listState.firstVisibleItemScrollOffset)
} }
} }
LaunchedEffect(selectedRecordsList.size) { LaunchedEffect(selectedRecordsList.size) {
if (selectedRecordsList.isEmpty() && isInEditMode) { if (selectedRecordsList.isEmpty() && isInEditMode) {
isInEditMode = false isInEditMode = false
onStateChange(false, emptySet(), expandedStatesMap.toMap(), listState.firstVisibleItemIndex, listState.firstVisibleItemScrollOffset) onStateChange(false, emptySet(), expandedStatesMap.toMap(), mapViewStatesMap.toMap(), listState.firstVisibleItemIndex, listState.firstVisibleItemScrollOffset)
} }
} }
@@ -1092,6 +1164,10 @@ fun HistoryScreen(
mergeSettings = mergeSettings, mergeSettings = mergeSettings,
isInEditMode = isInEditMode, isInEditMode = isInEditMode,
selectedRecords = selectedRecordsList, selectedRecords = selectedRecordsList,
mapViewState = mapViewStatesMap[item.groupKey],
onMapViewStateChange = { newState ->
mapViewStatesMap[item.groupKey] = newState
},
onToggleSelection = { record -> onToggleSelection = { record ->
if (selectedRecordsList.contains(record)) { if (selectedRecordsList.contains(record)) {
selectedRecordsList.remove(record) selectedRecordsList.remove(record)

View File

@@ -15,7 +15,7 @@ import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import kotlinx.coroutines.delay import kotlinx.coroutines.launch
import org.noxylva.lbjconsole.model.MergeSettings import org.noxylva.lbjconsole.model.MergeSettings
import org.noxylva.lbjconsole.model.GroupBy import org.noxylva.lbjconsole.model.GroupBy
import org.noxylva.lbjconsole.model.TimeWindow import org.noxylva.lbjconsole.model.TimeWindow
@@ -24,7 +24,6 @@ import org.noxylva.lbjconsole.BackgroundService
import org.noxylva.lbjconsole.NotificationService import org.noxylva.lbjconsole.NotificationService
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.DisposableEffect
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@@ -195,23 +194,14 @@ fun SettingsScreen(
val context = LocalContext.current val context = LocalContext.current
val notificationService = remember(context) { NotificationService(context) } val notificationService = remember(context) { NotificationService(context) }
var backgroundServiceEnabled by remember { mutableStateOf(false) } var backgroundServiceEnabled by remember { mutableStateOf<Boolean?>(null) }
val coroutineScope = rememberCoroutineScope()
LaunchedEffect(context) { LaunchedEffect(context) {
backgroundServiceEnabled = SettingsActivity.isBackgroundServiceEnabled(context) backgroundServiceEnabled = SettingsActivity.isBackgroundServiceEnabled(context)
} }
LaunchedEffect(backgroundServiceEnabled) {
SettingsActivity.setBackgroundServiceEnabled(context, backgroundServiceEnabled)
if (backgroundServiceEnabled) {
BackgroundService.startService(context)
} else {
BackgroundService.stopService(context)
}
}
var notificationEnabled by remember(context, notificationService) { var notificationEnabled by remember(context, notificationService) {
mutableStateOf(notificationService.isNotificationEnabled()) mutableStateOf(notificationService.isNotificationEnabled())
} }
@@ -233,12 +223,24 @@ fun SettingsScreen(
color = MaterialTheme.colorScheme.onSurfaceVariant color = MaterialTheme.colorScheme.onSurfaceVariant
) )
} }
Switch( if (backgroundServiceEnabled == null) {
checked = backgroundServiceEnabled, CircularProgressIndicator(modifier = Modifier.size(24.dp))
onCheckedChange = { enabled -> } else {
backgroundServiceEnabled = enabled Switch(
} checked = backgroundServiceEnabled!!,
) onCheckedChange = { enabled ->
backgroundServiceEnabled = enabled
coroutineScope.launch {
SettingsActivity.setBackgroundServiceEnabled(context, enabled)
if (enabled) {
BackgroundService.startService(context)
} else {
BackgroundService.stopService(context)
}
}
}
)
}
} }
Row( Row(
@@ -436,4 +438,4 @@ fun SettingsScreen(
.padding(12.dp) .padding(12.dp)
) )
} }
} }

0
app/src/main/res/drawable/ic_launcher_background.xml Normal file → Executable file
View File

0
app/src/main/res/drawable/ic_launcher_foreground.xml Normal file → Executable file
View File

0
app/src/main/res/drawable/ic_notification.xml Normal file → Executable file
View File

0
app/src/main/res/drawable/ic_person.xml Normal file → Executable file
View File

0
app/src/main/res/layout/activity_settings.xml Normal file → Executable file
View File

0
app/src/main/res/layout/notification_train_record.xml Normal file → Executable file
View File

0
app/src/main/res/mipmap-anydpi/ic_launcher.xml Normal file → Executable file
View File

0
app/src/main/res/mipmap-anydpi/ic_launcher_round.xml Normal file → Executable file
View File

0
app/src/main/res/mipmap-hdpi/ic_launcher.webp Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

0
app/src/main/res/mipmap-hdpi/ic_launcher_round.webp Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

0
app/src/main/res/mipmap-mdpi/ic_launcher.webp Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 982 B

After

Width:  |  Height:  |  Size: 982 B

0
app/src/main/res/mipmap-mdpi/ic_launcher_round.webp Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

0
app/src/main/res/mipmap-xhdpi/ic_launcher.webp Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

0
app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

0
app/src/main/res/mipmap-xxhdpi/ic_launcher.webp Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

0
app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

0
app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

0
app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

0
app/src/main/res/raw/loco_info.csv Normal file → Executable file
View File

0
app/src/main/res/values/colors.xml Normal file → Executable file
View File

0
app/src/main/res/values/strings.xml Normal file → Executable file
View File

0
app/src/main/res/values/themes.xml Normal file → Executable file
View File

0
app/src/main/res/xml/backup_rules.xml Normal file → Executable file
View File

0
app/src/main/res/xml/data_extraction_rules.xml Normal file → Executable file
View File

0
app/src/main/res/xml/file_paths.xml Normal file → Executable file
View File

View File

@@ -20,4 +20,4 @@ kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the # Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies, # resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library # thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true android.nonTransitiveRClass=true

0
gradlew vendored Normal file → Executable file
View File

View File

@@ -19,6 +19,6 @@ dependencyResolutionManagement {
} }
} }
rootProject.name = "LBJ Receiver" rootProject.name = "LBJ_Console"
include(":app") include(":app")