From ff6e3f95bd3558b3dae9770c91fb84b86c2428ed Mon Sep 17 00:00:00 2001 From: Arumugam J Date: Fri, 12 Apr 2024 17:37:27 -0400 Subject: [PATCH] Use New theme --- composeApp/src/commonMain/kotlin/App.kt | 2 +- .../commonMain/kotlin/ui/home/FileDetails.kt | 35 ++----- .../commonMain/kotlin/ui/home/HomeScreen.kt | 38 ++------ .../src/commonMain/kotlin/ui/theme/Color.kt | 92 +++++++++---------- .../src/commonMain/kotlin/ui/theme/Theme.kt | 4 +- .../jsixface/codexvert/api/ConversionApi.kt | 28 ++---- .../io/github/jsixface/common/MediaModels.kt | 50 +++++----- 7 files changed, 106 insertions(+), 143 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/App.kt b/composeApp/src/commonMain/kotlin/App.kt index 9c9302a..849dd82 100644 --- a/composeApp/src/commonMain/kotlin/App.kt +++ b/composeApp/src/commonMain/kotlin/App.kt @@ -1,8 +1,8 @@ import androidx.compose.runtime.Composable import org.koin.compose.KoinApplication import services.Koin -import ui.theme.AppTheme import ui.MainScreen +import ui.theme.AppTheme @Composable fun App() { diff --git a/composeApp/src/commonMain/kotlin/ui/home/FileDetails.kt b/composeApp/src/commonMain/kotlin/ui/home/FileDetails.kt index 8fc8142..d2a63d5 100644 --- a/composeApp/src/commonMain/kotlin/ui/home/FileDetails.kt +++ b/composeApp/src/commonMain/kotlin/ui/home/FileDetails.kt @@ -1,20 +1,10 @@ package ui.home -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.foundation.layout.width +import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Button -import androidx.compose.material3.Card -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.FilterChip -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text +import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateMapOf import androidx.compose.runtime.remember @@ -23,13 +13,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties -import io.github.jsixface.common.AudioCodecs -import io.github.jsixface.common.Conversion +import io.github.jsixface.common.* import io.github.jsixface.common.Conversion.Convert -import io.github.jsixface.common.MediaTrack -import io.github.jsixface.common.TrackType -import io.github.jsixface.common.VideoCodecs -import io.github.jsixface.common.VideoFile @Composable fun FileDetailsDialog(file: VideoFile, onDismiss: (Map?) -> Unit) { @@ -51,7 +36,7 @@ fun FileDetails(file: VideoFile, onDismiss: (Map?) -> Un } val padder = Modifier.padding(16.dp) - Card( + OutlinedCard( modifier = padder.width(800.dp), shape = RoundedCornerShape(16.dp), ) { @@ -79,8 +64,8 @@ fun FileDetails(file: VideoFile, onDismiss: (Map?) -> Un } Row { - Button(onClick = { onDismiss(null) }, modifier = padder) { Text("Cancel") } Button(onClick = { onDismiss(conversion.toMap()) }, modifier = padder) { Text("Convert") } + Button(onClick = { onDismiss(null) }, modifier = padder) { Text("Cancel") } } } } @@ -89,7 +74,7 @@ fun FileDetails(file: VideoFile, onDismiss: (Map?) -> Un @OptIn(ExperimentalMaterial3Api::class) @Composable private fun CodecRow(ai: Int, track: MediaTrack, selected: Conversion, onSelect: (Conversion) -> Unit) { - val codecsAvailable = if (track.type == TrackType.Audio) AudioCodecs else VideoCodecs + val codecsAvailable = Codec.entries.filter { it.type == track.type } Row(modifier = Modifier.padding(16.dp, 4.dp), verticalAlignment = Alignment.CenterVertically) { Text("Track $ai", modifier = Modifier.weight(1f)) Row(modifier = Modifier.weight(2f), verticalAlignment = Alignment.CenterVertically) { @@ -103,20 +88,20 @@ private fun CodecRow(ai: Int, track: MediaTrack, selected: Conversion, onSelect: label = { Text("KEEP") }, modifier = Modifier.padding(3.dp, 0.dp), ) - codecsAvailable.filter { it != track.codec }.forEach { c -> + codecsAvailable.filter { it.name.lowercase() != track.codec.lowercase() }.forEach { c -> val convert = Convert(c) FilterChip( onClick = { onSelect(convert) }, selected = (selected as? Convert)?.codec == c, - label = { Text(c) }, - modifier = Modifier.padding(3.dp, 0.dp) + label = { Text(c.name) }, + modifier = Modifier.padding(3.dp, 0.dp), ) } FilterChip( onClick = { onSelect(Conversion.Drop) }, selected = (selected == Conversion.Drop), label = { Text("DROP") }, - modifier = Modifier.padding(3.dp, 0.dp) + modifier = Modifier.padding(3.dp, 0.dp), ) } } diff --git a/composeApp/src/commonMain/kotlin/ui/home/HomeScreen.kt b/composeApp/src/commonMain/kotlin/ui/home/HomeScreen.kt index ddd9c50..b9a71a8 100644 --- a/composeApp/src/commonMain/kotlin/ui/home/HomeScreen.kt +++ b/composeApp/src/commonMain/kotlin/ui/home/HomeScreen.kt @@ -3,37 +3,16 @@ package ui.home import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.hoverable import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Home +import androidx.compose.material.icons.rounded.ArrowDropDown import androidx.compose.material.icons.rounded.Refresh import androidx.compose.material.icons.rounded.Search -import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ExposedDropdownMenuBox -import androidx.compose.material3.ExposedDropdownMenuDefaults -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedTextField -import androidx.compose.material3.Surface -import androidx.compose.material3.Text -import androidx.compose.material3.TextField -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -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.material3.* +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp @@ -204,16 +183,15 @@ object HomeScreen : Screen { onSelect: (String) -> Unit ) { var expanded by remember { mutableStateOf(false) } - ExposedDropdownMenuBox(expanded, onExpandedChange = { expanded = it }, modifier = sidePad.height(32.dp)) { + ExposedDropdownMenuBox(expanded, onExpandedChange = { expanded = it }, modifier = sidePad) { TextField( - // The `menuAnchor` modifier must be passed to the text field for correctness. modifier = sidePad.menuAnchor(), - readOnly = true, value = selected, - onValueChange = { onSelect(it) }, + onValueChange = { }, + readOnly = true, label = { Text(title) }, - trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) }, colors = ExposedDropdownMenuDefaults.textFieldColors(), + trailingIcon = { Icon(Icons.Rounded.ArrowDropDown, contentDescription = "Select") }, ) if (options.isNotEmpty()) { diff --git a/composeApp/src/commonMain/kotlin/ui/theme/Color.kt b/composeApp/src/commonMain/kotlin/ui/theme/Color.kt index 30e4045..5a60289 100644 --- a/composeApp/src/commonMain/kotlin/ui/theme/Color.kt +++ b/composeApp/src/commonMain/kotlin/ui/theme/Color.kt @@ -1,67 +1,67 @@ package ui.theme import androidx.compose.ui.graphics.Color -val md_theme_light_primary = Color(0xFF006590) +val md_theme_light_primary = Color(0xFF006D42) val md_theme_light_onPrimary = Color(0xFFFFFFFF) -val md_theme_light_primaryContainer = Color(0xFFC8E6FF) -val md_theme_light_onPrimaryContainer = Color(0xFF001E2F) -val md_theme_light_secondary = Color(0xFF4F606E) +val md_theme_light_primaryContainer = Color(0xFF92F7BC) +val md_theme_light_onPrimaryContainer = Color(0xFF002111) +val md_theme_light_secondary = Color(0xFF4E6355) val md_theme_light_onSecondary = Color(0xFFFFFFFF) -val md_theme_light_secondaryContainer = Color(0xFFD3E5F5) -val md_theme_light_onSecondaryContainer = Color(0xFF0B1D29) -val md_theme_light_tertiary = Color(0xFF006399) +val md_theme_light_secondaryContainer = Color(0xFFD1E8D6) +val md_theme_light_onSecondaryContainer = Color(0xFF0C1F14) +val md_theme_light_tertiary = Color(0xFF3B6471) val md_theme_light_onTertiary = Color(0xFFFFFFFF) -val md_theme_light_tertiaryContainer = Color(0xFFCDE5FF) -val md_theme_light_onTertiaryContainer = Color(0xFF001D32) +val md_theme_light_tertiaryContainer = Color(0xFFBFE9F8) +val md_theme_light_onTertiaryContainer = Color(0xFF001F27) val md_theme_light_error = Color(0xFFBA1A1A) val md_theme_light_errorContainer = Color(0xFFFFDAD6) val md_theme_light_onError = Color(0xFFFFFFFF) val md_theme_light_onErrorContainer = Color(0xFF410002) -val md_theme_light_background = Color(0xFFFCFCFF) -val md_theme_light_onBackground = Color(0xFF191C1E) -val md_theme_light_surface = Color(0xFFFCFCFF) -val md_theme_light_onSurface = Color(0xFF191C1E) -val md_theme_light_surfaceVariant = Color(0xFFDDE3EA) -val md_theme_light_onSurfaceVariant = Color(0xFF41474D) -val md_theme_light_outline = Color(0xFF71787E) -val md_theme_light_inverseOnSurface = Color(0xFFF0F0F3) -val md_theme_light_inverseSurface = Color(0xFF2E3133) -val md_theme_light_inversePrimary = Color(0xFF89CEFF) +val md_theme_light_background = Color(0xFFFBFDF8) +val md_theme_light_onBackground = Color(0xFF191C1A) +val md_theme_light_surface = Color(0xFFFBFDF8) +val md_theme_light_onSurface = Color(0xFF191C1A) +val md_theme_light_surfaceVariant = Color(0xFFDCE5DC) +val md_theme_light_onSurfaceVariant = Color(0xFF404942) +val md_theme_light_outline = Color(0xFF717972) +val md_theme_light_inverseOnSurface = Color(0xFFF0F1ED) +val md_theme_light_inverseSurface = Color(0xFF2E312E) +val md_theme_light_inversePrimary = Color(0xFF76DAA1) val md_theme_light_shadow = Color(0xFF000000) -val md_theme_light_surfaceTint = Color(0xFF006590) -val md_theme_light_outlineVariant = Color(0xFFC1C7CE) +val md_theme_light_surfaceTint = Color(0xFF006D42) +val md_theme_light_outlineVariant = Color(0xFFC0C9C0) val md_theme_light_scrim = Color(0xFF000000) -val md_theme_dark_primary = Color(0xFF89CEFF) -val md_theme_dark_onPrimary = Color(0xFF00344D) -val md_theme_dark_primaryContainer = Color(0xFF004C6E) -val md_theme_dark_onPrimaryContainer = Color(0xFFC8E6FF) -val md_theme_dark_secondary = Color(0xFFB7C9D9) -val md_theme_dark_onSecondary = Color(0xFF21323F) -val md_theme_dark_secondaryContainer = Color(0xFF384956) -val md_theme_dark_onSecondaryContainer = Color(0xFFD3E5F5) -val md_theme_dark_tertiary = Color(0xFF95CCFF) -val md_theme_dark_onTertiary = Color(0xFF003352) -val md_theme_dark_tertiaryContainer = Color(0xFF004A75) -val md_theme_dark_onTertiaryContainer = Color(0xFFCDE5FF) +val md_theme_dark_primary = Color(0xFF76DAA1) +val md_theme_dark_onPrimary = Color(0xFF003920) +val md_theme_dark_primaryContainer = Color(0xFF005231) +val md_theme_dark_onPrimaryContainer = Color(0xFF92F7BC) +val md_theme_dark_secondary = Color(0xFFB5CCBA) +val md_theme_dark_onSecondary = Color(0xFF213528) +val md_theme_dark_secondaryContainer = Color(0xFF374B3E) +val md_theme_dark_onSecondaryContainer = Color(0xFFD1E8D6) +val md_theme_dark_tertiary = Color(0xFFA3CDDC) +val md_theme_dark_onTertiary = Color(0xFF043541) +val md_theme_dark_tertiaryContainer = Color(0xFF224C58) +val md_theme_dark_onTertiaryContainer = Color(0xFFBFE9F8) val md_theme_dark_error = Color(0xFFFFB4AB) val md_theme_dark_errorContainer = Color(0xFF93000A) val md_theme_dark_onError = Color(0xFF690005) val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6) -val md_theme_dark_background = Color(0xFF191C1E) -val md_theme_dark_onBackground = Color(0xFFE2E2E5) -val md_theme_dark_surface = Color(0xFF191C1E) -val md_theme_dark_onSurface = Color(0xFFE2E2E5) -val md_theme_dark_surfaceVariant = Color(0xFF41474D) -val md_theme_dark_onSurfaceVariant = Color(0xFFC1C7CE) -val md_theme_dark_outline = Color(0xFF8B9198) -val md_theme_dark_inverseOnSurface = Color(0xFF191C1E) -val md_theme_dark_inverseSurface = Color(0xFFE2E2E5) -val md_theme_dark_inversePrimary = Color(0xFF006590) +val md_theme_dark_background = Color(0xFF191C1A) +val md_theme_dark_onBackground = Color(0xFFE1E3DE) +val md_theme_dark_surface = Color(0xFF191C1A) +val md_theme_dark_onSurface = Color(0xFFE1E3DE) +val md_theme_dark_surfaceVariant = Color(0xFF404942) +val md_theme_dark_onSurfaceVariant = Color(0xFFC0C9C0) +val md_theme_dark_outline = Color(0xFF8A938B) +val md_theme_dark_inverseOnSurface = Color(0xFF191C1A) +val md_theme_dark_inverseSurface = Color(0xFFE1E3DE) +val md_theme_dark_inversePrimary = Color(0xFF006D42) val md_theme_dark_shadow = Color(0xFF000000) -val md_theme_dark_surfaceTint = Color(0xFF89CEFF) -val md_theme_dark_outlineVariant = Color(0xFF41474D) +val md_theme_dark_surfaceTint = Color(0xFF76DAA1) +val md_theme_dark_outlineVariant = Color(0xFF404942) val md_theme_dark_scrim = Color(0xFF000000) -val seed = Color(0xFF006591) +val seed = Color(0xFF2A9260) diff --git a/composeApp/src/commonMain/kotlin/ui/theme/Theme.kt b/composeApp/src/commonMain/kotlin/ui/theme/Theme.kt index 0fbb7b9..2b1cbdd 100644 --- a/composeApp/src/commonMain/kotlin/ui/theme/Theme.kt +++ b/composeApp/src/commonMain/kotlin/ui/theme/Theme.kt @@ -78,9 +78,9 @@ fun AppTheme( content: @Composable() () -> Unit ) { val colors = if (!useDarkTheme) { - LightColors + LightColors } else { - DarkColors + DarkColors } MaterialTheme( diff --git a/server/src/main/kotlin/io/github/jsixface/codexvert/api/ConversionApi.kt b/server/src/main/kotlin/io/github/jsixface/codexvert/api/ConversionApi.kt index bb88b9e..2526320 100644 --- a/server/src/main/kotlin/io/github/jsixface/codexvert/api/ConversionApi.kt +++ b/server/src/main/kotlin/io/github/jsixface/codexvert/api/ConversionApi.kt @@ -5,28 +5,21 @@ import io.github.jsixface.common.Conversion import io.github.jsixface.common.MediaTrack import io.github.jsixface.common.VideoFile import io.ktor.utils.io.CancellationException +import kotlinx.coroutines.* +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.datetime.Clock.System +import kotlinx.datetime.LocalDateTime +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toLocalDateTime import java.io.File import java.io.InputStream import java.io.UncheckedIOException import java.nio.file.Files -import java.util.UUID +import java.util.* import kotlin.io.path.Path import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.isActive -import kotlinx.coroutines.launch -import kotlinx.datetime.Clock.System -import kotlinx.datetime.LocalDateTime -import kotlinx.datetime.TimeZone -import kotlinx.datetime.toLocalDateTime class ConversionApi(settingsApi: SettingsApi) { private val logger = logger() @@ -67,7 +60,7 @@ class ConversionApi(settingsApi: SettingsApi) { val convJob = ConvertingJob( videoFile = file, convSpecs = convSpecs, - outFile = File(newDir, file.fileName), + outFile = File(newDir, file.fileName), // TODO convert the output file always to mkv job = null, progress = MutableStateFlow(0), jobId = jobId @@ -176,9 +169,8 @@ class ConversionApi(settingsApi: SettingsApi) { is Conversion.Convert -> result += listOf( "-map", "0:${track.index}", - "-codec:$i", - conv.codec - ) + "-codec:$i" + ) + conv.codec.ffmpegParams } } return result diff --git a/shared/src/commonMain/kotlin/io/github/jsixface/common/MediaModels.kt b/shared/src/commonMain/kotlin/io/github/jsixface/common/MediaModels.kt index ef5aaed..e5e75ac 100644 --- a/shared/src/commonMain/kotlin/io/github/jsixface/common/MediaModels.kt +++ b/shared/src/commonMain/kotlin/io/github/jsixface/common/MediaModels.kt @@ -6,9 +6,17 @@ import kotlinx.datetime.toLocalDateTime import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -val AudioCodecs = listOf("aac", "libopus", "mp3") -val VideoCodecs = listOf("libx265", "libx264", "mpeg4") -val SubtitleCodecs = listOf("srt") +enum class Codec( + val type: TrackType, + val ffmpegParams: List = emptyList(), +) { + AAC(TrackType.Audio, listOf("aac")), + Opus(TrackType.Audio, listOf("libopus", "-b:a", "128K")), + MP3(TrackType.Audio, listOf("mp3", "-b:a", "128K")), + HEVC(TrackType.Video, listOf("libx265")), + H264(TrackType.Video, listOf("libx264")), + MPEG4(TrackType.Video, listOf("mpeg4")), +} @Serializable sealed class Conversion { @@ -19,7 +27,7 @@ sealed class Conversion { data object Drop : Conversion() @Serializable - data class Convert(val codec: String) : Conversion() + data class Convert(val codec: Codec) : Conversion() } enum class TrackType(val stream: String) { @@ -28,19 +36,19 @@ enum class TrackType(val stream: String) { @Serializable data class MediaTrack( - val type: TrackType, - val index: Int, - val codec: String + val type: TrackType, + val index: Int, + val codec: String ) @Serializable data class VideoFile( - val path: String, - val fileName: String, - val modifiedTime: Long, - val audios: List = listOf(), - val videos: List = listOf(), - val subtitles: List = listOf() + val path: String, + val fileName: String, + val modifiedTime: Long, + val audios: List = listOf(), + val videos: List = listOf(), + val subtitles: List = listOf() ) { val videoInfo: String get() = videos.joinToString { it.codec } @@ -54,7 +62,7 @@ data class VideoFile( val modified: String get() { val dateTime = Instant.fromEpochMilliseconds(modifiedTime) - .toLocalDateTime(TimeZone.currentSystemDefault()) + .toLocalDateTime(TimeZone.currentSystemDefault()) return "${dateTime.date} ${dateTime.time}" } @@ -62,15 +70,15 @@ data class VideoFile( @Serializable data class MediaStream( - val index: Int, - @SerialName("codec_name") - val codecName: String = "", - @SerialName("codec_type") - val codecType: String, - val channels: Int = 1 + val index: Int, + @SerialName("codec_name") + val codecName: String = "", + @SerialName("codec_type") + val codecType: String, + val channels: Int = 1 ) @Serializable data class MediaProbeInfo( - val streams: List + val streams: List )