Skip to content

Commit

Permalink
🎨 优化toast
Browse files Browse the repository at this point in the history
  • Loading branch information
yaoxieyoulei committed Jun 28, 2024
1 parent 3d18824 commit 5011078
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ class LeanbackActivity : ComponentActivity() {
}
}

HttpServer.start(applicationContext, showToast = { LeanbackToastState.I.showToast(it) })
HttpServer.start(applicationContext, showToast = {
LeanbackToastState.I.showToast(it, id = "httpServer")
})
}
}
4 changes: 2 additions & 2 deletions app/src/main/java/top/yogiczy/mytv/ui/LeanbackApp.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package top.yogiczy.mytv.ui

import android.widget.Toast
import androidx.annotation.IntRange
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.calculateEndPadding
Expand All @@ -23,6 +22,7 @@ import kotlinx.coroutines.flow.debounce
import top.yogiczy.mytv.ui.screens.leanback.components.LeanbackPadding
import top.yogiczy.mytv.ui.screens.leanback.main.LeanbackMainScreen
import top.yogiczy.mytv.ui.screens.leanback.toast.LeanbackToastScreen
import top.yogiczy.mytv.ui.screens.leanback.toast.LeanbackToastState

@Composable
fun LeanbackApp(
Expand All @@ -40,7 +40,7 @@ fun LeanbackApp(
onBackPressed()
} else {
doubleBackPressedExitState.backPress()
Toast.makeText(context, "再按一次退出", Toast.LENGTH_SHORT).show()
LeanbackToastState.I.showToast("再按一次退出")
}
},
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,40 +1,53 @@
package top.yogiczy.mytv.ui.screens.leanback.toast

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.sizeIn
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Info
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Popup
import androidx.tv.material3.Icon
import androidx.tv.material3.MaterialTheme
import kotlinx.coroutines.delay
import top.yogiczy.mytv.ui.rememberLeanbackChildPadding
import top.yogiczy.mytv.ui.theme.LeanbackTheme

@Composable
fun LeanbackToastScreen(
modifier: Modifier = Modifier,
state: LeanbackToastState = rememberLeanbackToastState(),
) {
val childPadding = rememberLeanbackChildPadding()

Box(modifier = modifier.fillMaxSize()) {
Popup(
offset = IntOffset(
x = with(LocalDensity.current) { childPadding.start.toPx().toInt() },
y = with(LocalDensity.current) { childPadding.top.toPx().toInt() },
),
) {
AnimatedVisibility(visible = state.visible) {
LeanbackToastItem(property = state.current)
Popup {
Box(modifier = Modifier.fillMaxSize()) {
AnimatedVisibility(
visible = state.visible,
enter = fadeIn() + scaleIn(),
exit = fadeOut() + scaleOut(),
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(bottom = 28.dp),
) {
LeanbackToastItem(property = state.current)
}
}
}
}
Expand All @@ -47,13 +60,50 @@ fun LeanbackToastItem(
) {
Box(
modifier = modifier
.background(
color = MaterialTheme.colorScheme.background.copy(alpha = 0.9f),
shape = MaterialTheme.shapes.small,
)
.padding(horizontal = 20.dp, vertical = 10.dp)
.sizeIn(maxWidth = 556.dp)
.background(MaterialTheme.colorScheme.inverseSurface, MaterialTheme.shapes.medium)
.padding(horizontal = 16.dp, vertical = 12.dp),
) {
Text(text = property.message)
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
LeanbackToastContentIcon(
showIcon = true,
icon = Icons.Outlined.Info,
iconColor = MaterialTheme.colorScheme.inverseOnSurface,
iconContainerColors = MaterialTheme.colorScheme.onSurfaceVariant,
)

androidx.tv.material3.Text(
property.message,
color = MaterialTheme.colorScheme.inverseOnSurface
)
}
}
}

@Composable
private fun LeanbackToastContentIcon(
modifier: Modifier = Modifier,
showIcon: Boolean,
icon: ImageVector,
iconColor: Color,
iconContainerColors: Color,
) {
if (showIcon) {
Box(
modifier = modifier
.background(iconContainerColors, CircleShape)
.padding(8.dp),
) {
Icon(
imageVector = icon,
contentDescription = null,
modifier = Modifier.size(16.dp),
tint = iconColor,
)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,45 @@ import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.consumeAsFlow
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.launch
import top.yogiczy.mytv.ui.screens.leanback.toast.LeanbackToastProperty.Companion.toMs
import java.util.UUID

@Stable
class LeanbackToastState {
class LeanbackToastState(private val coroutineScope: CoroutineScope) {
private var _visible by mutableStateOf(false)
val visible get() = _visible

private var _current by mutableStateOf(LeanbackToastProperty())
val current get() = _current

private fun showToast(toast: LeanbackToastProperty) {
// TODO 消息变化较生硬
_current = toast
_visible = true
channel.trySend(toast.duration.toMs())
coroutineScope.launch {
if (_current.id != toast.id) {
_visible = false
delay(300)
}

_current = toast
_visible = true
channel.trySend(toast.duration.toMs())
}
}

fun showToast(
message: String,
duration: LeanbackToastProperty.Duration = LeanbackToastProperty.Duration.Default,
id: String = UUID.randomUUID().toString(),
) {
showToast(LeanbackToastProperty(message = message, duration = duration))
showToast(LeanbackToastProperty(message = message, duration = duration, id = id))
}

private val channel = Channel<Int>(Channel.CONFLATED)
Expand All @@ -49,14 +61,21 @@ class LeanbackToastState {
}

@Composable
fun rememberLeanbackToastState() = remember { LeanbackToastState() }.also {
LeanbackToastState.I = it
LaunchedEffect(it) { it.observe() }
fun rememberLeanbackToastState(): LeanbackToastState {
val coroutineScope = rememberCoroutineScope()

return remember {
LeanbackToastState(coroutineScope)
}.also {
LeanbackToastState.I = it
LaunchedEffect(it) { it.observe() }
}
}

data class LeanbackToastProperty(
val message: String = "",
val duration: Duration = Duration.Default,
val id: String = UUID.randomUUID().toString(),
) {
sealed interface Duration {
data object Default : Duration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class LeanBackUpdateViewModel : ViewModel() {
LeanbackToastState.I.showToast(
"正在下载更新: $it%",
LeanbackToastProperty.Duration.Custom(10_000),
"downloadProcess"
)
}

Expand Down

0 comments on commit 5011078

Please sign in to comment.