Added various minor fixes, cleaned up classes

This commit is contained in:
Arty Bishop committed 2025-12-27 15:01:45 +00:00
1 parent 5a8108384f
commit fc0b995bac
35 files changed
+295 -310

No files matched your search

+4 -7
View File
@@ -1,11 +1,13 @@
@file: Suppress("UnstableApiUsage")
plugins {
id("com.android.application")
id("com.google.devtools.ksp")
id("org.jetbrains.kotlin.android")
}
kotlin {
jvmToolchain(17)
}
android {
namespace = "com.rtbishop.look4sat"
compileSdk = 33
@@ -29,12 +31,7 @@ android {
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
composeOptions { kotlinCompilerExtensionVersion = "1.5.1" }
packaging { resources { excludes += listOf("META-INF/{AL2.0,LGPL2.1}") } }
}
dependencies {
@@ -40,7 +40,7 @@ class MainApplication : Application() {
if (timeDelta > 172800000) { // 48 hours in ms
val sdf = SimpleDateFormat("d MMM yyyy - HH:mm:ss", Locale.getDefault())
println("Started periodic data update on ${sdf.format(Date())}")
container.databaseRepo.updateFromWeb()
container.databaseRepo.updateFromRemote()
}
}
}
@@ -10,18 +10,21 @@ import com.rtbishop.look4sat.data.database.MIGRATION_1_2
import com.rtbishop.look4sat.data.database.MainDatabase
import com.rtbishop.look4sat.data.framework.BluetoothReporter
import com.rtbishop.look4sat.data.framework.NetworkReporter
import com.rtbishop.look4sat.data.framework.SettingsRepo
import com.rtbishop.look4sat.data.repository.DatabaseRepo
import com.rtbishop.look4sat.data.repository.SatelliteRepo
import com.rtbishop.look4sat.data.repository.SelectionRepo
import com.rtbishop.look4sat.data.source.DataSource
import com.rtbishop.look4sat.data.source.LocalStorage
import com.rtbishop.look4sat.data.repository.SettingsRepo
import com.rtbishop.look4sat.data.source.FileSource
import com.rtbishop.look4sat.data.source.LocalSource
import com.rtbishop.look4sat.data.source.RemoteSource
import com.rtbishop.look4sat.data.source.SensorSource
import com.rtbishop.look4sat.domain.repository.IDatabaseRepo
import com.rtbishop.look4sat.domain.repository.ISatelliteRepo
import com.rtbishop.look4sat.domain.repository.ISelectionRepo
import com.rtbishop.look4sat.domain.repository.ISettingsRepo
import com.rtbishop.look4sat.domain.source.IDataSource
import com.rtbishop.look4sat.domain.source.IFileSource
import com.rtbishop.look4sat.domain.source.ILocalSource
import com.rtbishop.look4sat.domain.source.IRemoteSource
import com.rtbishop.look4sat.domain.source.ISensorSource
import com.rtbishop.look4sat.domain.utility.DataParser
import kotlinx.coroutines.CoroutineExceptionHandler
@@ -34,21 +37,16 @@ import org.osmdroid.config.Configuration
class MainContainer(private val context: Context) {
private val database =
Room.databaseBuilder(context, MainDatabase::class.java, "Look4SatDb").addMigrations(MIGRATION_1_2)
.fallbackToDestructiveMigration().build()
private val localStorage = LocalStorage(database.storageDao())
private val mainHandler = CoroutineExceptionHandler { _, error -> println("Look4Sat: $error") }
private val remoteSource = provideRemoteSource()
val mainScope = CoroutineScope(SupervisorJob() + Dispatchers.Default + mainHandler)
private val localSource = provideLocalSource()
val mainScope = provideMainScope()
val settingsRepo = provideSettingsRepo()
val databaseRepo = provideDatabaseRepo()
val satelliteRepo = provideSatelliteRepo()
val selectionRepo = provideSelectionRepo()
val satelliteRepo = provideSatelliteRepo()
val databaseRepo = provideDatabaseRepo()
fun provideBluetoothReporter(): BluetoothReporter {
val btManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
return BluetoothReporter(btManager, CoroutineScope(Dispatchers.IO))
val manager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
return BluetoothReporter(manager, CoroutineScope(Dispatchers.IO))
}
fun provideNetworkReporter(): NetworkReporter {
@@ -56,34 +54,53 @@ class MainContainer(private val context: Context) {
}
fun provideSensorSource(): ISensorSource {
val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR)
return SensorSource(sensorManager, sensor)
}
private fun provideRemoteSource(): IDataSource {
val cache = Cache(context.cacheDir, 1000 * 1000 * 10L)
val httpClient = OkHttpClient.Builder().cache(cache).build()
return DataSource(context.contentResolver, httpClient, Dispatchers.IO)
val manager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor = manager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR)
return SensorSource(manager, sensor)
}
private fun provideDatabaseRepo(): IDatabaseRepo {
val dataParser = DataParser(Dispatchers.Default)
return DatabaseRepo(Dispatchers.Default, dataParser, remoteSource, localStorage, settingsRepo)
val fileSource = provideFileSource()
val remoteSource = provideRemoteSource()
return DatabaseRepo(Dispatchers.Default, dataParser, fileSource, localSource, remoteSource, settingsRepo)
}
private fun provideFileSource(): IFileSource {
return FileSource(context.contentResolver, Dispatchers.IO)
}
private fun provideLocalSource(): ILocalSource {
val database = Room.databaseBuilder(context, MainDatabase::class.java, "Look4SatDb").apply {
addMigrations(MIGRATION_1_2)
fallbackToDestructiveMigration()
}.build()
return LocalSource(database.storageDao())
}
private fun provideMainScope(): CoroutineScope {
val mainHandler = CoroutineExceptionHandler { _, error -> println("Look4Sat: $error") }
return CoroutineScope(SupervisorJob() + Dispatchers.Default + mainHandler)
}
private fun provideRemoteSource(): IRemoteSource {
val cache = Cache(context.cacheDir, 1000 * 1000 * 10L)
val httpClient = OkHttpClient.Builder().cache(cache).build()
return RemoteSource(httpClient, Dispatchers.IO)
}
private fun provideSatelliteRepo(): ISatelliteRepo {
return SatelliteRepo(Dispatchers.Default, localStorage, settingsRepo)
return SatelliteRepo(Dispatchers.Default, localSource, settingsRepo)
}
private fun provideSelectionRepo(): ISelectionRepo {
return SelectionRepo(Dispatchers.Default, localStorage, settingsRepo)
return SelectionRepo(Dispatchers.Default, localSource, settingsRepo)
}
private fun provideSettingsRepo(): ISettingsRepo {
val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val manager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val preferences = context.getSharedPreferences("default", Context.MODE_PRIVATE)
Configuration.getInstance().load(context, preferences)
return SettingsRepo(locationManager, preferences)
return SettingsRepo(manager, preferences)
}
}
@@ -16,8 +16,6 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
@@ -34,18 +32,11 @@ private val allModes = listOf(
"LRPT", "LSB", "MFSK", "MSK", "MSK AX.100 Mode 5", "MSK AX.100 Mode 6", "OFDM", "OQPSK",
"PSK", "PSK31", "PSK63", "QPSK", "QPSK31", "QPSK63", "SSTV", "USB", "WSJT"
)
private val selectedModes = mutableListOf("AFSK", "AFSK S-Net")
@Preview(showBackground = true)
@Composable
private fun ModesDialogPreview() {
val modesList = remember { mutableStateOf(selectedModes) }
MainTheme {
ModesDialog(allModes, modesList.value, {}) {
if (modesList.value.contains(it)) modesList.value.remove(it)
else modesList.value.add(it)
}
}
MainTheme { ModesDialog(allModes, listOf("AFSK", "AFSK S-Net"), {}) {} }
}
@Composable
@@ -97,9 +97,7 @@ private fun setStationPosition(stationPos: GeoPos, mapView: MapView) {
}
}
private fun setPositions(
posMap: Map<Satellite, GeoPos>, mapView: MapView, action: (Satellite) -> Unit
) {
private fun setPositions(posMap: Map<Satellite, GeoPos>, mapView: MapView, action: (Satellite) -> Unit) {
val markers = FolderOverlay()
try {
posMap.entries.forEach {
@@ -247,9 +245,7 @@ private val tonerLiteTileSource = XYTileSource(
private fun getColorFilter(): ColorMatrixColorFilter {
val negativeMatrix = ColorMatrix(
floatArrayOf(
-1f, 0f, 0f, 0f, 260f, 0f, -1f, 0f, 0f, 260f, 0f, 0f, -1f, 0f, 260f, 0f, 0f, 0f, 1f, 0f
)
floatArrayOf(-1f, 0f, 0f, 0f, 260f, 0f, -1f, 0f, 0f, 260f, 0f, 0f, -1f, 0f, 260f, 0f, 0f, 0f, 1f, 0f)
)
return ColorMatrixColorFilter(negativeMatrix)
}
@@ -28,9 +28,9 @@ import com.rtbishop.look4sat.domain.predict.SatPos
import com.rtbishop.look4sat.domain.predict.Satellite
import com.rtbishop.look4sat.domain.repository.ISatelliteRepo
import com.rtbishop.look4sat.domain.repository.ISettingsRepo
import com.rtbishop.look4sat.domain.utility.QthConverter
import com.rtbishop.look4sat.domain.utility.clipLat
import com.rtbishop.look4sat.domain.utility.clipLon
import com.rtbishop.look4sat.domain.utility.positionToQth
import com.rtbishop.look4sat.domain.utility.toDegrees
import com.rtbishop.look4sat.domain.utility.toTimerString
import java.util.Date
@@ -66,23 +66,23 @@ class MapViewModel(private val satelliteRepo: ISatelliteRepo, settingsRepo: ISet
val footprint: SharedFlow<SatPos> = _footprint
private val _mapData = MutableSharedFlow<MapData>()
val mapData: SharedFlow<MapData> = _mapData
// val mapData: SharedFlow<MapData> = _mapData
private val _positions = MutableSharedFlow<Map<Satellite, GeoPos>>()
val positions: SharedFlow<Map<Satellite, GeoPos>> = _positions
fun scrollSelection(decrement: Boolean) {
if (allSatellites.isNotEmpty()) {
val index = allSatellites.indexOf(selectedSatellite)
if (decrement) {
if (index > 0) selectSatellite(allSatellites[index - 1])
else selectSatellite(allSatellites[allSatellites.size - 1])
} else {
if (index < allSatellites.size - 1) selectSatellite(allSatellites[index + 1])
else selectSatellite(allSatellites[0])
}
}
}
// fun scrollSelection(decrement: Boolean) {
// if (allSatellites.isNotEmpty()) {
// val index = allSatellites.indexOf(selectedSatellite)
// if (decrement) {
// if (index > 0) selectSatellite(allSatellites[index - 1])
// else selectSatellite(allSatellites[allSatellites.size - 1])
// } else {
// if (index < allSatellites.size - 1) selectSatellite(allSatellites[index + 1])
// else selectSatellite(allSatellites[0])
// }
// }
// }
fun selectDefaultSatellite(catnum: Int) {
if (allSatellites.isNotEmpty()) {
@@ -178,7 +178,7 @@ class MapViewModel(private val satelliteRepo: ISatelliteRepo, settingsRepo: ISet
val osmLat = clipLat(satPos.latitude.toDegrees())
val osmLon = clipLon(satPos.longitude.toDegrees())
val osmPos = GeoPos(osmLat, osmLon)
val qthLoc = QthConverter.positionToQth(osmPos.latitude, osmPos.longitude) ?: "-- --"
val qthLoc = positionToQth(osmPos.latitude, osmPos.longitude) ?: "-- --"
val velocity = satPos.getOrbitalVelocity()
val phase = satPos.phase.toDegrees()
val visibility = satPos.eclipsed
@@ -88,9 +88,7 @@ fun PassesScreen(navToRadar: (Int, Long) -> Unit) {
contentDescription = null
)
}
Column(
verticalArrangement = Arrangement.SpaceEvenly, modifier = Modifier.weight(1f)
) {
Column(verticalArrangement = Arrangement.SpaceEvenly, modifier = Modifier.weight(1f)) {
Text(text = timerText.value?.first ?: "Null")
Text(text = timerText.value?.second ?: "Null")
}
@@ -50,7 +50,7 @@ class PassesViewModel(
fun getFilterSettings() = settingsRepo.passesSettings.value
fun shouldUseUTC() = settingsRepo.otherSettings.value.utcState
// fun shouldUseUTC() = settingsRepo.otherSettings.value.utcState
init {
viewModelScope.launch { satelliteRepo.initRepository() }
@@ -73,27 +73,25 @@ fun PullRefreshIndicator(
val showElevation by remember(refreshing, state) {
derivedStateOf { refreshing || state.position > 0.5f }
}
Surface(
modifier = modifier
.size(IndicatorSize)
.size(indicatorSize)
.pullRefreshIndicatorTransform(state, scale),
shape = SpinnerShape,
shape = spinnerShape,
color = backgroundColor,
shadowElevation = if (showElevation) Elevation else 0.dp,
shadowElevation = if (showElevation) elevation else 0.dp,
) {
Crossfade(
targetState = refreshing, animationSpec = tween(durationMillis = CrossfadeDurationMs)
targetState = refreshing,
animationSpec = tween(durationMillis = CROSSFADE_DURATION_MS),
label = "pullToRefresh"
) { refreshing ->
Box(
modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center
) {
val spinnerSize = (ArcRadius + StrokeWidth).times(2)
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
val spinnerSize = (arcRadius + strokeWidth).times(2)
if (refreshing) {
CircularProgressIndicator(
color = contentColor,
strokeWidth = StrokeWidth,
strokeWidth = strokeWidth,
modifier = Modifier.size(spinnerSize),
)
} else {
@@ -108,18 +106,12 @@ fun PullRefreshIndicator(
* Modifier.size MUST be specified.
*/
@Composable
private fun CircularArrowIndicator(
state: PullRefreshState,
color: Color,
modifier: Modifier,
) {
private fun CircularArrowIndicator(state: PullRefreshState, color: Color, modifier: Modifier) {
val path = remember { Path().apply { fillType = PathFillType.EvenOdd } }
Canvas(modifier.semantics { contentDescription = "Refreshing" }) {
val values = ArrowValues(state.progress)
rotate(degrees = values.rotation) {
val arcRadius = ArcRadius.toPx() + StrokeWidth.toPx() / 2f
val arcRadius = arcRadius.toPx() + strokeWidth.toPx() / 2f
val arcBounds = Rect(
size.center.x - arcRadius,
size.center.y - arcRadius,
@@ -134,9 +126,7 @@ private fun CircularArrowIndicator(
useCenter = false,
topLeft = arcBounds.topLeft,
size = arcBounds.size,
style = Stroke(
width = StrokeWidth.toPx(), cap = StrokeCap.Square
)
style = Stroke(width = strokeWidth.toPx(), cap = StrokeCap.Square)
)
drawArrow(path, arcBounds, color, values)
}
@@ -145,11 +135,7 @@ private fun CircularArrowIndicator(
@Immutable
private class ArrowValues(
val alpha: Float,
val rotation: Float,
val startAngle: Float,
val endAngle: Float,
val scale: Float
val alpha: Float, val rotation: Float, val startAngle: Float, val endAngle: Float, val scale: Float
)
private fun ArrowValues(progress: Float): ArrowValues {
@@ -164,7 +150,7 @@ private fun ArrowValues(progress: Float): ArrowValues {
// Calculations based on SwipeRefreshLayout specification.
val alpha = progress.coerceIn(0f, 1f)
val endTrim = adjustedPercent * MaxProgressArc
val endTrim = adjustedPercent * MAX_PROGRESS_ARC
val rotation = (-0.25f + 0.4f * adjustedPercent + tensionPercent) * 0.5f
val startAngle = rotation * 360
val endAngle = (rotation + endTrim) * 360
@@ -176,33 +162,26 @@ private fun ArrowValues(progress: Float): ArrowValues {
private fun DrawScope.drawArrow(arrow: Path, bounds: Rect, color: Color, values: ArrowValues) {
arrow.reset()
arrow.moveTo(0f, 0f) // Move to left corner
arrow.lineTo(x = ArrowWidth.toPx() * values.scale, y = 0f) // Line to right corner
arrow.lineTo(x = arrowWidth.toPx() * values.scale, y = 0f) // Line to right corner
// Line to tip of arrow
arrow.lineTo(
x = ArrowWidth.toPx() * values.scale / 2, y = ArrowHeight.toPx() * values.scale
)
arrow.lineTo(x = arrowWidth.toPx() * values.scale / 2, y = arrowHeight.toPx() * values.scale)
val radius = min(bounds.width, bounds.height) / 2f
val inset = ArrowWidth.toPx() * values.scale / 2f
arrow.translate(
Offset(
x = radius + bounds.center.x - inset, y = bounds.center.y + StrokeWidth.toPx() / 2f
)
)
val inset = arrowWidth.toPx() * values.scale / 2f
arrow.translate(Offset(x = radius + bounds.center.x - inset, y = bounds.center.y + strokeWidth.toPx() / 2f))
arrow.close()
rotate(degrees = values.endAngle) {
drawPath(path = arrow, color = color, alpha = values.alpha)
}
}
private const val CrossfadeDurationMs = 100
private const val MaxProgressArc = 0.8f
private val IndicatorSize = 40.dp
private val SpinnerShape = CircleShape
private val ArcRadius = 7.5.dp
private val StrokeWidth = 2.5.dp
private val ArrowWidth = 10.dp
private val ArrowHeight = 5.dp
private val Elevation = 6.dp
private const val CROSSFADE_DURATION_MS = 100
private const val MAX_PROGRESS_ARC = 0.8f
private val indicatorSize = 40.dp
private val spinnerShape = CircleShape
private val arcRadius = 7.5.dp
private val strokeWidth = 2.5.dp
private val arrowWidth = 10.dp
private val arrowHeight = 5.dp
private val elevation = 6.dp
@@ -49,12 +49,10 @@ fun Modifier.pullRefreshIndicatorTransform(
properties["scale"] = scale
}) {
var height by remember { mutableStateOf(0) }
Modifier
.onSizeChanged { height = it.height }
.graphicsLayer {
translationY = state.position - height
if (scale && !state.refreshing) {
val scaleFraction = LinearOutSlowInEasing
.transform(state.position / state.threshold)
@@ -95,9 +93,7 @@ fun Modifier.pullRefresh(
* [onPull] nor [onRelease] will be invoked.
*/
fun Modifier.pullRefresh(
onPull: (pullDelta: Float) -> Float,
onRelease: suspend (flingVelocity: Float) -> Unit,
enabled: Boolean = true
onPull: (pullDelta: Float) -> Float, onRelease: suspend (flingVelocity: Float) -> Unit, enabled: Boolean = true
) = inspectable(inspectorInfo = debugInspectorInfo {
name = "pullRefresh"
properties["onPull"] = onPull
@@ -113,17 +109,13 @@ private class PullRefreshNestedScrollConnection(
private val enabled: Boolean
) : NestedScrollConnection {
override fun onPreScroll(
available: Offset, source: NestedScrollSource
): Offset = when {
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset = when {
!enabled -> Offset.Zero
source == Drag && available.y < 0 -> Offset(0f, onPull(available.y)) // Swiping up
else -> Offset.Zero
}
override fun onPostScroll(
consumed: Offset, available: Offset, source: NestedScrollSource
): Offset = when {
override fun onPostScroll(consumed: Offset, available: Offset, source: NestedScrollSource): Offset = when {
!enabled -> Offset.Zero
source == Drag && available.y > 0 -> Offset(0f, onPull(available.y)) // Pulling down
else -> Offset.Zero
@@ -53,27 +53,18 @@ fun rememberPullRefreshState(
refreshingOffset: Dp = PullRefreshDefaults.RefreshingOffset,
): PullRefreshState {
require(refreshThreshold > 0.dp) { "The refresh trigger must be greater than zero!" }
val scope = rememberCoroutineScope()
val onRefreshState = rememberUpdatedState(onRefresh)
val thresholdPx: Float
val refreshingOffsetPx: Float
with(LocalDensity.current) {
thresholdPx = refreshThreshold.toPx()
refreshingOffsetPx = refreshingOffset.toPx()
}
// refreshThreshold and refreshingOffset should not be changed after instantiation, so any
// changes to these values are ignored.
val state = remember(scope) {
PullRefreshState(scope, onRefreshState, refreshingOffsetPx, thresholdPx)
}
SideEffect {
state.setRefreshing(refreshing)
}
val state = remember(scope) { PullRefreshState(scope, onRefreshState, refreshingOffsetPx, thresholdPx) }
SideEffect { state.setRefreshing(refreshing) }
return state
}
@@ -109,7 +100,7 @@ class PullRefreshState internal constructor(
internal val refreshing get() = _refreshing
internal val position get() = _position
private val adjustedDistancePulled by derivedStateOf { distancePulled * DragMultiplier }
private val adjustedDistancePulled by derivedStateOf { distancePulled * DRAG_MULTIPLIER }
private var _refreshing by mutableStateOf(false)
private var _position by mutableStateOf(0f)
@@ -189,4 +180,4 @@ object PullRefreshDefaults {
* the refresh threshold, it is the indicator position, otherwise the indicator position is
* derived from the progress).
*/
private const val DragMultiplier = 0.5f
private const val DRAG_MULTIPLIER = 0.5f
@@ -44,14 +44,9 @@ fun RadarScreen() {
modifier = Modifier.fillMaxSize()
) {
IconButton(onClick = {}) {
Icon(
painter = painterResource(id = R.drawable.ic_filter),
contentDescription = null
)
Icon(painter = painterResource(id = R.drawable.ic_filter), contentDescription = null)
}
Column(
verticalArrangement = Arrangement.SpaceEvenly, modifier = Modifier.weight(1f)
) {
Column(verticalArrangement = Arrangement.SpaceEvenly, modifier = Modifier.weight(1f)) {
Text(text = "Null")
Text(text = "Null")
}
@@ -109,10 +104,7 @@ private fun TransmitterItem(radio: SatRadio) {
.background(MaterialTheme.colorScheme.surface)
.padding(6.dp)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) {
Icon(
painter = painterResource(id = R.drawable.ic_arrow),
contentDescription = null, modifier = Modifier.rotate(180f)
@@ -127,10 +119,7 @@ private fun TransmitterItem(radio: SatRadio) {
contentDescription = null
)
}
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) {
Text(
text = stringResource(id = R.string.radio_downlink, radio.downlink ?: 0L),
textAlign = TextAlign.Center,
@@ -43,9 +43,9 @@ fun RadarViewCompose(item: SatPos, items: List<SatPos>, azimElev: Pair<Float, Fl
val primaryColor = Color(0xFFFFE082)
val secondaryColor = Color(0xFFDC0000)
val strokeWidth = 4f
val animTransition = rememberInfiniteTransition()
val animTransition = rememberInfiniteTransition(label = "animScale")
val animSpec = infiniteRepeatable<Float>(tween(1000))
val animScale = animTransition.animateFloat(16f, 64f, animSpec)
val animScale = animTransition.animateFloat(16f, 64f, animSpec, label = "animScale")
val measurer = rememberTextMeasurer()
val sweepDegrees = remember { mutableStateOf(0f) }
val trackCreated = remember { mutableStateOf(false) }
@@ -99,9 +99,9 @@ class RadarViewModel(
}
}
fun getUseCompass(): Boolean = settingsRepo.otherSettings.value.sensorState
fun getShowSweep(): Boolean = settingsRepo.otherSettings.value.sweepState
// fun getUseCompass(): Boolean = settingsRepo.otherSettings.value.sensorState
//
// fun getShowSweep(): Boolean = settingsRepo.otherSettings.value.sweepState
private fun getMagDeclination(geoPos: GeoPos, time: Long = System.currentTimeMillis()): Float {
val latitude = geoPos.latitude.toFloat()
@@ -1,7 +1,6 @@
package com.rtbishop.look4sat.presentation.settings
import android.Manifest
import android.os.Build
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.Arrangement
@@ -61,16 +60,16 @@ fun SettingsScreen() {
val context = LocalContext.current
// Permissions setup
val bluetoothContract = ActivityResultContracts.RequestPermission()
val bluetoothError = stringResource(R.string.BTremote_perm_error)
val bluetoothPerm = when {
Build.VERSION.SDK_INT < Build.VERSION_CODES.S -> Manifest.permission.BLUETOOTH
else -> Manifest.permission.BLUETOOTH_CONNECT
}
val bluetoothRequest = rememberLauncherForActivityResult(bluetoothContract) { isGranted ->
// val bluetoothContract = ActivityResultContracts.RequestPermission()
// val bluetoothError = stringResource(R.string.BTremote_perm_error)
// val bluetoothPerm = when {
// Build.VERSION.SDK_INT < Build.VERSION_CODES.S -> Manifest.permission.BLUETOOTH
// else -> Manifest.permission.BLUETOOTH_CONNECT
// }
// val bluetoothRequest = rememberLauncherForActivityResult(bluetoothContract) { isGranted ->
// viewModel.setBTEnabled(isGranted)
if (!isGranted) showToast(context, bluetoothError)
}
// if (!isGranted) showToast(context, bluetoothError)
// }
val locationContract = ActivityResultContracts.RequestMultiplePermissions()
val locationError = stringResource(R.string.location_gps_error)
val locationPermCoarse = Manifest.permission.ACCESS_COARSE_LOCATION
@@ -119,9 +118,7 @@ fun SettingsScreen() {
val toggleSensor = { value: Boolean -> viewModel.toggleSensor(value) }
// Screen setup
LazyColumn(
modifier = Modifier.padding(6.dp), verticalArrangement = Arrangement.spacedBy(6.dp)
) {
LazyColumn(modifier = Modifier.padding(6.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) {
item { CardAbout(BuildConfig.VERSION_NAME) }
item { LocationCard(positionSettings, setGpsPos, showPosDialog, showLocDialog, dismissPos) }
item { DataCard(dataSettings, updateFromWeb, updateFromFile, clearAllData) }
@@ -376,8 +373,7 @@ private fun DataCard(
@Preview(showBackground = true)
@Composable
private fun OtherCardPreview() = MainTheme {
val values =
OtherSettings(utcState = false, updateState = true, sweepState = true, sensorState = true)
val values = OtherSettings(utcState = false, updateState = true, sweepState = true, sensorState = true)
OtherCard(settings = values, {}, {}, {}, {})
}
@@ -4,6 +4,4 @@ import com.rtbishop.look4sat.domain.predict.GeoPos
data class PositionSettings(val isUpdating: Boolean, val stationPos: GeoPos, val messageResId: Int)
data class DataSettings(
val isUpdating: Boolean, val entriesTotal: Int, val radiosTotal: Int, val timestamp: Long
)
data class DataSettings(val isUpdating: Boolean, val entriesTotal: Int, val radiosTotal: Int, val timestamp: Long)
@@ -106,7 +106,7 @@ class SettingsViewModel(
fun updateFromWeb() = viewModelScope.launch {
try {
_dataSettings.value = _dataSettings.value.copy(isUpdating = true)
databaseRepo.updateFromWeb()
databaseRepo.updateFromRemote()
} catch (exception: Exception) {
_dataSettings.value = _dataSettings.value.copy(isUpdating = false)
println(exception.printStackTrace())
-2
View File
@@ -147,8 +147,6 @@
<string name="data_success">යාවත්කාලීනය සම්පූර්ණ කිරීම සාර්ථකයි</string>
<string name="data_clear_success">දත්ත ඉවත් කිරීම සාර්ථකයි</string>
<string name="last_updated_pattern" translatable="false">d MMM yyyy - HH:mm:ss</string>
<string name="remote_title">භ්‍රමක මනාප</string>
<string name="remote_switch">දුරස්ථ පාලනය සබල ක°</string>
<string name="remote_ip_hint">IP ලිපිනය</string>