Skip to content

Commit

Permalink
Adding auto conversion customization UI
Browse files Browse the repository at this point in the history
  • Loading branch information
jsixface committed Jan 25, 2025
1 parent e50312d commit ceebacc
Show file tree
Hide file tree
Showing 9 changed files with 286 additions and 201 deletions.
2 changes: 1 addition & 1 deletion composeApp/src/commonMain/kotlin/services/Koin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.cbor.Cbor
import org.koin.core.module.dsl.factoryOf
import org.koin.dsl.module
import ui.settings.SettingsScreenModel
import viewmodels.BackupScreenViewModel
import viewmodels.JobsScreenModel
import viewmodels.SettingsScreenModel
import viewmodels.VideoListViewModel

object Koin {
Expand Down
164 changes: 82 additions & 82 deletions composeApp/src/commonMain/kotlin/ui/JobsScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,108 +46,108 @@ import viewmodels.JobsScreenModel


private val padding = Modifier.padding(16.dp)
private val paddingSmall = Modifier.padding(8.dp)
private val paddingSmall = Modifier.padding(8.dp)


@Composable
fun JobsScreen() {
Column(
modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
val jobsScreenModel = koinInject<JobsScreenModel>()
val scope = rememberCoroutineScope()
var jobs by remember { mutableStateOf(listOf<ConversionJob>()) }
LaunchedEffect(Unit) {
scope.launch {
jobsScreenModel.jobs.collect { jobResult ->
when (jobResult) {
is ModelState.Error, is ModelState.Init -> {}
is ModelState.Success -> jobs = jobResult.result
}
@Composable
fun JobsScreen() {
Column(
modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
) {
val jobsScreenModel = koinInject<JobsScreenModel>()
val scope = rememberCoroutineScope()
var jobs by remember { mutableStateOf(listOf<ConversionJob>()) }
LaunchedEffect(Unit) {
scope.launch {
jobsScreenModel.jobs.collect { jobResult ->
when (jobResult) {
is ModelState.Error, is ModelState.Init -> {}
is ModelState.Success -> jobs = jobResult.result
}
}
}
JobContent(
jobs,
onClear = { scope.launch { jobsScreenModel.clearJobs() } },
onDelete = { scope.launch { jobsScreenModel.delete(it) } })
}
JobContent(
jobs,
onClear = { scope.launch { jobsScreenModel.clearJobs() } },
onDelete = { scope.launch { jobsScreenModel.delete(it) } })
}
}

@Composable
fun JobContent(jobs: List<ConversionJob>, onDelete: (String) -> Unit, onClear: () -> Unit) {
Card(
modifier = Modifier.width(width = 900.dp).fillMaxHeight().padding(20.dp)
) {
Column(modifier = padding) {
Row {
Text(
text = "Jobs",
fontSize = 30.sp,
modifier = padding,
textAlign = TextAlign.Center,
)
}
Column {
jobs.forEach { job -> JobItem(job) { onDelete(job.jobId) } }
}
Row(modifier = Modifier.fillMaxSize()) {
Spacer(modifier = Modifier.weight(1f))
ElevatedButton(onClick = onClear, modifier = padding) {
Text("Clear Completed")
}
Spacer(modifier = Modifier.weight(1f))
@Composable
fun JobContent(jobs: List<ConversionJob>, onDelete: (String) -> Unit, onClear: () -> Unit) {
Card(
modifier = Modifier.width(width = 900.dp).fillMaxHeight().padding(20.dp)
) {
Column(modifier = padding) {
Row {
Text(
text = "Jobs",
fontSize = 30.sp,
modifier = padding,
textAlign = TextAlign.Center,
)
}
Column {
jobs.forEach { job -> JobItem(job) { onDelete(job.jobId) } }
}
Row(modifier = Modifier.fillMaxSize()) {
Spacer(modifier = Modifier.weight(1f))
ElevatedButton(onClick = onClear, modifier = padding) {
Text("Clear Completed")
}
Spacer(modifier = Modifier.weight(1f))
}
}
}
}

@Composable
fun JobItem(job: ConversionJob, onDelete: () -> Unit) {
Column {
val progressPadding = Modifier.padding(8.dp).fillMaxWidth()
OutlinedCard(
modifier = Modifier.padding(16.dp, 4.dp).fillMaxWidth()
) {
Row(verticalAlignment = Alignment.CenterVertically) {
Column(modifier = Modifier.weight(1f).padding(8.dp)) {
Text(job.file.fileName, modifier = paddingSmall)
when (job.status) {
Starting -> LinearProgressIndicator(modifier = progressPadding)
InProgress -> LinearProgressIndicator(
progress = { job.progress / 100.0f },
modifier = progressPadding,
)
@Composable
fun JobItem(job: ConversionJob, onDelete: () -> Unit) {
Column {
val progressPadding = Modifier.padding(8.dp).fillMaxWidth()
OutlinedCard(
modifier = Modifier.padding(16.dp, 4.dp).fillMaxWidth()
) {
Row(verticalAlignment = Alignment.CenterVertically) {
Column(modifier = Modifier.weight(1f).padding(8.dp)) {
Text(job.file.fileName, modifier = paddingSmall)
when (job.status) {
Starting -> LinearProgressIndicator(modifier = progressPadding)
InProgress -> LinearProgressIndicator(
progress = { job.progress / 100.0f },
modifier = progressPadding,
)

Completed -> Text(
"Completed",
style = MaterialTheme.typography.labelSmall,
modifier = paddingSmall
)
Completed -> Text(
"Completed",
style = MaterialTheme.typography.labelSmall,
modifier = paddingSmall
)

Failed -> Text(
"Failed",
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.error,
modifier = paddingSmall
)
Failed -> Text(
"Failed",
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.error,
modifier = paddingSmall
)

Queued -> Text(
"Queued",
style = MaterialTheme.typography.labelSmall,
modifier = paddingSmall
)
}
Queued -> Text(
"Queued",
style = MaterialTheme.typography.labelSmall,
modifier = paddingSmall
)
}
if (job.status !in listOf(Failed, Completed)) {
IconButton(onClick = onDelete) {
Icon(Icons.Sharp.Close, "Cancel")
}
}
if (job.status !in listOf(Failed, Completed)) {
IconButton(onClick = onDelete) {
Icon(Icons.Sharp.Close, "Cancel")
}
}
}
}
}
}

87 changes: 87 additions & 0 deletions composeApp/src/commonMain/kotlin/ui/settings/AutoConvertUI.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package ui.settings

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.ArrowForward
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
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.unit.dp
import io.github.jsixface.common.AutoConversion
import ui.utils.ComboBox
import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.minutes

@Composable
fun AutoConvertSettings(
setting: AutoConversion, modifier: Modifier = Modifier, onChanged: (AutoConversion) -> Unit = {}
) {
Column(modifier = modifier) {
var newFrom by remember { mutableStateOf("") }
var newTo by remember { mutableStateOf("") }
Text(
"Auto Conversion",
style = MaterialTheme.typography.headlineMedium,
modifier = Modifier.padding(vertical = 16.dp)
)
setting.conversion.forEach { (from, to) ->
Row(
verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(16.dp, 4.dp).fillMaxWidth()
) {
Row(modifier = Modifier.weight(1f), horizontalArrangement = Arrangement.Center) { Text(from) }
Row(
modifier = Modifier.weight(1f), horizontalArrangement = Arrangement.Center
) { Icon(Icons.AutoMirrored.Rounded.ArrowForward, "To") }
Row(modifier = Modifier.weight(1f), horizontalArrangement = Arrangement.Center) { Text(to) }
FilledTonalButton(modifier = Modifier.padding(start = 10.dp), onClick = {
onChanged(setting.copy(conversion = setting.conversion - from))
}) {
Icon(Icons.Filled.Delete, "Delete")
}
}
}
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(16.dp, 4.dp).fillMaxWidth()) {
Row(modifier = Modifier.weight(1f)) {
TextField(
value = newFrom, onValueChange = { newFrom = it },
label = { Text("From") })
}
Row(modifier = Modifier.weight(1f), horizontalArrangement = Arrangement.Center) {
Icon(Icons.AutoMirrored.Rounded.ArrowForward, "To")
}
Row(modifier = Modifier.weight(1f)) {
TextField(value = newTo, onValueChange = { newTo = it }, label = { Text("To") })
}
OutlinedButton(modifier = Modifier.padding(start = 10.dp), onClick = {
onChanged(setting.copy(conversion = setting.conversion + mapOf(newFrom to newTo)))
newFrom = ""
newTo = ""
}) {
Icon(Icons.Filled.Add, "Add")
}
}
ComboBox(
title = "Media Scan Duration",
options = listOf(1.minutes, 5.minutes, 15.minutes, 30.minutes, 1.hours),
modifier = Modifier.padding(16.dp).fillMaxWidth(),
selected = setting.watchDuration
) { onChanged(setting.copy(watchDuration = it)) }
}

}
Loading

0 comments on commit ceebacc

Please sign in to comment.