mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-04 08:08:55 +01:00 
			
		
		
		
	Initial migration of general reader settings to Compose
This commit is contained in:
		@@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.Column
 | 
			
		||||
import androidx.compose.foundation.layout.ColumnScope
 | 
			
		||||
import androidx.compose.foundation.layout.Row
 | 
			
		||||
import androidx.compose.foundation.layout.wrapContentSize
 | 
			
		||||
import androidx.compose.foundation.pager.PagerState
 | 
			
		||||
import androidx.compose.foundation.pager.rememberPagerState
 | 
			
		||||
import androidx.compose.material.icons.Icons
 | 
			
		||||
import androidx.compose.material.icons.filled.MoreVert
 | 
			
		||||
@@ -42,13 +43,13 @@ fun TabbedDialog(
 | 
			
		||||
    onDismissRequest: () -> Unit,
 | 
			
		||||
    tabTitles: List<String>,
 | 
			
		||||
    tabOverflowMenuContent: (@Composable ColumnScope.(() -> Unit) -> Unit)? = null,
 | 
			
		||||
    pagerState: PagerState = rememberPagerState { tabTitles.size },
 | 
			
		||||
    content: @Composable (Int) -> Unit,
 | 
			
		||||
) {
 | 
			
		||||
    AdaptiveSheet(
 | 
			
		||||
        onDismissRequest = onDismissRequest,
 | 
			
		||||
    ) {
 | 
			
		||||
        val scope = rememberCoroutineScope()
 | 
			
		||||
        val pagerState = rememberPagerState { tabTitles.size }
 | 
			
		||||
 | 
			
		||||
        Column {
 | 
			
		||||
            Row {
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,158 @@
 | 
			
		||||
package eu.kanade.presentation.reader.settings
 | 
			
		||||
 | 
			
		||||
import android.os.Build
 | 
			
		||||
import androidx.compose.foundation.layout.ColumnScope
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.getValue
 | 
			
		||||
import androidx.compose.ui.res.stringResource
 | 
			
		||||
import androidx.core.graphics.alpha
 | 
			
		||||
import androidx.core.graphics.blue
 | 
			
		||||
import androidx.core.graphics.green
 | 
			
		||||
import androidx.core.graphics.red
 | 
			
		||||
import eu.kanade.presentation.util.collectAsState
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
 | 
			
		||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel
 | 
			
		||||
import tachiyomi.core.preference.getAndSet
 | 
			
		||||
import tachiyomi.presentation.core.components.CheckboxItem
 | 
			
		||||
import tachiyomi.presentation.core.components.SelectItem
 | 
			
		||||
import tachiyomi.presentation.core.components.SliderItem
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel) {
 | 
			
		||||
    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 screenModel.preferences.customBrightness().collectAsState()
 | 
			
		||||
    CheckboxItem(
 | 
			
		||||
        label = stringResource(R.string.pref_custom_brightness),
 | 
			
		||||
        checked = customBrightness,
 | 
			
		||||
        onClick = {
 | 
			
		||||
            screenModel.togglePreference(ReaderPreferences::customBrightness)
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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.
 | 
			
		||||
     */
 | 
			
		||||
    if (customBrightness) {
 | 
			
		||||
        val customBrightnessValue by screenModel.preferences.customBrightnessValue().collectAsState()
 | 
			
		||||
        SliderItem(
 | 
			
		||||
            label = stringResource(R.string.pref_custom_brightness),
 | 
			
		||||
            min = -75,
 | 
			
		||||
            max = 100,
 | 
			
		||||
            value = customBrightnessValue,
 | 
			
		||||
            valueText = customBrightnessValue.toString(),
 | 
			
		||||
            onChange = { screenModel.preferences.customBrightnessValue().set(it) },
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val colorFilter by screenModel.preferences.colorFilter().collectAsState()
 | 
			
		||||
    CheckboxItem(
 | 
			
		||||
        label = stringResource(R.string.pref_custom_color_filter),
 | 
			
		||||
        checked = colorFilter,
 | 
			
		||||
        onClick = {
 | 
			
		||||
            screenModel.togglePreference(ReaderPreferences::colorFilter)
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
    if (colorFilter) {
 | 
			
		||||
        val colorFilterValue by screenModel.preferences.colorFilterValue().collectAsState()
 | 
			
		||||
        SliderItem(
 | 
			
		||||
            label = stringResource(R.string.color_filter_r_value),
 | 
			
		||||
            max = 255,
 | 
			
		||||
            value = colorFilterValue.red,
 | 
			
		||||
            valueText = colorFilterValue.red.toString(),
 | 
			
		||||
            onChange = { newRValue ->
 | 
			
		||||
                screenModel.preferences.colorFilterValue().getAndSet {
 | 
			
		||||
                    getColorValue(it, newRValue, RED_MASK, 16)
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
        SliderItem(
 | 
			
		||||
            label = stringResource(R.string.color_filter_g_value),
 | 
			
		||||
            max = 255,
 | 
			
		||||
            value = colorFilterValue.green,
 | 
			
		||||
            valueText = colorFilterValue.green.toString(),
 | 
			
		||||
            onChange = { newGValue ->
 | 
			
		||||
                screenModel.preferences.colorFilterValue().getAndSet {
 | 
			
		||||
                    getColorValue(it, newGValue, GREEN_MASK, 8)
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
        SliderItem(
 | 
			
		||||
            label = stringResource(R.string.color_filter_b_value),
 | 
			
		||||
            max = 255,
 | 
			
		||||
            value = colorFilterValue.blue,
 | 
			
		||||
            valueText = colorFilterValue.blue.toString(),
 | 
			
		||||
            onChange = { newBValue ->
 | 
			
		||||
                screenModel.preferences.colorFilterValue().getAndSet {
 | 
			
		||||
                    getColorValue(it, newBValue, BLUE_MASK, 0)
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
        SliderItem(
 | 
			
		||||
            label = stringResource(R.string.color_filter_a_value),
 | 
			
		||||
            max = 255,
 | 
			
		||||
            value = colorFilterValue.alpha,
 | 
			
		||||
            valueText = colorFilterValue.alpha.toString(),
 | 
			
		||||
            onChange = { newAValue ->
 | 
			
		||||
                screenModel.preferences.colorFilterValue().getAndSet {
 | 
			
		||||
                    getColorValue(it, newAValue, ALPHA_MASK, 24)
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        val colorFilterMode by screenModel.preferences.colorFilterMode().collectAsState()
 | 
			
		||||
        SelectItem(
 | 
			
		||||
            label = stringResource(R.string.pref_color_filter_mode),
 | 
			
		||||
            options = colorFilterModes.toTypedArray(),
 | 
			
		||||
            selectedIndex = colorFilterMode,
 | 
			
		||||
        ) {
 | 
			
		||||
            screenModel.preferences.colorFilterMode().set(it)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val grayscale by screenModel.preferences.grayscale().collectAsState()
 | 
			
		||||
    CheckboxItem(
 | 
			
		||||
        label = stringResource(R.string.pref_grayscale),
 | 
			
		||||
        checked = grayscale,
 | 
			
		||||
        onClick = {
 | 
			
		||||
            screenModel.togglePreference(ReaderPreferences::grayscale)
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
    val invertedColors by screenModel.preferences.invertedColors().collectAsState()
 | 
			
		||||
    CheckboxItem(
 | 
			
		||||
        label = stringResource(R.string.pref_inverted_colors),
 | 
			
		||||
        checked = invertedColors,
 | 
			
		||||
        onClick = {
 | 
			
		||||
            screenModel.togglePreference(ReaderPreferences::invertedColors)
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
@@ -0,0 +1,96 @@
 | 
			
		||||
package eu.kanade.presentation.reader.settings
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.layout.ColumnScope
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.getValue
 | 
			
		||||
import androidx.compose.ui.res.stringResource
 | 
			
		||||
import eu.kanade.presentation.util.collectAsState
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
 | 
			
		||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel
 | 
			
		||||
import tachiyomi.presentation.core.components.CheckboxItem
 | 
			
		||||
import tachiyomi.presentation.core.components.HeadingItem
 | 
			
		||||
import tachiyomi.presentation.core.components.RadioItem
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
internal fun ColumnScope.GeneralPage(screenModel: ReaderSettingsScreenModel) {
 | 
			
		||||
    // TODO: show this in a nicer way
 | 
			
		||||
    HeadingItem(stringResource(R.string.pref_reader_theme))
 | 
			
		||||
    val readerTheme by screenModel.preferences.readerTheme().collectAsState()
 | 
			
		||||
    listOf(
 | 
			
		||||
        R.string.black_background to 1,
 | 
			
		||||
        R.string.gray_background to 2,
 | 
			
		||||
        R.string.white_background to 0,
 | 
			
		||||
        R.string.automatic_background to 3,
 | 
			
		||||
    ).map { (titleRes, theme) ->
 | 
			
		||||
        RadioItem(
 | 
			
		||||
            label = stringResource(titleRes),
 | 
			
		||||
            selected = readerTheme == theme,
 | 
			
		||||
            onClick = { screenModel.preferences.readerTheme().set(theme) },
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val showPageNumber by screenModel.preferences.showPageNumber().collectAsState()
 | 
			
		||||
    CheckboxItem(
 | 
			
		||||
        label = stringResource(R.string.pref_show_page_number),
 | 
			
		||||
        checked = showPageNumber,
 | 
			
		||||
        onClick = {
 | 
			
		||||
            screenModel.togglePreference(ReaderPreferences::showPageNumber)
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    val fullscreen by screenModel.preferences.fullscreen().collectAsState()
 | 
			
		||||
    CheckboxItem(
 | 
			
		||||
        label = stringResource(R.string.pref_fullscreen),
 | 
			
		||||
        checked = fullscreen,
 | 
			
		||||
        onClick = {
 | 
			
		||||
            screenModel.togglePreference(ReaderPreferences::fullscreen)
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    // TODO: hide if there's no cutout
 | 
			
		||||
    val cutoutShort by screenModel.preferences.cutoutShort().collectAsState()
 | 
			
		||||
    CheckboxItem(
 | 
			
		||||
        label = stringResource(R.string.pref_cutout_short),
 | 
			
		||||
        checked = cutoutShort,
 | 
			
		||||
        onClick = {
 | 
			
		||||
            screenModel.togglePreference(ReaderPreferences::cutoutShort)
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    val keepScreenOn by screenModel.preferences.keepScreenOn().collectAsState()
 | 
			
		||||
    CheckboxItem(
 | 
			
		||||
        label = stringResource(R.string.pref_keep_screen_on),
 | 
			
		||||
        checked = keepScreenOn,
 | 
			
		||||
        onClick = {
 | 
			
		||||
            screenModel.togglePreference(ReaderPreferences::keepScreenOn)
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    val readWithLongTap by screenModel.preferences.readWithLongTap().collectAsState()
 | 
			
		||||
    CheckboxItem(
 | 
			
		||||
        label = stringResource(R.string.pref_read_with_long_tap),
 | 
			
		||||
        checked = readWithLongTap,
 | 
			
		||||
        onClick = {
 | 
			
		||||
            screenModel.togglePreference(ReaderPreferences::readWithLongTap)
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    val alwaysShowChapterTransition by screenModel.preferences.alwaysShowChapterTransition().collectAsState()
 | 
			
		||||
    CheckboxItem(
 | 
			
		||||
        label = stringResource(R.string.pref_always_show_chapter_transition),
 | 
			
		||||
        checked = alwaysShowChapterTransition,
 | 
			
		||||
        onClick = {
 | 
			
		||||
            screenModel.togglePreference(ReaderPreferences::alwaysShowChapterTransition)
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    val pageTransitions by screenModel.preferences.pageTransitions().collectAsState()
 | 
			
		||||
    CheckboxItem(
 | 
			
		||||
        label = stringResource(R.string.pref_page_transitions),
 | 
			
		||||
        checked = pageTransitions,
 | 
			
		||||
        onClick = {
 | 
			
		||||
            screenModel.togglePreference(ReaderPreferences::pageTransitions)
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,66 @@
 | 
			
		||||
package eu.kanade.presentation.reader.settings
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.layout.Column
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.foundation.pager.rememberPagerState
 | 
			
		||||
import androidx.compose.foundation.rememberScrollState
 | 
			
		||||
import androidx.compose.foundation.verticalScroll
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.LaunchedEffect
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.platform.LocalView
 | 
			
		||||
import androidx.compose.ui.res.stringResource
 | 
			
		||||
import androidx.compose.ui.window.DialogWindowProvider
 | 
			
		||||
import eu.kanade.presentation.components.TabbedDialog
 | 
			
		||||
import eu.kanade.presentation.components.TabbedDialogPaddings
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun ReaderSettingsDialog(
 | 
			
		||||
    onDismissRequest: () -> Unit,
 | 
			
		||||
    onShowMenus: () -> Unit,
 | 
			
		||||
    onHideMenus: () -> Unit,
 | 
			
		||||
    screenModel: ReaderSettingsScreenModel,
 | 
			
		||||
) {
 | 
			
		||||
    // TODO: undimming doesn't seem to work
 | 
			
		||||
    val window = (LocalView.current.parent as? DialogWindowProvider)?.window
 | 
			
		||||
 | 
			
		||||
    val tabTitles = listOf(
 | 
			
		||||
        stringResource(R.string.pref_category_reading_mode),
 | 
			
		||||
        stringResource(R.string.pref_category_general),
 | 
			
		||||
        stringResource(R.string.custom_filter),
 | 
			
		||||
    )
 | 
			
		||||
    val pagerState = rememberPagerState { tabTitles.size }
 | 
			
		||||
 | 
			
		||||
    LaunchedEffect(pagerState.currentPage) {
 | 
			
		||||
        if (pagerState.currentPage == 2) {
 | 
			
		||||
            window?.setDimAmount(0f)
 | 
			
		||||
            onHideMenus()
 | 
			
		||||
        } else {
 | 
			
		||||
            window?.setDimAmount(0.75f)
 | 
			
		||||
            onShowMenus()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    TabbedDialog(
 | 
			
		||||
        onDismissRequest = {
 | 
			
		||||
            onDismissRequest()
 | 
			
		||||
            onShowMenus()
 | 
			
		||||
        },
 | 
			
		||||
        tabTitles = tabTitles,
 | 
			
		||||
        pagerState = pagerState,
 | 
			
		||||
    ) { page ->
 | 
			
		||||
        Column(
 | 
			
		||||
            modifier = Modifier
 | 
			
		||||
                .padding(vertical = TabbedDialogPaddings.Vertical)
 | 
			
		||||
                .verticalScroll(rememberScrollState()),
 | 
			
		||||
        ) {
 | 
			
		||||
            when (page) {
 | 
			
		||||
                0 -> ReadingModePage(screenModel)
 | 
			
		||||
                1 -> GeneralPage(screenModel)
 | 
			
		||||
                2 -> ColorFilterPage(screenModel)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,10 @@
 | 
			
		||||
package eu.kanade.presentation.reader.settings
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.layout.ColumnScope
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
internal fun ColumnScope.ReadingModePage(screenModel: ReaderSettingsScreenModel) {
 | 
			
		||||
    // TODO
 | 
			
		||||
}
 | 
			
		||||
@@ -31,6 +31,7 @@ import androidx.compose.material3.CircularProgressIndicator
 | 
			
		||||
import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.runtime.collectAsState
 | 
			
		||||
import androidx.compose.runtime.getValue
 | 
			
		||||
import androidx.compose.runtime.remember
 | 
			
		||||
import androidx.compose.ui.Alignment
 | 
			
		||||
import androidx.compose.ui.res.stringResource
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
@@ -51,6 +52,7 @@ import eu.kanade.domain.base.BasePreferences
 | 
			
		||||
import eu.kanade.domain.manga.model.orientationType
 | 
			
		||||
import eu.kanade.presentation.reader.ChapterNavigator
 | 
			
		||||
import eu.kanade.presentation.reader.PageIndicatorText
 | 
			
		||||
import eu.kanade.presentation.reader.settings.ReaderSettingsDialog
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
 | 
			
		||||
import eu.kanade.tachiyomi.data.notification.Notifications
 | 
			
		||||
@@ -65,8 +67,8 @@ import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
 | 
			
		||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
 | 
			
		||||
import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
 | 
			
		||||
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.ReaderSettingsScreenModel
 | 
			
		||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsSheet
 | 
			
		||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
 | 
			
		||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressIndicator
 | 
			
		||||
@@ -389,6 +391,8 @@ class ReaderActivity : BaseActivity() {
 | 
			
		||||
 | 
			
		||||
        binding.dialogRoot.setComposeContent {
 | 
			
		||||
            val state by viewModel.state.collectAsState()
 | 
			
		||||
            val settingsScreenModel = remember { ReaderSettingsScreenModel() }
 | 
			
		||||
 | 
			
		||||
            val onDismissRequest = viewModel::closeDialog
 | 
			
		||||
            when (state.dialog) {
 | 
			
		||||
                is ReaderViewModel.Dialog.Loading -> {
 | 
			
		||||
@@ -406,14 +410,12 @@ class ReaderActivity : BaseActivity() {
 | 
			
		||||
                        },
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
                is ReaderViewModel.Dialog.ColorFilter -> {
 | 
			
		||||
                    setMenuVisibility(false)
 | 
			
		||||
                    ReaderColorFilterDialog(
 | 
			
		||||
                        onDismissRequest = {
 | 
			
		||||
                            onDismissRequest()
 | 
			
		||||
                            setMenuVisibility(true)
 | 
			
		||||
                        },
 | 
			
		||||
                        readerPreferences = viewModel.readerPreferences,
 | 
			
		||||
                is ReaderViewModel.Dialog.Settings -> {
 | 
			
		||||
                    ReaderSettingsDialog(
 | 
			
		||||
                        onDismissRequest = onDismissRequest,
 | 
			
		||||
                        onShowMenus = { setMenuVisibility(true) },
 | 
			
		||||
                        onHideMenus = { setMenuVisibility(false) },
 | 
			
		||||
                        screenModel = settingsScreenModel,
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
                is ReaderViewModel.Dialog.PageActions -> {
 | 
			
		||||
@@ -546,7 +548,7 @@ class ReaderActivity : BaseActivity() {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Settings sheet
 | 
			
		||||
        with(binding.actionSettings) {
 | 
			
		||||
        with(binding.actionSettingsLegacy) {
 | 
			
		||||
            setTooltip(R.string.action_settings)
 | 
			
		||||
 | 
			
		||||
            var readerSettingSheet: ReaderSettingsSheet? = null
 | 
			
		||||
@@ -556,13 +558,11 @@ class ReaderActivity : BaseActivity() {
 | 
			
		||||
                readerSettingSheet = ReaderSettingsSheet(this@ReaderActivity).apply { show() }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Color filter sheet
 | 
			
		||||
        with(binding.actionColorSettings) {
 | 
			
		||||
            setTooltip(R.string.custom_filter)
 | 
			
		||||
        with(binding.actionSettings) {
 | 
			
		||||
            setTooltip(R.string.action_settings)
 | 
			
		||||
 | 
			
		||||
            setOnClickListener {
 | 
			
		||||
                viewModel.openColorFilterDialog()
 | 
			
		||||
                viewModel.openSettingsDialog()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -685,8 +685,8 @@ class ReaderViewModel(
 | 
			
		||||
        mutableState.update { it.copy(dialog = Dialog.PageActions(page)) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun openColorFilterDialog() {
 | 
			
		||||
        mutableState.update { it.copy(dialog = Dialog.ColorFilter) }
 | 
			
		||||
    fun openSettingsDialog() {
 | 
			
		||||
        mutableState.update { it.copy(dialog = Dialog.Settings) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun closeDialog() {
 | 
			
		||||
@@ -863,7 +863,7 @@ class ReaderViewModel(
 | 
			
		||||
 | 
			
		||||
    sealed class Dialog {
 | 
			
		||||
        object Loading : Dialog()
 | 
			
		||||
        object ColorFilter : Dialog()
 | 
			
		||||
        object Settings : Dialog()
 | 
			
		||||
        data class PageActions(val page: ReaderPage) : Dialog()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,164 +0,0 @@
 | 
			
		||||
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,53 +0,0 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.reader.setting
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.util.AttributeSet
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import androidx.core.view.isVisible
 | 
			
		||||
import androidx.core.widget.NestedScrollView
 | 
			
		||||
import androidx.lifecycle.lifecycleScope
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.databinding.ReaderGeneralSettingsBinding
 | 
			
		||||
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 uy.kohesive.injekt.injectLazy
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Sheet to show reader and viewer preferences.
 | 
			
		||||
 */
 | 
			
		||||
class ReaderGeneralSettings @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
 | 
			
		||||
    NestedScrollView(context, attrs) {
 | 
			
		||||
 | 
			
		||||
    private val readerPreferences: ReaderPreferences by injectLazy()
 | 
			
		||||
 | 
			
		||||
    private val binding = ReaderGeneralSettingsBinding.inflate(LayoutInflater.from(context), this, false)
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        addView(binding.root)
 | 
			
		||||
 | 
			
		||||
        initGeneralPreferences()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Init general reader preferences.
 | 
			
		||||
     */
 | 
			
		||||
    private fun initGeneralPreferences() {
 | 
			
		||||
        binding.backgroundColor.bindToIntPreference(readerPreferences.readerTheme(), R.array.reader_themes_values)
 | 
			
		||||
        binding.showPageNumber.bindToPreference(readerPreferences.showPageNumber())
 | 
			
		||||
        binding.fullscreen.bindToPreference(readerPreferences.fullscreen())
 | 
			
		||||
        readerPreferences.fullscreen().changes()
 | 
			
		||||
            .onEach {
 | 
			
		||||
                // If the preference is explicitly disabled, that means the setting was configured since there is a cutout
 | 
			
		||||
                binding.cutoutShort.isVisible = it && ((context as ReaderActivity).hasCutout || !readerPreferences.cutoutShort().get())
 | 
			
		||||
                binding.cutoutShort.bindToPreference(readerPreferences.cutoutShort())
 | 
			
		||||
            }
 | 
			
		||||
            .launchIn((context as ReaderActivity).lifecycleScope)
 | 
			
		||||
 | 
			
		||||
        binding.keepscreen.bindToPreference(readerPreferences.keepScreenOn())
 | 
			
		||||
        binding.longTap.bindToPreference(readerPreferences.readWithLongTap())
 | 
			
		||||
        binding.alwaysShowChapterTransition.bindToPreference(readerPreferences.alwaysShowChapterTransition())
 | 
			
		||||
        binding.pageTransitions.bindToPreference(readerPreferences.pageTransitions())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,16 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.reader.setting
 | 
			
		||||
 | 
			
		||||
import cafe.adriel.voyager.core.model.ScreenModel
 | 
			
		||||
import eu.kanade.tachiyomi.util.preference.toggle
 | 
			
		||||
import tachiyomi.core.preference.Preference
 | 
			
		||||
import uy.kohesive.injekt.Injekt
 | 
			
		||||
import uy.kohesive.injekt.api.get
 | 
			
		||||
 | 
			
		||||
class ReaderSettingsScreenModel(
 | 
			
		||||
    val preferences: ReaderPreferences = Injekt.get(),
 | 
			
		||||
) : ScreenModel {
 | 
			
		||||
 | 
			
		||||
    fun togglePreference(preference: (ReaderPreferences) -> Preference<Boolean>) {
 | 
			
		||||
        preference(preferences).toggle()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -16,7 +16,6 @@ class ReaderSettingsSheet(
 | 
			
		||||
 | 
			
		||||
    private val tabs = listOf(
 | 
			
		||||
        ReaderReadingModeSettings(activity) to R.string.pref_category_reading_mode,
 | 
			
		||||
        ReaderGeneralSettings(activity) to R.string.pref_category_general,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    private lateinit var binding: CommonTabbedSheetBinding
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user