Switched to a different maps tile source

This commit is contained in:
Arty Bishop committed 2025-12-27 15:01:33 +00:00
1 parent 4c13cc98a1
commit 942c7ce65f
7 files changed
+76 -84

No files matched your search

+1 -3
View File
@@ -70,15 +70,13 @@ dependencies {
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version"
implementation "androidx.navigation:navigation-compose:$navigation_version" implementation "androidx.navigation:navigation-compose:$navigation_version"
// Utility // Utility
implementation "com.jakewharton.timber:timber:$timber_version"
implementation "org.osmdroid:osmdroid-android:$osmdroid_version" implementation "org.osmdroid:osmdroid-android:$osmdroid_version"
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version" debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version" debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
debugImplementation "com.squareup.leakcanary:leakcanary-android:$leakcanary_version" debugImplementation "com.squareup.leakcanary:leakcanary-android:$leakcanary_version"
// Test // Test
testImplementation "junit:junit:$junit_version" testImplementation "junit:junit:$junit_version"
testImplementation "org.mockito:mockito-core:$mockito_version" testImplementation "io.mockk:mockk:$mockk_version"
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_test_version" testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_test_version"
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version" androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
androidTestImplementation "org.mockito:mockito-android:$mockito_version"
} }
@@ -18,7 +18,6 @@
package com.rtbishop.look4sat package com.rtbishop.look4sat
import android.app.Application import android.app.Application
import timber.log.Timber
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
@@ -30,9 +29,6 @@ class MainApplication : Application() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
container = MainContainer(this) container = MainContainer(this)
if (BuildConfig.DEBUG) {
Timber.plant(Timber.DebugTree())
}
checkAutoUpdate() checkAutoUpdate()
} }
@@ -42,7 +38,7 @@ class MainApplication : Application() {
val timeDelta = System.currentTimeMillis() - settingsRepository.getLastUpdateTime() val timeDelta = System.currentTimeMillis() - settingsRepository.getLastUpdateTime()
if (timeDelta > 172800000) { // 48 hours in ms if (timeDelta > 172800000) { // 48 hours in ms
val sdf = SimpleDateFormat("d MMM yyyy - HH:mm:ss", Locale.getDefault()) val sdf = SimpleDateFormat("d MMM yyyy - HH:mm:ss", Locale.getDefault())
Timber.d("Started periodic data update on ${sdf.format(Date())}") println("Started periodic data update on ${sdf.format(Date())}")
container.dataRepository.updateFromWeb() container.dataRepository.updateFromWeb()
} }
} }
@@ -29,7 +29,6 @@ import com.rtbishop.look4sat.utility.QthConverter
import com.rtbishop.look4sat.utility.round import com.rtbishop.look4sat.utility.round
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import timber.log.Timber
import java.util.concurrent.Executors import java.util.concurrent.Executors
class SettingsRepository( class SettingsRepository(
@@ -73,12 +72,12 @@ class SettingsRepository(
try { try {
val criteria = Criteria().apply { isCostAllowed = true } val criteria = Criteria().apply { isCostAllowed = true }
val provider = manager.getBestProvider(criteria, true) ?: defaultProvider val provider = manager.getBestProvider(criteria, true) ?: defaultProvider
Timber.d("Requesting location for $provider provider") println("Requesting location for $provider provider")
LocationManagerCompat.getCurrentLocation(manager, provider, timeoutSignal, executor) { LocationManagerCompat.getCurrentLocation(manager, provider, timeoutSignal, executor) {
it?.let { setGeoPosition(it.latitude, it.longitude, it.altitude) } it?.let { setGeoPosition(it.latitude, it.longitude, it.altitude) }
} }
} catch (exception: SecurityException) { } catch (exception: SecurityException) {
Timber.d("No permissions were given") println("No permissions were given")
} }
return true return true
} }
@@ -119,7 +118,7 @@ class SettingsRepository(
val newLon = longitude.round(4) val newLon = longitude.round(4)
val newAlt = altitude.round(1) val newAlt = altitude.round(1)
val timestamp = System.currentTimeMillis() val timestamp = System.currentTimeMillis()
Timber.d("Received new Position($newLat, $newLon, $newAlt) & Locator $locator") println("Received new Position($newLat, $newLon, $newAlt) & Locator $locator")
saveStationPosition(GeoPos(newLat, newLon, newAlt, locator, timestamp)) saveStationPosition(GeoPos(newLat, newLon, newAlt, locator, timestamp))
} }
@@ -13,38 +13,62 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
private val AccentYellow = Color(0xFFFFE082) @Composable
private val TextWhite = Color(0xCCFFFFFF) fun MainTheme(
private val TextGrey = Color(0x66FFFFFF) // darkTheme: Boolean = isSystemInDarkTheme(),
private val TextBlack = Color(0xFF000000) // dynamicColor: Boolean = false,
private val SurfaceInverse = Color(0x40FFFFFF) content: @Composable () -> Unit
private val SurfaceBtn = Color(0xFF303030) ) {
private val SurfaceCard = Color(0xFF1C1C1C) // val colorScheme = when {
private val SurfaceBg = Color(0xFF121212) // dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
private val Transparent = Color(0x00000000) // val context = LocalContext.current
// if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
// }
// darkTheme -> DarkColorScheme
// else -> LightColorScheme
// }
val colors = themeColors
// val view = LocalView.current
// if (!view.isInEditMode) {
// SideEffect {
// (view.context as Activity).window.statusBarColor = colorScheme.primary.toArgb()
// ViewCompat.getWindowInsetsController(view)?.isAppearanceLightStatusBars = darkTheme
// }
// }
MaterialTheme(colorScheme = colors, typography = typography, content = content, shapes = shapes)
}
private val MainColors = lightColorScheme( private val accentYellow = Color(0xFFFFE082)
primary = AccentYellow, private val textWhite = Color(0xCCFFFFFF)
onPrimary = TextBlack, private val textGrey = Color(0x66FFFFFF)
private val textBlack = Color(0xFF000000)
private val surfaceInverse = Color(0x40FFFFFF)
private val surfaceBtn = Color(0xFF303030)
private val surfaceCard = Color(0xFF1C1C1C)
private val surfaceBg = Color(0xFF121212)
private val transparent = Color(0x00000000)
private val themeColors = lightColorScheme(
primary = accentYellow,
onPrimary = textBlack,
// primaryContainer = primaryContainer, // primaryContainer = primaryContainer,
// onPrimaryContainer = onPrimaryContainer, // onPrimaryContainer = onPrimaryContainer,
// inversePrimary = inversePrimary, // inversePrimary = inversePrimary,
secondary = AccentYellow, secondary = accentYellow,
onSecondary = TextBlack, onSecondary = textBlack,
secondaryContainer = AccentYellow, // navBar indicator secondaryContainer = accentYellow, // navBar indicator
onSecondaryContainer = TextBlack, // navBar active icon onSecondaryContainer = textBlack, // navBar active icon
tertiary = SurfaceBtn, tertiary = surfaceBtn,
onTertiary = TextWhite, onTertiary = textWhite,
// tertiaryContainer = tertiaryContainer, // tertiaryContainer = tertiaryContainer,
// onTertiaryContainer = onTertiaryContainer, // onTertiaryContainer = onTertiaryContainer,
background = SurfaceBg, background = surfaceBg,
onBackground = TextWhite, onBackground = textWhite,
surface = SurfaceCard, surface = surfaceCard,
onSurface = TextWhite, onSurface = textWhite,
surfaceVariant = SurfaceCard, surfaceVariant = surfaceCard,
onSurfaceVariant = TextGrey, // navBar inactive icon onSurfaceVariant = textGrey, // navBar inactive icon
surfaceTint = Transparent, surfaceTint = transparent,
inverseSurface = SurfaceInverse, inverseSurface = surfaceInverse,
// inverseOnSurface = inverseOnSurface, // inverseOnSurface = inverseOnSurface,
// error = error, // error = error,
// onError = onError, // onError = onError,
@@ -55,7 +79,7 @@ private val MainColors = lightColorScheme(
// scrim = scrim, // scrim = scrim,
) )
private val Typography = Typography( private val typography = Typography(
bodyLarge = TextStyle( bodyLarge = TextStyle(
fontFamily = FontFamily.Default, fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal, fontWeight = FontWeight.Normal,
@@ -77,33 +101,8 @@ private val Typography = Typography(
) )
) )
private val Shapes = Shapes( private val shapes = Shapes(
extraSmall = RoundedCornerShape(4.dp), small = RoundedCornerShape(6.dp), // buttons corners extraSmall = RoundedCornerShape(4.dp), small = RoundedCornerShape(6.dp), // buttons corners
medium = RoundedCornerShape(8.dp), // cards corners medium = RoundedCornerShape(8.dp), // cards corners
large = RoundedCornerShape(12.dp), extraLarge = RoundedCornerShape(16.dp) large = RoundedCornerShape(12.dp), extraLarge = RoundedCornerShape(16.dp)
) )
@Composable
fun MainTheme(
// darkTheme: Boolean = isSystemInDarkTheme(),
// dynamicColor: Boolean = false,
content: @Composable () -> Unit
) {
// val colorScheme = when {
// dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
// val context = LocalContext.current
// if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
// }
// darkTheme -> DarkColorScheme
// else -> LightColorScheme
// }
val colors = MainColors
// val view = LocalView.current
// if (!view.isInEditMode) {
// SideEffect {
// (view.context as Activity).window.statusBarColor = colorScheme.primary.toArgb()
// ViewCompat.getWindowInsetsController(view)?.isAppearanceLightStatusBars = darkTheme
// }
// }
MaterialTheme(colorScheme = colors, typography = Typography, content = content, shapes = Shapes)
}
@@ -33,14 +33,13 @@ import com.rtbishop.look4sat.domain.Satellite
import com.rtbishop.look4sat.model.GeoPos import com.rtbishop.look4sat.model.GeoPos
import com.rtbishop.look4sat.model.SatPos import com.rtbishop.look4sat.model.SatPos
import org.osmdroid.config.Configuration import org.osmdroid.config.Configuration
import org.osmdroid.tileprovider.tilesource.TileSourceFactory import org.osmdroid.tileprovider.tilesource.XYTileSource
import org.osmdroid.util.GeoPoint import org.osmdroid.util.GeoPoint
import org.osmdroid.views.CustomZoomButtonsController import org.osmdroid.views.CustomZoomButtonsController
import org.osmdroid.views.MapView import org.osmdroid.views.MapView
import org.osmdroid.views.overlay.FolderOverlay import org.osmdroid.views.overlay.FolderOverlay
import org.osmdroid.views.overlay.Marker import org.osmdroid.views.overlay.Marker
import org.osmdroid.views.overlay.Polyline import org.osmdroid.views.overlay.Polyline
import timber.log.Timber
private val minLat = MapView.getTileSystem().minLatitude private val minLat = MapView.getTileSystem().minLatitude
private val maxLat = MapView.getTileSystem().maxLatitude private val maxLat = MapView.getTileSystem().maxLatitude
@@ -59,7 +58,7 @@ private val footprintPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
textSize = 36f textSize = 36f
style = Paint.Style.FILL style = Paint.Style.FILL
color = Color.parseColor("#CCFFFFFF") color = Color.parseColor("#FFE082")
setShadowLayer(3f, 3f, 3f, Color.BLACK) setShadowLayer(3f, 3f, 3f, Color.BLACK)
} }
private val labelRect = Rect() private val labelRect = Rect()
@@ -76,11 +75,9 @@ fun MapScreen() {
val satTrack = viewModel.track.collectAsState(initial = null) val satTrack = viewModel.track.collectAsState(initial = null)
val footprint = viewModel.footprint.collectAsState(initial = null) val footprint = viewModel.footprint.collectAsState(initial = null)
val positionClick = { satellite: Satellite -> viewModel.selectSatellite(satellite) } val positionClick = { satellite: Satellite -> viewModel.selectSatellite(satellite) }
Timber.d("MapScreen recomposition")
Column(modifier = Modifier.padding(6.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) { Column(modifier = Modifier.padding(6.dp), verticalArrangement = Arrangement.spacedBy(6.dp)) {
ElevatedCard(modifier = Modifier.fillMaxSize()) { ElevatedCard(modifier = Modifier.fillMaxSize()) {
MapView(modifier = Modifier.fillMaxSize()) { mapView -> MapView(modifier = Modifier.fillMaxSize()) { mapView ->
Timber.d("MapView recomposition")
stationPos.value?.let { setStationPosition(it, mapView) } stationPos.value?.let { setStationPosition(it, mapView) }
positions.value?.let { setPositions(it, mapView, positionClick) } positions.value?.let { setPositions(it, mapView, positionClick) }
satTrack.value?.let { setSatelliteTrack(it, mapView) } satTrack.value?.let { setSatelliteTrack(it, mapView) }
@@ -101,7 +98,7 @@ private fun setStationPosition(stationPos: GeoPos, mapView: MapView) {
mapView.invalidate() mapView.invalidate()
} }
} catch (exception: Exception) { } catch (exception: Exception) {
Timber.d(exception) println(exception)
} }
} }
@@ -130,13 +127,13 @@ private fun setPositions(
mapView.overlays[3] = markers mapView.overlays[3] = markers
mapView.invalidate() mapView.invalidate()
} catch (exception: Exception) { } catch (exception: Exception) {
Timber.d(exception) println(exception)
} }
} }
private fun getCustomTextIcon(textLabel: String, mapView: MapView): Drawable { private fun getCustomTextIcon(textLabel: String, mapView: MapView): Drawable {
textPaint.getTextBounds(textLabel, 0, textLabel.length, labelRect) textPaint.getTextBounds(textLabel, 0, textLabel.length, labelRect)
val iconSize = 8f val iconSize = 10f
val width = labelRect.width() + iconSize * 2f val width = labelRect.width() + iconSize * 2f
val height = textPaint.textSize * 3f + iconSize * 2f val height = textPaint.textSize * 3f + iconSize * 2f
val bitmap = Bitmap.createBitmap(width.toInt(), height.toInt(), Bitmap.Config.ARGB_8888) val bitmap = Bitmap.createBitmap(width.toInt(), height.toInt(), Bitmap.Config.ARGB_8888)
@@ -161,7 +158,7 @@ private fun setSatelliteTrack(satTrack: List<List<GeoPos>>, mapView: MapView) {
} }
mapView.overlays[1] = trackOverlay mapView.overlays[1] = trackOverlay
} catch (exception: Exception) { } catch (exception: Exception) {
Timber.d(exception) println(exception)
} }
// mapView.controller.animateTo(center) // mapView.controller.animateTo(center)
} }
@@ -175,7 +172,7 @@ private fun setFootprint(satPos: SatPos, mapView: MapView) {
} }
mapView.overlays[2] = footprintOverlay mapView.overlays[2] = footprintOverlay
} catch (exception: Exception) { } catch (exception: Exception) {
Timber.d(exception) println(exception)
} }
} }
@@ -214,10 +211,10 @@ private fun rememberMapViewWithLifecycle(): MapView {
val context = LocalContext.current val context = LocalContext.current
val mapView = remember { MapView(context) }.apply { val mapView = remember { MapView(context) }.apply {
setMultiTouchControls(true) setMultiTouchControls(true)
setTileSource(TileSourceFactory.WIKIMEDIA) setTileSource(tonerLiteTileSource)
minZoomLevel = getMinZoom(resources.displayMetrics.heightPixels) + 0.25 minZoomLevel = getMinZoom(resources.displayMetrics.heightPixels) + 0.25
maxZoomLevel = 5.75 maxZoomLevel = 5.99
controller.setZoom(minZoomLevel + 0.25) controller.setZoom(minZoomLevel + 0.5)
zoomController.setVisibility(CustomZoomButtonsController.Visibility.NEVER) zoomController.setVisibility(CustomZoomButtonsController.Visibility.NEVER)
overlayManager.tilesOverlay.loadingBackgroundColor = Color.TRANSPARENT overlayManager.tilesOverlay.loadingBackgroundColor = Color.TRANSPARENT
overlayManager.tilesOverlay.loadingLineColor = Color.TRANSPARENT overlayManager.tilesOverlay.loadingLineColor = Color.TRANSPARENT
@@ -247,14 +244,18 @@ private fun rememberMapViewLifecycleObserver(mapView: MapView) = remember(mapVie
} }
} }
private val tonerLiteTileSource = XYTileSource(
"Stamen", 0, 6, 256, ".png",
arrayOf("https://stamen-tiles.a.ssl.fastly.net/toner-lite/"),
"Map tiles by Stamen Design, under CC BY 3.0. Data by OpenStreetMap, under ODbL."
)
private fun getColorFilter(): ColorMatrixColorFilter { private fun getColorFilter(): ColorMatrixColorFilter {
val grayScaleMatrix = ColorMatrix().apply { setSaturation(0f) }
val negativeMatrix = ColorMatrix( val negativeMatrix = ColorMatrix(
floatArrayOf( floatArrayOf(
-1f, 0f, 0f, 0f, 255f, 0f, -1f, 0f, 0f, 255f, 0f, 0f, -1f, 0f, 255f, 0f, 0f, 0f, 1f, 0f -1f, 0f, 0f, 0f, 260f, 0f, -1f, 0f, 0f, 260f, 0f, 0f, -1f, 0f, 260f, 0f, 0f, 0f, 1f, 0f
) )
) )
negativeMatrix.preConcat(grayScaleMatrix)
return ColorMatrixColorFilter(negativeMatrix) return ColorMatrixColorFilter(negativeMatrix)
} }
+1 -1
View File
@@ -11,6 +11,6 @@ dependencies {
implementation "org.json:json:$json_version" implementation "org.json:json:$json_version"
testImplementation "junit:junit:$junit_version" testImplementation "junit:junit:$junit_version"
testImplementation "org.mockito:mockito-core:$mockito_version" testImplementation "io.mockk:mockk:$mockk_version"
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_test_version" testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_test_version"
} }
+1 -2
View File
@@ -15,13 +15,12 @@ buildscript {
lifecycle_version = '2.6.0' lifecycle_version = '2.6.0'
navigation_version = '2.5.3' navigation_version = '2.5.3'
// Utility // Utility
timber_version = '5.0.1'
osmdroid_version = '6.1.14' osmdroid_version = '6.1.14'
json_version = '20230227' json_version = '20230227'
leakcanary_version = '2.10' leakcanary_version = '2.10'
// Test // Test
junit_version = '4.13.2' junit_version = '4.13.2'
mockito_version = '5.2.0' mockk_version = '1.13.4'
coroutines_test_version = '1.6.4' coroutines_test_version = '1.6.4'
} }
} }