fix: correct incorrect rendering and status of map marker points
4
.gitignore
vendored
@@ -13,10 +13,10 @@ captures
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
local.properties
|
||||
local.properties
|
||||
*.ps1
|
||||
.*.bat
|
||||
*.jks
|
||||
*.keystore
|
||||
*.base64
|
||||
docs
|
||||
docs
|
||||
gradle.properties
|
||||
@@ -13,8 +13,8 @@ android {
|
||||
applicationId = "org.noxylva.lbjconsole"
|
||||
minSdk = 29
|
||||
targetSdk = 35
|
||||
versionCode = 9
|
||||
versionName = "0.1.0"
|
||||
versionCode = 10
|
||||
versionName = "0.1.1"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
@@ -60,6 +60,7 @@ android {
|
||||
}
|
||||
lint {
|
||||
disable += "NullSafeMutableLiveData"
|
||||
warning += "MissingPermission"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<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"/>
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ import org.noxylva.lbjconsole.ui.screens.HistoryScreen
|
||||
|
||||
import org.noxylva.lbjconsole.ui.screens.MapScreen
|
||||
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.util.LocoInfoUtil
|
||||
@@ -108,6 +109,7 @@ class MainActivity : ComponentActivity() {
|
||||
private var historyExpandedStates by mutableStateOf<Map<String, Boolean>>(emptyMap())
|
||||
private var historyScrollPosition 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 mapZoomLevel by mutableStateOf(10.0)
|
||||
private var mapRailwayLayerVisible by mutableStateOf(true)
|
||||
@@ -365,12 +367,14 @@ class MainActivity : ComponentActivity() {
|
||||
historyEditMode = historyEditMode,
|
||||
historySelectedRecords = historySelectedRecords,
|
||||
historyExpandedStates = historyExpandedStates,
|
||||
historyMapViewStates = historyCardMapStates,
|
||||
historyScrollPosition = historyScrollPosition,
|
||||
historyScrollOffset = historyScrollOffset,
|
||||
onHistoryStateChange = { editMode, selectedRecords, expandedStates, scrollPosition, scrollOffset ->
|
||||
onHistoryStateChange = { editMode, selectedRecords, expandedStates, mapStates, scrollPosition, scrollOffset ->
|
||||
historyEditMode = editMode
|
||||
historySelectedRecords = selectedRecords
|
||||
historyExpandedStates = expandedStates
|
||||
historyCardMapStates = mapStates
|
||||
historyScrollPosition = scrollPosition
|
||||
historyScrollOffset = scrollOffset
|
||||
saveSettings()
|
||||
@@ -932,9 +936,10 @@ fun MainContent(
|
||||
historyEditMode: Boolean,
|
||||
historySelectedRecords: Set<String>,
|
||||
historyExpandedStates: Map<String, Boolean>,
|
||||
historyMapViewStates: Map<String, CardMapView>,
|
||||
historyScrollPosition: 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,
|
||||
@@ -1040,7 +1045,7 @@ fun MainContent(
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = {
|
||||
onHistoryStateChange(false, emptySet(), historyExpandedStates, historyScrollPosition, historyScrollOffset)
|
||||
onHistoryStateChange(false, emptySet(), historyExpandedStates, historyMapViewStates, historyScrollPosition, historyScrollOffset)
|
||||
}) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Close,
|
||||
@@ -1086,7 +1091,7 @@ fun MainContent(
|
||||
}
|
||||
|
||||
onDeleteRecords(recordsToDelete.toList())
|
||||
onHistoryStateChange(false, emptySet(), historyExpandedStates, historyScrollPosition, historyScrollOffset)
|
||||
onHistoryStateChange(false, emptySet(), historyExpandedStates, historyMapViewStates, historyScrollPosition, historyScrollOffset)
|
||||
}
|
||||
}
|
||||
) {
|
||||
@@ -1151,6 +1156,7 @@ fun MainContent(
|
||||
editMode = historyEditMode,
|
||||
selectedRecords = historySelectedRecords,
|
||||
expandedStates = historyExpandedStates,
|
||||
mapViewStates = historyMapViewStates,
|
||||
scrollPosition = historyScrollPosition,
|
||||
scrollOffset = historyScrollOffset,
|
||||
onStateChange = onHistoryStateChange
|
||||
|
||||
@@ -43,8 +43,14 @@ import org.noxylva.lbjconsole.model.MergeSettings
|
||||
import org.noxylva.lbjconsole.model.GroupBy
|
||||
import org.noxylva.lbjconsole.util.LocoInfoUtil
|
||||
import org.noxylva.lbjconsole.util.TrainTypeUtil
|
||||
import org.osmdroid.util.BoundingBox
|
||||
import org.osmdroid.util.GeoPoint
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
|
||||
data class CardMapView(val center: GeoPoint, val zoom: Double)
|
||||
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
@@ -328,6 +334,7 @@ fun TrainRecordItem(
|
||||
controller.setZoom(10.0)
|
||||
controller.setCenter(coordinates)
|
||||
this.isTilesScaledToDpi = true
|
||||
tilesScaleFactor = context.resources.displayMetrics.density * 0.2f
|
||||
this.setUseDataConnection(true)
|
||||
|
||||
try {
|
||||
@@ -409,6 +416,8 @@ fun MergedTrainRecordItem(
|
||||
mergeSettings: MergeSettings? = null,
|
||||
isInEditMode: Boolean = false,
|
||||
selectedRecords: List<TrainRecord> = emptyList(),
|
||||
mapViewState: CardMapView?,
|
||||
onMapViewStateChange: (CardMapView) -> Unit,
|
||||
onToggleSelection: (TrainRecord) -> Unit = {},
|
||||
onLongClick: (TrainRecord) -> Unit = {},
|
||||
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))
|
||||
) {
|
||||
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) {
|
||||
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
|
||||
}
|
||||
controller.setZoom(10.0)
|
||||
controller.setCenter(coordinates)
|
||||
this.isTilesScaledToDpi = true
|
||||
this.setUseDataConnection(true)
|
||||
override fun onZoom(event: org.osmdroid.events.ZoomEvent?): Boolean {
|
||||
val center = mapCenter
|
||||
val zoom = zoomLevelDouble
|
||||
onMapViewStateChange(CardMapView(center as GeoPoint, zoom))
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
try {
|
||||
val railwayTileSource = XYTileSource(
|
||||
"OpenRailwayMap", 8, 16, 256, ".png",
|
||||
arrayOf(
|
||||
"https://a.tiles.openrailwayMap.org/standard/",
|
||||
"https://b.tiles.openrailwaymap.org/standard/",
|
||||
"https://c.tiles.openrailwaymap.org/standard/"
|
||||
),
|
||||
"© OpenRailwayMap contributors, © OpenStreetMap contributors"
|
||||
)
|
||||
try {
|
||||
val railwayTileSource = XYTileSource(
|
||||
"OpenRailwayMap", 8, 16, 256, ".png",
|
||||
arrayOf(
|
||||
"https://a.tiles.openrailwaymap.org/standard/",
|
||||
"https://b.tiles.openrailwaymap.org/standard/",
|
||||
"https://c.tiles.openrailwaymap.org/standard/"
|
||||
),
|
||||
"© OpenRailwayMap contributors, © OpenStreetMap contributors"
|
||||
)
|
||||
|
||||
val railwayProvider = MapTileProviderBasic(context)
|
||||
railwayProvider.tileSource = railwayTileSource
|
||||
val railwayProvider = MapTileProviderBasic(context)
|
||||
railwayProvider.tileSource = railwayTileSource
|
||||
|
||||
val railwayOverlay = TilesOverlay(railwayProvider, context)
|
||||
railwayOverlay.loadingBackgroundColor = android.graphics.Color.TRANSPARENT
|
||||
railwayOverlay.loadingLineColor = android.graphics.Color.TRANSPARENT
|
||||
val railwayOverlay = TilesOverlay(railwayProvider, context)
|
||||
railwayOverlay.loadingBackgroundColor = android.graphics.Color.TRANSPARENT
|
||||
railwayOverlay.loadingLineColor = android.graphics.Color.TRANSPARENT
|
||||
|
||||
overlays.add(railwayOverlay)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
try {
|
||||
val locationProvider = GpsMyLocationProvider(context).apply {
|
||||
locationUpdateMinDistance = 10f
|
||||
locationUpdateMinTime = 1000
|
||||
overlays.add(railwayOverlay)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
MyLocationNewOverlay(locationProvider, this).apply {
|
||||
enableMyLocation()
|
||||
}.also { overlays.add(it) }
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
try {
|
||||
val locationProvider = GpsMyLocationProvider(context).apply {
|
||||
locationUpdateMinDistance = 10f
|
||||
locationUpdateMinTime = 1000
|
||||
}
|
||||
|
||||
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)
|
||||
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() }
|
||||
)
|
||||
},
|
||||
update = { mapView -> mapView.invalidate() }
|
||||
)
|
||||
}
|
||||
}
|
||||
if (recordMap.containsKey("position_info")) {
|
||||
@@ -903,9 +971,10 @@ fun HistoryScreen(
|
||||
editMode: Boolean = false,
|
||||
selectedRecords: Set<String> = emptySet(),
|
||||
expandedStates: Map<String, Boolean> = emptyMap(),
|
||||
mapViewStates: Map<String, CardMapView> = emptyMap(),
|
||||
scrollPosition: 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
|
||||
@@ -935,6 +1004,9 @@ fun HistoryScreen(
|
||||
val expandedStatesMap = remember(expandedStates) {
|
||||
mutableStateMapOf<String, Boolean>().apply { putAll(expandedStates) }
|
||||
}
|
||||
val mapViewStatesMap = remember(mapViewStates) {
|
||||
mutableStateMapOf<String, CardMapView>().apply { putAll(mapViewStates) }
|
||||
}
|
||||
|
||||
val listState = rememberLazyListState(
|
||||
initialFirstVisibleItemIndex = scrollPosition,
|
||||
@@ -965,28 +1037,28 @@ fun HistoryScreen(
|
||||
|
||||
LaunchedEffect(isInEditMode, selectedRecordsList.size) {
|
||||
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()) {
|
||||
if (!isInEditMode) {
|
||||
val selectedIds = selectedRecordsList.map { it.uniqueId }.toSet()
|
||||
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) {
|
||||
if (!isInEditMode) {
|
||||
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) {
|
||||
if (selectedRecordsList.isEmpty() && isInEditMode) {
|
||||
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,
|
||||
isInEditMode = isInEditMode,
|
||||
selectedRecords = selectedRecordsList,
|
||||
mapViewState = mapViewStatesMap[item.groupKey],
|
||||
onMapViewStateChange = { newState ->
|
||||
mapViewStatesMap[item.groupKey] = newState
|
||||
},
|
||||
onToggleSelection = { record ->
|
||||
if (selectedRecordsList.contains(record)) {
|
||||
selectedRecordsList.remove(record)
|
||||
|
||||
@@ -15,7 +15,7 @@ import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
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.GroupBy
|
||||
import org.noxylva.lbjconsole.model.TimeWindow
|
||||
@@ -24,7 +24,6 @@ import org.noxylva.lbjconsole.BackgroundService
|
||||
import org.noxylva.lbjconsole.NotificationService
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@@ -195,23 +194,14 @@ fun SettingsScreen(
|
||||
|
||||
val context = LocalContext.current
|
||||
val notificationService = remember(context) { NotificationService(context) }
|
||||
|
||||
var backgroundServiceEnabled by remember { mutableStateOf(false) }
|
||||
|
||||
|
||||
var backgroundServiceEnabled by remember { mutableStateOf<Boolean?>(null) }
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
LaunchedEffect(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) {
|
||||
mutableStateOf(notificationService.isNotificationEnabled())
|
||||
}
|
||||
@@ -233,12 +223,24 @@ fun SettingsScreen(
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
Switch(
|
||||
checked = backgroundServiceEnabled,
|
||||
onCheckedChange = { enabled ->
|
||||
backgroundServiceEnabled = enabled
|
||||
}
|
||||
)
|
||||
if (backgroundServiceEnabled == null) {
|
||||
CircularProgressIndicator(modifier = Modifier.size(24.dp))
|
||||
} else {
|
||||
Switch(
|
||||
checked = backgroundServiceEnabled!!,
|
||||
onCheckedChange = { enabled ->
|
||||
backgroundServiceEnabled = enabled
|
||||
coroutineScope.launch {
|
||||
SettingsActivity.setBackgroundServiceEnabled(context, enabled)
|
||||
if (enabled) {
|
||||
BackgroundService.startService(context)
|
||||
} else {
|
||||
BackgroundService.stopService(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Row(
|
||||
@@ -436,4 +438,4 @@ fun SettingsScreen(
|
||||
.padding(12.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
0
app/src/main/res/drawable/ic_launcher_background.xml
Normal file → Executable file
0
app/src/main/res/drawable/ic_launcher_foreground.xml
Normal file → Executable file
0
app/src/main/res/drawable/ic_notification.xml
Normal file → Executable file
0
app/src/main/res/drawable/ic_person.xml
Normal file → Executable file
0
app/src/main/res/layout/activity_settings.xml
Normal file → Executable file
0
app/src/main/res/layout/notification_train_record.xml
Normal file → Executable file
0
app/src/main/res/mipmap-anydpi/ic_launcher.xml
Normal file → Executable file
0
app/src/main/res/mipmap-anydpi/ic_launcher_round.xml
Normal file → Executable file
0
app/src/main/res/mipmap-hdpi/ic_launcher.webp
Normal file → Executable 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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
0
app/src/main/res/values/colors.xml
Normal file → Executable file
0
app/src/main/res/values/strings.xml
Normal file → Executable file
0
app/src/main/res/values/themes.xml
Normal file → Executable file
0
app/src/main/res/xml/backup_rules.xml
Normal file → Executable file
0
app/src/main/res/xml/data_extraction_rules.xml
Normal file → Executable file
0
app/src/main/res/xml/file_paths.xml
Normal file → Executable 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
|
||||
# resources declared in the library itself and none from the library's dependencies,
|
||||
# thereby reducing the size of the R class for that library
|
||||
android.nonTransitiveRClass=true
|
||||
android.nonTransitiveRClass=true
|
||||
|
||||
@@ -19,6 +19,6 @@ dependencyResolutionManagement {
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = "LBJ Receiver"
|
||||
rootProject.name = "LBJ_Console"
|
||||
include(":app")
|
||||
|
||||