From 54966f91246608ae87fe272eb26d16aa2e9d89c5 Mon Sep 17 00:00:00 2001 From: Damontecres Date: Wed, 12 Aug 2026 21:01:28 -0400 Subject: [PATCH] Handle density configuration changes to prevent unnecessary app restarts (#1828) ## Description Add `density` to `configChanges` and handle any changes to density that occur. Thankfully, Compose handles density changes itself, so only changes where a density calculation is "remembered" needed to be updated. Without this, some devices will recreate `MainActivity` when switching resolutions for playback. That recreation would cause playback to end immediately. ### Related issues Fixes #1809 ### Testing Tested on Onn 4k Pro & nvidia shield I was able to reproduce on the Onn, but not the Shield, so this might be device and/or API level specific ## Screenshots N/A ## AI or LLM usage None --- app/src/main/AndroidManifest.xml | 2 +- .../github/damontecres/wholphin/MainActivity.kt | 2 +- .../damontecres/wholphin/ui/cards/BannerCard.kt | 2 +- .../damontecres/wholphin/ui/cards/ChapterCard.kt | 2 +- .../ui/components/CollectionFolderGrid.kt | 2 +- .../wholphin/ui/components/GenreCardGrid.kt | 2 +- .../wholphin/ui/components/StudioCardGrid.kt | 2 +- .../wholphin/ui/detail/PlaylistDetails.kt | 2 +- .../ui/detail/collection/CollectionMixedGrid.kt | 2 +- .../wholphin/ui/playback/PlaybackPage.kt | 6 +++++- .../wholphin/ui/playback/PlaybackViewModel.kt | 15 +++++++++++++++ .../ui/playback/overlay/PlaybackOverlay.kt | 4 ++-- 12 files changed, 31 insertions(+), 12 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5a5994ae..6036dabd 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -51,7 +51,7 @@ android:name=".MainActivity" android:exported="true" android:launchMode="singleTask" - android:configChanges="keyboard|keyboardHidden|navigation|orientation|screenSize|screenLayout|smallestScreenSize"> + android:configChanges="keyboard|keyboardHidden|navigation|orientation|screenSize|screenLayout|smallestScreenSize|density"> diff --git a/app/src/main/java/com/github/damontecres/wholphin/MainActivity.kt b/app/src/main/java/com/github/damontecres/wholphin/MainActivity.kt index 73ad2cbc..9fa76ea0 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/MainActivity.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/MainActivity.kt @@ -380,7 +380,7 @@ class MainActivity : AppCompatActivity() { override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) - Timber.d("onConfigurationChanged") + Timber.d("onConfigurationChanged: newConfig=%s", newConfig) } override fun onNewIntent(intent: Intent) { diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/cards/BannerCard.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/cards/BannerCard.kt index d4d2ac50..4536a364 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/cards/BannerCard.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/cards/BannerCard.kt @@ -73,7 +73,7 @@ fun BannerCard( val imageUrlService = LocalImageUrlService.current val density = LocalDensity.current val fillHeight = - remember(cardHeight) { + remember(cardHeight, density) { if (cardHeight.isSpecified) { with(density) { cardHeight.roundToPx() diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/cards/ChapterCard.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/cards/ChapterCard.kt index 634cc988..34966e43 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/cards/ChapterCard.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/cards/ChapterCard.kt @@ -49,7 +49,7 @@ fun ChapterCard( val density = LocalDensity.current val imageUrlService = LocalImageUrlService.current val imageUrl = - remember(chapter, cardHeight) { + remember(chapter, cardHeight, density) { imageUrlService.getItemImageUrl( itemId = chapter.itemId, imageType = ImageType.CHAPTER, diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderGrid.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderGrid.kt index bdf454a8..0493629b 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderGrid.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderGrid.kt @@ -114,7 +114,7 @@ fun CollectionFolderGrid( columns = viewOptions.columns, spacing = viewOptions.spacing.dp, bringIntoViewSpec = - remember(viewOptions) { + remember(viewOptions, density) { val spacingPx = with(density) { viewOptions.spacing.dp.toPx() } if (viewOptions.showDetails) { ScrollToTopBringIntoViewSpec(spacingPx) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/GenreCardGrid.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/GenreCardGrid.kt index aeae3fd7..17133f4d 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/GenreCardGrid.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/GenreCardGrid.kt @@ -275,7 +275,7 @@ fun GenreCardGrid( val density = LocalDensity.current val configuration = LocalConfiguration.current val cardWidthPx = - remember { + remember(density) { with(density) { // Grid has 16dp padding on either side & 16dp spacing between 4 cards // This isn't exact though because it doesn't account for nav drawer or letters, but it's close and the calculation is much faster diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/StudioCardGrid.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/StudioCardGrid.kt index 461d1d94..78f2cbd3 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/StudioCardGrid.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/StudioCardGrid.kt @@ -166,7 +166,7 @@ fun StudioCardGrid( val density = LocalDensity.current val configuration = LocalConfiguration.current val cardWidthPx = - remember { + remember(density) { with(density) { // Grid has 16dp padding on either side & 16dp spacing between 4 cards // This isn't exact though because it doesn't account for nav drawer or letters, but it's close and the calculation is much faster diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/PlaylistDetails.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/PlaylistDetails.kt index 1e570c61..715104f5 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/PlaylistDetails.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/PlaylistDetails.kt @@ -796,7 +796,7 @@ fun PlaylistItem( val focused by interactionSource.collectIsFocusedAsState() val imageWidth = 160.dp val density = LocalDensity.current - val imageWidthPx = remember(imageWidth) { with(density) { imageWidth.roundToPx() } } + val imageWidthPx = remember(imageWidth, density) { with(density) { imageWidth.roundToPx() } } ListItem( selected = false, onClick = onClick, diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/collection/CollectionMixedGrid.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/collection/CollectionMixedGrid.kt index 757b4cf9..057c6db2 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/collection/CollectionMixedGrid.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/collection/CollectionMixedGrid.kt @@ -76,7 +76,7 @@ fun CollectionMixedGrid( columns = cardViewOptions.columns, spacing = cardViewOptions.spacing.dp, bringIntoViewSpec = - remember(cardViewOptions) { + remember(cardViewOptions, density) { val spacingPx = with(density) { cardViewOptions.spacing.dp.toPx() } if (cardViewOptions.showDetails) { ScrollToTopBringIntoViewSpec(spacingPx) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackPage.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackPage.kt index e428546f..209e8473 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackPage.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackPage.kt @@ -165,6 +165,7 @@ fun PlaybackPageContent( val prefs = preferences.appPreferences.playbackPreferences val scope = rememberCoroutineScope() val density = LocalDensity.current + LaunchedEffect(density) { viewModel.updateDensity(density) } val userDto by viewModel.currentUserDto.collectAsState() var showDebugInfo by remember { mutableStateOf(prefs.showDebugInfo) } @@ -504,7 +505,9 @@ fun PlaybackPageContent( val subtitleMaxSize by animateFloatAsState(if (controllerViewState.controlsVisible) .7f else 1f) val isImageSubtitles = remember(state.subtitleCues) { state.subtitleCues.firstOrNull()?.bitmap != null } - var cueCount by remember { mutableIntStateOf(0) } + + // Reset cueCount when density changes to force re-applying subtitle style + var cueCount by remember(density) { mutableIntStateOf(0) } val subtitleVisible = skipIndicatorDuration == 0L && @@ -540,6 +543,7 @@ fun PlaybackPageContent( } subtitleView.setCues(state.subtitleCues) if (state.subtitleCues.size > cueCount) { + Timber.i("Applying subtitle style to SubtitleView") // The output creates a painter for each cue, so need to apply the changes when the number of cues increases Media3SubtitleOverride(subtitleSettings.calculateEdgeSize(density)) .apply(subtitleView) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackViewModel.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackViewModel.kt index ceade4c0..009f3cc2 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackViewModel.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/PlaybackViewModel.kt @@ -1636,6 +1636,21 @@ class PlaybackViewModel } } + fun updateDensity(density: Density) { + Timber.d("Density changed") + viewModelScope.launchDefault { + val availableCommands = onMain { player.availableCommands } + if (availableCommands.contains(Player.COMMAND_PREPARE) && player is MpvPlayer) { + Timber.i("Applying density change for subtitle config to MPV") + val configuration = context.resources.configuration + preferences.appPreferences.interfacePreferences.subtitlesPreferences.applyToMpv( + configuration, + density, + ) + } + } + } + override fun onBandwidthEstimate( eventTime: AnalyticsListener.EventTime, totalLoadTimeMs: Int, diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/PlaybackOverlay.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/PlaybackOverlay.kt index 5f5891de..a1a83df6 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/PlaybackOverlay.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/PlaybackOverlay.kt @@ -100,11 +100,11 @@ fun PlaybackOverlay( val density = LocalDensity.current val titleHeight = - remember(item?.title) { + remember(item?.title, density) { if (item?.title.isNotNullOrBlank()) with(density) { titleTextSize.toDp() } else 0.dp } val subtitleHeight = - remember(item?.subtitleLong) { + remember(item?.subtitleLong, density) { if (item?.subtitleLong.isNotNullOrBlank()) with(density) { subtitleTextSize.toDp() } else 0.dp }