Add option to hide fab (close #1466)
This commit is contained in:
@@ -15,12 +15,17 @@ import androidx.core.os.LocaleListCompat
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import androidx.preference.PreferenceManager
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.ZoomMode
|
||||
import org.koitharu.kotatsu.core.network.DoHProvider
|
||||
import org.koitharu.kotatsu.core.util.ext.connectivityManager
|
||||
import org.koitharu.kotatsu.core.util.ext.getEnumValue
|
||||
import org.koitharu.kotatsu.core.util.ext.observe
|
||||
import org.koitharu.kotatsu.core.util.ext.observeChanges
|
||||
import org.koitharu.kotatsu.core.util.ext.putAll
|
||||
import org.koitharu.kotatsu.core.util.ext.putEnumValue
|
||||
import org.koitharu.kotatsu.core.util.ext.takeIfReadable
|
||||
@@ -82,6 +87,9 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
|
||||
val isNavBarPinned: Boolean
|
||||
get() = prefs.getBoolean(KEY_NAV_PINNED, false)
|
||||
|
||||
val isMainFabEnabled: Boolean
|
||||
get() = prefs.getBoolean(KEY_MAIN_FAB, true)
|
||||
|
||||
var gridSize: Int
|
||||
get() = prefs.getInt(KEY_GRID_SIZE, 100)
|
||||
set(value) = prefs.edit { putInt(KEY_GRID_SIZE, value) }
|
||||
@@ -598,7 +606,12 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
|
||||
prefs.unregisterOnSharedPreferenceChangeListener(listener)
|
||||
}
|
||||
|
||||
fun observe() = prefs.observe()
|
||||
fun observeChanges() = prefs.observeChanges()
|
||||
|
||||
fun observe(vararg keys: String): Flow<String?> = prefs.observeChanges()
|
||||
.filter { key -> key == null || key in keys }
|
||||
.onStart { emit(null) }
|
||||
.flowOn(Dispatchers.IO)
|
||||
|
||||
fun getAllValues(): Map<String, *> = prefs.all
|
||||
|
||||
@@ -743,6 +756,7 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
|
||||
const val KEY_NAV_MAIN = "nav_main"
|
||||
const val KEY_NAV_LABELS = "nav_labels"
|
||||
const val KEY_NAV_PINNED = "nav_pinned"
|
||||
const val KEY_MAIN_FAB = "main_fab"
|
||||
const val KEY_32BIT_COLOR = "enhanced_colors"
|
||||
const val KEY_SOURCES_ORDER = "sources_sort_order"
|
||||
const val KEY_SOURCES_CATALOG = "sources_catalog"
|
||||
|
||||
@@ -10,7 +10,7 @@ import kotlinx.coroutines.flow.transform
|
||||
fun <T> AppSettings.observeAsFlow(key: String, valueProducer: AppSettings.() -> T) = flow {
|
||||
var lastValue: T = valueProducer()
|
||||
emit(lastValue)
|
||||
observe().collect {
|
||||
observeChanges().collect {
|
||||
if (it == key) {
|
||||
val value = valueProducer()
|
||||
if (value != lastValue) {
|
||||
@@ -25,7 +25,7 @@ fun <T> AppSettings.observeAsStateFlow(
|
||||
scope: CoroutineScope,
|
||||
key: String,
|
||||
valueProducer: AppSettings.() -> T,
|
||||
): StateFlow<T> = observe().transform {
|
||||
): StateFlow<T> = observeChanges().transform {
|
||||
if (it == key) {
|
||||
emit(valueProducer())
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ fun <E : Enum<E>> SharedPreferences.Editor.putEnumValue(key: String, value: E?)
|
||||
putString(key, value?.name)
|
||||
}
|
||||
|
||||
fun SharedPreferences.observe(): Flow<String?> = callbackFlow {
|
||||
fun SharedPreferences.observeChanges(): Flow<String?> = callbackFlow {
|
||||
val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
|
||||
trySendBlocking(key)
|
||||
}
|
||||
@@ -49,7 +49,7 @@ fun SharedPreferences.observe(): Flow<String?> = callbackFlow {
|
||||
|
||||
fun <T> SharedPreferences.observe(key: String, valueProducer: suspend () -> T): Flow<T> = flow {
|
||||
emit(valueProducer())
|
||||
observe().collect { upstreamKey ->
|
||||
observeChanges().collect { upstreamKey ->
|
||||
if (upstreamKey == key) {
|
||||
emit(valueProducer())
|
||||
}
|
||||
|
||||
@@ -4,9 +4,7 @@ import androidx.room.withTransaction
|
||||
import dagger.Reusable
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
import org.koitharu.kotatsu.core.db.MangaDatabase
|
||||
import org.koitharu.kotatsu.core.db.entity.toEntity
|
||||
import org.koitharu.kotatsu.core.db.entity.toManga
|
||||
@@ -204,9 +202,7 @@ class HistoryRepository @Inject constructor(
|
||||
fun shouldSkip(manga: Manga): Boolean = settings.isIncognitoModeEnabled(manga.isNsfw())
|
||||
|
||||
fun observeShouldSkip(manga: Manga): Flow<Boolean> {
|
||||
return settings.observe()
|
||||
.filter { key -> key == AppSettings.KEY_INCOGNITO_MODE || key == AppSettings.KEY_INCOGNITO_NSFW }
|
||||
.onStart { emit("") }
|
||||
return settings.observe(AppSettings.KEY_INCOGNITO_MODE, AppSettings.KEY_INCOGNITO_NSFW)
|
||||
.map { shouldSkip(manga) }
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ abstract class MangaListViewModel(
|
||||
protected fun observeListModeWithTriggers(): Flow<ListMode> = combine(
|
||||
listMode,
|
||||
mangaDataRepository.observeOverridesTrigger(emitInitialState = true),
|
||||
settings.observe().filter { key ->
|
||||
settings.observeChanges().filter { key ->
|
||||
key == AppSettings.KEY_PROGRESS_INDICATORS
|
||||
|| key == AppSettings.KEY_TRACKER_ENABLED
|
||||
|| key == AppSettings.KEY_QUICK_FILTER
|
||||
|
||||
@@ -2,12 +2,13 @@ package org.koitharu.kotatsu.main.domain
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
import org.koitharu.kotatsu.core.model.isLocal
|
||||
import org.koitharu.kotatsu.core.os.NetworkState
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.core.prefs.observeAsFlow
|
||||
import org.koitharu.kotatsu.history.data.HistoryRepository
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -17,15 +18,21 @@ class ReadingResumeEnabledUseCase @Inject constructor(
|
||||
private val settings: AppSettings,
|
||||
) {
|
||||
|
||||
operator fun invoke(): Flow<Boolean> = settings.observeAsFlow(AppSettings.KEY_INCOGNITO_MODE) {
|
||||
isIncognitoModeEnabled
|
||||
}.flatMapLatest { incognito ->
|
||||
if (incognito) {
|
||||
flowOf(false)
|
||||
} else {
|
||||
combine(networkState, historyRepository.observeLast()) { isOnline, last ->
|
||||
last != null && (isOnline || last.isLocal)
|
||||
operator fun invoke(): Flow<Boolean> = settings.observe(
|
||||
AppSettings.KEY_MAIN_FAB,
|
||||
AppSettings.KEY_INCOGNITO_MODE,
|
||||
).map {
|
||||
settings.isMainFabEnabled && !settings.isIncognitoModeEnabled
|
||||
}.distinctUntilChanged()
|
||||
.flatMapLatest { isFabEnabled ->
|
||||
if (isFabEnabled) {
|
||||
observeCanResume()
|
||||
} else {
|
||||
flowOf(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeCanResume() = combine(networkState, historyRepository.observeLast()) { isOnline, last ->
|
||||
last != null && (isOnline || last.isLocal)
|
||||
}.distinctUntilChanged()
|
||||
}
|
||||
|
||||
@@ -320,6 +320,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>(), AppBarOwner, BottomNav
|
||||
topFragment: Fragment? = navigationDelegate.primaryFragment,
|
||||
isSearchOpened: Boolean = viewBinding.searchView.isShowing,
|
||||
) {
|
||||
navigationDelegate.navRailHeader?.railFab?.isVisible = isResumeEnabled
|
||||
val fab = viewBinding.fab ?: return
|
||||
if (isResumeEnabled && !actionModeDelegate.isActionModeStarted && !isSearchOpened && topFragment is HistoryListFragment) {
|
||||
if (!fab.isVisible) {
|
||||
|
||||
@@ -16,16 +16,12 @@ import androidx.lifecycle.lifecycleScope
|
||||
import com.google.android.material.navigation.NavigationBarView
|
||||
import com.google.android.material.navigationrail.NavigationRailView
|
||||
import com.google.android.material.transition.MaterialFadeThrough
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.channels.trySendBlocking
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.bookmarks.ui.AllBookmarksFragment
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
@@ -56,7 +52,7 @@ class MainNavigationDelegate(
|
||||
NavigationBarView.OnItemReselectedListener, View.OnClickListener {
|
||||
|
||||
private val listeners = LinkedList<OnFragmentChangedListener>()
|
||||
private val navRailHeader = (navBar as? NavigationRailView)?.headerView?.let {
|
||||
val navRailHeader = (navBar as? NavigationRailView)?.headerView?.let {
|
||||
NavigationRailFabBinding.bind(it)
|
||||
}
|
||||
|
||||
@@ -267,12 +263,7 @@ class MainNavigationDelegate(
|
||||
}
|
||||
|
||||
private fun observeSettings(lifecycleOwner: LifecycleOwner) {
|
||||
settings.observe()
|
||||
.filter { x ->
|
||||
x == AppSettings.KEY_TRACKER_ENABLED || x == AppSettings.KEY_SUGGESTIONS || x == AppSettings.KEY_NAV_LABELS
|
||||
}
|
||||
.onStart { emit("") }
|
||||
.flowOn(Dispatchers.IO)
|
||||
settings.observe(AppSettings.KEY_TRACKER_ENABLED, AppSettings.KEY_SUGGESTIONS, AppSettings.KEY_NAV_LABELS)
|
||||
.onEach {
|
||||
setItemVisibility(R.id.nav_suggestions, settings.isSuggestionsEnabled)
|
||||
setItemVisibility(R.id.nav_feed, settings.isTrackerEnabled)
|
||||
|
||||
@@ -8,7 +8,7 @@ import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import org.koitharu.kotatsu.core.util.ext.getEnumValue
|
||||
import org.koitharu.kotatsu.core.util.ext.observe
|
||||
import org.koitharu.kotatsu.core.util.ext.observeChanges
|
||||
import org.koitharu.kotatsu.core.util.ext.putAll
|
||||
import org.koitharu.kotatsu.core.util.ext.putEnumValue
|
||||
import org.koitharu.kotatsu.reader.domain.TapGridArea
|
||||
@@ -44,7 +44,7 @@ class TapGridSettings @Inject constructor(@ApplicationContext context: Context)
|
||||
initPrefs(withDefaultValues = false)
|
||||
}
|
||||
|
||||
fun observe() = prefs.observe().flowOn(Dispatchers.IO)
|
||||
fun observeChanges() = prefs.observeChanges().flowOn(Dispatchers.IO)
|
||||
|
||||
fun getAllValues(): Map<String, *> = prefs.all
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ data class ReaderSettings(
|
||||
private suspend fun observeImpl() {
|
||||
combine(
|
||||
mangaId.flatMapLatest { mangaDataRepository.observeColorFilter(it) },
|
||||
settings.observe().filter { x -> x == null || x in settingsKeys }.onStart { emit(null) },
|
||||
settings.observeChanges().filter { x -> x == null || x in settingsKeys }.onStart { emit(null) },
|
||||
) { mangaCf, settingsKey ->
|
||||
ReaderSettings(settings, mangaCf)
|
||||
}.collect {
|
||||
|
||||
@@ -20,7 +20,7 @@ class ReaderTapGridConfigViewModel @Inject constructor(
|
||||
private val tapGridSettings: TapGridSettings,
|
||||
) : BaseViewModel() {
|
||||
|
||||
val content = tapGridSettings.observe()
|
||||
val content = tapGridSettings.observeChanges()
|
||||
.onStart { emit(null) }
|
||||
.map { getData() }
|
||||
.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, emptyMap())
|
||||
|
||||
@@ -45,7 +45,7 @@ class SourcesListProducer @Inject constructor(
|
||||
}
|
||||
|
||||
init {
|
||||
settings.observe()
|
||||
settings.observeChanges()
|
||||
.filter { it == AppSettings.KEY_TIPS_CLOSED || it == AppSettings.KEY_DISABLE_NSFW }
|
||||
.flowOn(Dispatchers.Default)
|
||||
.onEach { onInvalidated(emptySet()) }
|
||||
|
||||
@@ -856,4 +856,7 @@
|
||||
<string name="book_effect">Yellowish background (blue filter)</string>
|
||||
<string name="local_storage_cleanup">Local storage cleanup</string>
|
||||
<string name="packup_creation_failed">Failed to create backup</string>
|
||||
<string name="main_screen">Main screen</string>
|
||||
<string name="main_screen_fab">Show floating Continue button</string>
|
||||
<string name="main_screen_fab_summary">Allows to continue reading in a one click. This button will not appear in incognito mode or when the history is empty</string>
|
||||
</resources>
|
||||
|
||||
@@ -23,6 +23,10 @@
|
||||
android:summary="@string/black_dark_theme_summary"
|
||||
android:title="@string/black_dark_theme" />
|
||||
|
||||
<org.koitharu.kotatsu.settings.utils.ActivityListPreference
|
||||
android:key="app_locale"
|
||||
android:title="@string/language" />
|
||||
|
||||
<PreferenceCategory android:title="@string/manga_list">
|
||||
|
||||
<ListPreference
|
||||
@@ -84,31 +88,36 @@
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceScreen
|
||||
android:fragment="org.koitharu.kotatsu.settings.nav.NavConfigFragment"
|
||||
android:key="nav_main"
|
||||
android:title="@string/main_screen_sections"
|
||||
app:allowDividerAbove="true" />
|
||||
<PreferenceCategory android:title="@string/main_screen">
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="nav_labels"
|
||||
android:title="@string/show_labels_in_navbar" />
|
||||
<PreferenceScreen
|
||||
android:fragment="org.koitharu.kotatsu.settings.nav.NavConfigFragment"
|
||||
android:key="nav_main"
|
||||
android:title="@string/main_screen_sections" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="nav_pinned"
|
||||
android:summary="@string/pin_navigation_ui_summary"
|
||||
android:title="@string/pin_navigation_ui" />
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="main_fab"
|
||||
android:summary="@string/main_screen_fab_summary"
|
||||
android:title="@string/main_screen_fab" />
|
||||
|
||||
<org.koitharu.kotatsu.settings.utils.ActivityListPreference
|
||||
android:key="app_locale"
|
||||
android:title="@string/language" />
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="nav_labels"
|
||||
android:title="@string/show_labels_in_navbar" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="exit_confirm"
|
||||
android:summary="@string/exit_confirmation_summary"
|
||||
android:title="@string/exit_confirmation" />
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="nav_pinned"
|
||||
android:summary="@string/pin_navigation_ui_summary"
|
||||
android:title="@string/pin_navigation_ui" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="exit_confirm"
|
||||
android:summary="@string/exit_confirmation_summary"
|
||||
android:title="@string/exit_confirmation" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
Reference in New Issue
Block a user