Stabilize globe quality selector layout

This commit is contained in:
a1denvalu3 2026-07-30 15:09:29 +02:00
parent 8602db88de
commit 6fc4583a15
4 changed files with 57 additions and 14 deletions

View File

@ -95,13 +95,18 @@ class GeohashPickerActivity : OrientationAwareActivity() {
BitchatTheme {
val context = LocalContext.current
val scope = rememberCoroutineScope()
val initialRenderQuality = remember(context) {
GlobeRenderQualityPreference.load(context)
}
var renderQuality by remember { mutableStateOf(initialRenderQuality) }
val globeState = remember {
GlobeState(
targetLat = targetLat,
targetLon = targetLon,
initialPrecision = initialPrecision,
startZoomedOut = true
startZoomedOut = true,
initialRenderQuality = initialRenderQuality
).apply {
introTarget = Triple(targetLat, targetLon, initialPrecision)
}
@ -157,9 +162,6 @@ class GeohashPickerActivity : OrientationAwareActivity() {
val labelTypeface = remember { ResourcesCompat.getFont(context, R.font.geist_mono_medium) }
val labelTypefaceBold = remember { ResourcesCompat.getFont(context, R.font.geist_mono_semibold) }
var renderQuality by remember {
mutableStateOf(GlobeRenderQualityPreference.load(context))
}
Box(
Modifier
@ -173,7 +175,6 @@ class GeohashPickerActivity : OrientationAwareActivity() {
land = rings,
borders = borders,
cities = cities,
renderQuality = renderQuality,
labelTypeface = labelTypeface,
labelTypefaceBold = labelTypefaceBold,
modifier = Modifier.fillMaxSize()
@ -210,9 +211,11 @@ class GeohashPickerActivity : OrientationAwareActivity() {
modifier = Modifier.fillMaxWidth()
) {
qualities.forEachIndexed { index, quality ->
val selected = renderQuality == quality
SegmentedButton(
selected = renderQuality == quality,
selected = selected,
onClick = {
globeState.setRenderQuality(quality)
renderQuality = quality
GlobeRenderQualityPreference.save(context, quality)
},
@ -220,12 +223,27 @@ class GeohashPickerActivity : OrientationAwareActivity() {
index = index,
count = qualities.size
),
icon = {},
label = {
Text(
text = stringResource(quality.labelResource),
fontSize = 11.sp,
fontFamily = BitchatFontFamily
)
Box(
modifier = Modifier.fillMaxWidth(),
contentAlignment = Alignment.Center
) {
if (selected) {
Icon(
imageVector = Icons.Filled.Check,
contentDescription = null,
modifier = Modifier
.align(Alignment.CenterStart)
.size(18.dp)
)
}
Text(
text = stringResource(quality.labelResource),
fontSize = 11.sp,
fontFamily = BitchatFontFamily
)
}
}
)
}

View File

@ -28,7 +28,8 @@ class GlobeState(
targetLat: Double,
targetLon: Double,
initialPrecision: Int,
startZoomedOut: Boolean
startZoomedOut: Boolean,
initialRenderQuality: GlobeRenderQuality = GlobeRenderQuality.MEDIUM
) {
var centerLat by mutableFloatStateOf(if (startZoomedOut) (targetLat * 0.4).toFloat() else targetLat.toFloat())
private set
@ -47,6 +48,8 @@ class GlobeState(
internal var baseRadiusPx by mutableFloatStateOf(0f)
internal var screenMinPx by mutableFloatStateOf(0f)
internal var renderQuality = initialRenderQuality
private set
private var scope: CoroutineScope? = null
private var animJob: Job? = null
@ -68,6 +71,14 @@ class GlobeState(
this.scope = scope
}
/**
* Rendering quality only affects moving frames. This is deliberately not snapshot state:
* changing it must not invalidate the expensive stationary globe beneath the selector.
*/
fun setRenderQuality(quality: GlobeRenderQuality) {
renderQuality = quality
}
fun setViewport(baseRadiusPx: Float, screenMinPx: Float) {
if (baseRadiusPx <= 0f || screenMinPx <= 0f) return
this.baseRadiusPx = baseRadiusPx

View File

@ -119,7 +119,6 @@ fun GlobeView(
land: List<LandData.Ring>,
borders: List<LandData.Ring>,
cities: List<LandData.City>,
renderQuality: GlobeRenderQuality,
labelTypeface: Typeface?,
labelTypefaceBold: Typeface?,
modifier: Modifier = Modifier
@ -324,7 +323,7 @@ fun GlobeView(
val clip = ClipRect(-size.width, -size.height, size.width * 2f, size.height * 2f)
val frameDetail = globeFrameDetail(renderQuality, state.isInMotion)
val frameDetail = globeFrameDetail(state.renderQuality, state.isInMotion)
// Graticule
drawGraticule(

View File

@ -14,6 +14,21 @@ class GlobeRenderQualityTest {
assertEquals(GlobeRenderQuality.MEDIUM, GlobeRenderQuality.fromStoredValue("UNKNOWN"))
}
@Test
fun globeState_usesAndUpdatesRenderQualityWithoutReplacingState() {
val state = GlobeState(
targetLat = 0.0,
targetLon = 0.0,
initialPrecision = 2,
startZoomedOut = false,
initialRenderQuality = GlobeRenderQuality.FAST
)
assertEquals(GlobeRenderQuality.FAST, state.renderQuality)
state.setRenderQuality(GlobeRenderQuality.HIGH)
assertEquals(GlobeRenderQuality.HIGH, state.renderQuality)
}
@Test
fun stationaryFrame_alwaysUsesFullDetail() {
GlobeRenderQuality.entries.forEach { quality ->