Skip to content

Commit c675efa

Browse files
committed
feat: Add ability to open library screen at startup
Signed-off-by: starry-shivam <[email protected]>
1 parent 7b96ef5 commit c675efa

File tree

14 files changed

+316
-177
lines changed

14 files changed

+316
-177
lines changed

app/src/main/java/com/starry/myne/MainViewModel.kt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import androidx.lifecycle.ViewModel
2929
import androidx.lifecycle.viewModelScope
3030
import com.starry.myne.database.library.LibraryDao
3131
import com.starry.myne.database.progress.ProgressDao
32+
import com.starry.myne.helpers.PreferenceUtil
3233
import com.starry.myne.ui.navigation.BottomBarScreen
3334
import com.starry.myne.ui.navigation.Screens
3435
import com.starry.myne.ui.screens.welcome.viewmodels.WelcomeDataStore
@@ -43,7 +44,8 @@ import javax.inject.Inject
4344
class MainViewModel @Inject constructor(
4445
private val welcomeDataStore: WelcomeDataStore,
4546
private val libraryDao: LibraryDao,
46-
private val progressDao: ProgressDao
47+
private val progressDao: ProgressDao,
48+
private val preferenceUtil: PreferenceUtil
4749
) :
4850
ViewModel() {
4951
private val _isLoading: MutableState<Boolean> = mutableStateOf(true)
@@ -69,7 +71,13 @@ class MainViewModel @Inject constructor(
6971
// Check if user has completed onboarding.
7072
welcomeDataStore.readOnBoardingState().collect { completed ->
7173
if (completed) {
72-
_startDestination.value = BottomBarScreen.Home.route
74+
val openLibrary =
75+
preferenceUtil.getBoolean(PreferenceUtil.OPEN_LIBRARY_AT_START_BOOL, false)
76+
if (openLibrary) {
77+
_startDestination.value = BottomBarScreen.Library.route
78+
} else {
79+
_startDestination.value = BottomBarScreen.Home.route
80+
}
7381
} else {
7482
_startDestination.value = Screens.WelcomeScreen.route
7583
}

app/src/main/java/com/starry/myne/helpers/Preferencesutils.kt

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,21 @@ class PreferenceUtil(context: Context) {
3030
companion object {
3131
private const val PREFS_NAME = "myne_settings"
3232

33-
// Preference keys
33+
// General settings preference keys
34+
const val INTERNAL_READER_BOOL = "internal_reader"
35+
const val USE_GOOGLE_API_BOOL = "use_google_books_api"
36+
const val OPEN_LIBRARY_AT_START_BOOL = "launch_library_at_start"
37+
38+
// App theme preference keys
3439
const val APP_THEME_INT = "theme_settings"
3540
const val AMOLED_THEME_BOOL = "amoled_theme"
3641
const val MATERIAL_YOU_BOOL = "material_you"
37-
const val INTERNAL_READER_BOOL = "internal_reader"
38-
const val USE_GOOGLE_API_BOOL = "use_google_books_api"
42+
43+
// Reader preference keys
3944
const val READER_FONT_SIZE_INT = "reader_font_size"
4045
const val READER_FONT_STYLE_STR = "reader_font_style"
46+
47+
// Home screen preference keys
4148
const val PREFERRED_BOOK_LANG_STR = "preferred_book_language"
4249

4350
// Temporary preference keys
@@ -54,6 +61,7 @@ class PreferenceUtil(context: Context) {
5461
prefs.edit {
5562
if (!keyExists(INTERNAL_READER_BOOL)) putBoolean(INTERNAL_READER_BOOL, true)
5663
if (!keyExists(USE_GOOGLE_API_BOOL)) putBoolean(USE_GOOGLE_API_BOOL, true)
64+
if (!keyExists(OPEN_LIBRARY_AT_START_BOOL)) putBoolean(OPEN_LIBRARY_AT_START_BOOL, false)
5765
}
5866
}
5967

app/src/main/java/com/starry/myne/ui/screens/settings/composables/SettingsItems.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ import androidx.compose.material3.SwitchDefaults
4444
import androidx.compose.material3.Text
4545
import androidx.compose.material3.surfaceColorAtElevation
4646
import androidx.compose.runtime.Composable
47-
import androidx.compose.runtime.MutableState
47+
import androidx.compose.runtime.State
4848
import androidx.compose.runtime.mutableStateOf
4949
import androidx.compose.runtime.remember
5050
import androidx.compose.ui.Alignment
@@ -141,7 +141,7 @@ fun SettingItemWIthSwitch(
141141
icon: ImageVector,
142142
mainText: String,
143143
subText: String,
144-
switchState: MutableState<Boolean>,
144+
switchState: State<Boolean>,
145145
onCheckChange: (Boolean) -> Unit
146146
) {
147147
val view = LocalView.current

app/src/main/java/com/starry/myne/ui/screens/settings/composables/SettingsScreen.kt

Lines changed: 40 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ import androidx.compose.material3.SnackbarHostState
6060
import androidx.compose.material3.Text
6161
import androidx.compose.material3.TextButton
6262
import androidx.compose.runtime.Composable
63+
import androidx.compose.runtime.livedata.observeAsState
6364
import androidx.compose.runtime.mutableStateOf
6465
import androidx.compose.runtime.remember
6566
import androidx.compose.runtime.rememberCoroutineScope
@@ -207,8 +208,11 @@ private fun GeneralOptionsUI(
207208
val context = LocalContext.current
208209
val coroutineScope = rememberCoroutineScope()
209210

210-
val googleBooksApiSwitchState = remember { mutableStateOf(viewModel.getUseGoogleApiValue()) }
211-
val internalReaderValue = when (viewModel.getInternalReaderValue()) {
211+
val googleBooksApiSwitchState = viewModel.useGoogleApi.observeAsState(initial = true)
212+
val internalReaderState = viewModel.internalReader.observeAsState(initial = true)
213+
val openLibraryAtStartState = viewModel.openLibraryAtStart.observeAsState(initial = false)
214+
215+
val internalReaderValue = when (internalReaderState.value) {
212216
true -> stringResource(id = R.string.reader_option_inbuilt)
213217
false -> stringResource(id = R.string.reader_option_external)
214218
}
@@ -268,7 +272,16 @@ private fun GeneralOptionsUI(
268272
switchState = googleBooksApiSwitchState,
269273
onCheckChange = {
270274
viewModel.setUseGoogleApiValue(it)
271-
googleBooksApiSwitchState.value = it
275+
}
276+
)
277+
278+
SettingItemWIthSwitch(
279+
icon = ImageVector.vectorResource(id = R.drawable.ic_settings_library_start),
280+
mainText = stringResource(id = R.string.open_library_at_start_setting),
281+
subText = stringResource(id = R.string.open_library_at_start_setting_desc),
282+
switchState = openLibraryAtStartState,
283+
onCheckChange = {
284+
viewModel.setOpenLibraryAtStartValue(it)
272285
}
273286
)
274287
}
@@ -358,31 +371,33 @@ private fun DisplayOptionsUI(
358371
val coroutineScope = rememberCoroutineScope()
359372

360373
// Display settings for the theme
361-
val displayValue =
362-
when (viewModel.getThemeValue()) {
363-
ThemeMode.Light.ordinal -> stringResource(id = R.string.theme_option_light)
364-
ThemeMode.Dark.ordinal -> stringResource(id = R.string.theme_option_dark)
365-
else -> stringResource(id = R.string.theme_option_system)
366-
}
367-
val displayDialog = remember { mutableStateOf(false) }
368-
val radioOptions = listOf(
374+
val appThemeState = viewModel.theme.observeAsState(initial = ThemeMode.Auto)
375+
val selectedAppTheme = when (appThemeState.value) {
376+
ThemeMode.Light -> stringResource(id = R.string.theme_option_light)
377+
ThemeMode.Dark -> stringResource(id = R.string.theme_option_dark)
378+
else -> stringResource(id = R.string.theme_option_system)
379+
}
380+
val appThemeDialog = remember { mutableStateOf(false) }
381+
val appThemeRadioOpts = listOf(
369382
stringResource(id = R.string.theme_option_light),
370383
stringResource(id = R.string.theme_option_dark),
371384
stringResource(id = R.string.theme_option_system)
372385
)
373-
val (selectedOption, onOptionSelected) = remember { mutableStateOf(displayValue) }
386+
val (selectedOption, onOptionSelected) = remember { mutableStateOf(selectedAppTheme) }
374387

375388
// Display settings for the amoled theme
376-
val amoledSwitch = remember { mutableStateOf(viewModel.getAmoledThemeValue()) }
377-
val amoledDesc = if (amoledSwitch.value) {
389+
val amoledState = viewModel.amoledTheme.observeAsState(initial = false)
390+
val amoledDesc = if (amoledState.value) {
378391
stringResource(id = R.string.amoled_theme_setting_enabled_desc)
379392
} else {
380393
stringResource(id = R.string.amoled_theme_setting_disabled_desc)
381394
}
382395

383396
// Display settings for the Material You theme
384-
val materialYouSwitch = remember { mutableStateOf(viewModel.getMaterialYouValue()) }
385-
val materialYouDesc = if (materialYouSwitch.value) {
397+
val materialYouState = viewModel.materialYou.observeAsState(
398+
initial = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
399+
)
400+
val materialYouDesc = if (materialYouState.value) {
386401
stringResource(id = R.string.material_you_setting_enabled_desc)
387402
} else {
388403
stringResource(id = R.string.material_you_setting_disabled_desc)
@@ -404,39 +419,36 @@ private fun DisplayOptionsUI(
404419
SettingItem(
405420
icon = Icons.Filled.BrightnessMedium,
406421
mainText = stringResource(id = R.string.theme_setting),
407-
subText = displayValue,
408-
onClick = { displayDialog.value = true }
422+
subText = selectedAppTheme,
423+
onClick = { appThemeDialog.value = true }
409424
)
410425
SettingItemWIthSwitch(
411426
icon = Icons.Filled.Contrast,
412427
mainText = stringResource(id = R.string.amoled_theme_setting),
413428
subText = amoledDesc,
414-
switchState = amoledSwitch,
429+
switchState = amoledState,
415430
onCheckChange = {
416431
viewModel.setAmoledTheme(it)
417-
amoledSwitch.value = it
418432
})
419433
SettingItemWIthSwitch(
420434
icon = Icons.Filled.Palette,
421435
mainText = stringResource(id = R.string.material_you_setting),
422436
subText = materialYouDesc,
423-
switchState = materialYouSwitch,
437+
switchState = materialYouState,
424438
onCheckChange = { materialYouValue ->
425439
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
426440
viewModel.setMaterialYou(materialYouValue)
427-
materialYouSwitch.value = materialYouValue
428441
} else {
429442
viewModel.setMaterialYou(false)
430-
materialYouSwitch.value = false
431443
coroutineScope.launch { snackBarHostState.showSnackbar(context.getString(R.string.material_you_error)) }
432444
}
433445
}
434446
)
435447
}
436448

437-
if (displayDialog.value) {
449+
if (appThemeDialog.value) {
438450
AlertDialog(onDismissRequest = {
439-
displayDialog.value = false
451+
appThemeDialog.value = false
440452
}, title = {
441453
Text(
442454
text = stringResource(id = R.string.theme_dialog_title),
@@ -447,7 +459,7 @@ private fun DisplayOptionsUI(
447459
modifier = Modifier.selectableGroup(),
448460
verticalArrangement = Arrangement.Center,
449461
) {
450-
radioOptions.forEach { text ->
462+
appThemeRadioOpts.forEach { text ->
451463
Row(
452464
modifier = Modifier
453465
.fillMaxWidth()
@@ -481,7 +493,7 @@ private fun DisplayOptionsUI(
481493
}, confirmButton = {
482494
FilledTonalButton(
483495
onClick = {
484-
displayDialog.value = false
496+
appThemeDialog.value = false
485497

486498
when (selectedOption) {
487499
context.getString(R.string.theme_option_light) -> {
@@ -505,7 +517,7 @@ private fun DisplayOptionsUI(
505517
}
506518
}, dismissButton = {
507519
TextButton(onClick = {
508-
displayDialog.value = false
520+
appThemeDialog.value = false
509521
}) {
510522
Text(stringResource(id = R.string.cancel))
511523
}

app/src/main/java/com/starry/myne/ui/screens/settings/viewmodels/SettingsViewModel.kt

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,28 @@ class SettingsViewModel @Inject constructor(
3838
private val _theme = MutableLiveData(ThemeMode.Auto)
3939
private val _amoledTheme = MutableLiveData(false)
4040
private val _materialYou = MutableLiveData(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
41+
private val _internalReader = MutableLiveData(true)
42+
private val _useGoogleApi = MutableLiveData(true)
43+
private val _openLibraryAtStart = MutableLiveData(false)
4144

4245
val theme: LiveData<ThemeMode> = _theme
4346
val amoledTheme: LiveData<Boolean> = _amoledTheme
4447
val materialYou: LiveData<Boolean> = _materialYou
48+
val internalReader: LiveData<Boolean> = _internalReader
49+
val useGoogleApi: LiveData<Boolean> = _useGoogleApi
50+
val openLibraryAtStart: LiveData<Boolean> = _openLibraryAtStart
4551

4652
init {
4753
_theme.value = ThemeMode.entries.toTypedArray()[getThemeValue()]
4854
_amoledTheme.value = getAmoledThemeValue()
4955
_materialYou.value = getMaterialYouValue()
56+
_internalReader.value = getInternalReaderValue()
57+
_useGoogleApi.value = getUseGoogleApiValue()
58+
_openLibraryAtStart.value = getOpenLibraryAtStartValue()
5059
}
5160

52-
// Getters ================================================================================
61+
// Getters =============================================================================
62+
5363
fun setTheme(newTheme: ThemeMode) {
5464
_theme.postValue(newTheme)
5565
preferenceUtil.putInt(PreferenceUtil.APP_THEME_INT, newTheme.ordinal)
@@ -66,35 +76,46 @@ class SettingsViewModel @Inject constructor(
6676
}
6777

6878
fun setInternalReaderValue(newValue: Boolean) {
79+
_internalReader.postValue(newValue)
6980
preferenceUtil.putBoolean(PreferenceUtil.INTERNAL_READER_BOOL, newValue)
7081
}
7182

7283
fun setUseGoogleApiValue(newValue: Boolean) {
84+
_useGoogleApi.postValue(newValue)
7385
preferenceUtil.putBoolean(PreferenceUtil.USE_GOOGLE_API_BOOL, newValue)
7486
}
7587

76-
// Getters ================================================================================
88+
fun setOpenLibraryAtStartValue(newValue: Boolean) {
89+
_openLibraryAtStart.postValue(newValue)
90+
preferenceUtil.putBoolean(PreferenceUtil.OPEN_LIBRARY_AT_START_BOOL, newValue)
91+
}
7792

78-
fun getThemeValue() = preferenceUtil.getInt(
93+
// Getters ============================================================================
94+
// Used only during initialization except getCurrentTheme()
95+
private fun getThemeValue() = preferenceUtil.getInt(
7996
PreferenceUtil.APP_THEME_INT, ThemeMode.Auto.ordinal
8097
)
8198

82-
fun getAmoledThemeValue() = preferenceUtil.getBoolean(
99+
private fun getAmoledThemeValue() = preferenceUtil.getBoolean(
83100
PreferenceUtil.AMOLED_THEME_BOOL, false
84101
)
85102

86-
fun getMaterialYouValue() = preferenceUtil.getBoolean(
103+
private fun getMaterialYouValue() = preferenceUtil.getBoolean(
87104
PreferenceUtil.MATERIAL_YOU_BOOL, Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
88105
)
89106

90-
fun getInternalReaderValue() = preferenceUtil.getBoolean(
107+
private fun getInternalReaderValue() = preferenceUtil.getBoolean(
91108
PreferenceUtil.INTERNAL_READER_BOOL, true
92109
)
93110

94-
fun getUseGoogleApiValue() = preferenceUtil.getBoolean(
111+
private fun getUseGoogleApiValue() = preferenceUtil.getBoolean(
95112
PreferenceUtil.USE_GOOGLE_API_BOOL, true
96113
)
97114

115+
private fun getOpenLibraryAtStartValue() = preferenceUtil.getBoolean(
116+
PreferenceUtil.OPEN_LIBRARY_AT_START_BOOL, false
117+
)
118+
98119
@Composable
99120
fun getCurrentTheme(): ThemeMode {
100121
return if (theme.value == ThemeMode.Auto) {
Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
<?xml version="1.0" encoding="utf-8"?>
12
<vector xmlns:android="http://schemas.android.com/apk/res/android"
23
android:width="24dp"
34
android:height="24dp"
@@ -6,6 +7,7 @@
67

78
<path
89
android:fillColor="#000000"
9-
android:pathData="M19.76,10.77L19.67,10.42H12.23V13.58H16.68C16.432,14.544 15.867,15.397 15.077,16.003C14.286,16.608 13.316,16.931 12.32,16.92C11.021,16.909 9.773,16.413 8.82,15.53C8.352,15.068 7.979,14.519 7.723,13.913C7.468,13.308 7.334,12.658 7.33,12C7.345,10.679 7.868,9.415 8.79,8.47C9.729,7.58 10.976,7.089 12.27,7.1C13.378,7.109 14.445,7.521 15.27,8.26L17.47,6C16.02,4.706 14.143,3.994 12.2,4C11.131,3.994 10.071,4.198 9.081,4.601C8.091,5.004 7.19,5.599 6.43,6.35C4.984,7.852 4.168,9.852 4.152,11.937C4.135,14.022 4.918,16.035 6.34,17.56C7.128,18.345 8.064,18.965 9.094,19.384C10.125,19.803 11.228,20.012 12.34,20C13.348,20.007 14.348,19.81 15.278,19.42C16.208,19.03 17.049,18.455 17.75,17.73C19.126,16.217 19.87,14.235 19.83,12.19C19.841,11.716 19.817,11.241 19.76,10.77Z" />
10-
11-
</vector>
10+
android:pathData="M12.5,10.2v3.8H18c-0.7,2.3-2.6,4-5.4,4c-3.3,0-6-2.7-6-6s2.7-6,6-6c1.5,0,2.9,0.5,3.9,1.5l2.8-2.8C17.5,3,15.1,2,12.5,2 C7,2,2.5,6.5,2.5,12s4.5,10,10,10c8.4,0,10.2-7.9,9.4-11.7L12.5,10.2z" />
11+
<path
12+
android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
13+
</vector>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:width="24dp"
4+
android:height="24dp"
5+
android:viewportWidth="24"
6+
android:viewportHeight="24">
7+
8+
<path android:pathData="M0 0h24v24H0z" />
9+
<path
10+
android:fillColor="#000000"
11+
android:pathData="M20 22H6.5A3.5 3.5 0 0 1 3 18.5V5a3 3 0 0 1 3-3h14a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1zm-1-2v-3H6.5a1.5 1.5 0 0 0 0 3H19zM10 4v8l3.5-2 3.5 2V4h-7z" />
12+
</vector>

app/src/main/res/drawable/ic_settings_reader.xml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
android:viewportWidth="24"
66
android:viewportHeight="24">
77

8-
<path android:pathData="M0 0h24v24H0z" />
98
<path
10-
android:fillColor="#000000"
11-
android:pathData="M20 22H6.5A3.5 3.5 0 0 1 3 18.5V5a3 3 0 0 1 3-3h14a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1zm-1-2v-3H6.5a1.5 1.5 0 0 0 0 3H19zM10 4v8l3.5-2 3.5 2V4h-7z" />
9+
android:fillColor="#292D32"
10+
android:pathData="M22 4.84969V16.7397C22 17.7097 21.21 18.5997 20.24 18.7197L19.93 18.7597C18.29 18.9797 15.98 19.6597 14.12 20.4397C13.47 20.7097 12.75 20.2197 12.75 19.5097V5.59969C12.75 5.22969 12.96 4.88969 13.29 4.70969C15.12 3.71969 17.89 2.83969 19.77 2.67969H19.83C21.03 2.67969 22 3.64969 22 4.84969Z" />
11+
<path
12+
android:fillColor="#292D32"
13+
android:pathData="M10.7083 4.70969C8.87828 3.71969 6.10828 2.83969 4.22828 2.67969H4.15828C2.95828 2.67969 1.98828 3.64969 1.98828 4.84969V16.7397C1.98828 17.7097 2.77828 18.5997 3.74828 18.7197L4.05828 18.7597C5.69828 18.9797 8.00828 19.6597 9.86828 20.4397C10.5183 20.7097 11.2383 20.2197 11.2383 19.5097V5.59969C11.2383 5.21969 11.0383 4.88969 10.7083 4.70969ZM4.99828 7.73969H7.24828C7.65828 7.73969 7.99828 8.07969 7.99828 8.48969C7.99828 8.90969 7.65828 9.23969 7.24828 9.23969H4.99828C4.58828 9.23969 4.24828 8.90969 4.24828 8.48969C4.24828 8.07969 4.58828 7.73969 4.99828 7.73969ZM7.99828 12.2397H4.99828C4.58828 12.2397 4.24828 11.9097 4.24828 11.4897C4.24828 11.0797 4.58828 10.7397 4.99828 10.7397H7.99828C8.40828 10.7397 8.74828 11.0797 8.74828 11.4897C8.74828 11.9097 8.40828 12.2397 7.99828 12.2397Z" />
1214
</vector>

app/src/main/res/values/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@
107107
<string name="locale_setting_not_found">Sorry! this feature is not yet supported by your OS.</string>
108108
<string name="google_books_api_setting">Google Books API</string>
109109
<string name="google_books_api_setting_desc">Use Google Books API to fetch additional book information.</string>
110+
<string name="open_library_at_start_setting">Open Library at Start</string>
111+
<string name="open_library_at_start_setting_desc">Launch Library screen when app starts.</string>
110112
<string name="display_setting_header">Display</string>
111113
<string name="theme_setting">Default Theme</string>
112114
<string name="theme_dialog_title">Change Theme</string>

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
buildscript {
22
ext {
33
kotlin_version = '2.2.21'
4-
gradle_version = '8.13.1'
4+
gradle_version = '8.13.2'
55
hilt_version = '2.57.1'
66
room_version = '2.7.1'
77
}

0 commit comments

Comments
 (0)