feat: format selection page (wip)

This commit is contained in:
junkfood
2024-06-30 00:26:58 +08:00
parent e5fbe6e71a
commit 8024c5c971
4 changed files with 241 additions and 159 deletions

3
.gitignore vendored
View File

@ -15,4 +15,5 @@
.externalNativeBuild
.cxx
local.properties
/keystore.properties
/keystore.properties
.kotlin

View File

@ -24,6 +24,7 @@ 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.unit.dp
import androidx.compose.ui.zIndex
@ -35,8 +36,9 @@ fun SealModalBottomSheetM2(
sheetState: ModalBottomSheetState = androidx.compose.material.rememberModalBottomSheetState(
ModalBottomSheetValue.Hidden
),
sheetContent: @Composable ColumnScope.() -> Unit = {},
horizontalPadding: PaddingValues = PaddingValues(horizontal = 28.dp),
sheetGesturesEnabled: Boolean = true,
sheetContent: @Composable ColumnScope.() -> Unit = {},
) {
androidx.compose.material.ModalBottomSheetLayout(
modifier = modifier,
@ -49,11 +51,11 @@ fun SealModalBottomSheetM2(
sheetState = sheetState,
sheetBackgroundColor = MaterialTheme.colorScheme.surfaceContainer,
sheetElevation = if (sheetState.isVisible) ModalBottomSheetDefaults.Elevation else 0.dp,
sheetGesturesEnabled = sheetGesturesEnabled,
sheetContent = {
Column {
Surface(
color = MaterialTheme.colorScheme.surfaceContainer,
tonalElevation = 6.dp,
) {
Box(modifier = Modifier.padding(horizontalPadding)) {
Row(
@ -89,5 +91,45 @@ fun SealModalBottomSheetM2(
)
}
},
){}
) {}
}
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun SealModalBottomSheetM2Variant(
modifier: Modifier = Modifier,
sheetState: ModalBottomSheetState = androidx.compose.material.rememberModalBottomSheetState(
ModalBottomSheetValue.Hidden
),
horizontalPadding: PaddingValues = PaddingValues(horizontal = 28.dp),
sheetGesturesEnabled: Boolean = true,
sheetContent: @Composable ColumnScope.() -> Unit = {},
) {
androidx.compose.material.ModalBottomSheetLayout(
modifier = modifier,
sheetShape = RoundedCornerShape(
topStart = 0.dp,
topEnd = 0.dp,
bottomEnd = 0.dp,
bottomStart = 0.dp
),
sheetState = sheetState,
sheetBackgroundColor = Color.Transparent,
sheetElevation = if (sheetState.isVisible) ModalBottomSheetDefaults.Elevation else 0.dp,
sheetGesturesEnabled = sheetGesturesEnabled,
sheetContent = {
Column {
Box(modifier = Modifier.padding(horizontalPadding)) {
Column {
sheetContent()
}
}
}
NavigationBarSpacer(
modifier = Modifier
.background(MaterialTheme.colorScheme.surfaceContainerHigh)
.fillMaxWidth()
)
},
) {}
}

View File

@ -184,7 +184,7 @@ private const val NOT_SELECTED = -1
@Preview
@Composable
private fun FormatPagePreview() {
fun FormatPagePreview() {
val captionsMap = mapOf(
"en-en" to listOf(SubtitleFormat(ext = "", url = "", name = "English from English")),
"ja-en" to listOf(SubtitleFormat(ext = "", url = "", name = "Japanese from English")),

View File

@ -1,8 +1,10 @@
package com.junkfood.seal.ui.page.downloadv2
import androidx.compose.animation.AnimatedContent
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
@ -13,31 +15,32 @@ import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.selection.selectable
import androidx.compose.material.ModalBottomSheetValue
import androidx.compose.material.Surface
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Download
import androidx.compose.material.icons.filled.ArrowForward
import androidx.compose.material.icons.outlined.Cancel
import androidx.compose.material.icons.outlined.Close
import androidx.compose.material.icons.outlined.DoneAll
import androidx.compose.material.icons.outlined.ExpandMore
import androidx.compose.material.icons.outlined.VideoFile
import androidx.compose.material.icons.outlined.VideoSettings
import androidx.compose.material.rememberModalBottomSheetState
import androidx.compose.material3.Button
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.SegmentedButton
import androidx.compose.material3.SegmentedButtonDefaults
import androidx.compose.material3.SingleChoiceSegmentedButtonRow
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
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 androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -48,15 +51,20 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.junkfood.seal.R
import com.junkfood.seal.ui.common.motion.materialSharedAxisX
import com.junkfood.seal.ui.component.DrawerSheetSubtitle
import com.junkfood.seal.ui.component.FilledButtonWithIcon
import com.junkfood.seal.ui.component.OutlinedButtonWithIcon
import com.junkfood.seal.ui.component.SealModalBottomSheetM2
import com.junkfood.seal.ui.component.SealModalBottomSheetM2Variant
import com.junkfood.seal.ui.page.download.FormatPagePreview
import com.junkfood.seal.ui.theme.SealTheme
import com.junkfood.seal.util.CUSTOM_COMMAND
import com.junkfood.seal.util.EXTRACT_AUDIO
import com.junkfood.seal.util.PLAYLIST
import com.junkfood.seal.util.PreferenceUtil.updateBoolean
import kotlinx.coroutines.launch
enum class DownloadType {
Audio, Video, Playlist, Command
@ -107,59 +115,95 @@ private fun ConfigurePage(
@OptIn(ExperimentalMaterial3Api::class)
@Preview
@Composable
private fun Loading() {
Surface {
Column(
modifier = Modifier
.fillMaxWidth()
private fun BottomSheet() {
val scope = rememberCoroutineScope()
var show by remember { mutableStateOf(0) }
val sheetState = rememberModalBottomSheetState(
initialValue = ModalBottomSheetValue.Hidden,
skipHalfExpanded = true
)
SealTheme {
SealModalBottomSheetM2(
sheetState = rememberModalBottomSheetState(
initialValue = ModalBottomSheetValue.Expanded,
skipHalfExpanded = true
),
sheetGesturesEnabled = false
) {
TopAppBar(
title = {
Text(
text = stringResource(R.string.format_selection),
style = MaterialTheme.typography.titleMedium.copy(fontSize = 18.sp)
)
},
navigationIcon = {
IconButton(onClick = {}) {
Icon(imageVector = Icons.Outlined.Close, contentDescription = null)
}
})
Spacer(Modifier.height(40.dp))
Column(
modifier = Modifier.align(Alignment.CenterHorizontally),
horizontalAlignment = Alignment.CenterHorizontally
) {
CircularProgressIndicator()
Spacer(Modifier.height(12.dp))
Text("Fetching formats...", style = MaterialTheme.typography.labelMedium)
}
AnimatedContent(
targetState = show,
label = "",
transitionSpec = {
materialSharedAxisX(
initialOffsetX = { it / 4 },
targetOffsetX = { -it / 4 })
}) {
when (it) {
Spacer(Modifier.height(40.dp))
1 -> {
Column {
Loading()
Button(onClick = { scope.launch { sheetState.show() } }) { Text("Show") }
Button(onClick = { show = 0 }) { Text("Hide") }
}
}
0 -> {
DownloadDialogV2() { show = 1 }
}
}
}
}
SealModalBottomSheetM2Variant(sheetState = sheetState, sheetGesturesEnabled = false, horizontalPadding = PaddingValues(0.dp)) {
FormatPagePreview()
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Preview
@Composable
private fun Loading() {
Column(
modifier = Modifier
.fillMaxWidth()
) {
Spacer(Modifier.height(80.dp))
Column(
modifier = Modifier.align(Alignment.CenterHorizontally),
horizontalAlignment = Alignment.CenterHorizontally
) {
CircularProgressIndicator()
Spacer(Modifier.height(12.dp))
Text("Fetching formats...", style = MaterialTheme.typography.labelLarge)
}
Spacer(Modifier.height(80.dp))
}
}
@Composable
@Preview
fun DownloadDialogV2() {
Surface {
Column(modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp)) {
Icon(
modifier = Modifier.align(Alignment.CenterHorizontally),
imageVector = Icons.Outlined.DoneAll,
contentDescription = null
)
Text(
text = stringResource(R.string.settings_before_download),
style = MaterialTheme.typography.headlineSmall,
modifier = Modifier
.align(Alignment.CenterHorizontally)
.padding(vertical = 16.dp),
maxLines = 2,
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Center
)/* DrawerSheetSubtitle(text = stringResource(id = R.string.video_url))
fun DownloadDialogV2(onClick: () -> Unit = {}) {
Column(modifier = Modifier.padding(vertical = 12.dp)) {
Icon(
modifier = Modifier.align(Alignment.CenterHorizontally),
imageVector = Icons.Outlined.DoneAll,
contentDescription = null
)
Text(
text = stringResource(R.string.settings_before_download),
style = MaterialTheme.typography.headlineSmall,
modifier = Modifier
.align(Alignment.CenterHorizontally)
.padding(vertical = 16.dp),
maxLines = 2,
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Center
)/* DrawerSheetSubtitle(text = stringResource(id = R.string.video_url))
OutlinedTextField(
value = "",
@ -170,73 +214,74 @@ fun DownloadDialogV2() {
)*/
var selectedType: DownloadType? by remember { mutableStateOf(DownloadType.Video) }
DrawerSheetSubtitle(text = stringResource(id = R.string.download_type))
var selectedType: DownloadType? by remember { mutableStateOf(DownloadType.Video) }
DrawerSheetSubtitle(text = stringResource(id = R.string.download_type))
SingleChoiceSegmentedButtonRow(modifier = Modifier.fillMaxWidth()) {
SegmentedButton(
selected = selectedType == DownloadType.Audio,
onClick = { selectedType = DownloadType.Audio },
modifier = Modifier.height(36.dp),
shape = SegmentedButtonDefaults.itemShape(0, 3)
) {
Text(text = stringResource(id = R.string.audio))
}
SegmentedButton(
selected = selectedType == DownloadType.Video,
onClick = { selectedType = DownloadType.Video },
modifier = Modifier.height(36.dp),
shape = SegmentedButtonDefaults.itemShape(1, 3)
) {
Text(text = stringResource(id = R.string.video))
}
SegmentedButton(
selected = selectedType == DownloadType.Playlist,
onClick = { selectedType = DownloadType.Playlist },
modifier = Modifier.height(36.dp),
shape = SegmentedButtonDefaults.itemShape(2, 3)
) {
Text(text = stringResource(id = R.string.playlist))
}
}
DrawerSheetSubtitle(text = stringResource(id = R.string.format_selection))
FormatSelectionAuto()
FormatSelectionCustom()
AdditionalSettings()
Spacer(Modifier.height(12.dp))
val state = rememberLazyListState()
LazyRow(
modifier = Modifier
.fillMaxWidth()
.padding(top = 12.dp),
horizontalArrangement = Arrangement.End,
state = state,
verticalAlignment = Alignment.CenterVertically
SingleChoiceSegmentedButtonRow(modifier = Modifier.fillMaxWidth()) {
SegmentedButton(
selected = selectedType == DownloadType.Audio,
onClick = { selectedType = DownloadType.Audio },
modifier = Modifier.height(36.dp),
colors = SegmentedButtonDefaults.colors(),
shape = SegmentedButtonDefaults.itemShape(0, 3)
) {
item {
OutlinedButtonWithIcon(
modifier = Modifier.padding(horizontal = 12.dp),
onClick = {},
icon = Icons.Outlined.Cancel,
text = stringResource(R.string.cancel)
)
}
item {
FilledButtonWithIcon(
modifier = Modifier.fillMaxWidth(),
onClick = {},
icon = Icons.Filled.Download,
text = stringResource(R.string.start_download),
enabled = selectedType != null
)
}
Text(text = stringResource(id = R.string.audio))
}
SegmentedButton(
selected = selectedType == DownloadType.Video,
onClick = { selectedType = DownloadType.Video },
modifier = Modifier.height(36.dp),
shape = SegmentedButtonDefaults.itemShape(1, 3)
) {
Text(text = stringResource(id = R.string.video))
}
SegmentedButton(
selected = selectedType == DownloadType.Playlist,
onClick = { selectedType = DownloadType.Playlist },
modifier = Modifier.height(36.dp),
shape = SegmentedButtonDefaults.itemShape(2, 3)
) {
Text(text = stringResource(id = R.string.playlist))
}
}
DrawerSheetSubtitle(text = stringResource(id = R.string.format_selection))
FormatSelectionAuto()
FormatSelectionCustom()
AdditionalSettings()
Spacer(Modifier.height(12.dp))
val state = rememberLazyListState()
LazyRow(
modifier = Modifier
.fillMaxWidth()
.padding(top = 12.dp),
horizontalArrangement = Arrangement.End,
state = state,
verticalAlignment = Alignment.CenterVertically
) {
item {
OutlinedButtonWithIcon(
modifier = Modifier.padding(horizontal = 12.dp),
onClick = {},
icon = Icons.Outlined.Cancel,
text = stringResource(R.string.cancel)
)
}
item {
FilledButtonWithIcon(
modifier = Modifier.fillMaxWidth(),
onClick = onClick,
icon = Icons.Filled.ArrowForward,
text = "Load info",
enabled = selectedType != null
)
}
}
}
@ -245,30 +290,28 @@ fun DownloadDialogV2() {
@Preview
@Composable
private fun AdditionalSettings() {
Surface {
Column {
Spacer(Modifier.height(8.dp))
HorizontalDivider(thickness = Dp.Hairline)
Row(modifier = Modifier
.fillMaxWidth()
.clickable { }
.padding(vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically) {
Spacer(modifier = Modifier.width(4.dp))
Text(
text = "Additional settings",
style = MaterialTheme.typography.labelLarge,
Column {
Spacer(Modifier.height(8.dp))
HorizontalDivider(thickness = Dp.Hairline)
Row(modifier = Modifier
.fillMaxWidth()
.clickable { }
.padding(vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically) {
Spacer(modifier = Modifier.width(4.dp))
Text(
text = "Additional settings",
style = MaterialTheme.typography.labelLarge,
// color = MaterialTheme.colorScheme.primary
)
Spacer(modifier = Modifier.weight(1f))
Icon(
imageVector = Icons.Outlined.ExpandMore,
contentDescription = null,
modifier = Modifier.size(16.dp)
)
)
Spacer(modifier = Modifier.weight(1f))
Icon(
imageVector = Icons.Outlined.ExpandMore,
contentDescription = null,
modifier = Modifier.size(16.dp)
)
}
}
}
@ -279,15 +322,13 @@ private fun AdditionalSettings() {
private fun FormatSelectionAuto() {
MaterialTheme {
var selected by remember { mutableStateOf(false) }
Surface {
SingleChoiceItem(
title = stringResource(R.string.presets),
desc = "Prefer Quality, 1080p",
icon = Icons.Outlined.VideoFile,
selected = selected
) {
selected = !selected
}
SingleChoiceItem(
title = stringResource(R.string.presets),
desc = "Prefer Quality, 1080p",
icon = Icons.Outlined.VideoFile,
selected = selected
) {
selected = !selected
}
}
}
@ -344,15 +385,13 @@ fun SingleChoiceItem(
private fun FormatSelectionCustom() {
MaterialTheme {
var selected by remember { mutableStateOf(true) }
Surface {
SingleChoiceItem(
title = "Custom",
desc = "Select from formats, subtitles, and customize further",
icon = Icons.Outlined.VideoSettings,
selected = selected
) {
selected = !selected
}
SingleChoiceItem(
title = "Custom",
desc = "Select from formats, subtitles, and customize further",
icon = Icons.Outlined.VideoSettings,
selected = selected
) {
selected = !selected
}
}
}