Merge branch 'master' of https://github.com/tachiyomiorg/tachiyomi into sync-part-final

This commit is contained in:
KaiserBh 2023-11-20 07:49:10 +11:00
commit 389d40ab41
No known key found for this signature in database
GPG Key ID: 14D73B142042BBA9
33 changed files with 1026 additions and 81 deletions

View File

@ -165,7 +165,6 @@ dependencies {
implementation(compose.ui.util) implementation(compose.ui.util)
implementation(compose.accompanist.webview) implementation(compose.accompanist.webview)
implementation(compose.accompanist.permissions) implementation(compose.accompanist.permissions)
implementation(compose.accompanist.themeadapter)
implementation(compose.accompanist.systemuicontroller) implementation(compose.accompanist.systemuicontroller)
lintChecks(compose.lintchecks) lintChecks(compose.lintchecks)

View File

@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.TextFieldDefaults
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.ArrowBack import androidx.compose.material.icons.automirrored.outlined.ArrowBack
import androidx.compose.material.icons.outlined.Close 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.MaterialTheme
import androidx.compose.material3.PlainTooltip import androidx.compose.material3.PlainTooltip
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.material3.TooltipBox import androidx.compose.material3.TooltipBox
import androidx.compose.material3.TooltipDefaults import androidx.compose.material3.TooltipDefaults
import androidx.compose.material3.TopAppBar 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.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.input.VisualTransformation
@ -62,10 +61,11 @@ const val SEARCH_DEBOUNCE_MILLIS = 250L
@Composable @Composable
fun AppBar( fun AppBar(
title: String?,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
backgroundColor: Color? = null, backgroundColor: Color? = null,
// Text // Text
title: String?,
subtitle: String? = null, subtitle: String? = null,
// Up button // Up button
navigateUp: (() -> Unit)? = null, navigateUp: (() -> Unit)? = null,
@ -90,7 +90,7 @@ fun AppBar(
if (isActionMode) { if (isActionMode) {
AppBarTitle(actionModeCounter.toString()) AppBarTitle(actionModeCounter.toString())
} else { } else {
AppBarTitle(title, subtitle) AppBarTitle(title, subtitle = subtitle)
} }
}, },
navigateUp = navigateUp, navigateUp = navigateUp,
@ -110,10 +110,11 @@ fun AppBar(
@Composable @Composable
fun AppBar( fun AppBar(
modifier: Modifier = Modifier,
backgroundColor: Color? = null,
// Title // Title
titleContent: @Composable () -> Unit, titleContent: @Composable () -> Unit,
modifier: Modifier = Modifier,
backgroundColor: Color? = null,
// Up button // Up button
navigateUp: (() -> Unit)? = null, navigateUp: (() -> Unit)? = null,
navigationIcon: ImageVector? = null, navigationIcon: ImageVector? = null,
@ -140,7 +141,7 @@ fun AppBar(
} else { } else {
navigateUp?.let { navigateUp?.let {
IconButton(onClick = it) { IconButton(onClick = it) {
UpIcon(navigationIcon) UpIcon(navigationIcon = navigationIcon)
} }
} }
} }
@ -160,9 +161,10 @@ fun AppBar(
@Composable @Composable
fun AppBarTitle( fun AppBarTitle(
title: String?, title: String?,
modifier: Modifier = Modifier,
subtitle: String? = null, subtitle: String? = null,
) { ) {
Column { Column(modifier = modifier) {
title?.let { title?.let {
Text( Text(
text = it, text = it,
@ -258,11 +260,12 @@ fun AppBarActions(
*/ */
@Composable @Composable
fun SearchToolbar( fun SearchToolbar(
searchQuery: String?,
onChangeSearchQuery: (String?) -> Unit,
modifier: Modifier = Modifier,
titleContent: @Composable () -> Unit = {}, titleContent: @Composable () -> Unit = {},
navigateUp: (() -> Unit)? = null, navigateUp: (() -> Unit)? = null,
searchEnabled: Boolean = true, searchEnabled: Boolean = true,
searchQuery: String?,
onChangeSearchQuery: (String?) -> Unit,
placeholderText: String? = null, placeholderText: String? = null,
onSearch: (String) -> Unit = {}, onSearch: (String) -> Unit = {},
onClickCloseSearch: () -> Unit = { onChangeSearchQuery(null) }, onClickCloseSearch: () -> Unit = { onChangeSearchQuery(null) },
@ -274,6 +277,7 @@ fun SearchToolbar(
val focusRequester = remember { FocusRequester() } val focusRequester = remember { FocusRequester() }
AppBar( AppBar(
modifier = modifier,
titleContent = { titleContent = {
if (searchQuery == null) return@AppBar titleContent() if (searchQuery == null) return@AppBar titleContent()
@ -390,12 +394,16 @@ fun SearchToolbar(
} }
@Composable @Composable
fun UpIcon(navigationIcon: ImageVector? = null) { fun UpIcon(
modifier: Modifier = Modifier,
navigationIcon: ImageVector? = null,
) {
val icon = navigationIcon val icon = navigationIcon
?: Icons.AutoMirrored.Outlined.ArrowBack ?: Icons.AutoMirrored.Outlined.ArrowBack
Icon( Icon(
imageVector = icon, imageVector = icon,
contentDescription = stringResource(MR.strings.action_bar_up_description), contentDescription = stringResource(MR.strings.action_bar_up_description),
modifier = modifier,
) )
} }

View File

@ -50,7 +50,7 @@ object CommonMangaItemDefaults {
const val BrowseFavoriteCoverAlpha = 0.34f const val BrowseFavoriteCoverAlpha = 0.34f
} }
private val ContinueReadingButtonSize = 32.dp private val ContinueReadingButtonSize = 28.dp
private val ContinueReadingButtonGridPadding = 6.dp private val ContinueReadingButtonGridPadding = 6.dp
private val ContinueReadingButtonListSpacing = 8.dp private val ContinueReadingButtonListSpacing = 8.dp

View File

@ -67,7 +67,7 @@ fun MangaToolbar(
}, },
navigationIcon = { navigationIcon = {
IconButton(onClick = onBackClicked) { IconButton(onClick = onBackClicked) {
UpIcon(Icons.Outlined.Close.takeIf { isActionMode }) UpIcon(navigationIcon = Icons.Outlined.Close.takeIf { isActionMode })
} }
}, },
actions = { actions = {

View File

@ -85,8 +85,6 @@ object SettingsDataScreen : SearchableSettings {
@Composable @Composable
private fun getBackupAndRestoreGroup(backupPreferences: BackupPreferences): Preference.PreferenceGroup { private fun getBackupAndRestoreGroup(backupPreferences: BackupPreferences): Preference.PreferenceGroup {
val context = LocalContext.current val context = LocalContext.current
val backupIntervalPref = backupPreferences.backupInterval()
val backupInterval by backupIntervalPref.collectAsState()
val lastAutoBackup by backupPreferences.lastAutoBackupTimestamp().collectAsState() val lastAutoBackup by backupPreferences.lastAutoBackupTimestamp().collectAsState()
return Preference.PreferenceGroup( return Preference.PreferenceGroup(
@ -98,7 +96,7 @@ object SettingsDataScreen : SearchableSettings {
// Automatic backups // Automatic backups
Preference.PreferenceItem.ListPreference( Preference.PreferenceItem.ListPreference(
pref = backupIntervalPref, pref = backupPreferences.backupInterval(),
title = stringResource(MR.strings.pref_backup_interval), title = stringResource(MR.strings.pref_backup_interval),
entries = mapOf( entries = mapOf(
0 to stringResource(MR.strings.off), 0 to stringResource(MR.strings.off),
@ -113,12 +111,6 @@ object SettingsDataScreen : SearchableSettings {
true 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( Preference.PreferenceItem.InfoPreference(
stringResource(MR.strings.backup_info) + "\n\n" + stringResource(MR.strings.backup_info) + "\n\n" +
stringResource(MR.strings.last_auto_backup_info, relativeTimeSpanString(lastAutoBackup)), stringResource(MR.strings.last_auto_backup_info, relativeTimeSpanString(lastAutoBackup)),

View File

@ -245,10 +245,12 @@ object SettingsReaderScreen : SearchableSettings {
val navModePref = readerPreferences.navigationModeWebtoon() val navModePref = readerPreferences.navigationModeWebtoon()
val dualPageSplitPref = readerPreferences.dualPageSplitWebtoon() val dualPageSplitPref = readerPreferences.dualPageSplitWebtoon()
val rotateToFitPref = readerPreferences.dualPageRotateToFitWebtoon()
val webtoonSidePaddingPref = readerPreferences.webtoonSidePadding() val webtoonSidePaddingPref = readerPreferences.webtoonSidePadding()
val navMode by navModePref.collectAsState() val navMode by navModePref.collectAsState()
val dualPageSplit by dualPageSplitPref.collectAsState() val dualPageSplit by dualPageSplitPref.collectAsState()
val rotateToFit by rotateToFitPref.collectAsState()
val webtoonSidePadding by webtoonSidePaddingPref.collectAsState() val webtoonSidePadding by webtoonSidePaddingPref.collectAsState()
return Preference.PreferenceGroup( return Preference.PreferenceGroup(
@ -300,6 +302,10 @@ object SettingsReaderScreen : SearchableSettings {
Preference.PreferenceItem.SwitchPreference( Preference.PreferenceItem.SwitchPreference(
pref = dualPageSplitPref, pref = dualPageSplitPref,
title = stringResource(MR.strings.pref_dual_page_split), title = stringResource(MR.strings.pref_dual_page_split),
onValueChanged = {
rotateToFitPref.set(false)
true
},
), ),
Preference.PreferenceItem.SwitchPreference( Preference.PreferenceItem.SwitchPreference(
pref = readerPreferences.dualPageInvertWebtoon(), pref = readerPreferences.dualPageInvertWebtoon(),
@ -307,6 +313,19 @@ object SettingsReaderScreen : SearchableSettings {
subtitle = stringResource(MR.strings.pref_dual_page_invert_summary), subtitle = stringResource(MR.strings.pref_dual_page_invert_summary),
enabled = dualPageSplit, 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( Preference.PreferenceItem.SwitchPreference(
pref = readerPreferences.webtoonDoubleTapZoomEnabled(), pref = readerPreferences.webtoonDoubleTapZoomEnabled(),
title = stringResource(MR.strings.pref_double_tap_zoom), title = stringResource(MR.strings.pref_double_tap_zoom),

View File

@ -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( CheckboxItem(
label = stringResource(MR.strings.pref_double_tap_zoom), label = stringResource(MR.strings.pref_double_tap_zoom),
pref = screenModel.preferences.webtoonDoubleTapZoomEnabled(), pref = screenModel.preferences.webtoonDoubleTapZoomEnabled(),

View File

@ -1,54 +1,62 @@
package eu.kanade.presentation.theme 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.material3.MaterialTheme
import androidx.compose.runtime.Composable 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.LocalContext
import androidx.compose.ui.platform.LocalLayoutDirection import eu.kanade.domain.ui.UiPreferences
import com.google.accompanist.themeadapter.material3.createMdc3Theme
import eu.kanade.domain.ui.model.AppTheme import eu.kanade.domain.ui.model.AppTheme
import eu.kanade.tachiyomi.ui.base.delegate.ThemingDelegate import eu.kanade.presentation.theme.colorscheme.GreenAppleColorScheme
import eu.kanade.presentation.theme.colorscheme.LavenderColorScheme
@Composable import eu.kanade.presentation.theme.colorscheme.MidnightDuskColorScheme
fun TachiyomiTheme(content: @Composable () -> Unit) { import eu.kanade.presentation.theme.colorscheme.MonetColorScheme
val context = LocalContext.current import eu.kanade.presentation.theme.colorscheme.StrawberryColorScheme
val layoutDirection = LocalLayoutDirection.current import eu.kanade.presentation.theme.colorscheme.TachiyomiColorScheme
import eu.kanade.presentation.theme.colorscheme.TakoColorScheme
val (colorScheme, typography) = createMdc3Theme( import eu.kanade.presentation.theme.colorscheme.TealTurqoiseColorScheme
context = context, import eu.kanade.presentation.theme.colorscheme.TidalWaveColorScheme
layoutDirection = layoutDirection, import eu.kanade.presentation.theme.colorscheme.YinYangColorScheme
) import eu.kanade.presentation.theme.colorscheme.YotsubaColorScheme
import uy.kohesive.injekt.Injekt
MaterialTheme( import uy.kohesive.injekt.api.get
colorScheme = colorScheme!!,
typography = typography!!,
content = content,
)
}
@Composable @Composable
fun TachiyomiTheme( fun TachiyomiTheme(
appTheme: AppTheme, appTheme: AppTheme? = null,
amoled: Boolean, amoled: Boolean? = null,
content: @Composable () -> Unit, 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( MaterialTheme(
colorScheme = colorScheme!!, colorScheme = getThemeColorScheme(appTheme, amoled),
typography = typography!!,
content = content, content = content,
) )
} }
@Composable
@ReadOnlyComposable
private fun getThemeColorScheme(
appTheme: AppTheme?,
amoled: Boolean?,
): ColorScheme {
val uiPreferences = Injekt.get<UiPreferences>()
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(),
)
}

View File

@ -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
}
}
}
}

View File

@ -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),
)
}

View File

@ -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),
)
}

View File

@ -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),
)
}

View File

@ -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<UiModeManager>()?.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(),
)
}
}
}

View File

@ -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),
)
}

View File

@ -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),
)
}

View File

@ -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),
)
}

View File

@ -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),
)
}

View File

@ -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),
)
}

View File

@ -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),
)
}

View File

@ -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),
)
}

View File

@ -1,7 +1,6 @@
package eu.kanade.tachiyomi package eu.kanade.tachiyomi
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.ActivityManager
import android.app.Application import android.app.Application
import android.app.PendingIntent import android.app.PendingIntent
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
@ -12,7 +11,6 @@ import android.os.Build
import android.os.Looper import android.os.Looper
import android.webkit.WebView import android.webkit.WebView
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ProcessLifecycleOwner 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.NetworkHelper
import eu.kanade.tachiyomi.network.NetworkPreferences import eu.kanade.tachiyomi.network.NetworkPreferences
import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegate 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.WebViewUtil
import eu.kanade.tachiyomi.util.system.animatorDurationScale import eu.kanade.tachiyomi.util.system.animatorDurationScale
import eu.kanade.tachiyomi.util.system.cancelNotification import eu.kanade.tachiyomi.util.system.cancelNotification
@ -157,7 +156,7 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
callFactory(callFactoryInit) callFactory(callFactoryInit)
diskCache(diskCacheInit) diskCache(diskCacheInit)
crossfade((300 * this@App.animatorDurationScale).toInt()) crossfade((300 * this@App.animatorDurationScale).toInt())
allowRgb565(getSystemService<ActivityManager>()!!.isLowRamDevice) allowRgb565(DeviceUtil.isLowRamDevice(this@App))
if (networkPreferences.verboseLogging().get()) logger(DebugLogger()) if (networkPreferences.verboseLogging().get()) logger(DebugLogger())
// Coil spawns a new thread for every image load by default // Coil spawns a new thread for every image load by default

View File

@ -295,9 +295,6 @@ object Migrations {
} }
} }
if (oldVersion < 84) { if (oldVersion < 84) {
if (backupPreferences.numberOfBackups().get() == 1) {
backupPreferences.numberOfBackups().set(2)
}
if (backupPreferences.backupInterval().get() == 0) { if (backupPreferences.backupInterval().get() == 0) {
backupPreferences.backupInterval().set(12) backupPreferences.backupInterval().set(12)
BackupCreateJob.setupTask(context) BackupCreateJob.setupTask(context)

View File

@ -42,7 +42,6 @@ import tachiyomi.core.preference.Preference
import tachiyomi.core.preference.PreferenceStore import tachiyomi.core.preference.PreferenceStore
import tachiyomi.core.util.system.logcat import tachiyomi.core.util.system.logcat
import tachiyomi.data.DatabaseHandler import tachiyomi.data.DatabaseHandler
import tachiyomi.domain.backup.service.BackupPreferences
import tachiyomi.domain.category.interactor.GetCategories import tachiyomi.domain.category.interactor.GetCategories
import tachiyomi.domain.category.model.Category import tachiyomi.domain.category.model.Category
import tachiyomi.domain.history.interactor.GetHistory import tachiyomi.domain.history.interactor.GetHistory
@ -60,7 +59,6 @@ class BackupCreator(
private val handler: DatabaseHandler = Injekt.get() private val handler: DatabaseHandler = Injekt.get()
private val sourceManager: SourceManager = Injekt.get() private val sourceManager: SourceManager = Injekt.get()
private val backupPreferences: BackupPreferences = Injekt.get()
private val getCategories: GetCategories = Injekt.get() private val getCategories: GetCategories = Injekt.get()
private val getFavorites: GetFavorites = Injekt.get() private val getFavorites: GetFavorites = Injekt.get()
private val getHistory: GetHistory = Injekt.get() private val getHistory: GetHistory = Injekt.get()
@ -98,11 +96,10 @@ class BackupCreator(
dir = dir.createDirectory("automatic") dir = dir.createDirectory("automatic")
// Delete older backups // Delete older backups
val numberOfBackups = backupPreferences.numberOfBackups().get()
dir.listFiles { _, filename -> Backup.filenameRegex.matches(filename) } dir.listFiles { _, filename -> Backup.filenameRegex.matches(filename) }
.orEmpty() .orEmpty()
.sortedByDescending { it.name } .sortedByDescending { it.name }
.drop(numberOfBackups - 1) .drop(MAX_AUTO_BACKUPS - 1)
.forEach { it.delete() } .forEach { it.delete() }
// Create new file to place backup // Create new file to place backup
@ -269,3 +266,5 @@ class BackupCreator(
} }
} }
} }
private val MAX_AUTO_BACKUPS: Int = 4

View File

@ -86,6 +86,10 @@ class ReaderPreferences(
fun dualPageRotateToFitInvert() = preferenceStore.getBoolean("pref_dual_page_rotate_invert", false) 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 // endregion
// region Color filter // region Color filter

View File

@ -62,6 +62,18 @@ class WebtoonConfig(
readerPreferences.dualPageInvertWebtoon() readerPreferences.dualPageInvertWebtoon()
.register({ dualPageInvert = it }, { imagePropertyChangedListener?.invoke() }) .register({ dualPageInvert = it }, { imagePropertyChangedListener?.invoke() })
readerPreferences.dualPageRotateToFitWebtoon()
.register(
{ dualPageRotateToFit = it },
{ imagePropertyChangedListener?.invoke() },
)
readerPreferences.dualPageRotateToFitInvertWebtoon()
.register(
{ dualPageRotateToFitInvert = it },
{ imagePropertyChangedListener?.invoke() },
)
readerPreferences.webtoonDoubleTapZoomEnabled() readerPreferences.webtoonDoubleTapZoomEnabled()
.register( .register(
{ doubleTapZoom = it }, { doubleTapZoom = it },

View File

@ -210,6 +210,10 @@ class WebtoonPageHolder(
} }
private fun process(imageStream: BufferedInputStream): InputStream { private fun process(imageStream: BufferedInputStream): InputStream {
if (viewer.config.dualPageRotateToFit) {
return rotateDualPage(imageStream)
}
if (viewer.config.dualPageSplit) { if (viewer.config.dualPageSplit) {
val isDoublePage = ImageUtil.isWideImage(imageStream) val isDoublePage = ImageUtil.isWideImage(imageStream)
if (isDoublePage) { if (isDoublePage) {
@ -221,6 +225,16 @@ class WebtoonPageHolder(
return imageStream 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. * Called when the page has an error.
*/ */

View File

@ -1,13 +1,16 @@
package eu.kanade.tachiyomi.util.system package eu.kanade.tachiyomi.util.system
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.ActivityManager
import android.content.Context
import android.os.Build import android.os.Build
import androidx.core.content.getSystemService
import logcat.LogPriority import logcat.LogPriority
import tachiyomi.core.util.system.logcat import tachiyomi.core.util.system.logcat
object DeviceUtil { object DeviceUtil {
val isMiui by lazy { val isMiui: Boolean by lazy {
getSystemProperty("ro.miui.ui.version.name")?.isNotEmpty() ?: false 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. * @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 if (!isMiui) return@lazy null
Build.VERSION.INCREMENTAL Build.VERSION.INCREMENTAL
@ -41,11 +44,11 @@ object DeviceUtil {
} }
} }
val isSamsung by lazy { val isSamsung: Boolean by lazy {
Build.MANUFACTURER.equals("samsung", ignoreCase = true) Build.MANUFACTURER.equals("samsung", ignoreCase = true)
} }
val oneUiVersion by lazy { val oneUiVersion: Double? by lazy {
try { try {
val semPlatformIntField = Build.VERSION::class.java.getDeclaredField("SEM_PLATFORM_INT") val semPlatformIntField = Build.VERSION::class.java.getDeclaredField("SEM_PLATFORM_INT")
val version = semPlatformIntField.getInt(null) - 90000 val version = semPlatformIntField.getInt(null) - 90000
@ -65,6 +68,20 @@ object DeviceUtil {
"com.zui.resolver", "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<ActivityManager>()!!.getMemoryInfo(memInfo)
val totalMemBytes = memInfo.totalMem
return totalMemBytes < 3L * 1024 * 1024 * 1024
}
@SuppressLint("PrivateApi") @SuppressLint("PrivateApi")
private fun getSystemProperty(key: String?): String? { private fun getSystemProperty(key: String?): String? {
return try { return try {

View File

@ -11,8 +11,6 @@ class BackupPreferences(
fun backupsDirectory() = preferenceStore.getString("backup_directory", folderProvider.path()) fun backupsDirectory() = preferenceStore.getString("backup_directory", folderProvider.path())
fun numberOfBackups() = preferenceStore.getInt("backup_slots", 2)
fun backupInterval() = preferenceStore.getInt("backup_interval", 12) fun backupInterval() = preferenceStore.getInt("backup_interval", 12)
fun lastAutoBackupTimestamp() = preferenceStore.getLong(Preference.appStateKey("last_auto_backup_timestamp"), 0L) fun lastAutoBackupTimestamp() = preferenceStore.getLong(Preference.appStateKey("last_auto_backup_timestamp"), 0L)

View File

@ -23,7 +23,6 @@ glance = "androidx.glance:glance-appwidget:1.0.0"
accompanist-webview = { module = "com.google.accompanist:accompanist-webview", version.ref = "accompanist" } accompanist-webview = { module = "com.google.accompanist:accompanist-webview", version.ref = "accompanist" }
accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", 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" } accompanist-systemuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanist" }
lintchecks = { module = "com.slack.lint.compose:compose-lint-checks", version = "1.2.0" } lintchecks = { module = "com.slack.lint.compose:compose-lint-checks", version = "1.2.0" }

View File

@ -38,8 +38,13 @@ multiplatformResources {
tasks { tasks {
val localesConfigTask = registerLocalesConfigTask(project) val localesConfigTask = registerLocalesConfigTask(project)
preBuild { preBuild {
dependsOn(localesConfigTask) dependsOn(localesConfigTask)
} }
withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions.freeCompilerArgs += listOf(
"-Xexpect-actual-classes",
)
}
} }

View File

@ -476,7 +476,6 @@
<string name="pref_restore_backup_summ">Restore library from backup file</string> <string name="pref_restore_backup_summ">Restore library from backup file</string>
<string name="pref_backup_directory">Backup location</string> <string name="pref_backup_directory">Backup location</string>
<string name="pref_backup_interval">Automatic backup frequency</string> <string name="pref_backup_interval">Automatic backup frequency</string>
<string name="pref_backup_slots">Maximum automatic backups</string>
<string name="action_create">Create</string> <string name="action_create">Create</string>
<string name="backup_created">Backup created</string> <string name="backup_created">Backup created</string>
<string name="invalid_backup_file">Invalid backup file</string> <string name="invalid_backup_file">Invalid backup file</string>

View File

@ -35,3 +35,11 @@ android {
consumerProguardFile("consumer-proguard.pro") consumerProguardFile("consumer-proguard.pro")
} }
} }
tasks {
withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions.freeCompilerArgs += listOf(
"-Xexpect-actual-classes",
)
}
}

View File

@ -41,6 +41,7 @@ android {
tasks { tasks {
withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> { withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions.freeCompilerArgs += listOf( kotlinOptions.freeCompilerArgs += listOf(
"-Xexpect-actual-classes",
"-opt-in=kotlinx.serialization.ExperimentalSerializationApi", "-opt-in=kotlinx.serialization.ExperimentalSerializationApi",
) )
} }