🚀 Screen Brightness option

* Added "Screen Brightness" option in Reader
* Lets user change screen brightness in Reader
This commit is contained in:
Acclorite 2024-10-26 12:02:07 +03:00
parent bc249521db
commit 628f10f4e7
15 changed files with 143 additions and 11 deletions

View file

@ -1,3 +1,5 @@
@file:Suppress("SameReturnValue")
package ua.acclorite.book_story.presentation.core.constants package ua.acclorite.book_story.presentation.core.constants
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color

View file

@ -1,6 +1,7 @@
package ua.acclorite.book_story.presentation.core.constants package ua.acclorite.book_story.presentation.core.constants
import androidx.datastore.preferences.core.booleanPreferencesKey import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.doublePreferencesKey
import androidx.datastore.preferences.core.intPreferencesKey import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.core.stringSetPreferencesKey import androidx.datastore.preferences.core.stringSetPreferencesKey
@ -40,6 +41,8 @@ object DataStoreConstants {
val CHECK_FOR_TEXT_UPDATE = booleanPreferencesKey("check_for_text_update") val CHECK_FOR_TEXT_UPDATE = booleanPreferencesKey("check_for_text_update")
val CHECK_FOR_TEXT_UPDATE_TOAST = booleanPreferencesKey("check_for_text_update_toast") val CHECK_FOR_TEXT_UPDATE_TOAST = booleanPreferencesKey("check_for_text_update_toast")
val SCREEN_ORIENTATION = stringPreferencesKey("screen_orientation") val SCREEN_ORIENTATION = stringPreferencesKey("screen_orientation")
val CUSTOM_SCREEN_BRIGHTNESS = booleanPreferencesKey("custom_screen_brightness")
val SCREEN_BRIGHTNESS = doublePreferencesKey("screen_brightness")
// Browse settings // Browse settings
val BROWSE_FILES_STRUCTURE = stringPreferencesKey("browse_files_structure") val BROWSE_FILES_STRUCTURE = stringPreferencesKey("browse_files_structure")

View file

@ -1,3 +1,5 @@
@file:Suppress("SameReturnValue")
package ua.acclorite.book_story.presentation.core.constants package ua.acclorite.book_story.presentation.core.constants
fun Constants.provideDownloadLatestReleasePage() = fun Constants.provideDownloadLatestReleasePage() =

View file

@ -1,6 +1,7 @@
package ua.acclorite.book_story.presentation.core.util package ua.acclorite.book_story.presentation.core.util
import android.content.Intent import android.content.Intent
import android.view.WindowManager
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
fun Intent.launchActivity( fun Intent.launchActivity(
@ -21,4 +22,11 @@ fun Intent.launchActivity(
error() error()
return return
} }
}
fun ComponentActivity.setBrightness(brightness: Float?) {
window.attributes.apply {
screenBrightness = brightness ?: WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE
window.attributes = this
}
} }

View file

@ -49,4 +49,6 @@ sealed class MainEvent {
data class OnChangeCheckForTextUpdate(val value: Boolean) : MainEvent() data class OnChangeCheckForTextUpdate(val value: Boolean) : MainEvent()
data class OnChangeCheckForTextUpdateToast(val value: Boolean) : MainEvent() data class OnChangeCheckForTextUpdateToast(val value: Boolean) : MainEvent()
data class OnChangeScreenOrientation(val value: String) : MainEvent() data class OnChangeScreenOrientation(val value: String) : MainEvent()
data class OnChangeCustomScreenBrightness(val value: Boolean) : MainEvent()
data class OnChangeScreenBrightness(val value: Float) : MainEvent()
} }

View file

@ -82,6 +82,8 @@ data class MainState(
val screenOrientation: ReaderScreenOrientation = provideDefaultValue { val screenOrientation: ReaderScreenOrientation = provideDefaultValue {
ReaderScreenOrientation.DEFAULT ReaderScreenOrientation.DEFAULT
}, },
val customScreenBrightness: Boolean = provideDefaultValue { false },
val screenBrightness: Float = provideDefaultValue { 0.5f },
// Browse Settings // Browse Settings
val browseFilesStructure: BrowseFilesStructure = provideDefaultValue { val browseFilesStructure: BrowseFilesStructure = provideDefaultValue {
@ -271,6 +273,14 @@ data class MainState(
screenOrientation = provideValue( screenOrientation = provideValue(
SCREEN_ORIENTATION, convert = { toReaderScreenOrientation() } SCREEN_ORIENTATION, convert = { toReaderScreenOrientation() }
) { screenOrientation }, ) { screenOrientation },
customScreenBrightness = provideValue(
CUSTOM_SCREEN_BRIGHTNESS
) { customScreenBrightness },
screenBrightness = provideValue(
SCREEN_BRIGHTNESS, convert = { this.toFloat() }
) { screenBrightness },
) )
} }
} }

View file

@ -373,6 +373,22 @@ class MainViewModel @Inject constructor(
it.copy(screenOrientation = toReaderScreenOrientation()) it.copy(screenOrientation = toReaderScreenOrientation())
} }
) )
is MainEvent.OnChangeCustomScreenBrightness -> handleDatastoreUpdate(
key = DataStoreConstants.CUSTOM_SCREEN_BRIGHTNESS,
value = event.value,
updateState = {
it.copy(customScreenBrightness = this)
}
)
is MainEvent.OnChangeScreenBrightness -> handleDatastoreUpdate(
key = DataStoreConstants.SCREEN_BRIGHTNESS,
value = event.value.toDouble(),
updateState = {
it.copy(screenBrightness = this.toFloat())
}
)
} }
} }

View file

@ -55,8 +55,6 @@ import androidx.compose.ui.unit.em
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import ua.acclorite.book_story.R import ua.acclorite.book_story.R
import ua.acclorite.book_story.domain.model.Chapter import ua.acclorite.book_story.domain.model.Chapter
import ua.acclorite.book_story.presentation.core.components.common.AnimatedVisibility import ua.acclorite.book_story.presentation.core.components.common.AnimatedVisibility
@ -67,6 +65,7 @@ import ua.acclorite.book_story.presentation.core.constants.provideFonts
import ua.acclorite.book_story.presentation.core.navigation.LocalNavigator import ua.acclorite.book_story.presentation.core.navigation.LocalNavigator
import ua.acclorite.book_story.presentation.core.navigation.Screen import ua.acclorite.book_story.presentation.core.navigation.Screen
import ua.acclorite.book_story.presentation.core.util.noRippleClickable import ua.acclorite.book_story.presentation.core.util.noRippleClickable
import ua.acclorite.book_story.presentation.core.util.setBrightness
import ua.acclorite.book_story.presentation.core.util.showToast import ua.acclorite.book_story.presentation.core.util.showToast
import ua.acclorite.book_story.presentation.data.MainViewModel import ua.acclorite.book_story.presentation.data.MainViewModel
import ua.acclorite.book_story.presentation.screens.history.data.HistoryEvent import ua.acclorite.book_story.presentation.screens.history.data.HistoryEvent
@ -161,14 +160,6 @@ fun ReaderScreenRoot(screen: Screen.Reader) {
) )
) )
} }
LaunchedEffect(mainState.value.keepScreenOn) {
withContext(Dispatchers.Main) {
when (mainState.value.keepScreenOn) {
true -> context.window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
false -> context.window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
}
}
LaunchedEffect(lazyListState) { LaunchedEffect(lazyListState) {
onEvent( onEvent(
ReaderEvent.OnUpdateProgress( ReaderEvent.OnUpdateProgress(
@ -185,6 +176,28 @@ fun ReaderScreenRoot(screen: Screen.Reader) {
context.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED context.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
} }
} }
DisposableEffect(
mainState.value.screenBrightness,
mainState.value.customScreenBrightness
) {
when (mainState.value.customScreenBrightness) {
true -> context.setBrightness(brightness = mainState.value.screenBrightness)
false -> context.setBrightness(brightness = null)
}
onDispose {
context.setBrightness(brightness = null)
}
}
DisposableEffect(mainState.value.keepScreenOn) {
when (mainState.value.keepScreenOn) {
true -> context.window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
false -> context.window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
onDispose {
context.window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
}
ReaderScreen(lazyListState = lazyListState) ReaderScreen(lazyListState = lazyListState)
@ -195,7 +208,6 @@ fun ReaderScreenRoot(screen: Screen.Reader) {
context.window, context.window,
context.window.decorView context.window.decorView
).show(WindowInsetsCompat.Type.systemBars()) ).show(WindowInsetsCompat.Type.systemBars())
context.window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} }
} }
} }

View file

@ -38,6 +38,7 @@ import ua.acclorite.book_story.domain.util.UIViewModel
import ua.acclorite.book_story.presentation.core.navigation.Screen import ua.acclorite.book_story.presentation.core.navigation.Screen
import ua.acclorite.book_story.presentation.core.util.coerceAndPreventNaN import ua.acclorite.book_story.presentation.core.util.coerceAndPreventNaN
import ua.acclorite.book_story.presentation.core.util.launchActivity import ua.acclorite.book_story.presentation.core.util.launchActivity
import ua.acclorite.book_story.presentation.core.util.setBrightness
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.roundToInt import kotlin.math.roundToInt
@ -216,6 +217,7 @@ class ReaderViewModel @Inject constructor(
event.context.window, event.context.window,
event.context.window.decorView event.context.window.decorView
).show(WindowInsetsCompat.Type.systemBars()) ).show(WindowInsetsCompat.Type.systemBars())
event.context.setBrightness(brightness = null)
event.navigate() event.navigate()
} }

View file

@ -0,0 +1,30 @@
package ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import ua.acclorite.book_story.R
import ua.acclorite.book_story.presentation.core.components.settings.SwitchWithTitle
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainViewModel
/**
* Custom Screen Brightness setting.
* If true, applies custom brightness in Reader.
*/
@Composable
fun CustomScreenBrightnessSetting() {
val state = MainViewModel.getState()
val onMainEvent = MainViewModel.getEvent()
SwitchWithTitle(
selected = state.value.customScreenBrightness,
title = stringResource(id = R.string.custom_screen_brightness_option),
onClick = {
onMainEvent(
MainEvent.OnChangeCustomScreenBrightness(
!state.value.customScreenBrightness
)
)
}
)
}

View file

@ -0,0 +1,29 @@
package ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import ua.acclorite.book_story.R
import ua.acclorite.book_story.presentation.core.components.settings.SliderWithTitle
import ua.acclorite.book_story.presentation.data.MainEvent
import ua.acclorite.book_story.presentation.data.MainViewModel
/**
* Screen Brightness setting.
* Changes screen brightness in Reader.
*/
@Composable
fun ScreenBrightnessSetting() {
val state = MainViewModel.getState()
val onMainEvent = MainViewModel.getEvent()
SliderWithTitle(
value = state.value.screenBrightness to "",
toValue = 100,
title = stringResource(id = R.string.screen_brightness_option),
onValueChange = {
onMainEvent(
MainEvent.OnChangeScreenBrightness(it)
)
}
)
}

View file

@ -10,6 +10,8 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import ua.acclorite.book_story.R import ua.acclorite.book_story.R
import ua.acclorite.book_story.presentation.screens.settings.components.SettingsSubcategory import ua.acclorite.book_story.presentation.screens.settings.components.SettingsSubcategory
import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings.CustomScreenBrightnessSetting
import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings.ScreenBrightnessSetting
import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings.ScreenOrientationSetting import ua.acclorite.book_story.presentation.screens.settings.nested.reader.components.settings.ScreenOrientationSetting
/** /**
@ -32,6 +34,14 @@ fun LazyListScope.SystemSubcategory(
topPadding = topPadding, topPadding = topPadding,
bottomPadding = bottomPadding bottomPadding = bottomPadding
) { ) {
item {
CustomScreenBrightnessSetting()
}
item {
ScreenBrightnessSetting()
}
item { item {
ScreenOrientationSetting() ScreenOrientationSetting()
} }

View file

@ -1,3 +1,5 @@
@file:Suppress("unused")
package ua.acclorite.book_story.presentation.ui package ua.acclorite.book_story.presentation.ui
import android.util.Log import android.util.Log

View file

@ -262,6 +262,8 @@
<string name="check_for_text_update_option_desc">Автоматично перевіряти чи є оновлення тексту</string> <string name="check_for_text_update_option_desc">Автоматично перевіряти чи є оновлення тексту</string>
<string name="check_for_text_update_toast_option">Показувати повідомлення \"текст актуальний\"</string> <string name="check_for_text_update_toast_option">Показувати повідомлення \"текст актуальний\"</string>
<string name="screen_orientation_option">Орієнтація екрана</string> <string name="screen_orientation_option">Орієнтація екрана</string>
<string name="custom_screen_brightness_option">Користувацька яскравість</string>
<string name="screen_brightness_option">Яскравість</string>
<!-- Browse --> <!-- Browse -->
<string name="browse_files_structure_option">Структура файлів</string> <string name="browse_files_structure_option">Структура файлів</string>

View file

@ -263,6 +263,8 @@
<string name="check_for_text_update_option_desc">Automatically check whether there is text update</string> <string name="check_for_text_update_option_desc">Automatically check whether there is text update</string>
<string name="check_for_text_update_toast_option">Show \"text is up-to-date\" toast</string> <string name="check_for_text_update_toast_option">Show \"text is up-to-date\" toast</string>
<string name="screen_orientation_option">Screen orientation</string> <string name="screen_orientation_option">Screen orientation</string>
<string name="custom_screen_brightness_option">Custom brightness</string>
<string name="screen_brightness_option">Brightness</string>
<!-- Browse --> <!-- Browse -->
<string name="browse_files_structure_option">Files structure</string> <string name="browse_files_structure_option">Files structure</string>