diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c56d8278b0..632eacf87f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -165,7 +165,6 @@ dependencies { implementation(compose.ui.util) implementation(compose.accompanist.webview) implementation(compose.accompanist.permissions) - implementation(compose.accompanist.themeadapter) implementation(compose.accompanist.systemuicontroller) lintChecks(compose.lintchecks) diff --git a/app/src/main/java/eu/kanade/presentation/components/AppBar.kt b/app/src/main/java/eu/kanade/presentation/components/AppBar.kt index 0bfd039eb2..e7338c13e4 100644 --- a/app/src/main/java/eu/kanade/presentation/components/AppBar.kt +++ b/app/src/main/java/eu/kanade/presentation/components/AppBar.kt @@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.TextFieldDefaults import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.outlined.ArrowBack import androidx.compose.material.icons.outlined.Close @@ -20,7 +21,6 @@ import androidx.compose.material3.LocalContentColor import androidx.compose.material3.MaterialTheme import androidx.compose.material3.PlainTooltip import androidx.compose.material3.Text -import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TooltipBox import androidx.compose.material3.TooltipDefaults import androidx.compose.material3.TopAppBar @@ -43,7 +43,6 @@ import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalSoftwareKeyboardController -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.VisualTransformation @@ -62,10 +61,11 @@ const val SEARCH_DEBOUNCE_MILLIS = 250L @Composable fun AppBar( + title: String?, + modifier: Modifier = Modifier, backgroundColor: Color? = null, // Text - title: String?, subtitle: String? = null, // Up button navigateUp: (() -> Unit)? = null, @@ -90,7 +90,7 @@ fun AppBar( if (isActionMode) { AppBarTitle(actionModeCounter.toString()) } else { - AppBarTitle(title, subtitle) + AppBarTitle(title, subtitle = subtitle) } }, navigateUp = navigateUp, @@ -110,10 +110,11 @@ fun AppBar( @Composable fun AppBar( - modifier: Modifier = Modifier, - backgroundColor: Color? = null, // Title titleContent: @Composable () -> Unit, + + modifier: Modifier = Modifier, + backgroundColor: Color? = null, // Up button navigateUp: (() -> Unit)? = null, navigationIcon: ImageVector? = null, @@ -140,7 +141,7 @@ fun AppBar( } else { navigateUp?.let { IconButton(onClick = it) { - UpIcon(navigationIcon) + UpIcon(navigationIcon = navigationIcon) } } } @@ -160,9 +161,10 @@ fun AppBar( @Composable fun AppBarTitle( title: String?, + modifier: Modifier = Modifier, subtitle: String? = null, ) { - Column { + Column(modifier = modifier) { title?.let { Text( text = it, @@ -258,11 +260,12 @@ fun AppBarActions( */ @Composable fun SearchToolbar( + searchQuery: String?, + onChangeSearchQuery: (String?) -> Unit, + modifier: Modifier = Modifier, titleContent: @Composable () -> Unit = {}, navigateUp: (() -> Unit)? = null, searchEnabled: Boolean = true, - searchQuery: String?, - onChangeSearchQuery: (String?) -> Unit, placeholderText: String? = null, onSearch: (String) -> Unit = {}, onClickCloseSearch: () -> Unit = { onChangeSearchQuery(null) }, @@ -274,6 +277,7 @@ fun SearchToolbar( val focusRequester = remember { FocusRequester() } AppBar( + modifier = modifier, titleContent = { if (searchQuery == null) return@AppBar titleContent() @@ -390,12 +394,16 @@ fun SearchToolbar( } @Composable -fun UpIcon(navigationIcon: ImageVector? = null) { +fun UpIcon( + modifier: Modifier = Modifier, + navigationIcon: ImageVector? = null, +) { val icon = navigationIcon ?: Icons.AutoMirrored.Outlined.ArrowBack Icon( imageVector = icon, contentDescription = stringResource(MR.strings.action_bar_up_description), + modifier = modifier, ) } diff --git a/app/src/main/java/eu/kanade/presentation/library/components/CommonMangaItem.kt b/app/src/main/java/eu/kanade/presentation/library/components/CommonMangaItem.kt index 83a679336b..5e4cb8d34b 100644 --- a/app/src/main/java/eu/kanade/presentation/library/components/CommonMangaItem.kt +++ b/app/src/main/java/eu/kanade/presentation/library/components/CommonMangaItem.kt @@ -50,7 +50,7 @@ object CommonMangaItemDefaults { const val BrowseFavoriteCoverAlpha = 0.34f } -private val ContinueReadingButtonSize = 32.dp +private val ContinueReadingButtonSize = 28.dp private val ContinueReadingButtonGridPadding = 6.dp private val ContinueReadingButtonListSpacing = 8.dp diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MangaToolbar.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MangaToolbar.kt index 5aa17a449f..e25eb8b259 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/MangaToolbar.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/MangaToolbar.kt @@ -67,7 +67,7 @@ fun MangaToolbar( }, navigationIcon = { IconButton(onClick = onBackClicked) { - UpIcon(Icons.Outlined.Close.takeIf { isActionMode }) + UpIcon(navigationIcon = Icons.Outlined.Close.takeIf { isActionMode }) } }, actions = { diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt index 77dd72587d..70debc941e 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt @@ -85,8 +85,6 @@ object SettingsDataScreen : SearchableSettings { @Composable private fun getBackupAndRestoreGroup(backupPreferences: BackupPreferences): Preference.PreferenceGroup { val context = LocalContext.current - val backupIntervalPref = backupPreferences.backupInterval() - val backupInterval by backupIntervalPref.collectAsState() val lastAutoBackup by backupPreferences.lastAutoBackupTimestamp().collectAsState() return Preference.PreferenceGroup( @@ -98,7 +96,7 @@ object SettingsDataScreen : SearchableSettings { // Automatic backups Preference.PreferenceItem.ListPreference( - pref = backupIntervalPref, + pref = backupPreferences.backupInterval(), title = stringResource(MR.strings.pref_backup_interval), entries = mapOf( 0 to stringResource(MR.strings.off), @@ -113,12 +111,6 @@ object SettingsDataScreen : SearchableSettings { true }, ), - Preference.PreferenceItem.ListPreference( - pref = backupPreferences.numberOfBackups(), - enabled = backupInterval != 0, - title = stringResource(MR.strings.pref_backup_slots), - entries = listOf(2, 3, 4, 5).associateWith { it.toString() }, - ), Preference.PreferenceItem.InfoPreference( stringResource(MR.strings.backup_info) + "\n\n" + stringResource(MR.strings.last_auto_backup_info, relativeTimeSpanString(lastAutoBackup)), diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt index 0e254d8a66..aac9259a1b 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt @@ -245,10 +245,12 @@ object SettingsReaderScreen : SearchableSettings { val navModePref = readerPreferences.navigationModeWebtoon() val dualPageSplitPref = readerPreferences.dualPageSplitWebtoon() + val rotateToFitPref = readerPreferences.dualPageRotateToFitWebtoon() val webtoonSidePaddingPref = readerPreferences.webtoonSidePadding() val navMode by navModePref.collectAsState() val dualPageSplit by dualPageSplitPref.collectAsState() + val rotateToFit by rotateToFitPref.collectAsState() val webtoonSidePadding by webtoonSidePaddingPref.collectAsState() return Preference.PreferenceGroup( @@ -300,6 +302,10 @@ object SettingsReaderScreen : SearchableSettings { Preference.PreferenceItem.SwitchPreference( pref = dualPageSplitPref, title = stringResource(MR.strings.pref_dual_page_split), + onValueChanged = { + rotateToFitPref.set(false) + true + }, ), Preference.PreferenceItem.SwitchPreference( pref = readerPreferences.dualPageInvertWebtoon(), @@ -307,6 +313,19 @@ object SettingsReaderScreen : SearchableSettings { subtitle = stringResource(MR.strings.pref_dual_page_invert_summary), enabled = dualPageSplit, ), + Preference.PreferenceItem.SwitchPreference( + pref = rotateToFitPref, + title = stringResource(MR.strings.pref_page_rotate), + onValueChanged = { + dualPageSplitPref.set(false) + true + }, + ), + Preference.PreferenceItem.SwitchPreference( + pref = readerPreferences.dualPageRotateToFitInvertWebtoon(), + title = stringResource(MR.strings.pref_page_rotate_invert), + enabled = rotateToFit, + ), Preference.PreferenceItem.SwitchPreference( pref = readerPreferences.webtoonDoubleTapZoomEnabled(), title = stringResource(MR.strings.pref_double_tap_zoom), diff --git a/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt b/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt index 89fcac78ab..ee2eb854f7 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/settings/ReadingModePage.kt @@ -180,6 +180,19 @@ private fun ColumnScope.WebtoonViewerSettings(screenModel: ReaderSettingsScreenM ) } + val dualPageRotateToFitWebtoon by screenModel.preferences.dualPageRotateToFitWebtoon().collectAsState() + CheckboxItem( + label = stringResource(MR.strings.pref_page_rotate), + pref = screenModel.preferences.dualPageRotateToFitWebtoon(), + ) + + if (dualPageRotateToFitWebtoon) { + CheckboxItem( + label = stringResource(MR.strings.pref_page_rotate_invert), + pref = screenModel.preferences.dualPageRotateToFitInvertWebtoon(), + ) + } + CheckboxItem( label = stringResource(MR.strings.pref_double_tap_zoom), pref = screenModel.preferences.webtoonDoubleTapZoomEnabled(), diff --git a/app/src/main/java/eu/kanade/presentation/theme/TachiyomiTheme.kt b/app/src/main/java/eu/kanade/presentation/theme/TachiyomiTheme.kt index 7edfb01328..c464ceb3ae 100644 --- a/app/src/main/java/eu/kanade/presentation/theme/TachiyomiTheme.kt +++ b/app/src/main/java/eu/kanade/presentation/theme/TachiyomiTheme.kt @@ -1,54 +1,62 @@ package eu.kanade.presentation.theme -import androidx.appcompat.view.ContextThemeWrapper +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.ColorScheme import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember +import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalLayoutDirection -import com.google.accompanist.themeadapter.material3.createMdc3Theme +import eu.kanade.domain.ui.UiPreferences import eu.kanade.domain.ui.model.AppTheme -import eu.kanade.tachiyomi.ui.base.delegate.ThemingDelegate - -@Composable -fun TachiyomiTheme(content: @Composable () -> Unit) { - val context = LocalContext.current - val layoutDirection = LocalLayoutDirection.current - - val (colorScheme, typography) = createMdc3Theme( - context = context, - layoutDirection = layoutDirection, - ) - - MaterialTheme( - colorScheme = colorScheme!!, - typography = typography!!, - content = content, - ) -} +import eu.kanade.presentation.theme.colorscheme.GreenAppleColorScheme +import eu.kanade.presentation.theme.colorscheme.LavenderColorScheme +import eu.kanade.presentation.theme.colorscheme.MidnightDuskColorScheme +import eu.kanade.presentation.theme.colorscheme.MonetColorScheme +import eu.kanade.presentation.theme.colorscheme.StrawberryColorScheme +import eu.kanade.presentation.theme.colorscheme.TachiyomiColorScheme +import eu.kanade.presentation.theme.colorscheme.TakoColorScheme +import eu.kanade.presentation.theme.colorscheme.TealTurqoiseColorScheme +import eu.kanade.presentation.theme.colorscheme.TidalWaveColorScheme +import eu.kanade.presentation.theme.colorscheme.YinYangColorScheme +import eu.kanade.presentation.theme.colorscheme.YotsubaColorScheme +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get @Composable fun TachiyomiTheme( - appTheme: AppTheme, - amoled: Boolean, + appTheme: AppTheme? = null, + amoled: Boolean? = null, content: @Composable () -> Unit, ) { - val originalContext = LocalContext.current - val layoutDirection = LocalLayoutDirection.current - val themedContext = remember(appTheme, originalContext) { - val themeResIds = ThemingDelegate.getThemeResIds(appTheme, amoled) - themeResIds.fold(originalContext) { context, themeResId -> - ContextThemeWrapper(context, themeResId) - } - } - val (colorScheme, typography) = createMdc3Theme( - context = themedContext, - layoutDirection = layoutDirection, - ) - MaterialTheme( - colorScheme = colorScheme!!, - typography = typography!!, + colorScheme = getThemeColorScheme(appTheme, amoled), content = content, ) } + +@Composable +@ReadOnlyComposable +private fun getThemeColorScheme( + appTheme: AppTheme?, + amoled: Boolean?, +): ColorScheme { + val uiPreferences = Injekt.get() + val colorScheme = when (appTheme ?: uiPreferences.appTheme().get()) { + AppTheme.DEFAULT -> TachiyomiColorScheme + AppTheme.MONET -> MonetColorScheme(LocalContext.current) + AppTheme.GREEN_APPLE -> GreenAppleColorScheme + AppTheme.LAVENDER -> LavenderColorScheme + AppTheme.MIDNIGHT_DUSK -> MidnightDuskColorScheme + AppTheme.STRAWBERRY_DAIQUIRI -> StrawberryColorScheme + AppTheme.TAKO -> TakoColorScheme + AppTheme.TEALTURQUOISE -> TealTurqoiseColorScheme + AppTheme.TIDAL_WAVE -> TidalWaveColorScheme + AppTheme.YINYANG -> YinYangColorScheme + AppTheme.YOTSUBA -> YotsubaColorScheme + else -> TachiyomiColorScheme + } + return colorScheme.getColorScheme( + isSystemInDarkTheme(), + amoled ?: uiPreferences.themeDarkAmoled().get(), + ) +} diff --git a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/BaseColorScheme.kt b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/BaseColorScheme.kt new file mode 100644 index 0000000000..605d5e5a5b --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/BaseColorScheme.kt @@ -0,0 +1,26 @@ +package eu.kanade.presentation.theme.colorscheme + +import androidx.compose.material3.ColorScheme +import androidx.compose.ui.graphics.Color + +internal abstract class BaseColorScheme { + + abstract val darkScheme: ColorScheme + abstract val lightScheme: ColorScheme + + fun getColorScheme(isDark: Boolean, isAmoled: Boolean): ColorScheme { + return (if (isDark) darkScheme else lightScheme) + .let { + if (isDark && isAmoled) { + it.copy( + background = Color.Black, + onBackground = Color.White, + surface = Color.Black, + onSurface = Color.White, + ) + } else { + it + } + } + } +} diff --git a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/GreenAppleColorScheme.kt b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/GreenAppleColorScheme.kt new file mode 100644 index 0000000000..354faed5f2 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/GreenAppleColorScheme.kt @@ -0,0 +1,71 @@ +package eu.kanade.presentation.theme.colorscheme + +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.ui.graphics.Color + +/** + * Colors for Green Apple theme + * Original color scheme by CarlosEsco, Jays2Kings and CrepeTF + * M3 colors generated by Material Theme Builder (https://goo.gle/material-theme-builder-web) + * + * Key colors: + * Primary #188140 + * Secondary #188140 + * Tertiary #D33131 + * Neutral #5D5F5B + */ +internal object GreenAppleColorScheme : BaseColorScheme() { + + override val darkScheme = darkColorScheme( + primary = Color(0xFF7ADB8F), + onPrimary = Color(0xFF003915), + primaryContainer = Color(0xFF005322), + onPrimaryContainer = Color(0xFF96F8A9), + inversePrimary = Color(0xFF006D2F), + secondary = Color(0xFF7ADB8F), + onSecondary = Color(0xFF003915), + secondaryContainer = Color(0xFF005322), + onSecondaryContainer = Color(0xFF96F8A9), + tertiary = Color(0xFFFFB3AA), + onTertiary = Color(0xFF680006), + tertiaryContainer = Color(0xFF93000D), + onTertiaryContainer = Color(0xFFFFDAD5), + background = Color(0xFF1A1C19), + onBackground = Color(0xFFE1E3DD), + surface = Color(0xFF1A1C19), + onSurface = Color(0xFFE1E3DD), + surfaceVariant = Color(0xFF414941), + onSurfaceVariant = Color(0xFFC1C8BE), + surfaceTint = Color(0xFF7ADB8F), + inverseSurface = Color(0xFFE1E3DD), + inverseOnSurface = Color(0xFF1A1C19), + outline = Color(0xFF8B9389), + ) + + override val lightScheme = lightColorScheme( + primary = Color(0xFF006D2F), + onPrimary = Color(0xFFFFFFFF), + primaryContainer = Color(0xFF96F8A9), + onPrimaryContainer = Color(0xFF002109), + inversePrimary = Color(0xFF7ADB8F), + secondary = Color(0xFF006D2F), + onSecondary = Color(0xFFFFFFFF), + secondaryContainer = Color(0xFF96F8A9), + onSecondaryContainer = Color(0xFF002109), + tertiary = Color(0xFFB91D22), + onTertiary = Color(0xFFFFFFFF), + tertiaryContainer = Color(0xFFFFDAD5), + onTertiaryContainer = Color(0xFF410003), + background = Color(0xFFFBFDF7), + onBackground = Color(0xFF1A1C19), + surface = Color(0xFFFBFDF7), + onSurface = Color(0xFF1A1C19), + surfaceVariant = Color(0xFFDDE5DA), + onSurfaceVariant = Color(0xFF414941), + surfaceTint = Color(0xFF006D2F), + inverseSurface = Color(0xFF2F312E), + inverseOnSurface = Color(0xFFF0F2EC), + outline = Color(0xFF717970), + ) +} diff --git a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/LavenderColorScheme.kt b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/LavenderColorScheme.kt new file mode 100644 index 0000000000..70a9bd196f --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/LavenderColorScheme.kt @@ -0,0 +1,70 @@ +package eu.kanade.presentation.theme.colorscheme + +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.ui.graphics.Color + +/** + * Colors for Lavender theme + * Color scheme by Osyx + * + * Key colors: + * Primary #A177FF + * Secondary #A177FF + * Tertiary #5E25E1 + * Neutral #111129 + */ +internal object LavenderColorScheme : BaseColorScheme() { + + override val darkScheme = darkColorScheme( + primary = Color(0xFFA177FF), + onPrimary = Color(0xFF111129), + primaryContainer = Color(0xFFA177FF), + onPrimaryContainer = Color(0xFF111129), + inversePrimary = Color(0xFF006D2F), + secondary = Color(0xFFA177FF), + onSecondary = Color(0xFF111129), + secondaryContainer = Color(0xFFA177FF), + onSecondaryContainer = Color(0xFF111129), + tertiary = Color(0xFF5E25E1), + onTertiary = Color(0xFFE8E8E8), + tertiaryContainer = Color(0xFF111129), + onTertiaryContainer = Color(0xFFDEE8FF), + background = Color(0xFF111129), + onBackground = Color(0xFFDEE8FF), + surface = Color(0xFF111129), + onSurface = Color(0xFFDEE8FF), + surfaceVariant = Color(0x2CB6B6B6), + onSurfaceVariant = Color(0xFFE8E8E8), + surfaceTint = Color(0xFFA177FF), + inverseSurface = Color(0xFF221247), + inverseOnSurface = Color(0xFFDEE8FF), + outline = Color(0xA8905FFF), + ) + + override val lightScheme = lightColorScheme( + primary = Color(0xFF7B46AF), + onPrimary = Color(0xFFEDE2FF), + primaryContainer = Color(0xFF7B46AF), + onPrimaryContainer = Color(0xFFEDE2FF), + inversePrimary = Color(0xFFD6BAFF), + secondary = Color(0xFF7B46AF), + onSecondary = Color(0xFFEDE2FF), + secondaryContainer = Color(0xFF7B46AF), + onSecondaryContainer = Color(0xFFEDE2FF), + tertiary = Color(0xFFEDE2FF), + onTertiary = Color(0xFF7B46AF), + tertiaryContainer = Color(0xFFEDE2FF), + onTertiaryContainer = Color(0xFF7B46AF), + background = Color(0xFFEDE2FF), + onBackground = Color(0xFF1B1B22), + surface = Color(0xFFEDE2FF), + onSurface = Color(0xFF1B1B22), + surfaceVariant = Color(0xFFB9B0CC), + onSurfaceVariant = Color(0xD849454E), + surfaceTint = Color(0xFF7B46AF), + inverseSurface = Color(0xFF313033), + inverseOnSurface = Color(0xFFF3EFF4), + outline = Color(0xFF7B46AF), + ) +} diff --git a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/MidnightDuskColorScheme.kt b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/MidnightDuskColorScheme.kt new file mode 100644 index 0000000000..7feaae333a --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/MidnightDuskColorScheme.kt @@ -0,0 +1,71 @@ +package eu.kanade.presentation.theme.colorscheme + +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.ui.graphics.Color + +/** + * Colors for Midnight Dusk theme + * Original color scheme by CrepeTF + * M3 color scheme generated by Material Theme Builder (https://goo.gle/material-theme-builder-web) + * + * Key colors: + * Primary #F02475 + * Secondary #F02475 + * Tertiary #7A5733 + * Neutral #16151D + */ +internal object MidnightDuskColorScheme : BaseColorScheme() { + + override val darkScheme = darkColorScheme( + primary = Color(0xFFF02475), + onPrimary = Color(0xFFFFFFFF), + primaryContainer = Color(0xFFBD1C5C), + onPrimaryContainer = Color(0xFFFFFFFF), + inversePrimary = Color(0xFFF02475), + secondary = Color(0xFFF02475), + onSecondary = Color(0xFFFFFFFF), + secondaryContainer = Color(0xFFF02475), + onSecondaryContainer = Color(0xFFFFFFFF), + tertiary = Color(0xFF55971C), + onTertiary = Color(0xFFFFFFFF), + tertiaryContainer = Color(0xFF386412), + onTertiaryContainer = Color(0xFFE5E1E5), + background = Color(0xFF16151D), + onBackground = Color(0xFFE5E1E5), + surface = Color(0xFF16151D), + onSurface = Color(0xFFE5E1E5), + surfaceVariant = Color(0xFF524346), + onSurfaceVariant = Color(0xFFD6C1C4), + surfaceTint = Color(0xFFF02475), + inverseSurface = Color(0xFF333043), + inverseOnSurface = Color(0xFFFFFFFF), + outline = Color(0xFF9F8C8F), + ) + + override val lightScheme = lightColorScheme( + primary = Color(0xFFBB0054), + onPrimary = Color(0xFFFFFFFF), + primaryContainer = Color(0xFFFFD9E1), + onPrimaryContainer = Color(0xFF3F0017), + inversePrimary = Color(0xFFFFB1C4), + secondary = Color(0xFFBB0054), + onSecondary = Color(0xFFFFFFFF), + secondaryContainer = Color(0xFFFFD9E1), + onSecondaryContainer = Color(0xFF3F0017), + tertiary = Color(0xFF006638), + onTertiary = Color(0xFFFFFFFF), + tertiaryContainer = Color(0xFF00894b), + onTertiaryContainer = Color(0xFF2D1600), + background = Color(0xFFFFFBFF), + onBackground = Color(0xFF1C1B1F), + surface = Color(0xFFFFFBFF), + onSurface = Color(0xFF1C1B1F), + surfaceVariant = Color(0xFFF3DDE0), + onSurfaceVariant = Color(0xFF524346), + surfaceTint = Color(0xFFBB0054), + inverseSurface = Color(0xFF313033), + inverseOnSurface = Color(0xFFF4F0F4), + outline = Color(0xFF847376), + ) +} diff --git a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/MonetColorScheme.kt b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/MonetColorScheme.kt new file mode 100644 index 0000000000..adcbaf62fa --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/MonetColorScheme.kt @@ -0,0 +1,125 @@ +package eu.kanade.presentation.theme.colorscheme + +import android.annotation.SuppressLint +import android.app.UiModeManager +import android.app.WallpaperManager +import android.content.Context +import android.graphics.Bitmap +import android.os.Build +import androidx.annotation.RequiresApi +import androidx.compose.material3.ColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.ui.graphics.Color +import androidx.core.content.getSystemService +import com.google.android.material.color.utilities.Hct +import com.google.android.material.color.utilities.MaterialDynamicColors +import com.google.android.material.color.utilities.QuantizerCelebi +import com.google.android.material.color.utilities.SchemeContent +import com.google.android.material.color.utilities.Score + +internal class MonetColorScheme(context: Context) : BaseColorScheme() { + + private val monet = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + MonetSystemColorScheme(context) + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { + val seed = WallpaperManager.getInstance(context) + .getWallpaperColors(WallpaperManager.FLAG_SYSTEM) + ?.primaryColor + ?.toArgb() + if (seed != null) { + MonetCompatColorScheme(context, seed) + } else { + TachiyomiColorScheme + } + } else { + TachiyomiColorScheme + } + + override val darkScheme + get() = monet.darkScheme + + override val lightScheme + get() = monet.lightScheme + + companion object { + @Suppress("Unused") + @SuppressLint("RestrictedApi") + fun extractSeedColorFromImage(bitmap: Bitmap): Int? { + val width = bitmap.width + val height = bitmap.height + val bitmapPixels = IntArray(width * height) + bitmap.getPixels(bitmapPixels, 0, width, 0, 0, width, height) + return Score.score(QuantizerCelebi.quantize(bitmapPixels, 128), 1, 0)[0] + .takeIf { it != 0 } // Don't take fallback color + } + } +} + +@RequiresApi(Build.VERSION_CODES.S) +private class MonetSystemColorScheme(context: Context) : BaseColorScheme() { + override val lightScheme = dynamicLightColorScheme(context) + override val darkScheme = dynamicDarkColorScheme(context) +} + +private class MonetCompatColorScheme(context: Context, seed: Int) : BaseColorScheme() { + + override val lightScheme = generateColorSchemeFromSeed(context = context, seed = seed, dark = false) + override val darkScheme = generateColorSchemeFromSeed(context = context, seed = seed, dark = true) + + companion object { + private fun Int.toComposeColor(): Color = Color(this) + + @SuppressLint("PrivateResource", "RestrictedApi") + private fun generateColorSchemeFromSeed(context: Context, seed: Int, dark: Boolean): ColorScheme { + val scheme = SchemeContent( + Hct.fromInt(seed), + dark, + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + context.getSystemService()?.contrast?.toDouble() ?: 0.0 + } else { + 0.0 + }, + ) + val dynamicColors = MaterialDynamicColors() + return ColorScheme( + primary = dynamicColors.primary().getArgb(scheme).toComposeColor(), + onPrimary = dynamicColors.onPrimary().getArgb(scheme).toComposeColor(), + primaryContainer = dynamicColors.primaryContainer().getArgb(scheme).toComposeColor(), + onPrimaryContainer = dynamicColors.onPrimaryContainer().getArgb(scheme).toComposeColor(), + inversePrimary = dynamicColors.inversePrimary().getArgb(scheme).toComposeColor(), + secondary = dynamicColors.secondary().getArgb(scheme).toComposeColor(), + onSecondary = dynamicColors.onSecondary().getArgb(scheme).toComposeColor(), + secondaryContainer = dynamicColors.secondaryContainer().getArgb(scheme).toComposeColor(), + onSecondaryContainer = dynamicColors.onSecondaryContainer().getArgb(scheme).toComposeColor(), + tertiary = dynamicColors.tertiary().getArgb(scheme).toComposeColor(), + onTertiary = dynamicColors.onTertiary().getArgb(scheme).toComposeColor(), + tertiaryContainer = dynamicColors.tertiary().getArgb(scheme).toComposeColor(), + onTertiaryContainer = dynamicColors.onTertiaryContainer().getArgb(scheme).toComposeColor(), + background = dynamicColors.background().getArgb(scheme).toComposeColor(), + onBackground = dynamicColors.onBackground().getArgb(scheme).toComposeColor(), + surface = dynamicColors.surface().getArgb(scheme).toComposeColor(), + onSurface = dynamicColors.onSurface().getArgb(scheme).toComposeColor(), + surfaceVariant = dynamicColors.surfaceVariant().getArgb(scheme).toComposeColor(), + onSurfaceVariant = dynamicColors.onSurfaceVariant().getArgb(scheme).toComposeColor(), + surfaceTint = dynamicColors.surfaceTint().getArgb(scheme).toComposeColor(), + inverseSurface = dynamicColors.inverseSurface().getArgb(scheme).toComposeColor(), + inverseOnSurface = dynamicColors.inverseOnSurface().getArgb(scheme).toComposeColor(), + error = dynamicColors.error().getArgb(scheme).toComposeColor(), + onError = dynamicColors.onError().getArgb(scheme).toComposeColor(), + errorContainer = dynamicColors.errorContainer().getArgb(scheme).toComposeColor(), + onErrorContainer = dynamicColors.onErrorContainer().getArgb(scheme).toComposeColor(), + outline = dynamicColors.outline().getArgb(scheme).toComposeColor(), + outlineVariant = dynamicColors.outlineVariant().getArgb(scheme).toComposeColor(), + scrim = Color.Black, + surfaceBright = dynamicColors.surfaceBright().getArgb(scheme).toComposeColor(), + surfaceDim = dynamicColors.surfaceDim().getArgb(scheme).toComposeColor(), + surfaceContainer = dynamicColors.surfaceContainer().getArgb(scheme).toComposeColor(), + surfaceContainerHigh = dynamicColors.surfaceContainerHigh().getArgb(scheme).toComposeColor(), + surfaceContainerHighest = dynamicColors.surfaceContainerHighest().getArgb(scheme).toComposeColor(), + surfaceContainerLow = dynamicColors.surfaceContainerLow().getArgb(scheme).toComposeColor(), + surfaceContainerLowest = dynamicColors.surfaceContainerLowest().getArgb(scheme).toComposeColor(), + ) + } + } +} diff --git a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/StrawberryColorScheme.kt b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/StrawberryColorScheme.kt new file mode 100644 index 0000000000..98417e3364 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/StrawberryColorScheme.kt @@ -0,0 +1,71 @@ +package eu.kanade.presentation.theme.colorscheme + +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.ui.graphics.Color + +/** + * Colors for Strawberry Daiquiri theme + * Original color scheme by Soitora + * M3 color scheme generated by Material Theme Builder (https://goo.gle/material-theme-builder-web) + * + * Key colors: + * Primary #ED4A65 + * Secondary #ED4A65 + * Tertiary #775930 + * Neutral #655C5C + */ +internal object StrawberryColorScheme : BaseColorScheme() { + + override val darkScheme = darkColorScheme( + primary = Color(0xFFFFB2B9), + onPrimary = Color(0xFF67001B), + primaryContainer = Color(0xFF91002A), + onPrimaryContainer = Color(0xFFFFDADD), + inversePrimary = Color(0xFFB61E40), + secondary = Color(0xFFFFB2B9), + onSecondary = Color(0xFF67001B), + secondaryContainer = Color(0xFF91002A), + onSecondaryContainer = Color(0xFFFFDADD), + tertiary = Color(0xFFE8C08E), + onTertiary = Color(0xFF432C06), + tertiaryContainer = Color(0xFF5D421B), + onTertiaryContainer = Color(0xFFFFDDB1), + background = Color(0xFF201A1A), + onBackground = Color(0xFFECDFDF), + surface = Color(0xFF201A1A), + onSurface = Color(0xFFECDFDF), + surfaceVariant = Color(0xFF534344), + onSurfaceVariant = Color(0xFFD7C1C2), + surfaceTint = Color(0xFFFFB2B9), + inverseSurface = Color(0xFFECDFDF), + inverseOnSurface = Color(0xFF201A1A), + outline = Color(0xFFA08C8D), + ) + + override val lightScheme = lightColorScheme( + primary = Color(0xFFB61E40), + onPrimary = Color(0xFFFFFFFF), + primaryContainer = Color(0xFFFFDADD), + onPrimaryContainer = Color(0xFF40000D), + inversePrimary = Color(0xFFFFB2B9), + secondary = Color(0xFFB61E40), + onSecondary = Color(0xFFFFFFFF), + secondaryContainer = Color(0xFFFFDADD), + onSecondaryContainer = Color(0xFF40000D), + tertiary = Color(0xFF775930), + onTertiary = Color(0xFFFFFFFF), + tertiaryContainer = Color(0xFFFFDDB1), + onTertiaryContainer = Color(0xFF2A1800), + background = Color(0xFFFCFCFC), + onBackground = Color(0xFF201A1A), + surface = Color(0xFFFCFCFC), + onSurface = Color(0xFF201A1A), + surfaceVariant = Color(0xFFF4DDDD), + onSurfaceVariant = Color(0xFF534344), + surfaceTint = Color(0xFFB61E40), + inverseSurface = Color(0xFF362F2F), + inverseOnSurface = Color(0xFFFBEDED), + outline = Color(0xFF857374), + ) +} diff --git a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TachiyomiColorScheme.kt b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TachiyomiColorScheme.kt new file mode 100644 index 0000000000..974d5f22d3 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TachiyomiColorScheme.kt @@ -0,0 +1,80 @@ +package eu.kanade.presentation.theme.colorscheme + +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.ui.graphics.Color + +/** + * Colors for Default theme + * M3 colors generated by Material Theme Builder (https://goo.gle/material-theme-builder-web) + * + * Key colors: + * Primary #2979FF + * Secondary #2979FF + * Tertiary #47A84A + * Neutral #919094 + */ +internal object TachiyomiColorScheme : BaseColorScheme() { + + override val darkScheme = darkColorScheme( + primary = Color(0xFFB0C6FF), + onPrimary = Color(0xFF002D6E), + primaryContainer = Color(0xFF00429B), + onPrimaryContainer = Color(0xFFD9E2FF), + inversePrimary = Color(0xFF0058CA), + secondary = Color(0xFFB0C6FF), + onSecondary = Color(0xFF002D6E), + secondaryContainer = Color(0xFF00429B), + onSecondaryContainer = Color(0xFFD9E2FF), + tertiary = Color(0xFF7ADC77), + onTertiary = Color(0xFF003909), + tertiaryContainer = Color(0xFF005312), + onTertiaryContainer = Color(0xFF95F990), + background = Color(0xFF1B1B1F), + onBackground = Color(0xFFE3E2E6), + surface = Color(0xFF1B1B1F), + onSurface = Color(0xFFE3E2E6), + surfaceVariant = Color(0xFF44464F), + onSurfaceVariant = Color(0xFFC5C6D0), + surfaceTint = Color(0xFFB0C6FF), + inverseSurface = Color(0xFFE3E2E6), + inverseOnSurface = Color(0xFF1B1B1F), + error = Color(0xFFFFB4AB), + onError = Color(0xFF690005), + errorContainer = Color(0xFF93000A), + onErrorContainer = Color(0xFFFFDAD6), + outline = Color(0xFF8F9099), + outlineVariant = Color(0xFF44464F), + ) + + override val lightScheme = lightColorScheme( + primary = Color(0xFF0058CA), + onPrimary = Color(0xFFFFFFFF), + primaryContainer = Color(0xFFD9E2FF), + onPrimaryContainer = Color(0xFF001945), + inversePrimary = Color(0xFFB0C6FF), + secondary = Color(0xFF0058CA), + onSecondary = Color(0xFFFFFFFF), + secondaryContainer = Color(0xFFD9E2FF), + onSecondaryContainer = Color(0xFF001945), + tertiary = Color(0xFF006E1B), + onTertiary = Color(0xFFFFFFFF), + tertiaryContainer = Color(0xFF95F990), + onTertiaryContainer = Color(0xFF002203), + background = Color(0xFFFEFBFF), + onBackground = Color(0xFF1B1B1F), + surface = Color(0xFFFEFBFF), + onSurface = Color(0xFF1B1B1F), + surfaceVariant = Color(0xFFE1E2EC), + onSurfaceVariant = Color(0xFF44464F), + surfaceTint = Color(0xFF0058CA), + inverseSurface = Color(0xFF303034), + inverseOnSurface = Color(0xFFF2F0F4), + error = Color(0xFFBA1A1A), + onError = Color(0xFFFFFFFF), + errorContainer = Color(0xFFFFDAD6), + onErrorContainer = Color(0xFF410002), + outline = Color(0xFF757780), + outlineVariant = Color(0xFFC5C6D0), + ) +} diff --git a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TakoColorScheme.kt b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TakoColorScheme.kt new file mode 100644 index 0000000000..244e769d4c --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TakoColorScheme.kt @@ -0,0 +1,71 @@ +package eu.kanade.presentation.theme.colorscheme + +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.ui.graphics.Color + +/** + * Colors for Tako theme + * Original color scheme by ghostbear + * M3 color scheme generated by Material Theme Builder (https://goo.gle/material-theme-builder-web) + * + * Key colors: + * Primary #F3B375 + * Secondary #F3B375 + * Tertiary #66577E + * Neutral #21212E + */ +internal object TakoColorScheme : BaseColorScheme() { + + override val darkScheme = darkColorScheme( + primary = Color(0xFFF3B375), + onPrimary = Color(0xFF38294E), + primaryContainer = Color(0xFFF3B375), + onPrimaryContainer = Color(0xFF38294E), + inversePrimary = Color(0xFF84531E), + secondary = Color(0xFFF3B375), + onSecondary = Color(0xFF38294E), + secondaryContainer = Color(0xFFF3B375), + onSecondaryContainer = Color(0xFF38294E), + tertiary = Color(0xFF66577E), + onTertiary = Color(0xFFF3B375), + tertiaryContainer = Color(0xFF4E4065), + onTertiaryContainer = Color(0xFFEDDCFF), + background = Color(0xFF21212E), + onBackground = Color(0xFFE3E0F2), + surface = Color(0xFF21212E), + onSurface = Color(0xFFE3E0F2), + surfaceVariant = Color(0xFF49454E), + onSurfaceVariant = Color(0xFFCBC4CE), + surfaceTint = Color(0xFF66577E), + inverseSurface = Color(0xFFE5E1E6), + inverseOnSurface = Color(0xFF1B1B1E), + outline = Color(0xFF958F99), + ) + + override val lightScheme = lightColorScheme( + primary = Color(0xFF66577E), + onPrimary = Color(0xFFF3B375), + primaryContainer = Color(0xFF66577E), + onPrimaryContainer = Color(0xFFF3B375), + inversePrimary = Color(0xFFD6BAFF), + secondary = Color(0xFF66577E), + onSecondary = Color(0xFFF3B375), + secondaryContainer = Color(0xFF66577E), + onSecondaryContainer = Color(0xFFF3B375), + tertiary = Color(0xFFF3B375), + onTertiary = Color(0xFF574360), + tertiaryContainer = Color(0xFFFDD6B0), + onTertiaryContainer = Color(0xFF221437), + background = Color(0xFFF7F5FF), + onBackground = Color(0xFF1B1B22), + surface = Color(0xFFF7F5FF), + onSurface = Color(0xFF1B1B22), + surfaceVariant = Color(0xFFE8E0EB), + onSurfaceVariant = Color(0xFF49454E), + surfaceTint = Color(0xFF66577E), + inverseSurface = Color(0xFF313033), + inverseOnSurface = Color(0xFFF3EFF4), + outline = Color(0xFF7A757E), + ) +} diff --git a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TealTurqoiseColorScheme.kt b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TealTurqoiseColorScheme.kt new file mode 100644 index 0000000000..e914b49fcb --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TealTurqoiseColorScheme.kt @@ -0,0 +1,63 @@ +package eu.kanade.presentation.theme.colorscheme + +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.ui.graphics.Color + +/** + * Colors for Teal Turqoise theme + */ +internal object TealTurqoiseColorScheme : BaseColorScheme() { + + override val darkScheme = darkColorScheme( + primary = Color(0xFF40E0D0), + onPrimary = Color(0xFF000000), + primaryContainer = Color(0xFF40E0D0), + onPrimaryContainer = Color(0xFF000000), + inversePrimary = Color(0xFF008080), + secondary = Color(0xFF40E0D0), + onSecondary = Color(0xFF000000), + secondaryContainer = Color(0xFF18544E), + onSecondaryContainer = Color(0xFF40E0D0), + tertiary = Color(0xFFBF1F2F), + onTertiary = Color(0xFFFFFFFF), + tertiaryContainer = Color(0xFF200508), + onTertiaryContainer = Color(0xFFBF1F2F), + background = Color(0xFF202125), + onBackground = Color(0xFFDFDEDA), + surface = Color(0xFF202125), + onSurface = Color(0xFFDFDEDA), + surfaceVariant = Color(0xFF3F4947), + onSurfaceVariant = Color(0xFFDFDEDA), + surfaceTint = Color(0xFF40E0D0), + inverseSurface = Color(0xFFDFDEDA), + inverseOnSurface = Color(0xFF202125), + outline = Color(0xFF899391), + ) + + override val lightScheme = lightColorScheme( + primary = Color(0xFF008080), + onPrimary = Color(0xFFFFFFFF), + primaryContainer = Color(0xFF008080), + onPrimaryContainer = Color(0xFFFFFFFF), + inversePrimary = Color(0xFF40E0D0), + secondary = Color(0xFF008080), + onSecondary = Color(0xFFFFFFFF), + secondaryContainer = Color(0xFFBFDFDF), + onSecondaryContainer = Color(0xFF008080), + tertiary = Color(0xFFFF7F7F), + onTertiary = Color(0xFF000000), + tertiaryContainer = Color(0xFF2A1616), + onTertiaryContainer = Color(0xFFFF7F7F), + background = Color(0xFFFAFAFA), + onBackground = Color(0xFF050505), + surface = Color(0xFFFAFAFA), + onSurface = Color(0xFF050505), + surfaceVariant = Color(0xFFDAE5E2), + onSurfaceVariant = Color(0xFF050505), + surfaceTint = Color(0xFFBFDFDF), + inverseSurface = Color(0xFF050505), + inverseOnSurface = Color(0xFFFAFAFA), + outline = Color(0xFF6F7977), + ) +} diff --git a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TidalWaveColorScheme.kt b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TidalWaveColorScheme.kt new file mode 100644 index 0000000000..c56a1fa57e --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/TidalWaveColorScheme.kt @@ -0,0 +1,70 @@ +package eu.kanade.presentation.theme.colorscheme + +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.ui.graphics.Color + +/** + * Colors for Tidal Wave theme + * Original color scheme by NahutabDevelop + * + * Key colors: + * Primary #004152 + * Secondary #5ed4fc + * Tertiary #92f7bc + * Neutral #16151D + */ +internal object TidalWaveColorScheme : BaseColorScheme() { + + override val darkScheme = darkColorScheme( + primary = Color(0xFF5ed4fc), + onPrimary = Color(0xFF003544), + primaryContainer = Color(0xFF004d61), + onPrimaryContainer = Color(0xFFb8eaff), + inversePrimary = Color(0xFFa12b03), + secondary = Color(0xFF5ed4fc), + onSecondary = Color(0xFF003544), + secondaryContainer = Color(0xFF004d61), + onSecondaryContainer = Color(0xFFb8eaff), + tertiary = Color(0xFF92f7bc), + onTertiary = Color(0xFF001c3b), + tertiaryContainer = Color(0xFFc3fada), + onTertiaryContainer = Color(0xFF78ffd6), + background = Color(0xFF001c3b), + onBackground = Color(0xFFd5e3ff), + surface = Color(0xFF001c3b), + onSurface = Color(0xFFd5e3ff), + surfaceVariant = Color(0xFF40484c), + onSurfaceVariant = Color(0xFFbfc8cc), + surfaceTint = Color(0xFF5ed4fc), + inverseSurface = Color(0xFFffe3c4), + inverseOnSurface = Color(0xFF001c3b), + outline = Color(0xFF8a9296), + ) + + override val lightScheme = lightColorScheme( + primary = Color(0xFF006780), + onPrimary = Color(0xFFffffff), + primaryContainer = Color(0xFFB4D4DF), + onPrimaryContainer = Color(0xFF001f28), + inversePrimary = Color(0xFFff987f), + secondary = Color(0xFF006780), + onSecondary = Color(0xFFffffff), + secondaryContainer = Color(0xFFb8eaff), + onSecondaryContainer = Color(0xFF001f28), + tertiary = Color(0xFF92f7bc), + onTertiary = Color(0xFF001c3b), + tertiaryContainer = Color(0xFFc3fada), + onTertiaryContainer = Color(0xFF78ffd6), + background = Color(0xFFfdfbff), + onBackground = Color(0xFF001c3b), + surface = Color(0xFFfdfbff), + onSurface = Color(0xFF001c3b), + surfaceVariant = Color(0xFFdce4e8), + onSurfaceVariant = Color(0xFF40484c), + surfaceTint = Color(0xFF006780), + inverseSurface = Color(0xFF020400), + inverseOnSurface = Color(0xFFffe3c4), + outline = Color(0xFF70787c), + ) +} diff --git a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/YinYangColorScheme.kt b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/YinYangColorScheme.kt new file mode 100644 index 0000000000..da9dee4241 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/YinYangColorScheme.kt @@ -0,0 +1,65 @@ +package eu.kanade.presentation.theme.colorscheme + +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.ui.graphics.Color + +/** + * Colors for Yin & Yang theme + * Original color scheme by Riztard + * M3 colors generated by yours truly + tweaked manually + */ +internal object YinYangColorScheme : BaseColorScheme() { + + override val darkScheme = darkColorScheme( + primary = Color(0xFFFFFFFF), + onPrimary = Color(0xFF5A5A5A), + primaryContainer = Color(0xFFFFFFFF), + onPrimaryContainer = Color(0xFF000000), + inversePrimary = Color(0xFFCECECE), + secondary = Color(0xFFFFFFFF), + onSecondary = Color(0xFF5A5A5A), + secondaryContainer = Color(0xFF717171), + onSecondaryContainer = Color(0xFFE4E4E4), + tertiary = Color(0xFF000000), + onTertiary = Color(0xFFFFFFFF), + tertiaryContainer = Color(0xFF00419E), + onTertiaryContainer = Color(0xFFD8E2FF), + background = Color(0xFF1E1E1E), + onBackground = Color(0xFFE6E6E6), + surface = Color(0xFF1E1E1E), + onSurface = Color(0xFFE6E6E6), + surfaceVariant = Color(0xFF4E4E4E), + onSurfaceVariant = Color(0xFFD1D1D1), + surfaceTint = Color(0xFFFFFFFF), + inverseSurface = Color(0xFFE6E6E6), + inverseOnSurface = Color(0xFF1E1E1E), + outline = Color(0xFF999999), + ) + + override val lightScheme = lightColorScheme( + primary = Color(0xFF000000), + onPrimary = Color(0xFFFFFFFF), + primaryContainer = Color(0xFF000000), + onPrimaryContainer = Color(0xFFFFFFFF), + inversePrimary = Color(0xFFA6A6A6), + secondary = Color(0xFF000000), + onSecondary = Color(0xFFFFFFFF), + secondaryContainer = Color(0xFFDDDDDD), + onSecondaryContainer = Color(0xFF0C0C0C), + tertiary = Color(0xFFFFFFFF), + onTertiary = Color(0xFF000000), + tertiaryContainer = Color(0xFFD8E2FF), + onTertiaryContainer = Color(0xFF001947), + background = Color(0xFFFDFDFD), + onBackground = Color(0xFF222222), + surface = Color(0xFFFDFDFD), + onSurface = Color(0xFF222222), + surfaceVariant = Color(0xFFEDEDED), + onSurfaceVariant = Color(0xFF515151), + surfaceTint = Color(0xFF000000), + inverseSurface = Color(0xFF333333), + inverseOnSurface = Color(0xFFF4F4F4), + outline = Color(0xFF838383), + ) +} diff --git a/app/src/main/java/eu/kanade/presentation/theme/colorscheme/YotsubaColorScheme.kt b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/YotsubaColorScheme.kt new file mode 100644 index 0000000000..fdda6b7dca --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/theme/colorscheme/YotsubaColorScheme.kt @@ -0,0 +1,71 @@ +package eu.kanade.presentation.theme.colorscheme + +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.ui.graphics.Color + +/** + * Colors for Yotsuba theme + * Original color scheme by ztimms73 + * M3 colors generated by Material Theme Builder (https://goo.gle/material-theme-builder-web) + * + * Key colors: + * Primary 0xFFAE3200 + * Secondary 0xFFAE3200 + * Tertiary 0xFF6B5E2F + * Neutral 0xFF655C5A + */ +internal object YotsubaColorScheme : BaseColorScheme() { + + override val darkScheme = darkColorScheme( + primary = Color(0xFFFFB59D), + onPrimary = Color(0xFF5F1600), + primaryContainer = Color(0xFF862200), + onPrimaryContainer = Color(0xFFFFDBCF), + inversePrimary = Color(0xFFAE3200), + secondary = Color(0xFFFFB59D), + onSecondary = Color(0xFF5F1600), + secondaryContainer = Color(0xFF862200), + onSecondaryContainer = Color(0xFFFFDBCF), + tertiary = Color(0xFFD7C68D), + onTertiary = Color(0xFF3A2F05), + tertiaryContainer = Color(0xFF524619), + onTertiaryContainer = Color(0xFFF5E2A7), + background = Color(0xFF211A18), + onBackground = Color(0xFFEDE0DD), + surface = Color(0xFF211A18), + onSurface = Color(0xFFEDE0DD), + surfaceVariant = Color(0xFF53433F), + onSurfaceVariant = Color(0xFFD8C2BC), + surfaceTint = Color(0xFFFFB59D), + inverseSurface = Color(0xFFEDE0DD), + inverseOnSurface = Color(0xFF211A18), + outline = Color(0xFFA08C87), + ) + + override val lightScheme = lightColorScheme( + primary = Color(0xFFAE3200), + onPrimary = Color(0xFFFFFFFF), + primaryContainer = Color(0xFFFFDBCF), + onPrimaryContainer = Color(0xFF3B0A00), + inversePrimary = Color(0xFFFFB59D), + secondary = Color(0xFFAE3200), + onSecondary = Color(0xFFFFFFFF), + secondaryContainer = Color(0xFFFFDBCF), + onSecondaryContainer = Color(0xFF3B0A00), + tertiary = Color(0xFF6B5E2F), + onTertiary = Color(0xFFFFFFFF), + tertiaryContainer = Color(0xFFF5E2A7), + onTertiaryContainer = Color(0xFF231B00), + background = Color(0xFFFCFCFC), + onBackground = Color(0xFF211A18), + surface = Color(0xFFFCFCFC), + onSurface = Color(0xFF211A18), + surfaceVariant = Color(0xFFF5DED8), + onSurfaceVariant = Color(0xFF53433F), + surfaceTint = Color(0xFFAE3200), + inverseSurface = Color(0xFF362F2D), + inverseOnSurface = Color(0xFFFBEEEB), + outline = Color(0xFF85736E), + ) +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/App.kt b/app/src/main/java/eu/kanade/tachiyomi/App.kt index 6c293a635c..67ed7146e9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/App.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/App.kt @@ -1,7 +1,6 @@ package eu.kanade.tachiyomi import android.annotation.SuppressLint -import android.app.ActivityManager import android.app.Application import android.app.PendingIntent import android.content.BroadcastReceiver @@ -12,7 +11,6 @@ import android.os.Build import android.os.Looper import android.webkit.WebView import androidx.core.content.ContextCompat -import androidx.core.content.getSystemService import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.ProcessLifecycleOwner @@ -39,6 +37,7 @@ import eu.kanade.tachiyomi.di.PreferenceModule import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.NetworkPreferences import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegate +import eu.kanade.tachiyomi.util.system.DeviceUtil import eu.kanade.tachiyomi.util.system.WebViewUtil import eu.kanade.tachiyomi.util.system.animatorDurationScale import eu.kanade.tachiyomi.util.system.cancelNotification @@ -157,7 +156,7 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory { callFactory(callFactoryInit) diskCache(diskCacheInit) crossfade((300 * this@App.animatorDurationScale).toInt()) - allowRgb565(getSystemService()!!.isLowRamDevice) + allowRgb565(DeviceUtil.isLowRamDevice(this@App)) if (networkPreferences.verboseLogging().get()) logger(DebugLogger()) // Coil spawns a new thread for every image load by default diff --git a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt index 93d2c0d04d..f38dd415c3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt @@ -295,9 +295,6 @@ object Migrations { } } if (oldVersion < 84) { - if (backupPreferences.numberOfBackups().get() == 1) { - backupPreferences.numberOfBackups().set(2) - } if (backupPreferences.backupInterval().get() == 0) { backupPreferences.backupInterval().set(12) BackupCreateJob.setupTask(context) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreator.kt index b8562b6b59..549779dcf3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreator.kt @@ -42,7 +42,6 @@ import tachiyomi.core.preference.Preference import tachiyomi.core.preference.PreferenceStore import tachiyomi.core.util.system.logcat import tachiyomi.data.DatabaseHandler -import tachiyomi.domain.backup.service.BackupPreferences import tachiyomi.domain.category.interactor.GetCategories import tachiyomi.domain.category.model.Category import tachiyomi.domain.history.interactor.GetHistory @@ -60,7 +59,6 @@ class BackupCreator( private val handler: DatabaseHandler = Injekt.get() private val sourceManager: SourceManager = Injekt.get() - private val backupPreferences: BackupPreferences = Injekt.get() private val getCategories: GetCategories = Injekt.get() private val getFavorites: GetFavorites = Injekt.get() private val getHistory: GetHistory = Injekt.get() @@ -98,11 +96,10 @@ class BackupCreator( dir = dir.createDirectory("automatic") // Delete older backups - val numberOfBackups = backupPreferences.numberOfBackups().get() dir.listFiles { _, filename -> Backup.filenameRegex.matches(filename) } .orEmpty() .sortedByDescending { it.name } - .drop(numberOfBackups - 1) + .drop(MAX_AUTO_BACKUPS - 1) .forEach { it.delete() } // Create new file to place backup @@ -269,3 +266,5 @@ class BackupCreator( } } } + +private val MAX_AUTO_BACKUPS: Int = 4 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt index ec47364e14..f4992dbc02 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt @@ -86,6 +86,10 @@ class ReaderPreferences( fun dualPageRotateToFitInvert() = preferenceStore.getBoolean("pref_dual_page_rotate_invert", false) + fun dualPageRotateToFitWebtoon() = preferenceStore.getBoolean("pref_dual_page_rotate_webtoon", false) + + fun dualPageRotateToFitInvertWebtoon() = preferenceStore.getBoolean("pref_dual_page_rotate_invert_webtoon", false) + // endregion // region Color filter diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt index a64826ab1d..28ad91a51d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt @@ -62,6 +62,18 @@ class WebtoonConfig( readerPreferences.dualPageInvertWebtoon() .register({ dualPageInvert = it }, { imagePropertyChangedListener?.invoke() }) + readerPreferences.dualPageRotateToFitWebtoon() + .register( + { dualPageRotateToFit = it }, + { imagePropertyChangedListener?.invoke() }, + ) + + readerPreferences.dualPageRotateToFitInvertWebtoon() + .register( + { dualPageRotateToFitInvert = it }, + { imagePropertyChangedListener?.invoke() }, + ) + readerPreferences.webtoonDoubleTapZoomEnabled() .register( { doubleTapZoom = it }, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt index aeb25d9057..6503457c47 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt @@ -210,6 +210,10 @@ class WebtoonPageHolder( } private fun process(imageStream: BufferedInputStream): InputStream { + if (viewer.config.dualPageRotateToFit) { + return rotateDualPage(imageStream) + } + if (viewer.config.dualPageSplit) { val isDoublePage = ImageUtil.isWideImage(imageStream) if (isDoublePage) { @@ -221,6 +225,16 @@ class WebtoonPageHolder( return imageStream } + private fun rotateDualPage(imageStream: BufferedInputStream): InputStream { + val isDoublePage = ImageUtil.isWideImage(imageStream) + return if (isDoublePage) { + val rotation = if (viewer.config.dualPageRotateToFitInvert) -90f else 90f + ImageUtil.rotateImage(imageStream, rotation) + } else { + imageStream + } + } + /** * Called when the page has an error. */ diff --git a/core/src/main/java/eu/kanade/tachiyomi/util/system/DeviceUtil.kt b/core/src/main/java/eu/kanade/tachiyomi/util/system/DeviceUtil.kt index 57950eda34..e2011f0c54 100644 --- a/core/src/main/java/eu/kanade/tachiyomi/util/system/DeviceUtil.kt +++ b/core/src/main/java/eu/kanade/tachiyomi/util/system/DeviceUtil.kt @@ -1,13 +1,16 @@ package eu.kanade.tachiyomi.util.system import android.annotation.SuppressLint +import android.app.ActivityManager +import android.content.Context import android.os.Build +import androidx.core.content.getSystemService import logcat.LogPriority import tachiyomi.core.util.system.logcat object DeviceUtil { - val isMiui by lazy { + val isMiui: Boolean by lazy { getSystemProperty("ro.miui.ui.version.name")?.isNotEmpty() ?: false } @@ -16,7 +19,7 @@ object DeviceUtil { * * @return MIUI major version code (e.g., 13) or null if can't be parsed. */ - val miuiMajorVersion by lazy { + val miuiMajorVersion: Int? by lazy { if (!isMiui) return@lazy null Build.VERSION.INCREMENTAL @@ -41,11 +44,11 @@ object DeviceUtil { } } - val isSamsung by lazy { + val isSamsung: Boolean by lazy { Build.MANUFACTURER.equals("samsung", ignoreCase = true) } - val oneUiVersion by lazy { + val oneUiVersion: Double? by lazy { try { val semPlatformIntField = Build.VERSION::class.java.getDeclaredField("SEM_PLATFORM_INT") val version = semPlatformIntField.getInt(null) - 90000 @@ -65,6 +68,20 @@ object DeviceUtil { "com.zui.resolver", ) + /** + * ActivityManager#isLowRamDevice is based on a system property, which isn't + * necessarily trustworthy. 1GB is supposedly the regular threshold. + * + * Instead, we consider anything with less than 3GB of RAM as low memory + * considering how heavy image processing can be. + */ + fun isLowRamDevice(context: Context): Boolean { + val memInfo = ActivityManager.MemoryInfo() + context.getSystemService()!!.getMemoryInfo(memInfo) + val totalMemBytes = memInfo.totalMem + return totalMemBytes < 3L * 1024 * 1024 * 1024 + } + @SuppressLint("PrivateApi") private fun getSystemProperty(key: String?): String? { return try { diff --git a/domain/src/main/java/tachiyomi/domain/backup/service/BackupPreferences.kt b/domain/src/main/java/tachiyomi/domain/backup/service/BackupPreferences.kt index e923b2daaf..6144709de7 100644 --- a/domain/src/main/java/tachiyomi/domain/backup/service/BackupPreferences.kt +++ b/domain/src/main/java/tachiyomi/domain/backup/service/BackupPreferences.kt @@ -11,8 +11,6 @@ class BackupPreferences( fun backupsDirectory() = preferenceStore.getString("backup_directory", folderProvider.path()) - fun numberOfBackups() = preferenceStore.getInt("backup_slots", 2) - fun backupInterval() = preferenceStore.getInt("backup_interval", 12) fun lastAutoBackupTimestamp() = preferenceStore.getLong(Preference.appStateKey("last_auto_backup_timestamp"), 0L) diff --git a/gradle/compose.versions.toml b/gradle/compose.versions.toml index 8f47b2db2c..bdafa0fe23 100644 --- a/gradle/compose.versions.toml +++ b/gradle/compose.versions.toml @@ -23,7 +23,6 @@ glance = "androidx.glance:glance-appwidget:1.0.0" accompanist-webview = { module = "com.google.accompanist:accompanist-webview", version.ref = "accompanist" } accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanist" } -accompanist-themeadapter = { module = "com.google.accompanist:accompanist-themeadapter-material3", version.ref = "accompanist" } accompanist-systemuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanist" } lintchecks = { module = "com.slack.lint.compose:compose-lint-checks", version = "1.2.0" } \ No newline at end of file diff --git a/i18n/build.gradle.kts b/i18n/build.gradle.kts index 542afc3597..366e19ad3d 100644 --- a/i18n/build.gradle.kts +++ b/i18n/build.gradle.kts @@ -38,8 +38,13 @@ multiplatformResources { tasks { val localesConfigTask = registerLocalesConfigTask(project) - preBuild { dependsOn(localesConfigTask) } + + withType { + kotlinOptions.freeCompilerArgs += listOf( + "-Xexpect-actual-classes", + ) + } } diff --git a/i18n/src/commonMain/resources/MR/base/strings.xml b/i18n/src/commonMain/resources/MR/base/strings.xml index 6cf9241217..6aba4e8119 100644 --- a/i18n/src/commonMain/resources/MR/base/strings.xml +++ b/i18n/src/commonMain/resources/MR/base/strings.xml @@ -476,7 +476,6 @@ Restore library from backup file Backup location Automatic backup frequency - Maximum automatic backups Create Backup created Invalid backup file diff --git a/source-api/build.gradle.kts b/source-api/build.gradle.kts index 020695b6c0..f8c78fb19a 100644 --- a/source-api/build.gradle.kts +++ b/source-api/build.gradle.kts @@ -35,3 +35,11 @@ android { consumerProguardFile("consumer-proguard.pro") } } + +tasks { + withType { + kotlinOptions.freeCompilerArgs += listOf( + "-Xexpect-actual-classes", + ) + } +} diff --git a/source-local/build.gradle.kts b/source-local/build.gradle.kts index 71d88804cc..98eb4d55ad 100644 --- a/source-local/build.gradle.kts +++ b/source-local/build.gradle.kts @@ -41,6 +41,7 @@ android { tasks { withType { kotlinOptions.freeCompilerArgs += listOf( + "-Xexpect-actual-classes", "-opt-in=kotlinx.serialization.ExperimentalSerializationApi", ) }