Migrate ReaderColorFilterSettings to Compose
It'll eventually be a tab with the other settings again once the other tabs are also migrated over so it's just a single Compose sheet.
This commit is contained in:
parent
b354e37cc3
commit
fe82cdb9c8
15 changed files with 241 additions and 562 deletions
|
@ -199,7 +199,6 @@ private fun ColumnScope.DisplayPage(
|
||||||
val columns by columnPreference.collectAsState()
|
val columns by columnPreference.collectAsState()
|
||||||
SliderItem(
|
SliderItem(
|
||||||
label = stringResource(R.string.pref_library_columns),
|
label = stringResource(R.string.pref_library_columns),
|
||||||
min = 0,
|
|
||||||
max = 10,
|
max = 10,
|
||||||
value = columns,
|
value = columns,
|
||||||
valueText = if (columns > 0) {
|
valueText = if (columns > 0) {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import androidx.compose.runtime.compositionLocalOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.structuralEqualityPolicy
|
import androidx.compose.runtime.structuralEqualityPolicy
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import eu.kanade.domain.track.service.TrackPreferences
|
import eu.kanade.domain.track.service.TrackPreferences
|
||||||
import eu.kanade.domain.ui.UiPreferences
|
import eu.kanade.domain.ui.UiPreferences
|
||||||
import eu.kanade.presentation.more.settings.widget.AppThemePreferenceWidget
|
import eu.kanade.presentation.more.settings.widget.AppThemePreferenceWidget
|
||||||
|
@ -24,10 +25,12 @@ import eu.kanade.presentation.more.settings.widget.TrackingPreferenceWidget
|
||||||
import eu.kanade.presentation.util.collectAsState
|
import eu.kanade.presentation.util.collectAsState
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import tachiyomi.core.preference.PreferenceStore
|
import tachiyomi.core.preference.PreferenceStore
|
||||||
|
import tachiyomi.presentation.core.components.SliderItem
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
val LocalPreferenceHighlighted = compositionLocalOf(structuralEqualityPolicy()) { false }
|
val LocalPreferenceHighlighted = compositionLocalOf(structuralEqualityPolicy()) { false }
|
||||||
|
val LocalPreferenceMinHeight = compositionLocalOf(structuralEqualityPolicy()) { 56.dp }
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun StatusWrapper(
|
fun StatusWrapper(
|
||||||
|
@ -77,6 +80,21 @@ internal fun PreferenceItem(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
is Preference.PreferenceItem.SliderPreference -> {
|
||||||
|
// TODO: use different composable?
|
||||||
|
SliderItem(
|
||||||
|
label = item.title,
|
||||||
|
min = item.min,
|
||||||
|
max = item.max,
|
||||||
|
value = item.value,
|
||||||
|
valueText = item.value.toString(),
|
||||||
|
onChange = {
|
||||||
|
scope.launch {
|
||||||
|
item.onValueChanged(it)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
is Preference.PreferenceItem.ListPreference<*> -> {
|
is Preference.PreferenceItem.ListPreference<*> -> {
|
||||||
val value by item.pref.collectAsState()
|
val value by item.pref.collectAsState()
|
||||||
ListPreferenceWidget(
|
ListPreferenceWidget(
|
||||||
|
|
|
@ -5,6 +5,7 @@ import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import eu.kanade.domain.ui.model.AppTheme
|
import eu.kanade.domain.ui.model.AppTheme
|
||||||
|
import eu.kanade.presentation.more.settings.Preference.PreferenceItem
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.track.TrackService
|
import eu.kanade.tachiyomi.data.track.TrackService
|
||||||
import tachiyomi.core.preference.Preference as PreferenceData
|
import tachiyomi.core.preference.Preference as PreferenceData
|
||||||
|
@ -43,6 +44,20 @@ sealed class Preference {
|
||||||
override val onValueChanged: suspend (newValue: Boolean) -> Boolean = { true },
|
override val onValueChanged: suspend (newValue: Boolean) -> Boolean = { true },
|
||||||
) : PreferenceItem<Boolean>()
|
) : PreferenceItem<Boolean>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A [PreferenceItem] that provides a slider to select an integer number.
|
||||||
|
*/
|
||||||
|
data class SliderPreference(
|
||||||
|
val value: Int,
|
||||||
|
val min: Int = 0,
|
||||||
|
val max: Int,
|
||||||
|
override val title: String = "",
|
||||||
|
override val subtitle: String? = null,
|
||||||
|
override val icon: ImageVector? = null,
|
||||||
|
override val enabled: Boolean = true,
|
||||||
|
override val onValueChanged: suspend (newValue: Int) -> Boolean = { true },
|
||||||
|
) : PreferenceItem<Int>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A [PreferenceItem] that displays a list of entries as a dialog.
|
* A [PreferenceItem] that displays a list of entries as a dialog.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -31,6 +31,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import eu.kanade.presentation.more.settings.LocalPreferenceHighlighted
|
import eu.kanade.presentation.more.settings.LocalPreferenceHighlighted
|
||||||
|
import eu.kanade.presentation.more.settings.LocalPreferenceMinHeight
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
||||||
|
@ -44,10 +45,11 @@ internal fun BasePreferenceWidget(
|
||||||
widget: @Composable (() -> Unit)? = null,
|
widget: @Composable (() -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
val highlighted = LocalPreferenceHighlighted.current
|
val highlighted = LocalPreferenceHighlighted.current
|
||||||
|
val minHeight = LocalPreferenceMinHeight.current
|
||||||
Row(
|
Row(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.highlightBackground(highlighted)
|
.highlightBackground(highlighted)
|
||||||
.sizeIn(minHeight = 56.dp)
|
.sizeIn(minHeight = minHeight)
|
||||||
.clickable(enabled = onClick != null, onClick = { onClick?.invoke() })
|
.clickable(enabled = onClick != null, onClick = { onClick?.invoke() })
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
|
|
@ -58,6 +58,7 @@ import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
||||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||||
import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
|
import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.setting.ReaderColorFilterDialog
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsSheet
|
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsSheet
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
||||||
|
@ -409,10 +410,20 @@ class ReaderActivity : BaseActivity() {
|
||||||
|
|
||||||
binding.dialogRoot.setComposeContent {
|
binding.dialogRoot.setComposeContent {
|
||||||
val state by viewModel.state.collectAsState()
|
val state by viewModel.state.collectAsState()
|
||||||
|
val onDismissRequest = viewModel::closeDialog
|
||||||
when (state.dialog) {
|
when (state.dialog) {
|
||||||
|
is ReaderViewModel.Dialog.ColorFilter -> {
|
||||||
|
setMenuVisibility(false)
|
||||||
|
ReaderColorFilterDialog(
|
||||||
|
onDismissRequest = {
|
||||||
|
onDismissRequest()
|
||||||
|
setMenuVisibility(true)
|
||||||
|
},
|
||||||
|
readerPreferences = viewModel.readerPreferences,
|
||||||
|
)
|
||||||
|
}
|
||||||
is ReaderViewModel.Dialog.Page -> ReaderPageDialog(
|
is ReaderViewModel.Dialog.Page -> ReaderPageDialog(
|
||||||
onDismissRequest = viewModel::closeDialog,
|
onDismissRequest = onDismissRequest,
|
||||||
onSetAsCover = viewModel::setAsCover,
|
onSetAsCover = viewModel::setAsCover,
|
||||||
onShare = viewModel::shareImage,
|
onShare = viewModel::shareImage,
|
||||||
onSave = viewModel::saveImage,
|
onSave = viewModel::saveImage,
|
||||||
|
@ -548,11 +559,14 @@ class ReaderActivity : BaseActivity() {
|
||||||
if (readerSettingSheet?.isShowing == true) return@setOnClickListener
|
if (readerSettingSheet?.isShowing == true) return@setOnClickListener
|
||||||
readerSettingSheet = ReaderSettingsSheet(this@ReaderActivity).apply { show() }
|
readerSettingSheet = ReaderSettingsSheet(this@ReaderActivity).apply { show() }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setOnLongClickListener {
|
// Color filter sheet
|
||||||
if (readerSettingSheet?.isShowing == true) return@setOnLongClickListener false
|
with(binding.actionColorSettings) {
|
||||||
readerSettingSheet = ReaderSettingsSheet(this@ReaderActivity, showColorFilterSettings = true).apply { show() }
|
setTooltip(R.string.custom_filter)
|
||||||
true
|
|
||||||
|
setOnClickListener {
|
||||||
|
viewModel.openColorFilterDialog()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,9 +92,9 @@ class ReaderViewModel(
|
||||||
private val downloadProvider: DownloadProvider = Injekt.get(),
|
private val downloadProvider: DownloadProvider = Injekt.get(),
|
||||||
private val imageSaver: ImageSaver = Injekt.get(),
|
private val imageSaver: ImageSaver = Injekt.get(),
|
||||||
preferences: BasePreferences = Injekt.get(),
|
preferences: BasePreferences = Injekt.get(),
|
||||||
|
val readerPreferences: ReaderPreferences = Injekt.get(),
|
||||||
private val basePreferences: BasePreferences = Injekt.get(),
|
private val basePreferences: BasePreferences = Injekt.get(),
|
||||||
private val downloadPreferences: DownloadPreferences = Injekt.get(),
|
private val downloadPreferences: DownloadPreferences = Injekt.get(),
|
||||||
private val readerPreferences: ReaderPreferences = Injekt.get(),
|
|
||||||
private val trackPreferences: TrackPreferences = Injekt.get(),
|
private val trackPreferences: TrackPreferences = Injekt.get(),
|
||||||
private val delayedTrackingStore: DelayedTrackingStore = Injekt.get(),
|
private val delayedTrackingStore: DelayedTrackingStore = Injekt.get(),
|
||||||
private val getManga: GetManga = Injekt.get(),
|
private val getManga: GetManga = Injekt.get(),
|
||||||
|
@ -723,6 +723,10 @@ class ReaderViewModel(
|
||||||
mutableState.update { it.copy(dialog = Dialog.Page(page)) }
|
mutableState.update { it.copy(dialog = Dialog.Page(page)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun openColorFilterDialog() {
|
||||||
|
mutableState.update { it.copy(dialog = Dialog.ColorFilter) }
|
||||||
|
}
|
||||||
|
|
||||||
fun closeDialog() {
|
fun closeDialog() {
|
||||||
mutableState.update { it.copy(dialog = null) }
|
mutableState.update { it.copy(dialog = null) }
|
||||||
}
|
}
|
||||||
|
@ -925,6 +929,7 @@ class ReaderViewModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class Dialog {
|
sealed class Dialog {
|
||||||
|
object ColorFilter : Dialog()
|
||||||
data class Page(val page: ReaderPage) : Dialog()
|
data class Page(val page: ReaderPage) : Dialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,164 @@
|
||||||
|
package eu.kanade.tachiyomi.ui.reader.setting
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.ui.platform.LocalView
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.window.DialogWindowProvider
|
||||||
|
import androidx.core.graphics.alpha
|
||||||
|
import androidx.core.graphics.blue
|
||||||
|
import androidx.core.graphics.green
|
||||||
|
import androidx.core.graphics.red
|
||||||
|
import eu.kanade.presentation.components.AdaptiveSheet
|
||||||
|
import eu.kanade.presentation.more.settings.LocalPreferenceMinHeight
|
||||||
|
import eu.kanade.presentation.more.settings.Preference
|
||||||
|
import eu.kanade.presentation.more.settings.PreferenceScreen
|
||||||
|
import eu.kanade.presentation.util.collectAsState
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import tachiyomi.core.preference.getAndSet
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ReaderColorFilterDialog(
|
||||||
|
onDismissRequest: () -> Unit,
|
||||||
|
readerPreferences: ReaderPreferences,
|
||||||
|
) {
|
||||||
|
val colorFilterModes = buildList {
|
||||||
|
addAll(
|
||||||
|
listOf(
|
||||||
|
R.string.label_default,
|
||||||
|
R.string.filter_mode_multiply,
|
||||||
|
R.string.filter_mode_screen,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
|
addAll(
|
||||||
|
listOf(
|
||||||
|
R.string.filter_mode_overlay,
|
||||||
|
R.string.filter_mode_lighten,
|
||||||
|
R.string.filter_mode_darken,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}.map { stringResource(it) }
|
||||||
|
|
||||||
|
val customBrightness by readerPreferences.customBrightness().collectAsState()
|
||||||
|
val customBrightnessValue by readerPreferences.customBrightnessValue().collectAsState()
|
||||||
|
val colorFilter by readerPreferences.colorFilter().collectAsState()
|
||||||
|
val colorFilterValue by readerPreferences.colorFilterValue().collectAsState()
|
||||||
|
val colorFilterMode by readerPreferences.colorFilterMode().collectAsState()
|
||||||
|
|
||||||
|
AdaptiveSheet(
|
||||||
|
onDismissRequest = onDismissRequest,
|
||||||
|
) {
|
||||||
|
(LocalView.current.parent as? DialogWindowProvider)?.window?.setDimAmount(0f)
|
||||||
|
|
||||||
|
CompositionLocalProvider(
|
||||||
|
LocalPreferenceMinHeight provides 48.dp,
|
||||||
|
) {
|
||||||
|
PreferenceScreen(
|
||||||
|
items = listOfNotNull(
|
||||||
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
|
pref = readerPreferences.customBrightness(),
|
||||||
|
title = stringResource(R.string.pref_custom_brightness),
|
||||||
|
),
|
||||||
|
/**
|
||||||
|
* Sets the brightness of the screen. Range is [-75, 100].
|
||||||
|
* From -75 to -1 a semi-transparent black view is shown at the top with the minimum brightness.
|
||||||
|
* From 1 to 100 it sets that value as brightness.
|
||||||
|
* 0 sets system brightness and hides the overlay.
|
||||||
|
*/
|
||||||
|
Preference.PreferenceItem.SliderPreference(
|
||||||
|
value = customBrightnessValue,
|
||||||
|
title = stringResource(R.string.pref_custom_brightness),
|
||||||
|
min = -75,
|
||||||
|
max = 100,
|
||||||
|
onValueChanged = {
|
||||||
|
readerPreferences.customBrightnessValue().set(it)
|
||||||
|
true
|
||||||
|
},
|
||||||
|
).takeIf { customBrightness },
|
||||||
|
|
||||||
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
|
pref = readerPreferences.colorFilter(),
|
||||||
|
title = stringResource(R.string.pref_custom_color_filter),
|
||||||
|
),
|
||||||
|
Preference.PreferenceItem.SliderPreference(
|
||||||
|
value = colorFilterValue.red,
|
||||||
|
title = stringResource(R.string.color_filter_r_value),
|
||||||
|
max = 255,
|
||||||
|
onValueChanged = { newRValue ->
|
||||||
|
readerPreferences.colorFilterValue().getAndSet {
|
||||||
|
getColorValue(it, newRValue, RED_MASK, 16)
|
||||||
|
}
|
||||||
|
true
|
||||||
|
},
|
||||||
|
).takeIf { colorFilter },
|
||||||
|
Preference.PreferenceItem.SliderPreference(
|
||||||
|
value = colorFilterValue.green,
|
||||||
|
title = stringResource(R.string.color_filter_g_value),
|
||||||
|
max = 255,
|
||||||
|
onValueChanged = { newRValue ->
|
||||||
|
readerPreferences.colorFilterValue().getAndSet {
|
||||||
|
getColorValue(it, newRValue, GREEN_MASK, 8)
|
||||||
|
}
|
||||||
|
true
|
||||||
|
},
|
||||||
|
).takeIf { colorFilter },
|
||||||
|
Preference.PreferenceItem.SliderPreference(
|
||||||
|
value = colorFilterValue.blue,
|
||||||
|
title = stringResource(R.string.color_filter_b_value),
|
||||||
|
max = 255,
|
||||||
|
onValueChanged = { newRValue ->
|
||||||
|
readerPreferences.colorFilterValue().getAndSet {
|
||||||
|
getColorValue(it, newRValue, BLUE_MASK, 0)
|
||||||
|
}
|
||||||
|
true
|
||||||
|
},
|
||||||
|
).takeIf { colorFilter },
|
||||||
|
Preference.PreferenceItem.SliderPreference(
|
||||||
|
value = colorFilterValue.alpha,
|
||||||
|
title = stringResource(R.string.color_filter_a_value),
|
||||||
|
max = 255,
|
||||||
|
onValueChanged = { newRValue ->
|
||||||
|
readerPreferences.colorFilterValue().getAndSet {
|
||||||
|
getColorValue(it, newRValue, ALPHA_MASK, 24)
|
||||||
|
}
|
||||||
|
true
|
||||||
|
},
|
||||||
|
).takeIf { colorFilter },
|
||||||
|
Preference.PreferenceItem.BasicListPreference(
|
||||||
|
value = colorFilterMode.toString(),
|
||||||
|
title = stringResource(R.string.pref_color_filter_mode),
|
||||||
|
entries = colorFilterModes
|
||||||
|
.mapIndexed { index, mode -> index.toString() to mode }
|
||||||
|
.toMap(),
|
||||||
|
onValueChanged = { newValue ->
|
||||||
|
readerPreferences.colorFilterMode().set(newValue.toInt())
|
||||||
|
true
|
||||||
|
},
|
||||||
|
).takeIf { colorFilter },
|
||||||
|
|
||||||
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
|
pref = readerPreferences.grayscale(),
|
||||||
|
title = stringResource(R.string.pref_grayscale),
|
||||||
|
),
|
||||||
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
|
pref = readerPreferences.invertedColors(),
|
||||||
|
title = stringResource(R.string.pref_inverted_colors),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getColorValue(currentColor: Int, color: Int, mask: Long, bitShift: Int): Int {
|
||||||
|
return (color shl bitShift) or (currentColor and mask.inv().toInt())
|
||||||
|
}
|
||||||
|
private const val ALPHA_MASK: Long = 0xFF000000
|
||||||
|
private const val RED_MASK: Long = 0x00FF0000
|
||||||
|
private const val GREEN_MASK: Long = 0x0000FF00
|
||||||
|
private const val BLUE_MASK: Long = 0x000000FF
|
|
@ -1,202 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.ui.reader.setting
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.util.AttributeSet
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import androidx.annotation.ColorInt
|
|
||||||
import androidx.core.graphics.alpha
|
|
||||||
import androidx.core.graphics.blue
|
|
||||||
import androidx.core.graphics.green
|
|
||||||
import androidx.core.graphics.red
|
|
||||||
import androidx.core.widget.NestedScrollView
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import eu.kanade.tachiyomi.databinding.ReaderColorFilterSettingsBinding
|
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
|
||||||
import eu.kanade.tachiyomi.util.preference.bindToPreference
|
|
||||||
import kotlinx.coroutines.flow.launchIn
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import kotlinx.coroutines.flow.sample
|
|
||||||
import tachiyomi.core.preference.getAndSet
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Color filter sheet to toggle custom filter and brightness overlay.
|
|
||||||
*/
|
|
||||||
class ReaderColorFilterSettings @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
|
||||||
NestedScrollView(context, attrs) {
|
|
||||||
|
|
||||||
private val readerPreferences: ReaderPreferences by injectLazy()
|
|
||||||
|
|
||||||
private val binding = ReaderColorFilterSettingsBinding.inflate(LayoutInflater.from(context), this, false)
|
|
||||||
|
|
||||||
init {
|
|
||||||
addView(binding.root)
|
|
||||||
|
|
||||||
readerPreferences.colorFilter().changes()
|
|
||||||
.onEach(::setColorFilter)
|
|
||||||
.launchIn((context as ReaderActivity).lifecycleScope)
|
|
||||||
|
|
||||||
readerPreferences.colorFilterMode().changes()
|
|
||||||
.onEach { setColorFilter(readerPreferences.colorFilter().get()) }
|
|
||||||
.launchIn(context.lifecycleScope)
|
|
||||||
|
|
||||||
readerPreferences.customBrightness().changes()
|
|
||||||
.onEach(::setCustomBrightness)
|
|
||||||
.launchIn(context.lifecycleScope)
|
|
||||||
|
|
||||||
// Get color and update values
|
|
||||||
val color = readerPreferences.colorFilterValue().get()
|
|
||||||
val brightness = readerPreferences.customBrightnessValue().get()
|
|
||||||
|
|
||||||
val argb = setValues(color)
|
|
||||||
|
|
||||||
// Set brightness value
|
|
||||||
binding.txtBrightnessSeekbarValue.text = brightness.toString()
|
|
||||||
binding.sliderBrightness.value = brightness.toFloat()
|
|
||||||
|
|
||||||
// Initialize seekBar progress
|
|
||||||
binding.sliderColorFilterAlpha.value = argb[0].toFloat()
|
|
||||||
binding.sliderColorFilterRed.value = argb[1].toFloat()
|
|
||||||
binding.sliderColorFilterGreen.value = argb[2].toFloat()
|
|
||||||
binding.sliderColorFilterBlue.value = argb[3].toFloat()
|
|
||||||
|
|
||||||
// Set listeners
|
|
||||||
binding.switchColorFilter.bindToPreference(readerPreferences.colorFilter())
|
|
||||||
binding.customBrightness.bindToPreference(readerPreferences.customBrightness())
|
|
||||||
binding.colorFilterMode.bindToPreference(readerPreferences.colorFilterMode())
|
|
||||||
binding.grayscale.bindToPreference(readerPreferences.grayscale())
|
|
||||||
binding.invertedColors.bindToPreference(readerPreferences.invertedColors())
|
|
||||||
|
|
||||||
binding.sliderColorFilterAlpha.addOnChangeListener { _, value, fromUser ->
|
|
||||||
if (fromUser) {
|
|
||||||
setColorValue(value.toInt(), ALPHA_MASK, 24)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
binding.sliderColorFilterRed.addOnChangeListener { _, value, fromUser ->
|
|
||||||
if (fromUser) {
|
|
||||||
setColorValue(value.toInt(), RED_MASK, 16)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
binding.sliderColorFilterGreen.addOnChangeListener { _, value, fromUser ->
|
|
||||||
if (fromUser) {
|
|
||||||
setColorValue(value.toInt(), GREEN_MASK, 8)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
binding.sliderColorFilterBlue.addOnChangeListener { _, value, fromUser ->
|
|
||||||
if (fromUser) {
|
|
||||||
setColorValue(value.toInt(), BLUE_MASK, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.sliderBrightness.addOnChangeListener { _, value, fromUser ->
|
|
||||||
if (fromUser) {
|
|
||||||
readerPreferences.customBrightnessValue().set(value.toInt())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set enabled status of seekBars belonging to color filter
|
|
||||||
* @param enabled determines if seekBar gets enabled
|
|
||||||
*/
|
|
||||||
private fun setColorFilterSeekBar(enabled: Boolean) {
|
|
||||||
binding.sliderColorFilterRed.isEnabled = enabled
|
|
||||||
binding.sliderColorFilterGreen.isEnabled = enabled
|
|
||||||
binding.sliderColorFilterBlue.isEnabled = enabled
|
|
||||||
binding.sliderColorFilterAlpha.isEnabled = enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set enabled status of seekBars belonging to custom brightness
|
|
||||||
* @param enabled value which determines if seekBar gets enabled
|
|
||||||
*/
|
|
||||||
private fun setCustomBrightnessSeekBar(enabled: Boolean) {
|
|
||||||
binding.sliderBrightness.isEnabled = enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the text value's of color filter
|
|
||||||
* @param color integer containing color information
|
|
||||||
*/
|
|
||||||
private fun setValues(color: Int): Array<Int> {
|
|
||||||
val alpha = color.alpha
|
|
||||||
val red = color.red
|
|
||||||
val green = color.green
|
|
||||||
val blue = color.blue
|
|
||||||
|
|
||||||
// Initialize values
|
|
||||||
binding.txtColorFilterAlphaValue.text = "$alpha"
|
|
||||||
binding.txtColorFilterRedValue.text = "$red"
|
|
||||||
binding.txtColorFilterGreenValue.text = "$green"
|
|
||||||
binding.txtColorFilterBlueValue.text = "$blue"
|
|
||||||
|
|
||||||
return arrayOf(alpha, red, green, blue)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manages the custom brightness value subscription
|
|
||||||
* @param enabled determines if the subscription get (un)subscribed
|
|
||||||
*/
|
|
||||||
private fun setCustomBrightness(enabled: Boolean) {
|
|
||||||
if (enabled) {
|
|
||||||
readerPreferences.customBrightnessValue().changes()
|
|
||||||
.sample(100)
|
|
||||||
.onEach(::setCustomBrightnessValue)
|
|
||||||
.launchIn((context as ReaderActivity).lifecycleScope)
|
|
||||||
} else {
|
|
||||||
setCustomBrightnessValue(0, true)
|
|
||||||
}
|
|
||||||
setCustomBrightnessSeekBar(enabled)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the brightness of the screen. Range is [-75, 100].
|
|
||||||
* From -75 to -1 a semi-transparent black view is shown at the top with the minimum brightness.
|
|
||||||
* From 1 to 100 it sets that value as brightness.
|
|
||||||
* 0 sets system brightness and hides the overlay.
|
|
||||||
*/
|
|
||||||
private fun setCustomBrightnessValue(value: Int, isDisabled: Boolean = false) {
|
|
||||||
if (!isDisabled) {
|
|
||||||
binding.txtBrightnessSeekbarValue.text = value.toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manages the color filter value subscription
|
|
||||||
* @param enabled determines if the subscription get (un)subscribed
|
|
||||||
*/
|
|
||||||
private fun setColorFilter(enabled: Boolean) {
|
|
||||||
if (enabled) {
|
|
||||||
readerPreferences.colorFilterValue().changes()
|
|
||||||
.sample(100)
|
|
||||||
.onEach(::setColorFilterValue)
|
|
||||||
.launchIn((context as ReaderActivity).lifecycleScope)
|
|
||||||
}
|
|
||||||
setColorFilterSeekBar(enabled)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the color filter overlay of the screen. Determined by HEX of integer
|
|
||||||
* @param color hex of color.
|
|
||||||
*/
|
|
||||||
private fun setColorFilterValue(@ColorInt color: Int) {
|
|
||||||
setValues(color)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the color value in preference
|
|
||||||
* @param color value of color range [0,255]
|
|
||||||
* @param mask contains hex mask of chosen color
|
|
||||||
* @param bitShift amounts of bits that gets shifted to receive value
|
|
||||||
*/
|
|
||||||
private fun setColorValue(color: Int, mask: Long, bitShift: Int) {
|
|
||||||
readerPreferences.colorFilterValue().getAndSet { currentColor ->
|
|
||||||
(color shl bitShift) or (currentColor and mask.inv().toInt())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private const val ALPHA_MASK: Long = 0xFF000000
|
|
||||||
private const val RED_MASK: Long = 0x00FF0000
|
|
||||||
private const val GREEN_MASK: Long = 0x0000FF00
|
|
||||||
private const val BLUE_MASK: Long = 0x000000FF
|
|
|
@ -1,46 +1,30 @@
|
||||||
package eu.kanade.tachiyomi.ui.reader.setting
|
package eu.kanade.tachiyomi.ui.reader.setting
|
||||||
|
|
||||||
import android.animation.ValueAnimator
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import com.google.android.material.tabs.TabLayout
|
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.databinding.CommonTabbedSheetBinding
|
import eu.kanade.tachiyomi.databinding.CommonTabbedSheetBinding
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||||
import eu.kanade.tachiyomi.widget.ViewPagerAdapter
|
import eu.kanade.tachiyomi.widget.ViewPagerAdapter
|
||||||
import eu.kanade.tachiyomi.widget.listener.SimpleTabSelectedListener
|
|
||||||
import eu.kanade.tachiyomi.widget.sheet.BaseBottomSheetDialog
|
import eu.kanade.tachiyomi.widget.sheet.BaseBottomSheetDialog
|
||||||
|
|
||||||
class ReaderSettingsSheet(
|
class ReaderSettingsSheet(
|
||||||
private val activity: ReaderActivity,
|
private val activity: ReaderActivity,
|
||||||
private val showColorFilterSettings: Boolean = false,
|
|
||||||
) : BaseBottomSheetDialog(activity) {
|
) : BaseBottomSheetDialog(activity) {
|
||||||
|
|
||||||
private val tabs = listOf(
|
private val tabs = listOf(
|
||||||
ReaderReadingModeSettings(activity) to R.string.pref_category_reading_mode,
|
ReaderReadingModeSettings(activity) to R.string.pref_category_reading_mode,
|
||||||
ReaderGeneralSettings(activity) to R.string.pref_category_general,
|
ReaderGeneralSettings(activity) to R.string.pref_category_general,
|
||||||
ReaderColorFilterSettings(activity) to R.string.custom_filter,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
private val backgroundDimAnimator by lazy {
|
|
||||||
val sheetBackgroundDim = window?.attributes?.dimAmount ?: 0.25f
|
|
||||||
ValueAnimator.ofFloat(sheetBackgroundDim, 0f).also { valueAnimator ->
|
|
||||||
valueAnimator.duration = 250
|
|
||||||
valueAnimator.addUpdateListener {
|
|
||||||
window?.setDimAmount(it.animatedValue as Float)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private lateinit var binding: CommonTabbedSheetBinding
|
private lateinit var binding: CommonTabbedSheetBinding
|
||||||
|
|
||||||
override fun createView(inflater: LayoutInflater): View {
|
override fun createView(inflater: LayoutInflater): View {
|
||||||
binding = CommonTabbedSheetBinding.inflate(activity.layoutInflater)
|
binding = CommonTabbedSheetBinding.inflate(activity.layoutInflater)
|
||||||
|
|
||||||
val adapter = Adapter()
|
val adapter = Adapter()
|
||||||
binding.pager.offscreenPageLimit = 2
|
|
||||||
binding.pager.adapter = adapter
|
binding.pager.adapter = adapter
|
||||||
binding.tabs.setupWithViewPager(binding.pager)
|
binding.tabs.setupWithViewPager(binding.pager)
|
||||||
|
|
||||||
|
@ -52,35 +36,6 @@ class ReaderSettingsSheet(
|
||||||
|
|
||||||
behavior.isFitToContents = false
|
behavior.isFitToContents = false
|
||||||
behavior.halfExpandedRatio = 0.25f
|
behavior.halfExpandedRatio = 0.25f
|
||||||
|
|
||||||
val filterTabIndex = tabs.indexOfFirst { it.first is ReaderColorFilterSettings }
|
|
||||||
binding.tabs.addOnTabSelectedListener(
|
|
||||||
object : SimpleTabSelectedListener() {
|
|
||||||
override fun onTabSelected(tab: TabLayout.Tab?) {
|
|
||||||
val isFilterTab = tab?.position == filterTabIndex
|
|
||||||
|
|
||||||
// Remove dimmed backdrop so color filter changes can be previewed
|
|
||||||
backgroundDimAnimator.run {
|
|
||||||
if (isFilterTab) {
|
|
||||||
if (animatedFraction < 1f) {
|
|
||||||
start()
|
|
||||||
}
|
|
||||||
} else if (animatedFraction > 0f) {
|
|
||||||
reverse()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hide toolbars
|
|
||||||
if (activity.menuVisible != !isFilterTab) {
|
|
||||||
activity.setMenuVisibility(!isFilterTab)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
if (showColorFilterSettings) {
|
|
||||||
binding.tabs.getTabAt(filterTabIndex)?.select()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class Adapter : ViewPagerAdapter() {
|
private inner class Adapter : ViewPagerAdapter() {
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.widget.listener
|
|
||||||
|
|
||||||
import com.google.android.material.tabs.TabLayout
|
|
||||||
|
|
||||||
open class SimpleTabSelectedListener : TabLayout.OnTabSelectedListener {
|
|
||||||
override fun onTabSelected(tab: TabLayout.Tab?) {
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onTabUnselected(tab: TabLayout.Tab?) {
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onTabReselected(tab: TabLayout.Tab?) {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -119,12 +119,25 @@
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
android:contentDescription="@string/action_settings"
|
android:contentDescription="@string/action_settings"
|
||||||
android:padding="@dimen/screen_edge_margin"
|
android:padding="@dimen/screen_edge_margin"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toStartOf="@+id/action_color_settings"
|
||||||
app:layout_constraintStart_toEndOf="@id/action_rotation"
|
app:layout_constraintStart_toEndOf="@id/action_rotation"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:srcCompat="@drawable/ic_settings_24dp"
|
app:srcCompat="@drawable/ic_settings_24dp"
|
||||||
app:tint="?attr/colorOnSurface" />
|
app:tint="?attr/colorOnSurface" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/action_color_settings"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:contentDescription="@string/custom_filter"
|
||||||
|
android:padding="@dimen/screen_edge_margin"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/action_settings"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:srcCompat="@drawable/ic_brightness_5_24dp"
|
||||||
|
app:tint="?attr/colorOnSurface" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -1,269 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<!-- Brightness -->
|
|
||||||
|
|
||||||
<com.google.android.material.materialswitch.MaterialSwitch
|
|
||||||
android:id="@+id/custom_brightness"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingHorizontal="16dp"
|
|
||||||
android:paddingVertical="16dp"
|
|
||||||
android:text="@string/pref_custom_brightness"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<!-- Brightness value -->
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
|
||||||
android:id="@+id/txt_brightness_seekbar_icon"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingStart="16dp"
|
|
||||||
android:textAppearance="?attr/textAppearanceTitleSmall"
|
|
||||||
android:tint="?attr/colorOnBackground"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/slider_brightness"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/slider_brightness"
|
|
||||||
app:srcCompat="@drawable/ic_brightness_5_24dp" />
|
|
||||||
|
|
||||||
<com.google.android.material.slider.Slider
|
|
||||||
android:id="@+id/slider_brightness"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:padding="8dp"
|
|
||||||
android:valueFrom="-75.0"
|
|
||||||
android:valueTo="100.0"
|
|
||||||
android:stepSize="1.0"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/txt_brightness_seekbar_value"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/txt_brightness_seekbar_icon"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/custom_brightness" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/txt_brightness_seekbar_value"
|
|
||||||
android:layout_width="30dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:textAppearance="?attr/textAppearanceTitleSmall"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/slider_brightness"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/slider_brightness"
|
|
||||||
tools:text="50" />
|
|
||||||
|
|
||||||
<!-- Color filter -->
|
|
||||||
|
|
||||||
<com.google.android.material.materialswitch.MaterialSwitch
|
|
||||||
android:id="@+id/switch_color_filter"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingHorizontal="16dp"
|
|
||||||
android:paddingVertical="16dp"
|
|
||||||
android:text="@string/pref_custom_color_filter"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/slider_brightness" />
|
|
||||||
|
|
||||||
<!-- Red filter -->
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/txt_color_filter_red_symbol"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingStart="16dp"
|
|
||||||
android:text="@string/color_filter_r_value"
|
|
||||||
android:textAppearance="?attr/textAppearanceTitleSmall"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/slider_color_filter_red"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/slider_color_filter_red" />
|
|
||||||
|
|
||||||
<com.google.android.material.slider.Slider
|
|
||||||
android:id="@+id/slider_color_filter_red"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:stepSize="1.0"
|
|
||||||
android:valueTo="255.0"
|
|
||||||
android:padding="8dp"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/txt_color_filter_red_value"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/color_filter_symbols_barrier"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/switch_color_filter" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/txt_color_filter_red_value"
|
|
||||||
android:layout_width="30dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:textAppearance="?attr/textAppearanceTitleSmall"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/slider_color_filter_red"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/slider_color_filter_red"
|
|
||||||
tools:text="255" />
|
|
||||||
|
|
||||||
<!-- Green filter -->
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/txt_color_filter_green_symbol"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingStart="16dp"
|
|
||||||
android:text="@string/color_filter_g_value"
|
|
||||||
android:textAppearance="?attr/textAppearanceTitleSmall"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/slider_color_filter_green"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/slider_color_filter_green" />
|
|
||||||
|
|
||||||
<com.google.android.material.slider.Slider
|
|
||||||
android:id="@+id/slider_color_filter_green"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:stepSize="1.0"
|
|
||||||
android:valueTo="255.0"
|
|
||||||
android:padding="8dp"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/txt_color_filter_green_value"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/color_filter_symbols_barrier"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/slider_color_filter_red" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/txt_color_filter_green_value"
|
|
||||||
android:layout_width="30dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:textAppearance="?attr/textAppearanceTitleSmall"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/slider_color_filter_green"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/slider_color_filter_green"
|
|
||||||
tools:text="255" />
|
|
||||||
|
|
||||||
<!-- Blue filter -->
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/txt_color_filter_blue_symbol"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingStart="16dp"
|
|
||||||
android:text="@string/color_filter_b_value"
|
|
||||||
android:textAppearance="?attr/textAppearanceTitleSmall"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/slider_color_filter_blue"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/slider_color_filter_blue" />
|
|
||||||
|
|
||||||
<com.google.android.material.slider.Slider
|
|
||||||
android:id="@+id/slider_color_filter_blue"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:stepSize="1.0"
|
|
||||||
android:valueTo="255.0"
|
|
||||||
android:padding="8dp"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/txt_color_filter_blue_value"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/color_filter_symbols_barrier"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/slider_color_filter_green" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/txt_color_filter_blue_value"
|
|
||||||
android:layout_width="30dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:textAppearance="?attr/textAppearanceTitleSmall"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/slider_color_filter_blue"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/slider_color_filter_blue"
|
|
||||||
tools:text="255" />
|
|
||||||
|
|
||||||
<!-- Alpha filter -->
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/txt_color_filter_alpha_symbol"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingStart="16dp"
|
|
||||||
android:text="@string/color_filter_a_value"
|
|
||||||
android:textAppearance="?attr/textAppearanceTitleSmall"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/slider_color_filter_alpha"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/slider_color_filter_alpha" />
|
|
||||||
|
|
||||||
<com.google.android.material.slider.Slider
|
|
||||||
android:id="@+id/slider_color_filter_alpha"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:stepSize="1.0"
|
|
||||||
android:valueTo="255.0"
|
|
||||||
android:padding="8dp"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/txt_color_filter_alpha_value"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/color_filter_symbols_barrier"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/slider_color_filter_blue" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/txt_color_filter_alpha_value"
|
|
||||||
android:layout_width="30dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:textAppearance="?attr/textAppearanceTitleSmall"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/slider_color_filter_alpha"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/slider_color_filter_alpha"
|
|
||||||
tools:text="255" />
|
|
||||||
|
|
||||||
<!-- Filter mode -->
|
|
||||||
|
|
||||||
<eu.kanade.tachiyomi.widget.MaterialSpinnerView
|
|
||||||
android:id="@+id/color_filter_mode"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:entries="@array/color_filter_modes"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/slider_color_filter_alpha"
|
|
||||||
app:title="@string/pref_color_filter_mode" />
|
|
||||||
|
|
||||||
<!-- Grayscale -->
|
|
||||||
|
|
||||||
<com.google.android.material.materialswitch.MaterialSwitch
|
|
||||||
android:id="@+id/grayscale"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingHorizontal="16dp"
|
|
||||||
android:paddingVertical="16dp"
|
|
||||||
android:text="@string/pref_grayscale"
|
|
||||||
android:textColor="?android:attr/textColorSecondary"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/color_filter_mode" />
|
|
||||||
|
|
||||||
<com.google.android.material.materialswitch.MaterialSwitch
|
|
||||||
android:id="@+id/inverted_colors"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingHorizontal="16dp"
|
|
||||||
android:paddingVertical="16dp"
|
|
||||||
android:text="@string/pref_inverted_colors"
|
|
||||||
android:textColor="?android:attr/textColorSecondary"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/grayscale" />
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.Barrier
|
|
||||||
android:id="@+id/color_filter_symbols_barrier"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:barrierDirection="end"
|
|
||||||
app:constraint_referenced_ids="txt_color_filter_alpha_symbol,txt_color_filter_blue_symbol,txt_color_filter_red_symbol,txt_color_filter_green_symbol" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
</androidx.core.widget.NestedScrollView>
|
|
|
@ -1,15 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
|
|
||||||
<string-array name="color_filter_modes">
|
|
||||||
<item>@string/label_default</item>
|
|
||||||
<item>@string/filter_mode_multiply</item>
|
|
||||||
<item>@string/filter_mode_screen</item>
|
|
||||||
|
|
||||||
<!-- Attributes specific for SDK 28 and up -->
|
|
||||||
<item>@string/filter_mode_overlay</item>
|
|
||||||
<item>@string/filter_mode_lighten</item>
|
|
||||||
<item>@string/filter_mode_darken</item>
|
|
||||||
</string-array>
|
|
||||||
|
|
||||||
</resources>
|
|
|
@ -67,12 +67,6 @@
|
||||||
<item>@string/rotation_reverse_portrait</item>
|
<item>@string/rotation_reverse_portrait</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string-array name="color_filter_modes">
|
|
||||||
<item>@string/label_default</item>
|
|
||||||
<item>@string/filter_mode_multiply</item>
|
|
||||||
<item>@string/filter_mode_screen</item>
|
|
||||||
</string-array>
|
|
||||||
|
|
||||||
<string-array name="invert_tapping_mode">
|
<string-array name="invert_tapping_mode">
|
||||||
<item>@string/tapping_inverted_none</item>
|
<item>@string/tapping_inverted_none</item>
|
||||||
<item>@string/tapping_inverted_horizontal</item>
|
<item>@string/tapping_inverted_horizontal</item>
|
||||||
|
|
|
@ -140,7 +140,7 @@ fun RadioItem(
|
||||||
@Composable
|
@Composable
|
||||||
fun SliderItem(
|
fun SliderItem(
|
||||||
label: String,
|
label: String,
|
||||||
min: Int,
|
min: Int = 0,
|
||||||
max: Int,
|
max: Int,
|
||||||
value: Int,
|
value: Int,
|
||||||
valueText: String,
|
valueText: String,
|
||||||
|
|
Reference in a new issue