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
This commit is contained in:
parent
e6304f79a2
commit
54966f9124
12 changed files with 31 additions and 12 deletions
|
|
@ -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">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue