mirror of
https://github.com/JunkFood02/Seal.git
synced 2025-08-06 14:21:18 +08:00
feat: format selection page (wip)
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@ -15,4 +15,5 @@
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
local.properties
|
||||
/keystore.properties
|
||||
/keystore.properties
|
||||
.kotlin
|
@ -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()
|
||||
)
|
||||
},
|
||||
) {}
|
||||
}
|
@ -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")),
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user