mirror of
https://github.com/bbara04/Purefin.git
synced 2026-03-31 17:10:08 +02:00
Refactor tv components and cleaned up code
This commit is contained in:
@@ -1,153 +1,16 @@
|
|||||||
package hu.bbara.purefin.app.content.episode
|
package hu.bbara.purefin.app.content.episode
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
|
||||||
import androidx.compose.foundation.layout.FlowRow
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.sizeIn
|
|
||||||
import androidx.compose.foundation.layout.statusBarsPadding
|
|
||||||
import androidx.compose.foundation.layout.width
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.outlined.Add
|
|
||||||
import androidx.compose.material.icons.outlined.ArrowBack
|
|
||||||
import androidx.compose.material.icons.outlined.Cast
|
|
||||||
import androidx.compose.material.icons.outlined.MoreVert
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.VerticalDivider
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import hu.bbara.purefin.common.ui.components.MediaDetailsTopBar
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
import hu.bbara.purefin.common.ui.MediaCastRow
|
|
||||||
import hu.bbara.purefin.common.ui.MediaMetaChip
|
|
||||||
import hu.bbara.purefin.common.ui.MediaSynopsis
|
|
||||||
import hu.bbara.purefin.common.ui.components.GhostIconButton
|
|
||||||
import hu.bbara.purefin.common.ui.components.MediaActionButton
|
|
||||||
import hu.bbara.purefin.common.ui.components.MediaPlaybackSettings
|
|
||||||
import hu.bbara.purefin.common.ui.components.MediaResumeButton
|
|
||||||
import hu.bbara.purefin.core.model.Episode
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun EpisodeTopBar(
|
internal fun EpisodeTopBar(
|
||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
Row(
|
MediaDetailsTopBar(
|
||||||
|
onBack = onBack,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
|
||||||
.statusBarsPadding()
|
|
||||||
.padding(16.dp),
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
GhostIconButton(
|
|
||||||
icon = Icons.Outlined.ArrowBack,
|
|
||||||
contentDescription = "Back",
|
|
||||||
onClick = onBack
|
|
||||||
)
|
)
|
||||||
Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
|
|
||||||
GhostIconButton(icon = Icons.Outlined.Cast, contentDescription = "Cast", onClick = { })
|
|
||||||
GhostIconButton(icon = Icons.Outlined.MoreVert, contentDescription = "More", onClick = { })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalLayoutApi::class)
|
|
||||||
@Composable
|
|
||||||
internal fun EpisodeDetails(
|
|
||||||
episode: Episode,
|
|
||||||
onPlay: () -> Unit,
|
|
||||||
modifier: Modifier = Modifier
|
|
||||||
) {
|
|
||||||
val scheme = MaterialTheme.colorScheme
|
|
||||||
|
|
||||||
Column(modifier = modifier) {
|
|
||||||
Text(
|
|
||||||
text = episode.title,
|
|
||||||
color = scheme.onBackground,
|
|
||||||
fontSize = 32.sp,
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
lineHeight = 38.sp
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(4.dp))
|
|
||||||
Text(
|
|
||||||
text = "Episode ${episode.index}",
|
|
||||||
color = scheme.onBackground,
|
|
||||||
fontSize = 14.sp,
|
|
||||||
fontWeight = FontWeight.Medium
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
|
||||||
FlowRow(
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
|
||||||
) {
|
|
||||||
MediaMetaChip(text = episode.releaseDate)
|
|
||||||
MediaMetaChip(text = episode.rating)
|
|
||||||
MediaMetaChip(text = episode.runtime)
|
|
||||||
MediaMetaChip(
|
|
||||||
text = episode.format,
|
|
||||||
background = scheme.primary.copy(alpha = 0.2f),
|
|
||||||
border = scheme.primary.copy(alpha = 0.3f),
|
|
||||||
textColor = scheme.primary
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.height(24.dp))
|
|
||||||
|
|
||||||
MediaSynopsis(
|
|
||||||
synopsis = episode.synopsis
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(24.dp))
|
|
||||||
|
|
||||||
Row() {
|
|
||||||
MediaResumeButton(
|
|
||||||
text = if (episode.progress == null) "Play" else "Resume",
|
|
||||||
progress = episode.progress?.div(100)?.toFloat() ?: 0f,
|
|
||||||
onClick = onPlay,
|
|
||||||
modifier = Modifier.sizeIn(maxWidth = 200.dp)
|
|
||||||
)
|
|
||||||
VerticalDivider(
|
|
||||||
color = MaterialTheme.colorScheme.secondary,
|
|
||||||
thickness = 4.dp,
|
|
||||||
modifier = Modifier
|
|
||||||
.height(48.dp)
|
|
||||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
|
||||||
)
|
|
||||||
Row() {
|
|
||||||
MediaActionButton(
|
|
||||||
backgroundColor = MaterialTheme.colorScheme.secondary,
|
|
||||||
iconColor = MaterialTheme.colorScheme.onSecondary,
|
|
||||||
icon = Icons.Outlined.Add,
|
|
||||||
height = 48.dp
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.height(24.dp))
|
|
||||||
|
|
||||||
MediaPlaybackSettings(
|
|
||||||
backgroundColor = MaterialTheme.colorScheme.surface,
|
|
||||||
foregroundColor = MaterialTheme.colorScheme.onSurface,
|
|
||||||
audioTrack = "ENG",
|
|
||||||
subtitles = "ENG"
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(24.dp))
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = "Cast",
|
|
||||||
color = scheme.onBackground,
|
|
||||||
fontSize = 18.sp,
|
|
||||||
fontWeight = FontWeight.Bold
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(12.dp))
|
|
||||||
MediaCastRow(
|
|
||||||
cast = emptyList()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,149 +1,16 @@
|
|||||||
package hu.bbara.purefin.app.content.movie
|
package hu.bbara.purefin.app.content.movie
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
|
||||||
import androidx.compose.foundation.layout.FlowRow
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.sizeIn
|
|
||||||
import androidx.compose.foundation.layout.statusBarsPadding
|
|
||||||
import androidx.compose.foundation.layout.width
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.outlined.Add
|
|
||||||
import androidx.compose.material.icons.outlined.ArrowBack
|
|
||||||
import androidx.compose.material.icons.outlined.Cast
|
|
||||||
import androidx.compose.material.icons.outlined.MoreVert
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.VerticalDivider
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import hu.bbara.purefin.common.ui.components.MediaDetailsTopBar
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
import hu.bbara.purefin.common.ui.MediaCastRow
|
|
||||||
import hu.bbara.purefin.common.ui.MediaMetaChip
|
|
||||||
import hu.bbara.purefin.common.ui.MediaSynopsis
|
|
||||||
import hu.bbara.purefin.common.ui.components.GhostIconButton
|
|
||||||
import hu.bbara.purefin.common.ui.components.MediaActionButton
|
|
||||||
import hu.bbara.purefin.common.ui.components.MediaPlaybackSettings
|
|
||||||
import hu.bbara.purefin.common.ui.components.MediaResumeButton
|
|
||||||
import hu.bbara.purefin.core.model.Movie
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun MovieTopBar(
|
internal fun MovieTopBar(
|
||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val scheme = MaterialTheme.colorScheme
|
MediaDetailsTopBar(
|
||||||
Row(
|
onBack = onBack,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
|
||||||
.statusBarsPadding()
|
|
||||||
.padding(16.dp),
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
GhostIconButton(
|
|
||||||
icon = Icons.Outlined.ArrowBack,
|
|
||||||
contentDescription = "Back",
|
|
||||||
onClick = onBack
|
|
||||||
)
|
)
|
||||||
Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
|
|
||||||
GhostIconButton(icon = Icons.Outlined.Cast, contentDescription = "Cast", onClick = { })
|
|
||||||
GhostIconButton(icon = Icons.Outlined.MoreVert, contentDescription = "More", onClick = { })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalLayoutApi::class)
|
|
||||||
@Composable
|
|
||||||
internal fun MovieDetails(
|
|
||||||
movie: Movie,
|
|
||||||
onPlay: () -> Unit,
|
|
||||||
modifier: Modifier = Modifier
|
|
||||||
) {
|
|
||||||
val scheme = MaterialTheme.colorScheme
|
|
||||||
|
|
||||||
Column(modifier = modifier) {
|
|
||||||
Text(
|
|
||||||
text = movie.title,
|
|
||||||
color = scheme.onBackground,
|
|
||||||
fontSize = 32.sp,
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
lineHeight = 38.sp
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
|
||||||
FlowRow(
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
|
||||||
) {
|
|
||||||
MediaMetaChip(text = movie.year)
|
|
||||||
MediaMetaChip(text = movie.rating)
|
|
||||||
MediaMetaChip(text = movie.runtime)
|
|
||||||
MediaMetaChip(
|
|
||||||
text = movie.format,
|
|
||||||
background = scheme.primary.copy(alpha = 0.2f),
|
|
||||||
border = scheme.primary.copy(alpha = 0.3f),
|
|
||||||
textColor = scheme.primary
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.height(24.dp))
|
|
||||||
|
|
||||||
MediaSynopsis(
|
|
||||||
synopsis = movie.synopsis
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(24.dp))
|
|
||||||
|
|
||||||
Row() {
|
|
||||||
MediaResumeButton(
|
|
||||||
text = if (movie.progress == null) "Play" else "Resume",
|
|
||||||
progress = movie.progress?.div(100)?.toFloat() ?: 0f,
|
|
||||||
onClick = onPlay,
|
|
||||||
modifier = Modifier.sizeIn(maxWidth = 200.dp)
|
|
||||||
)
|
|
||||||
VerticalDivider(
|
|
||||||
color = MaterialTheme.colorScheme.secondary,
|
|
||||||
thickness = 4.dp,
|
|
||||||
modifier = Modifier
|
|
||||||
.height(48.dp)
|
|
||||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
|
||||||
)
|
|
||||||
Row() {
|
|
||||||
MediaActionButton(
|
|
||||||
backgroundColor = MaterialTheme.colorScheme.secondary,
|
|
||||||
iconColor = MaterialTheme.colorScheme.onSecondary,
|
|
||||||
icon = Icons.Outlined.Add,
|
|
||||||
height = 48.dp
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Spacer(modifier = Modifier.height(24.dp))
|
|
||||||
|
|
||||||
MediaPlaybackSettings(
|
|
||||||
backgroundColor = MaterialTheme.colorScheme.surface,
|
|
||||||
foregroundColor = MaterialTheme.colorScheme.onSurface,
|
|
||||||
audioTrack = movie.audioTrack,
|
|
||||||
subtitles = movie.subtitles
|
|
||||||
)
|
|
||||||
|
|
||||||
if (movie.cast.isNotEmpty()) {
|
|
||||||
Spacer(modifier = Modifier.height(24.dp))
|
|
||||||
Text(
|
|
||||||
text = "Cast",
|
|
||||||
color = scheme.onBackground,
|
|
||||||
fontSize = 18.sp,
|
|
||||||
fontWeight = FontWeight.Bold
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(12.dp))
|
|
||||||
MediaCastRow(
|
|
||||||
cast = movie.cast
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.statusBarsPadding
|
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.lazy.LazyRow
|
import androidx.compose.foundation.lazy.LazyRow
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
@@ -27,9 +26,6 @@ import androidx.compose.foundation.rememberScrollState
|
|||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.Add
|
import androidx.compose.material.icons.outlined.Add
|
||||||
import androidx.compose.material.icons.outlined.ArrowBack
|
|
||||||
import androidx.compose.material.icons.outlined.Cast
|
|
||||||
import androidx.compose.material.icons.outlined.MoreVert
|
|
||||||
import androidx.compose.material.icons.outlined.PlayCircle
|
import androidx.compose.material.icons.outlined.PlayCircle
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
@@ -54,8 +50,8 @@ import androidx.compose.ui.unit.sp
|
|||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import hu.bbara.purefin.common.ui.MediaCastRow
|
import hu.bbara.purefin.common.ui.MediaCastRow
|
||||||
import hu.bbara.purefin.common.ui.MediaMetaChip
|
import hu.bbara.purefin.common.ui.MediaMetaChip
|
||||||
import hu.bbara.purefin.common.ui.components.GhostIconButton
|
|
||||||
import hu.bbara.purefin.common.ui.components.MediaActionButton
|
import hu.bbara.purefin.common.ui.components.MediaActionButton
|
||||||
|
import hu.bbara.purefin.common.ui.components.MediaDetailsTopBar
|
||||||
import hu.bbara.purefin.common.ui.components.MediaProgressBar
|
import hu.bbara.purefin.common.ui.components.MediaProgressBar
|
||||||
import hu.bbara.purefin.common.ui.components.PurefinAsyncImage
|
import hu.bbara.purefin.common.ui.components.PurefinAsyncImage
|
||||||
import hu.bbara.purefin.common.ui.components.WatchStateIndicator
|
import hu.bbara.purefin.common.ui.components.WatchStateIndicator
|
||||||
@@ -70,23 +66,10 @@ internal fun SeriesTopBar(
|
|||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
Row(
|
MediaDetailsTopBar(
|
||||||
|
onBack = onBack,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
)
|
||||||
.statusBarsPadding()
|
|
||||||
.padding(16.dp),
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
GhostIconButton(
|
|
||||||
onClick = onBack,
|
|
||||||
icon = Icons.Outlined.ArrowBack,
|
|
||||||
contentDescription = "Back")
|
|
||||||
Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
|
|
||||||
GhostIconButton(icon = Icons.Outlined.Cast, contentDescription = "Cast", onClick = { })
|
|
||||||
GhostIconButton(icon = Icons.Outlined.MoreVert, contentDescription = "More", onClick = { })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalLayoutApi::class)
|
@OptIn(ExperimentalLayoutApi::class)
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package hu.bbara.purefin.common.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.statusBarsPadding
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
|
||||||
|
import androidx.compose.material.icons.outlined.Cast
|
||||||
|
import androidx.compose.material.icons.outlined.MoreVert
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MediaDetailsTopBar(
|
||||||
|
onBack: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
onCastClick: () -> Unit = {},
|
||||||
|
onMoreClick: () -> Unit = {}
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.statusBarsPadding()
|
||||||
|
.padding(16.dp),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
GhostIconButton(
|
||||||
|
icon = Icons.AutoMirrored.Outlined.ArrowBack,
|
||||||
|
contentDescription = "Back",
|
||||||
|
onClick = onBack
|
||||||
|
)
|
||||||
|
Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||||
|
GhostIconButton(icon = Icons.Outlined.Cast, contentDescription = "Cast", onClick = onCastClick)
|
||||||
|
GhostIconButton(icon = Icons.Outlined.MoreVert, contentDescription = "More", onClick = onMoreClick)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package hu.bbara.purefin.common.ui.components
|
package hu.bbara.purefin.common.ui.components
|
||||||
|
|
||||||
import androidx.compose.animation.animateColorAsState
|
|
||||||
import androidx.compose.animation.core.animateFloatAsState
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.border
|
import androidx.compose.foundation.border
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
package hu.bbara.purefin.common.ui.components
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.outlined.Search
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.material3.TextField
|
|
||||||
import androidx.compose.material3.TextFieldDefaults
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.draw.clip
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun SearchField(
|
|
||||||
value: String,
|
|
||||||
onValueChange: (String) -> Unit,
|
|
||||||
placeholder: String,
|
|
||||||
backgroundColor: Color = Color.Unspecified,
|
|
||||||
textColor: Color = Color.Unspecified,
|
|
||||||
cursorColor: Color = Color.Unspecified,
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
) {
|
|
||||||
val scheme = MaterialTheme.colorScheme
|
|
||||||
val resolvedBackgroundColor =
|
|
||||||
if (backgroundColor == Color.Unspecified) scheme.surfaceVariant else backgroundColor
|
|
||||||
val resolvedTextColor = if (textColor == Color.Unspecified) scheme.onSurface else textColor
|
|
||||||
val resolvedCursorColor = if (cursorColor == Color.Unspecified) scheme.primary else cursorColor
|
|
||||||
|
|
||||||
TextField(
|
|
||||||
value = value,
|
|
||||||
onValueChange = onValueChange,
|
|
||||||
modifier = modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.clip(RoundedCornerShape(12.dp)),
|
|
||||||
singleLine = true,
|
|
||||||
placeholder = { Text(placeholder) },
|
|
||||||
leadingIcon = { Icon(imageVector = Icons.Outlined.Search, contentDescription = null) },
|
|
||||||
colors = TextFieldDefaults.colors(
|
|
||||||
focusedContainerColor = resolvedBackgroundColor,
|
|
||||||
unfocusedContainerColor = resolvedBackgroundColor,
|
|
||||||
focusedIndicatorColor = Color.Transparent,
|
|
||||||
unfocusedIndicatorColor = Color.Transparent,
|
|
||||||
cursorColor = resolvedCursorColor,
|
|
||||||
focusedTextColor = resolvedTextColor,
|
|
||||||
unfocusedTextColor = resolvedTextColor,
|
|
||||||
focusedLeadingIconColor = scheme.onSurfaceVariant,
|
|
||||||
unfocusedLeadingIconColor = scheme.onSurfaceVariant,
|
|
||||||
focusedPlaceholderColor = scheme.onSurfaceVariant,
|
|
||||||
unfocusedPlaceholderColor = scheme.onSurfaceVariant,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
package hu.bbara.purefin.tv.home.ui
|
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.border
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.draw.clip
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
|
||||||
import androidx.compose.ui.unit.Dp
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun TvHomeAvatar(
|
|
||||||
size: Dp,
|
|
||||||
borderWidth: Dp,
|
|
||||||
borderColor: Color,
|
|
||||||
backgroundColor: Color,
|
|
||||||
icon: ImageVector,
|
|
||||||
iconTint: Color,
|
|
||||||
modifier: Modifier = Modifier
|
|
||||||
) {
|
|
||||||
Box(
|
|
||||||
modifier = modifier
|
|
||||||
.size(size)
|
|
||||||
.clip(CircleShape)
|
|
||||||
.border(borderWidth, borderColor, CircleShape)
|
|
||||||
.background(backgroundColor),
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = icon,
|
|
||||||
contentDescription = null,
|
|
||||||
tint = iconTint
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,217 +0,0 @@
|
|||||||
package hu.bbara.purefin.tv.home.ui
|
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.border
|
|
||||||
import androidx.compose.foundation.clickable
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.filled.PlayArrow
|
|
||||||
import androidx.compose.material.icons.outlined.Person
|
|
||||||
import androidx.compose.material3.HorizontalDivider
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
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.focus.onFocusChanged
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun TvHomeDrawerContent(
|
|
||||||
title: String,
|
|
||||||
subtitle: String,
|
|
||||||
primaryNavItems: List<TvHomeNavItem>,
|
|
||||||
secondaryNavItems: List<TvHomeNavItem>,
|
|
||||||
user: TvHomeUser,
|
|
||||||
onLibrarySelected: (TvHomeNavItem) -> Unit,
|
|
||||||
onLogout: () -> Unit,
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
) {
|
|
||||||
Column(modifier = modifier.fillMaxSize()) {
|
|
||||||
TvHomeDrawerHeader(
|
|
||||||
title = title,
|
|
||||||
subtitle = subtitle
|
|
||||||
)
|
|
||||||
TvHomeDrawerNav(
|
|
||||||
primaryItems = primaryNavItems,
|
|
||||||
secondaryItems = secondaryNavItems,
|
|
||||||
onLibrarySelected = onLibrarySelected
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
|
||||||
TvHomeDrawerFooter(user = user, onLogout = onLogout)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun TvHomeDrawerHeader(
|
|
||||||
title: String,
|
|
||||||
subtitle: String,
|
|
||||||
modifier: Modifier = Modifier
|
|
||||||
) {
|
|
||||||
val scheme = MaterialTheme.colorScheme
|
|
||||||
|
|
||||||
Row(
|
|
||||||
modifier = modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(start = 24.dp, end = 16.dp, top = 24.dp, bottom = 20.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.size(40.dp)
|
|
||||||
.background(scheme.primary, RoundedCornerShape(12.dp)),
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
horizontalArrangement = Arrangement.Center
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Filled.PlayArrow,
|
|
||||||
contentDescription = "Play",
|
|
||||||
tint = scheme.onPrimary
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Column(modifier = Modifier.padding(start = 12.dp)) {
|
|
||||||
Text(
|
|
||||||
text = title,
|
|
||||||
color = scheme.onBackground,
|
|
||||||
fontSize = 20.sp,
|
|
||||||
fontWeight = FontWeight.Bold
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = subtitle,
|
|
||||||
color = scheme.onSurfaceVariant,
|
|
||||||
fontSize = 12.sp
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
HorizontalDivider(color = scheme.onSurfaceVariant.copy(alpha = 0.2f))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun TvHomeDrawerNav(
|
|
||||||
primaryItems: List<TvHomeNavItem>,
|
|
||||||
secondaryItems: List<TvHomeNavItem>,
|
|
||||||
onLibrarySelected: (TvHomeNavItem) -> Unit,
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
) {
|
|
||||||
Column(
|
|
||||||
modifier = modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(vertical = 16.dp)
|
|
||||||
) {
|
|
||||||
primaryItems.forEach { item ->
|
|
||||||
TvHomeDrawerNavItem(item = item, onLibrarySelected = onLibrarySelected)
|
|
||||||
}
|
|
||||||
if (secondaryItems.isNotEmpty()) {
|
|
||||||
HorizontalDivider(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(horizontal = 20.dp, vertical = 12.dp),
|
|
||||||
color = MaterialTheme.colorScheme.outlineVariant
|
|
||||||
)
|
|
||||||
secondaryItems.forEach { item ->
|
|
||||||
TvHomeDrawerNavItem(item = item, onLibrarySelected = onLibrarySelected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun TvHomeDrawerNavItem(
|
|
||||||
item: TvHomeNavItem,
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
onLibrarySelected: (TvHomeNavItem) -> Unit
|
|
||||||
) {
|
|
||||||
val scheme = MaterialTheme.colorScheme
|
|
||||||
var isFocused by remember { mutableStateOf(false) }
|
|
||||||
val background = when {
|
|
||||||
isFocused -> scheme.primary.copy(alpha = 0.28f)
|
|
||||||
item.selected -> scheme.primary.copy(alpha = 0.12f)
|
|
||||||
else -> Color.Transparent
|
|
||||||
}
|
|
||||||
val tint = if (item.selected || isFocused) scheme.primary else scheme.onSurfaceVariant
|
|
||||||
Row(
|
|
||||||
modifier = modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 16.dp, vertical = 4.dp)
|
|
||||||
.then(if (isFocused) Modifier.border(2.dp, scheme.primary, RoundedCornerShape(12.dp)) else Modifier)
|
|
||||||
.background(background, RoundedCornerShape(12.dp))
|
|
||||||
.onFocusChanged { isFocused = it.isFocused }
|
|
||||||
.clickable { onLibrarySelected(item) }
|
|
||||||
.padding(horizontal = 16.dp, vertical = 12.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = item.icon,
|
|
||||||
contentDescription = item.label,
|
|
||||||
tint = tint
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = item.label,
|
|
||||||
color = if (item.selected || isFocused) scheme.primary else scheme.onBackground,
|
|
||||||
fontSize = 15.sp,
|
|
||||||
fontWeight = FontWeight.Medium,
|
|
||||||
modifier = Modifier.padding(start = 12.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun TvHomeDrawerFooter(
|
|
||||||
user: TvHomeUser,
|
|
||||||
onLogout: () -> Unit,
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
) {
|
|
||||||
val scheme = MaterialTheme.colorScheme
|
|
||||||
|
|
||||||
Row(
|
|
||||||
modifier = modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(16.dp)
|
|
||||||
.background(scheme.surfaceVariant, RoundedCornerShape(12.dp))
|
|
||||||
.padding(12.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
TvHomeAvatar(
|
|
||||||
size = 32.dp,
|
|
||||||
borderWidth = 1.dp,
|
|
||||||
borderColor = scheme.outlineVariant,
|
|
||||||
backgroundColor = scheme.primaryContainer,
|
|
||||||
icon = Icons.Outlined.Person,
|
|
||||||
iconTint = scheme.onBackground
|
|
||||||
)
|
|
||||||
Column(modifier = Modifier.padding(start = 12.dp)
|
|
||||||
.clickable { onLogout() }) {
|
|
||||||
Text(
|
|
||||||
text = user.name,
|
|
||||||
color = scheme.onBackground,
|
|
||||||
fontSize = 14.sp,
|
|
||||||
fontWeight = FontWeight.SemiBold,
|
|
||||||
maxLines = 1,
|
|
||||||
overflow = TextOverflow.Ellipsis
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = user.plan,
|
|
||||||
color = scheme.onSurfaceVariant,
|
|
||||||
fontSize = 11.sp,
|
|
||||||
maxLines = 1,
|
|
||||||
overflow = TextOverflow.Ellipsis
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user