mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-04-29 20:33:42 +00:00
fix: adjust toast ui
This commit is contained in:
parent
c235be2352
commit
7a76d9d38c
4 changed files with 124 additions and 41 deletions
|
|
@ -76,6 +76,7 @@ import com.nuvio.app.core.ui.NuvioContinueWatchingActionSheet
|
|||
import com.nuvio.app.core.ui.NuvioPosterActionSheet
|
||||
import com.nuvio.app.core.ui.PlatformBackHandler
|
||||
import com.nuvio.app.core.ui.configurePlatformImageLoader
|
||||
import com.nuvio.app.core.ui.NuvioToastHost
|
||||
import com.nuvio.app.core.ui.TraktListPickerDialog
|
||||
import com.nuvio.app.core.ui.NuvioTheme
|
||||
import com.nuvio.app.features.auth.AuthScreen
|
||||
|
|
@ -1375,6 +1376,12 @@ private fun MainAppContent(
|
|||
profileSwitchLoading = false
|
||||
}
|
||||
}
|
||||
|
||||
NuvioToastHost(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopCenter)
|
||||
.zIndex(20f),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.nuvio.app.core.ui
|
|||
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.MutableTransitionState
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.slideInVertically
|
||||
|
|
@ -46,6 +47,11 @@ import androidx.compose.material3.Surface
|
|||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
|
|
@ -59,6 +65,9 @@ import androidx.compose.ui.unit.Dp
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
|
||||
@Composable
|
||||
fun NuvioScreen(
|
||||
|
|
@ -436,42 +445,94 @@ fun NuvioStatusModal(
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun NuvioPinnedCollectionToast(
|
||||
visible: Boolean,
|
||||
onDismiss: () -> Unit,
|
||||
message: String = "Remove pin to top from collection to move",
|
||||
fun NuvioToastHost(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
LaunchedEffect(visible) {
|
||||
if (visible) {
|
||||
kotlinx.coroutines.delay(2500L)
|
||||
onDismiss()
|
||||
val toast by NuvioToastController.currentToast.collectAsState()
|
||||
val statusBarTop = WindowInsets.statusBars.asPaddingValues().calculateTopPadding()
|
||||
val visibilityState = remember { MutableTransitionState(false) }
|
||||
var renderedToast by remember { mutableStateOf<NuvioToastMessage?>(null) }
|
||||
|
||||
LaunchedEffect(toast?.id) {
|
||||
val currentToast = toast
|
||||
if (currentToast != null) {
|
||||
renderedToast = currentToast
|
||||
visibilityState.targetState = true
|
||||
delay(currentToast.durationMillis)
|
||||
NuvioToastController.dismiss(currentToast.id)
|
||||
} else {
|
||||
visibilityState.targetState = false
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(
|
||||
visibilityState.currentState,
|
||||
visibilityState.targetState,
|
||||
visibilityState.isIdle,
|
||||
) {
|
||||
if (visibilityState.isIdle && !visibilityState.currentState && !visibilityState.targetState) {
|
||||
renderedToast = null
|
||||
}
|
||||
}
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = visible,
|
||||
visibleState = visibilityState,
|
||||
modifier = modifier,
|
||||
enter = fadeIn() + slideInVertically { -it },
|
||||
exit = fadeOut() + slideOutVertically { -it },
|
||||
) {
|
||||
val currentToast = renderedToast ?: return@AnimatedVisibility
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
contentAlignment = Alignment.Center,
|
||||
.padding(top = statusBarTop + 12.dp)
|
||||
.padding(horizontal = 16.dp),
|
||||
contentAlignment = Alignment.TopCenter,
|
||||
) {
|
||||
Surface(
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
color = MaterialTheme.colorScheme.inverseSurface,
|
||||
shape = RoundedCornerShape(18.dp),
|
||||
color = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||
tonalElevation = 6.dp,
|
||||
shadowElevation = 4.dp,
|
||||
shadowElevation = 10.dp,
|
||||
) {
|
||||
Text(
|
||||
text = message,
|
||||
modifier = Modifier.padding(horizontal = 16.dp, vertical = 10.dp),
|
||||
text = currentToast.message,
|
||||
modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.inverseOnSurface,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class NuvioToastMessage(
|
||||
val id: Long,
|
||||
val message: String,
|
||||
val durationMillis: Long,
|
||||
)
|
||||
|
||||
object NuvioToastController {
|
||||
private val _currentToast = MutableStateFlow<NuvioToastMessage?>(null)
|
||||
val currentToast = _currentToast.asStateFlow()
|
||||
private var nextToastId = 0L
|
||||
|
||||
fun show(
|
||||
message: String,
|
||||
durationMillis: Long = 2500L,
|
||||
) {
|
||||
nextToastId += 1L
|
||||
_currentToast.value = NuvioToastMessage(
|
||||
id = nextToastId,
|
||||
message = message,
|
||||
durationMillis = durationMillis,
|
||||
)
|
||||
}
|
||||
|
||||
fun dismiss(id: Long? = null) {
|
||||
val activeToast = _currentToast.value ?: return
|
||||
if (id == null || activeToast.id == id) {
|
||||
_currentToast.value = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,12 @@ import androidx.compose.foundation.layout.Box
|
|||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
|
|
@ -60,6 +62,7 @@ import com.nuvio.app.core.ui.NuvioScreen
|
|||
import com.nuvio.app.core.ui.NuvioScreenHeader
|
||||
import com.nuvio.app.core.ui.NuvioSectionLabel
|
||||
import com.nuvio.app.core.ui.NuvioSurfaceCard
|
||||
import com.nuvio.app.core.ui.nuvioPlatformExtraBottomPadding
|
||||
import com.nuvio.app.features.home.PosterShape
|
||||
import sh.calvin.reorderable.ReorderableCollectionItemScope
|
||||
import sh.calvin.reorderable.ReorderableItem
|
||||
|
|
@ -72,6 +75,7 @@ fun CollectionEditorScreen(
|
|||
onBack: () -> Unit,
|
||||
) {
|
||||
val state by CollectionEditorRepository.uiState.collectAsState()
|
||||
val bottomInset = nuvioPlatformExtraBottomPadding
|
||||
|
||||
LaunchedEffect(collectionId) {
|
||||
CollectionEditorRepository.initialize(collectionId)
|
||||
|
|
@ -93,16 +97,18 @@ fun CollectionEditorScreen(
|
|||
)
|
||||
}
|
||||
|
||||
NuvioScreen {
|
||||
stickyHeader {
|
||||
NuvioScreenHeader(
|
||||
title = if (state.isNew) "New Collection" else "Edit Collection",
|
||||
onBack = onBack,
|
||||
)
|
||||
}
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
NuvioScreen(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
) {
|
||||
stickyHeader {
|
||||
NuvioScreenHeader(
|
||||
title = if (state.isNew) "New Collection" else "Edit Collection",
|
||||
onBack = onBack,
|
||||
)
|
||||
}
|
||||
|
||||
// Title
|
||||
item {
|
||||
item {
|
||||
NuvioInputField(
|
||||
value = state.title,
|
||||
onValueChange = { CollectionEditorRepository.setTitle(it) },
|
||||
|
|
@ -110,8 +116,7 @@ fun CollectionEditorScreen(
|
|||
)
|
||||
}
|
||||
|
||||
// Backdrop URL
|
||||
item {
|
||||
item {
|
||||
NuvioInputField(
|
||||
value = state.backdropImageUrl,
|
||||
onValueChange = { CollectionEditorRepository.setBackdropImageUrl(it) },
|
||||
|
|
@ -119,8 +124,7 @@ fun CollectionEditorScreen(
|
|||
)
|
||||
}
|
||||
|
||||
// Pin to Top
|
||||
item {
|
||||
item {
|
||||
NuvioSurfaceCard {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
|
|
@ -325,9 +329,25 @@ fun CollectionEditorScreen(
|
|||
}
|
||||
}
|
||||
|
||||
// Save button
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(96.dp + bottomInset))
|
||||
}
|
||||
}
|
||||
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.fillMaxWidth(),
|
||||
color = MaterialTheme.colorScheme.background.copy(alpha = 0.96f),
|
||||
tonalElevation = 6.dp,
|
||||
shadowElevation = 10.dp,
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp)
|
||||
.padding(bottom = bottomInset),
|
||||
) {
|
||||
NuvioPrimaryButton(
|
||||
text = if (state.isNew) "Create Collection" else "Save Changes",
|
||||
enabled = state.title.isNotBlank(),
|
||||
|
|
@ -337,6 +357,7 @@ fun CollectionEditorScreen(
|
|||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ import androidx.compose.ui.platform.LocalHapticFeedback
|
|||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.nuvio.app.core.ui.NuvioActionLabel
|
||||
import com.nuvio.app.core.ui.NuvioPinnedCollectionToast
|
||||
import com.nuvio.app.core.ui.NuvioToastController
|
||||
import com.nuvio.app.features.home.HomeCatalogSettingsItem
|
||||
import com.nuvio.app.features.home.HomeCatalogSettingsRepository
|
||||
import com.nuvio.app.features.home.components.HomeEmptyStateCard
|
||||
|
|
@ -114,20 +114,14 @@ internal fun LazyListScope.homescreenSettingsContent(
|
|||
)
|
||||
},
|
||||
) {
|
||||
var showPinnedToast by remember { mutableStateOf(false) }
|
||||
val hapticFeedback = LocalHapticFeedback.current
|
||||
|
||||
NuvioPinnedCollectionToast(
|
||||
visible = showPinnedToast,
|
||||
onDismiss = { showPinnedToast = false },
|
||||
)
|
||||
|
||||
HomescreenCatalogList(
|
||||
isTablet = isTablet,
|
||||
items = items,
|
||||
onPinnedDragAttempt = {
|
||||
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
showPinnedToast = true
|
||||
NuvioToastController.show("Remove pin to top from collection to move")
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue