mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-03 23:58:55 +01:00 
			
		
		
		
	Move app state banner to the very top (#8706)
This moves the banners to the root composable and so eliminates the need to track the app states in every screen.
This commit is contained in:
		@@ -182,6 +182,7 @@ dependencies {
 | 
			
		||||
    implementation(compose.accompanist.flowlayout)
 | 
			
		||||
    implementation(compose.accompanist.permissions)
 | 
			
		||||
    implementation(compose.accompanist.themeadapter)
 | 
			
		||||
    implementation(compose.accompanist.systemuicontroller)
 | 
			
		||||
 | 
			
		||||
    implementation(androidx.paging.runtime)
 | 
			
		||||
    implementation(androidx.paging.compose)
 | 
			
		||||
 
 | 
			
		||||
@@ -63,9 +63,6 @@ fun AppBar(
 | 
			
		||||
    actionModeCounter: Int = 0,
 | 
			
		||||
    onCancelActionMode: () -> Unit = {},
 | 
			
		||||
    actionModeActions: @Composable RowScope.() -> Unit = {},
 | 
			
		||||
    // Banners
 | 
			
		||||
    downloadedOnlyMode: Boolean = false,
 | 
			
		||||
    incognitoMode: Boolean = false,
 | 
			
		||||
 | 
			
		||||
    scrollBehavior: TopAppBarScrollBehavior? = null,
 | 
			
		||||
) {
 | 
			
		||||
@@ -93,8 +90,6 @@ fun AppBar(
 | 
			
		||||
        },
 | 
			
		||||
        isActionMode = isActionMode,
 | 
			
		||||
        onCancelActionMode = onCancelActionMode,
 | 
			
		||||
        downloadedOnlyMode = downloadedOnlyMode,
 | 
			
		||||
        incognitoMode = incognitoMode,
 | 
			
		||||
        scrollBehavior = scrollBehavior,
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
@@ -112,9 +107,6 @@ fun AppBar(
 | 
			
		||||
    // Action mode
 | 
			
		||||
    isActionMode: Boolean = false,
 | 
			
		||||
    onCancelActionMode: () -> Unit = {},
 | 
			
		||||
    // Banners
 | 
			
		||||
    downloadedOnlyMode: Boolean = false,
 | 
			
		||||
    incognitoMode: Boolean = false,
 | 
			
		||||
 | 
			
		||||
    scrollBehavior: TopAppBarScrollBehavior? = null,
 | 
			
		||||
) {
 | 
			
		||||
@@ -150,8 +142,6 @@ fun AppBar(
 | 
			
		||||
            ),
 | 
			
		||||
            scrollBehavior = scrollBehavior,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        AppStateBanners(downloadedOnlyMode, incognitoMode)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -236,8 +226,6 @@ fun SearchToolbar(
 | 
			
		||||
    onSearch: (String) -> Unit = {},
 | 
			
		||||
    onClickCloseSearch: () -> Unit = { onChangeSearchQuery(null) },
 | 
			
		||||
    actions: @Composable RowScope.() -> Unit = {},
 | 
			
		||||
    incognitoMode: Boolean = false,
 | 
			
		||||
    downloadedOnlyMode: Boolean = false,
 | 
			
		||||
    scrollBehavior: TopAppBarScrollBehavior? = null,
 | 
			
		||||
    visualTransformation: VisualTransformation = VisualTransformation.None,
 | 
			
		||||
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
 | 
			
		||||
@@ -326,8 +314,6 @@ fun SearchToolbar(
 | 
			
		||||
            key("actions") { actions() }
 | 
			
		||||
        },
 | 
			
		||||
        isActionMode = false,
 | 
			
		||||
        downloadedOnlyMode = downloadedOnlyMode,
 | 
			
		||||
        incognitoMode = incognitoMode,
 | 
			
		||||
        scrollBehavior = scrollBehavior,
 | 
			
		||||
    )
 | 
			
		||||
    LaunchedEffect(searchClickCount) {
 | 
			
		||||
 
 | 
			
		||||
@@ -3,8 +3,13 @@ package eu.kanade.presentation.components
 | 
			
		||||
import androidx.annotation.StringRes
 | 
			
		||||
import androidx.compose.foundation.background
 | 
			
		||||
import androidx.compose.foundation.layout.Column
 | 
			
		||||
import androidx.compose.foundation.layout.WindowInsets
 | 
			
		||||
import androidx.compose.foundation.layout.WindowInsetsSides
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxWidth
 | 
			
		||||
import androidx.compose.foundation.layout.only
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.foundation.layout.systemBars
 | 
			
		||||
import androidx.compose.foundation.layout.windowInsetsPadding
 | 
			
		||||
import androidx.compose.material3.MaterialTheme
 | 
			
		||||
import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
@@ -37,24 +42,34 @@ fun AppStateBanners(
 | 
			
		||||
    incognitoMode: Boolean,
 | 
			
		||||
    modifier: Modifier = Modifier,
 | 
			
		||||
) {
 | 
			
		||||
    val insets = WindowInsets.systemBars.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
 | 
			
		||||
    Column(modifier = modifier) {
 | 
			
		||||
        if (downloadedOnlyMode) {
 | 
			
		||||
            DownloadedOnlyModeBanner()
 | 
			
		||||
            DownloadedOnlyModeBanner(
 | 
			
		||||
                modifier = Modifier.windowInsetsPadding(insets),
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        if (incognitoMode) {
 | 
			
		||||
            IncognitoModeBanner()
 | 
			
		||||
            IncognitoModeBanner(
 | 
			
		||||
                modifier = if (!downloadedOnlyMode) {
 | 
			
		||||
                    Modifier.windowInsetsPadding(insets)
 | 
			
		||||
                } else {
 | 
			
		||||
                    Modifier
 | 
			
		||||
                },
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
private fun DownloadedOnlyModeBanner() {
 | 
			
		||||
private fun DownloadedOnlyModeBanner(modifier: Modifier = Modifier) {
 | 
			
		||||
    Text(
 | 
			
		||||
        text = stringResource(R.string.label_downloaded_only),
 | 
			
		||||
        modifier = Modifier
 | 
			
		||||
            .background(color = MaterialTheme.colorScheme.tertiary)
 | 
			
		||||
            .fillMaxWidth()
 | 
			
		||||
            .padding(4.dp),
 | 
			
		||||
            .padding(4.dp)
 | 
			
		||||
            .then(modifier),
 | 
			
		||||
        color = MaterialTheme.colorScheme.onTertiary,
 | 
			
		||||
        textAlign = TextAlign.Center,
 | 
			
		||||
        style = MaterialTheme.typography.labelMedium,
 | 
			
		||||
@@ -62,13 +77,14 @@ private fun DownloadedOnlyModeBanner() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
private fun IncognitoModeBanner() {
 | 
			
		||||
private fun IncognitoModeBanner(modifier: Modifier = Modifier) {
 | 
			
		||||
    Text(
 | 
			
		||||
        text = stringResource(R.string.pref_incognito_mode),
 | 
			
		||||
        modifier = Modifier
 | 
			
		||||
            .background(color = MaterialTheme.colorScheme.primary)
 | 
			
		||||
            .fillMaxWidth()
 | 
			
		||||
            .padding(4.dp),
 | 
			
		||||
            .padding(4.dp)
 | 
			
		||||
            .then(modifier),
 | 
			
		||||
        color = MaterialTheme.colorScheme.onPrimary,
 | 
			
		||||
        textAlign = TextAlign.Center,
 | 
			
		||||
        style = MaterialTheme.typography.labelMedium,
 | 
			
		||||
 
 | 
			
		||||
@@ -29,8 +29,6 @@ fun TabbedScreen(
 | 
			
		||||
    startIndex: Int? = null,
 | 
			
		||||
    searchQuery: String? = null,
 | 
			
		||||
    onChangeSearchQuery: (String?) -> Unit = {},
 | 
			
		||||
    incognitoMode: Boolean,
 | 
			
		||||
    downloadedOnlyMode: Boolean,
 | 
			
		||||
) {
 | 
			
		||||
    val scope = rememberCoroutineScope()
 | 
			
		||||
    val state = rememberPagerState()
 | 
			
		||||
@@ -78,8 +76,6 @@ fun TabbedScreen(
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            AppStateBanners(downloadedOnlyMode, incognitoMode)
 | 
			
		||||
 | 
			
		||||
            HorizontalPager(
 | 
			
		||||
                count = tabs.size,
 | 
			
		||||
                modifier = Modifier.fillMaxSize(),
 | 
			
		||||
 
 | 
			
		||||
@@ -26,8 +26,6 @@ import java.util.Date
 | 
			
		||||
fun HistoryScreen(
 | 
			
		||||
    state: HistoryState,
 | 
			
		||||
    snackbarHostState: SnackbarHostState,
 | 
			
		||||
    incognitoMode: Boolean,
 | 
			
		||||
    downloadedOnlyMode: Boolean,
 | 
			
		||||
    onSearchQueryChange: (String?) -> Unit,
 | 
			
		||||
    onClickCover: (mangaId: Long) -> Unit,
 | 
			
		||||
    onClickResume: (mangaId: Long, chapterId: Long) -> Unit,
 | 
			
		||||
@@ -47,8 +45,6 @@ fun HistoryScreen(
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                downloadedOnlyMode = downloadedOnlyMode,
 | 
			
		||||
                incognitoMode = incognitoMode,
 | 
			
		||||
                scrollBehavior = scrollBehavior,
 | 
			
		||||
            )
 | 
			
		||||
        },
 | 
			
		||||
 
 | 
			
		||||
@@ -45,8 +45,6 @@ fun LibraryContent(
 | 
			
		||||
    getDisplayModeForPage: @Composable (Int) -> LibraryDisplayMode,
 | 
			
		||||
    getColumnsForOrientation: (Boolean) -> PreferenceMutableState<Int>,
 | 
			
		||||
    getLibraryForPage: (Int) -> List<LibraryItem>,
 | 
			
		||||
    isDownloadOnly: Boolean,
 | 
			
		||||
    isIncognitoMode: Boolean,
 | 
			
		||||
) {
 | 
			
		||||
    Column(
 | 
			
		||||
        modifier = Modifier.padding(
 | 
			
		||||
@@ -65,8 +63,6 @@ fun LibraryContent(
 | 
			
		||||
            LibraryTabs(
 | 
			
		||||
                categories = categories,
 | 
			
		||||
                currentPageIndex = pagerState.currentPage,
 | 
			
		||||
                isDownloadOnly = isDownloadOnly,
 | 
			
		||||
                isIncognitoMode = isIncognitoMode,
 | 
			
		||||
                getNumberOfMangaForCategory = getNumberOfMangaForCategory,
 | 
			
		||||
            ) { scope.launch { pagerState.animateScrollToPage(it) } }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,6 @@ import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import eu.kanade.domain.category.model.Category
 | 
			
		||||
import eu.kanade.presentation.category.visualName
 | 
			
		||||
import eu.kanade.presentation.components.AppStateBanners
 | 
			
		||||
import eu.kanade.presentation.components.Divider
 | 
			
		||||
import eu.kanade.presentation.components.TabIndicator
 | 
			
		||||
import eu.kanade.presentation.components.TabText
 | 
			
		||||
@@ -17,8 +16,6 @@ import eu.kanade.presentation.components.TabText
 | 
			
		||||
fun LibraryTabs(
 | 
			
		||||
    categories: List<Category>,
 | 
			
		||||
    currentPageIndex: Int,
 | 
			
		||||
    isDownloadOnly: Boolean,
 | 
			
		||||
    isIncognitoMode: Boolean,
 | 
			
		||||
    getNumberOfMangaForCategory: (Category) -> Int?,
 | 
			
		||||
    onTabItemClick: (Int) -> Unit,
 | 
			
		||||
) {
 | 
			
		||||
@@ -47,7 +44,5 @@ fun LibraryTabs(
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Divider()
 | 
			
		||||
 | 
			
		||||
        AppStateBanners(isDownloadOnly, isIncognitoMode)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -32,8 +32,6 @@ fun LibraryToolbar(
 | 
			
		||||
    hasActiveFilters: Boolean,
 | 
			
		||||
    selectedCount: Int,
 | 
			
		||||
    title: LibraryToolbarTitle,
 | 
			
		||||
    incognitoMode: Boolean,
 | 
			
		||||
    downloadedOnlyMode: Boolean,
 | 
			
		||||
    onClickUnselectAll: () -> Unit,
 | 
			
		||||
    onClickSelectAll: () -> Unit,
 | 
			
		||||
    onClickInvertSelection: () -> Unit,
 | 
			
		||||
@@ -46,8 +44,6 @@ fun LibraryToolbar(
 | 
			
		||||
) = when {
 | 
			
		||||
    selectedCount > 0 -> LibrarySelectionToolbar(
 | 
			
		||||
        selectedCount = selectedCount,
 | 
			
		||||
        incognitoMode = incognitoMode,
 | 
			
		||||
        downloadedOnlyMode = downloadedOnlyMode,
 | 
			
		||||
        onClickUnselectAll = onClickUnselectAll,
 | 
			
		||||
        onClickSelectAll = onClickSelectAll,
 | 
			
		||||
        onClickInvertSelection = onClickInvertSelection,
 | 
			
		||||
@@ -55,8 +51,6 @@ fun LibraryToolbar(
 | 
			
		||||
    else -> LibraryRegularToolbar(
 | 
			
		||||
        title = title,
 | 
			
		||||
        hasFilters = hasActiveFilters,
 | 
			
		||||
        incognitoMode = incognitoMode,
 | 
			
		||||
        downloadedOnlyMode = downloadedOnlyMode,
 | 
			
		||||
        searchQuery = searchQuery,
 | 
			
		||||
        onSearchQueryChange = onSearchQueryChange,
 | 
			
		||||
        onClickFilter = onClickFilter,
 | 
			
		||||
@@ -70,8 +64,6 @@ fun LibraryToolbar(
 | 
			
		||||
fun LibraryRegularToolbar(
 | 
			
		||||
    title: LibraryToolbarTitle,
 | 
			
		||||
    hasFilters: Boolean,
 | 
			
		||||
    incognitoMode: Boolean,
 | 
			
		||||
    downloadedOnlyMode: Boolean,
 | 
			
		||||
    searchQuery: String?,
 | 
			
		||||
    onSearchQueryChange: (String?) -> Unit,
 | 
			
		||||
    onClickFilter: () -> Unit,
 | 
			
		||||
@@ -123,8 +115,6 @@ fun LibraryRegularToolbar(
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        incognitoMode = incognitoMode,
 | 
			
		||||
        downloadedOnlyMode = downloadedOnlyMode,
 | 
			
		||||
        scrollBehavior = scrollBehavior,
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
@@ -132,8 +122,6 @@ fun LibraryRegularToolbar(
 | 
			
		||||
@Composable
 | 
			
		||||
fun LibrarySelectionToolbar(
 | 
			
		||||
    selectedCount: Int,
 | 
			
		||||
    incognitoMode: Boolean,
 | 
			
		||||
    downloadedOnlyMode: Boolean,
 | 
			
		||||
    onClickUnselectAll: () -> Unit,
 | 
			
		||||
    onClickSelectAll: () -> Unit,
 | 
			
		||||
    onClickInvertSelection: () -> Unit,
 | 
			
		||||
@@ -150,8 +138,6 @@ fun LibrarySelectionToolbar(
 | 
			
		||||
        },
 | 
			
		||||
        isActionMode = true,
 | 
			
		||||
        onCancelActionMode = onClickUnselectAll,
 | 
			
		||||
        incognitoMode = incognitoMode,
 | 
			
		||||
        downloadedOnlyMode = downloadedOnlyMode,
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -238,8 +238,6 @@ private fun MangaScreenSmallImpl(
 | 
			
		||||
                titleAlphaProvider = { animatedTitleAlpha },
 | 
			
		||||
                backgroundAlphaProvider = { animatedBgAlpha },
 | 
			
		||||
                hasFilters = state.manga.chaptersFiltered(),
 | 
			
		||||
                incognitoMode = state.isIncognitoMode,
 | 
			
		||||
                downloadedOnlyMode = state.isDownloadedOnlyMode,
 | 
			
		||||
                onBackClicked = internalOnBackPressed,
 | 
			
		||||
                onClickFilter = onFilterClicked,
 | 
			
		||||
                onClickShare = onShareClicked,
 | 
			
		||||
@@ -450,8 +448,6 @@ fun MangaScreenLargeImpl(
 | 
			
		||||
                    titleAlphaProvider = { if (chapters.fastAny { it.selected }) 1f else 0f },
 | 
			
		||||
                    backgroundAlphaProvider = { 1f },
 | 
			
		||||
                    hasFilters = state.manga.chaptersFiltered(),
 | 
			
		||||
                    incognitoMode = state.isIncognitoMode,
 | 
			
		||||
                    downloadedOnlyMode = state.isDownloadedOnlyMode,
 | 
			
		||||
                    onBackClicked = internalOnBackPressed,
 | 
			
		||||
                    onClickFilter = onFilterButtonClicked,
 | 
			
		||||
                    onClickShare = onShareClicked,
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,6 @@ import androidx.compose.ui.draw.alpha
 | 
			
		||||
import androidx.compose.ui.res.stringResource
 | 
			
		||||
import androidx.compose.ui.text.style.TextOverflow
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import eu.kanade.presentation.components.AppStateBanners
 | 
			
		||||
import eu.kanade.presentation.components.DownloadDropdownMenu
 | 
			
		||||
import eu.kanade.presentation.components.OverflowMenu
 | 
			
		||||
import eu.kanade.presentation.manga.DownloadAction
 | 
			
		||||
@@ -40,8 +39,6 @@ fun MangaToolbar(
 | 
			
		||||
    titleAlphaProvider: () -> Float,
 | 
			
		||||
    backgroundAlphaProvider: () -> Float = titleAlphaProvider,
 | 
			
		||||
    hasFilters: Boolean,
 | 
			
		||||
    incognitoMode: Boolean,
 | 
			
		||||
    downloadedOnlyMode: Boolean,
 | 
			
		||||
    onBackClicked: () -> Unit,
 | 
			
		||||
    onClickFilter: () -> Unit,
 | 
			
		||||
    onClickShare: (() -> Unit)?,
 | 
			
		||||
@@ -151,7 +148,5 @@ fun MangaToolbar(
 | 
			
		||||
                    .copy(alpha = if (isActionMode) 1f else backgroundAlphaProvider()),
 | 
			
		||||
            ),
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        AppStateBanners(downloadedOnlyMode, incognitoMode)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,13 @@
 | 
			
		||||
package eu.kanade.presentation.more
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.clickable
 | 
			
		||||
import androidx.compose.foundation.layout.systemBarsPadding
 | 
			
		||||
import androidx.compose.foundation.layout.Column
 | 
			
		||||
import androidx.compose.foundation.layout.WindowInsets
 | 
			
		||||
import androidx.compose.foundation.layout.WindowInsetsSides
 | 
			
		||||
import androidx.compose.foundation.layout.only
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.foundation.layout.systemBars
 | 
			
		||||
import androidx.compose.foundation.layout.windowInsetsPadding
 | 
			
		||||
import androidx.compose.material.icons.Icons
 | 
			
		||||
import androidx.compose.material.icons.outlined.CloudOff
 | 
			
		||||
import androidx.compose.material.icons.outlined.GetApp
 | 
			
		||||
@@ -18,8 +24,8 @@ import androidx.compose.ui.platform.LocalUriHandler
 | 
			
		||||
import androidx.compose.ui.res.pluralStringResource
 | 
			
		||||
import androidx.compose.ui.res.stringResource
 | 
			
		||||
import androidx.compose.ui.res.vectorResource
 | 
			
		||||
import eu.kanade.presentation.components.AppStateBanners
 | 
			
		||||
import eu.kanade.presentation.components.Divider
 | 
			
		||||
import eu.kanade.presentation.components.Scaffold
 | 
			
		||||
import eu.kanade.presentation.components.ScrollbarLazyColumn
 | 
			
		||||
import eu.kanade.presentation.components.WarningBanner
 | 
			
		||||
import eu.kanade.presentation.more.settings.widget.SwitchPreferenceWidget
 | 
			
		||||
@@ -45,125 +51,125 @@ fun MoreScreen(
 | 
			
		||||
) {
 | 
			
		||||
    val uriHandler = LocalUriHandler.current
 | 
			
		||||
 | 
			
		||||
    ScrollbarLazyColumn(
 | 
			
		||||
        modifier = Modifier.systemBarsPadding(),
 | 
			
		||||
    ) {
 | 
			
		||||
        if (isFDroid) {
 | 
			
		||||
    Scaffold(
 | 
			
		||||
        topBar = {
 | 
			
		||||
            Column(
 | 
			
		||||
                modifier = Modifier.windowInsetsPadding(
 | 
			
		||||
                    WindowInsets.systemBars.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
 | 
			
		||||
                ),
 | 
			
		||||
            ) {
 | 
			
		||||
                if (isFDroid) {
 | 
			
		||||
                    WarningBanner(
 | 
			
		||||
                        textRes = R.string.fdroid_warning,
 | 
			
		||||
                        modifier = Modifier.clickable {
 | 
			
		||||
                            uriHandler.openUri("https://tachiyomi.org/help/faq/#how-do-i-migrate-from-the-f-droid-version")
 | 
			
		||||
                        },
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
    ) { contentPadding ->
 | 
			
		||||
        ScrollbarLazyColumn(
 | 
			
		||||
            modifier = Modifier.padding(contentPadding),
 | 
			
		||||
        ) {
 | 
			
		||||
            item {
 | 
			
		||||
                WarningBanner(
 | 
			
		||||
                    textRes = R.string.fdroid_warning,
 | 
			
		||||
                    modifier = Modifier.clickable {
 | 
			
		||||
                        uriHandler.openUri("https://tachiyomi.org/help/faq/#how-do-i-migrate-from-the-f-droid-version")
 | 
			
		||||
                LogoHeader()
 | 
			
		||||
            }
 | 
			
		||||
            item {
 | 
			
		||||
                SwitchPreferenceWidget(
 | 
			
		||||
                    title = stringResource(R.string.label_downloaded_only),
 | 
			
		||||
                    subtitle = stringResource(R.string.downloaded_only_summary),
 | 
			
		||||
                    icon = Icons.Outlined.CloudOff,
 | 
			
		||||
                    checked = downloadedOnly,
 | 
			
		||||
                    onCheckedChanged = onDownloadedOnlyChange,
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
            item {
 | 
			
		||||
                SwitchPreferenceWidget(
 | 
			
		||||
                    title = stringResource(R.string.pref_incognito_mode),
 | 
			
		||||
                    subtitle = stringResource(R.string.pref_incognito_mode_summary),
 | 
			
		||||
                    icon = ImageVector.vectorResource(R.drawable.ic_glasses_24dp),
 | 
			
		||||
                    checked = incognitoMode,
 | 
			
		||||
                    onCheckedChanged = onIncognitoModeChange,
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            item { Divider() }
 | 
			
		||||
 | 
			
		||||
            item {
 | 
			
		||||
                val downloadQueueState = downloadQueueStateProvider()
 | 
			
		||||
                TextPreferenceWidget(
 | 
			
		||||
                    title = stringResource(R.string.label_download_queue),
 | 
			
		||||
                    subtitle = when (downloadQueueState) {
 | 
			
		||||
                        DownloadQueueState.Stopped -> null
 | 
			
		||||
                        is DownloadQueueState.Paused -> {
 | 
			
		||||
                            val pending = downloadQueueState.pending
 | 
			
		||||
                            if (pending == 0) {
 | 
			
		||||
                                stringResource(R.string.paused)
 | 
			
		||||
                            } else {
 | 
			
		||||
                                "${stringResource(R.string.paused)} • ${
 | 
			
		||||
                                pluralStringResource(
 | 
			
		||||
                                    id = R.plurals.download_queue_summary,
 | 
			
		||||
                                    count = pending,
 | 
			
		||||
                                    pending,
 | 
			
		||||
                                )
 | 
			
		||||
                                }"
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        is DownloadQueueState.Downloading -> {
 | 
			
		||||
                            val pending = downloadQueueState.pending
 | 
			
		||||
                            pluralStringResource(id = R.plurals.download_queue_summary, count = pending, pending)
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    icon = Icons.Outlined.GetApp,
 | 
			
		||||
                    onPreferenceClick = onClickDownloadQueue,
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
            item {
 | 
			
		||||
                TextPreferenceWidget(
 | 
			
		||||
                    title = stringResource(R.string.categories),
 | 
			
		||||
                    icon = Icons.Outlined.Label,
 | 
			
		||||
                    onPreferenceClick = onClickCategories,
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
            item {
 | 
			
		||||
                TextPreferenceWidget(
 | 
			
		||||
                    title = stringResource(R.string.label_stats),
 | 
			
		||||
                    icon = Icons.Outlined.QueryStats,
 | 
			
		||||
                    onPreferenceClick = onClickStats,
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
            item {
 | 
			
		||||
                TextPreferenceWidget(
 | 
			
		||||
                    title = stringResource(R.string.label_backup),
 | 
			
		||||
                    icon = Icons.Outlined.SettingsBackupRestore,
 | 
			
		||||
                    onPreferenceClick = onClickBackupAndRestore,
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            item { Divider() }
 | 
			
		||||
 | 
			
		||||
            item {
 | 
			
		||||
                TextPreferenceWidget(
 | 
			
		||||
                    title = stringResource(R.string.label_settings),
 | 
			
		||||
                    icon = Icons.Outlined.Settings,
 | 
			
		||||
                    onPreferenceClick = onClickSettings,
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
            item {
 | 
			
		||||
                TextPreferenceWidget(
 | 
			
		||||
                    title = stringResource(R.string.pref_category_about),
 | 
			
		||||
                    icon = Icons.Outlined.Info,
 | 
			
		||||
                    onPreferenceClick = onClickAbout,
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
            item {
 | 
			
		||||
                TextPreferenceWidget(
 | 
			
		||||
                    title = stringResource(R.string.label_help),
 | 
			
		||||
                    icon = Icons.Outlined.HelpOutline,
 | 
			
		||||
                    onPreferenceClick = { uriHandler.openUri(Constants.URL_HELP) },
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        item {
 | 
			
		||||
            LogoHeader()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        item {
 | 
			
		||||
            AppStateBanners(
 | 
			
		||||
                downloadedOnlyMode = downloadedOnly,
 | 
			
		||||
                incognitoMode = incognitoMode,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        item {
 | 
			
		||||
            SwitchPreferenceWidget(
 | 
			
		||||
                title = stringResource(R.string.label_downloaded_only),
 | 
			
		||||
                subtitle = stringResource(R.string.downloaded_only_summary),
 | 
			
		||||
                icon = Icons.Outlined.CloudOff,
 | 
			
		||||
                checked = downloadedOnly,
 | 
			
		||||
                onCheckedChanged = onDownloadedOnlyChange,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        item {
 | 
			
		||||
            SwitchPreferenceWidget(
 | 
			
		||||
                title = stringResource(R.string.pref_incognito_mode),
 | 
			
		||||
                subtitle = stringResource(R.string.pref_incognito_mode_summary),
 | 
			
		||||
                icon = ImageVector.vectorResource(R.drawable.ic_glasses_24dp),
 | 
			
		||||
                checked = incognitoMode,
 | 
			
		||||
                onCheckedChanged = onIncognitoModeChange,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        item { Divider() }
 | 
			
		||||
 | 
			
		||||
        item {
 | 
			
		||||
            val downloadQueueState = downloadQueueStateProvider()
 | 
			
		||||
            TextPreferenceWidget(
 | 
			
		||||
                title = stringResource(R.string.label_download_queue),
 | 
			
		||||
                subtitle = when (downloadQueueState) {
 | 
			
		||||
                    DownloadQueueState.Stopped -> null
 | 
			
		||||
                    is DownloadQueueState.Paused -> {
 | 
			
		||||
                        val pending = downloadQueueState.pending
 | 
			
		||||
                        if (pending == 0) {
 | 
			
		||||
                            stringResource(R.string.paused)
 | 
			
		||||
                        } else {
 | 
			
		||||
                            "${stringResource(R.string.paused)} • ${
 | 
			
		||||
                            pluralStringResource(
 | 
			
		||||
                                id = R.plurals.download_queue_summary,
 | 
			
		||||
                                count = pending,
 | 
			
		||||
                                pending,
 | 
			
		||||
                            )
 | 
			
		||||
                            }"
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    is DownloadQueueState.Downloading -> {
 | 
			
		||||
                        val pending = downloadQueueState.pending
 | 
			
		||||
                        pluralStringResource(id = R.plurals.download_queue_summary, count = pending, pending)
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                icon = Icons.Outlined.GetApp,
 | 
			
		||||
                onPreferenceClick = onClickDownloadQueue,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        item {
 | 
			
		||||
            TextPreferenceWidget(
 | 
			
		||||
                title = stringResource(R.string.categories),
 | 
			
		||||
                icon = Icons.Outlined.Label,
 | 
			
		||||
                onPreferenceClick = onClickCategories,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        item {
 | 
			
		||||
            TextPreferenceWidget(
 | 
			
		||||
                title = stringResource(R.string.label_stats),
 | 
			
		||||
                icon = Icons.Outlined.QueryStats,
 | 
			
		||||
                onPreferenceClick = onClickStats,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        item {
 | 
			
		||||
            TextPreferenceWidget(
 | 
			
		||||
                title = stringResource(R.string.label_backup),
 | 
			
		||||
                icon = Icons.Outlined.SettingsBackupRestore,
 | 
			
		||||
                onPreferenceClick = onClickBackupAndRestore,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        item { Divider() }
 | 
			
		||||
 | 
			
		||||
        item {
 | 
			
		||||
            TextPreferenceWidget(
 | 
			
		||||
                title = stringResource(R.string.label_settings),
 | 
			
		||||
                icon = Icons.Outlined.Settings,
 | 
			
		||||
                onPreferenceClick = onClickSettings,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        item {
 | 
			
		||||
            TextPreferenceWidget(
 | 
			
		||||
                title = stringResource(R.string.pref_category_about),
 | 
			
		||||
                icon = Icons.Outlined.Info,
 | 
			
		||||
                onPreferenceClick = onClickAbout,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        item {
 | 
			
		||||
            TextPreferenceWidget(
 | 
			
		||||
                title = stringResource(R.string.label_help),
 | 
			
		||||
                icon = Icons.Outlined.HelpOutline,
 | 
			
		||||
                onPreferenceClick = { uriHandler.openUri(Constants.URL_HELP) },
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -43,8 +43,6 @@ import kotlin.time.Duration.Companion.seconds
 | 
			
		||||
fun UpdateScreen(
 | 
			
		||||
    state: UpdatesState,
 | 
			
		||||
    snackbarHostState: SnackbarHostState,
 | 
			
		||||
    incognitoMode: Boolean,
 | 
			
		||||
    downloadedOnlyMode: Boolean,
 | 
			
		||||
    lastUpdated: Long,
 | 
			
		||||
    relativeTime: Int,
 | 
			
		||||
    onClickCover: (UpdatesItem) -> Unit,
 | 
			
		||||
@@ -65,8 +63,6 @@ fun UpdateScreen(
 | 
			
		||||
    Scaffold(
 | 
			
		||||
        topBar = { scrollBehavior ->
 | 
			
		||||
            UpdatesAppBar(
 | 
			
		||||
                incognitoMode = incognitoMode,
 | 
			
		||||
                downloadedOnlyMode = downloadedOnlyMode,
 | 
			
		||||
                onUpdateLibrary = { onUpdateLibrary() },
 | 
			
		||||
                actionModeCounter = state.selected.size,
 | 
			
		||||
                onSelectAll = { onSelectAll(true) },
 | 
			
		||||
@@ -136,8 +132,6 @@ fun UpdateScreen(
 | 
			
		||||
@Composable
 | 
			
		||||
private fun UpdatesAppBar(
 | 
			
		||||
    modifier: Modifier = Modifier,
 | 
			
		||||
    incognitoMode: Boolean,
 | 
			
		||||
    downloadedOnlyMode: Boolean,
 | 
			
		||||
    onUpdateLibrary: () -> Unit,
 | 
			
		||||
    // For action mode
 | 
			
		||||
    actionModeCounter: Int,
 | 
			
		||||
@@ -173,8 +167,6 @@ private fun UpdatesAppBar(
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        downloadedOnlyMode = downloadedOnlyMode,
 | 
			
		||||
        incognitoMode = incognitoMode,
 | 
			
		||||
        scrollBehavior = scrollBehavior,
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,13 +9,9 @@ import androidx.compose.runtime.collectAsState
 | 
			
		||||
import androidx.compose.runtime.getValue
 | 
			
		||||
import androidx.compose.ui.platform.LocalContext
 | 
			
		||||
import androidx.compose.ui.res.stringResource
 | 
			
		||||
import cafe.adriel.voyager.core.model.ScreenModel
 | 
			
		||||
import cafe.adriel.voyager.core.model.coroutineScope
 | 
			
		||||
import cafe.adriel.voyager.core.model.rememberScreenModel
 | 
			
		||||
import cafe.adriel.voyager.navigator.tab.LocalTabNavigator
 | 
			
		||||
import cafe.adriel.voyager.navigator.tab.TabOptions
 | 
			
		||||
import eu.kanade.core.prefs.asState
 | 
			
		||||
import eu.kanade.domain.base.BasePreferences
 | 
			
		||||
import eu.kanade.presentation.components.TabbedScreen
 | 
			
		||||
import eu.kanade.presentation.util.Tab
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
@@ -25,8 +21,6 @@ import eu.kanade.tachiyomi.ui.browse.migration.sources.migrateSourceTab
 | 
			
		||||
import eu.kanade.tachiyomi.ui.browse.source.sourcesTab
 | 
			
		||||
import eu.kanade.tachiyomi.ui.main.MainActivity
 | 
			
		||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
 | 
			
		||||
import uy.kohesive.injekt.Injekt
 | 
			
		||||
import uy.kohesive.injekt.api.get
 | 
			
		||||
 | 
			
		||||
data class BrowseTab(
 | 
			
		||||
    private val toExtensions: Boolean = false,
 | 
			
		||||
@@ -47,7 +41,6 @@ data class BrowseTab(
 | 
			
		||||
    @Composable
 | 
			
		||||
    override fun Content() {
 | 
			
		||||
        val context = LocalContext.current
 | 
			
		||||
        val screenModel = rememberScreenModel { BrowseScreenModel() }
 | 
			
		||||
 | 
			
		||||
        // Hoisted for extensions tab's search bar
 | 
			
		||||
        val extensionsScreenModel = rememberScreenModel { ExtensionsScreenModel() }
 | 
			
		||||
@@ -63,8 +56,6 @@ data class BrowseTab(
 | 
			
		||||
            startIndex = 1.takeIf { toExtensions },
 | 
			
		||||
            searchQuery = extensionsQuery,
 | 
			
		||||
            onChangeSearchQuery = extensionsScreenModel::search,
 | 
			
		||||
            incognitoMode = screenModel.isIncognitoMode,
 | 
			
		||||
            downloadedOnlyMode = screenModel.isDownloadOnly,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        // For local source
 | 
			
		||||
@@ -75,10 +66,3 @@ data class BrowseTab(
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
private class BrowseScreenModel(
 | 
			
		||||
    preferences: BasePreferences = Injekt.get(),
 | 
			
		||||
) : ScreenModel {
 | 
			
		||||
    val isDownloadOnly: Boolean by preferences.downloadedOnly().asState(coroutineScope)
 | 
			
		||||
    val isIncognitoMode: Boolean by preferences.incognitoMode().asState(coroutineScope)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,6 @@ import eu.kanade.domain.source.interactor.GetRemoteManga
 | 
			
		||||
import eu.kanade.presentation.browse.BrowseSourceContent
 | 
			
		||||
import eu.kanade.presentation.browse.components.BrowseSourceToolbar
 | 
			
		||||
import eu.kanade.presentation.browse.components.RemoveMangaDialog
 | 
			
		||||
import eu.kanade.presentation.components.AppStateBanners
 | 
			
		||||
import eu.kanade.presentation.components.ChangeCategoryDialog
 | 
			
		||||
import eu.kanade.presentation.components.Divider
 | 
			
		||||
import eu.kanade.presentation.components.DuplicateMangaDialog
 | 
			
		||||
@@ -167,8 +166,6 @@ data class BrowseSourceScreen(
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    Divider()
 | 
			
		||||
 | 
			
		||||
                    AppStateBanners(screenModel.isDownloadOnly, screenModel.isIncognitoMode)
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,6 @@ import eu.davidea.flexibleadapter.items.IFlexible
 | 
			
		||||
import eu.kanade.core.prefs.CheckboxState
 | 
			
		||||
import eu.kanade.core.prefs.asState
 | 
			
		||||
import eu.kanade.core.prefs.mapAsCheckboxState
 | 
			
		||||
import eu.kanade.domain.base.BasePreferences
 | 
			
		||||
import eu.kanade.domain.category.interactor.GetCategories
 | 
			
		||||
import eu.kanade.domain.category.interactor.SetMangaCategories
 | 
			
		||||
import eu.kanade.domain.category.model.Category
 | 
			
		||||
@@ -82,7 +81,6 @@ class BrowseSourceScreenModel(
 | 
			
		||||
    private val sourceId: Long,
 | 
			
		||||
    searchQuery: String?,
 | 
			
		||||
    private val sourceManager: SourceManager = Injekt.get(),
 | 
			
		||||
    preferences: BasePreferences = Injekt.get(),
 | 
			
		||||
    sourcePreferences: SourcePreferences = Injekt.get(),
 | 
			
		||||
    private val libraryPreferences: LibraryPreferences = Injekt.get(),
 | 
			
		||||
    private val coverCache: CoverCache = Injekt.get(),
 | 
			
		||||
@@ -103,9 +101,6 @@ class BrowseSourceScreenModel(
 | 
			
		||||
 | 
			
		||||
    var displayMode by sourcePreferences.sourceDisplayMode().asState(coroutineScope)
 | 
			
		||||
 | 
			
		||||
    val isDownloadOnly: Boolean by preferences.downloadedOnly().asState(coroutineScope)
 | 
			
		||||
    val isIncognitoMode: Boolean by preferences.incognitoMode().asState(coroutineScope)
 | 
			
		||||
 | 
			
		||||
    val source = sourceManager.get(sourceId) as CatalogueSource
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,9 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.history
 | 
			
		||||
 | 
			
		||||
import androidx.compose.runtime.Immutable
 | 
			
		||||
import androidx.compose.runtime.getValue
 | 
			
		||||
import cafe.adriel.voyager.core.model.StateScreenModel
 | 
			
		||||
import cafe.adriel.voyager.core.model.coroutineScope
 | 
			
		||||
import eu.kanade.core.prefs.asState
 | 
			
		||||
import eu.kanade.core.util.insertSeparators
 | 
			
		||||
import eu.kanade.domain.base.BasePreferences
 | 
			
		||||
import eu.kanade.domain.chapter.model.Chapter
 | 
			
		||||
import eu.kanade.domain.history.interactor.GetHistory
 | 
			
		||||
import eu.kanade.domain.history.interactor.GetNextChapters
 | 
			
		||||
@@ -37,15 +34,11 @@ class HistoryScreenModel(
 | 
			
		||||
    private val getHistory: GetHistory = Injekt.get(),
 | 
			
		||||
    private val getNextChapters: GetNextChapters = Injekt.get(),
 | 
			
		||||
    private val removeHistory: RemoveHistory = Injekt.get(),
 | 
			
		||||
    preferences: BasePreferences = Injekt.get(),
 | 
			
		||||
) : StateScreenModel<HistoryState>(HistoryState()) {
 | 
			
		||||
 | 
			
		||||
    private val _events: Channel<Event> = Channel(Channel.UNLIMITED)
 | 
			
		||||
    val events: Flow<Event> = _events.receiveAsFlow()
 | 
			
		||||
 | 
			
		||||
    val isDownloadOnly: Boolean by preferences.downloadedOnly().asState(coroutineScope)
 | 
			
		||||
    val isIncognitoMode: Boolean by preferences.incognitoMode().asState(coroutineScope)
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        coroutineScope.launch {
 | 
			
		||||
            state.map { it.searchQuery }
 | 
			
		||||
 
 | 
			
		||||
@@ -62,8 +62,6 @@ object HistoryTab : Tab {
 | 
			
		||||
        HistoryScreen(
 | 
			
		||||
            state = state,
 | 
			
		||||
            snackbarHostState = snackbarHostState,
 | 
			
		||||
            incognitoMode = screenModel.isIncognitoMode,
 | 
			
		||||
            downloadedOnlyMode = screenModel.isDownloadOnly,
 | 
			
		||||
            onSearchQueryChange = screenModel::updateSearchQuery,
 | 
			
		||||
            onClickCover = { navigator.push(MangaScreen(it)) },
 | 
			
		||||
            onClickResume = screenModel::getNextChapterForManga,
 | 
			
		||||
 
 | 
			
		||||
@@ -89,9 +89,6 @@ class LibraryScreenModel(
 | 
			
		||||
 | 
			
		||||
    var activeCategoryIndex: Int by libraryPreferences.lastUsedCategory().asState(coroutineScope)
 | 
			
		||||
 | 
			
		||||
    val isDownloadOnly: Boolean by preferences.downloadedOnly().asState(coroutineScope)
 | 
			
		||||
    val isIncognitoMode: Boolean by preferences.incognitoMode().asState(coroutineScope)
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        coroutineScope.launchIO {
 | 
			
		||||
            combine(
 | 
			
		||||
 
 | 
			
		||||
@@ -112,8 +112,6 @@ object LibraryTab : Tab {
 | 
			
		||||
                    hasActiveFilters = state.hasActiveFilters,
 | 
			
		||||
                    selectedCount = state.selection.size,
 | 
			
		||||
                    title = title,
 | 
			
		||||
                    incognitoMode = !tabVisible && screenModel.isIncognitoMode,
 | 
			
		||||
                    downloadedOnlyMode = !tabVisible && screenModel.isDownloadOnly,
 | 
			
		||||
                    onClickUnselectAll = screenModel::clearSelection,
 | 
			
		||||
                    onClickSelectAll = { screenModel.selectAll(screenModel.activeCategoryIndex) },
 | 
			
		||||
                    onClickInvertSelection = { screenModel.invertSelection(screenModel.activeCategoryIndex) },
 | 
			
		||||
@@ -197,10 +195,7 @@ object LibraryTab : Tab {
 | 
			
		||||
                        getNumberOfMangaForCategory = { state.getMangaCountForCategory(it) },
 | 
			
		||||
                        getDisplayModeForPage = { state.categories[it].display },
 | 
			
		||||
                        getColumnsForOrientation = { screenModel.getColumnsPreferenceForCurrentOrientation(it) },
 | 
			
		||||
                        getLibraryForPage = { state.getLibraryItemsByPage(it) },
 | 
			
		||||
                        isDownloadOnly = screenModel.isDownloadOnly,
 | 
			
		||||
                        isIncognitoMode = screenModel.isIncognitoMode,
 | 
			
		||||
                    )
 | 
			
		||||
                    ) { state.getLibraryItemsByPage(it) }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,12 @@ import android.view.View
 | 
			
		||||
import android.view.Window
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import androidx.activity.compose.BackHandler
 | 
			
		||||
import androidx.compose.foundation.isSystemInDarkTheme
 | 
			
		||||
import androidx.compose.foundation.layout.Box
 | 
			
		||||
import androidx.compose.foundation.layout.Column
 | 
			
		||||
import androidx.compose.foundation.layout.WindowInsets
 | 
			
		||||
import androidx.compose.foundation.layout.consumeWindowInsets
 | 
			
		||||
import androidx.compose.foundation.layout.statusBars
 | 
			
		||||
import androidx.compose.material3.AlertDialog
 | 
			
		||||
import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.material3.TextButton
 | 
			
		||||
@@ -20,6 +26,7 @@ import androidx.compose.runtime.mutableStateOf
 | 
			
		||||
import androidx.compose.runtime.remember
 | 
			
		||||
import androidx.compose.runtime.rememberCoroutineScope
 | 
			
		||||
import androidx.compose.runtime.setValue
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.platform.LocalContext
 | 
			
		||||
import androidx.compose.ui.res.stringResource
 | 
			
		||||
import androidx.core.animation.doOnEnd
 | 
			
		||||
@@ -36,12 +43,14 @@ import cafe.adriel.voyager.navigator.Navigator
 | 
			
		||||
import cafe.adriel.voyager.navigator.NavigatorDisposeBehavior
 | 
			
		||||
import cafe.adriel.voyager.navigator.currentOrThrow
 | 
			
		||||
import cafe.adriel.voyager.transitions.ScreenTransition
 | 
			
		||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
 | 
			
		||||
import com.google.android.material.transition.platform.MaterialContainerTransformSharedElementCallback
 | 
			
		||||
import eu.kanade.domain.base.BasePreferences
 | 
			
		||||
import eu.kanade.domain.category.model.Category
 | 
			
		||||
import eu.kanade.domain.library.service.LibraryPreferences
 | 
			
		||||
import eu.kanade.domain.source.service.SourcePreferences
 | 
			
		||||
import eu.kanade.domain.ui.UiPreferences
 | 
			
		||||
import eu.kanade.presentation.components.AppStateBanners
 | 
			
		||||
import eu.kanade.presentation.util.Transition
 | 
			
		||||
import eu.kanade.presentation.util.collectAsState
 | 
			
		||||
import eu.kanade.tachiyomi.BuildConfig
 | 
			
		||||
@@ -142,47 +151,73 @@ class MainActivity : BaseActivity() {
 | 
			
		||||
            .launchIn(lifecycleScope)
 | 
			
		||||
 | 
			
		||||
        setComposeContent {
 | 
			
		||||
            Navigator(
 | 
			
		||||
                screen = HomeScreen,
 | 
			
		||||
                disposeBehavior = NavigatorDisposeBehavior(disposeNestedNavigators = false, disposeSteps = true),
 | 
			
		||||
            ) { navigator ->
 | 
			
		||||
                if (navigator.size == 1) {
 | 
			
		||||
                    ConfirmExit()
 | 
			
		||||
            val incognito by preferences.incognitoMode().collectAsState()
 | 
			
		||||
            val download by preferences.downloadedOnly().collectAsState()
 | 
			
		||||
            Column {
 | 
			
		||||
                AppStateBanners(
 | 
			
		||||
                    downloadedOnlyMode = download,
 | 
			
		||||
                    incognitoMode = incognito,
 | 
			
		||||
                )
 | 
			
		||||
                val systemUiController = rememberSystemUiController()
 | 
			
		||||
                val active = incognito || download
 | 
			
		||||
                val useDarkIcons = if (isSystemInDarkTheme()) active else !active
 | 
			
		||||
                LaunchedEffect(systemUiController, useDarkIcons) {
 | 
			
		||||
                    systemUiController.setStatusBarColor(
 | 
			
		||||
                        color = androidx.compose.ui.graphics.Color.Transparent,
 | 
			
		||||
                        darkIcons = useDarkIcons,
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                LaunchedEffect(navigator) {
 | 
			
		||||
                    this@MainActivity.navigator = navigator
 | 
			
		||||
 | 
			
		||||
                    if (savedInstanceState == null) {
 | 
			
		||||
                        // Set start screen
 | 
			
		||||
                        handleIntentAction(intent)
 | 
			
		||||
 | 
			
		||||
                        // Reset Incognito Mode on relaunch
 | 
			
		||||
                        preferences.incognitoMode().set(false)
 | 
			
		||||
                Navigator(
 | 
			
		||||
                    screen = HomeScreen,
 | 
			
		||||
                    disposeBehavior = NavigatorDisposeBehavior(disposeNestedNavigators = false, disposeSteps = true),
 | 
			
		||||
                ) { navigator ->
 | 
			
		||||
                    if (navigator.size == 1) {
 | 
			
		||||
                        ConfirmExit()
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Shows current screen
 | 
			
		||||
                ScreenTransition(navigator = navigator, transition = { Transition.OneWayFade })
 | 
			
		||||
                    LaunchedEffect(navigator) {
 | 
			
		||||
                        this@MainActivity.navigator = navigator
 | 
			
		||||
 | 
			
		||||
                // Pop source-related screens when incognito mode is turned off
 | 
			
		||||
                LaunchedEffect(Unit) {
 | 
			
		||||
                    preferences.incognitoMode().changes()
 | 
			
		||||
                        .drop(1)
 | 
			
		||||
                        .onEach {
 | 
			
		||||
                            if (!it) {
 | 
			
		||||
                                val currentScreen = navigator.lastItem
 | 
			
		||||
                                if (currentScreen is BrowseSourceScreen ||
 | 
			
		||||
                                    (currentScreen is MangaScreen && currentScreen.fromSource)
 | 
			
		||||
                                ) {
 | 
			
		||||
                                    navigator.popUntilRoot()
 | 
			
		||||
                        if (savedInstanceState == null) {
 | 
			
		||||
                            // Set start screen
 | 
			
		||||
                            handleIntentAction(intent)
 | 
			
		||||
 | 
			
		||||
                            // Reset Incognito Mode on relaunch
 | 
			
		||||
                            preferences.incognitoMode().set(false)
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // Consume insets already used by app state banners
 | 
			
		||||
                    val boxModifier = if (incognito || download) {
 | 
			
		||||
                        Modifier.consumeWindowInsets(WindowInsets.statusBars)
 | 
			
		||||
                    } else {
 | 
			
		||||
                        Modifier
 | 
			
		||||
                    }
 | 
			
		||||
                    Box(modifier = boxModifier) {
 | 
			
		||||
                        // Shows current screen
 | 
			
		||||
                        ScreenTransition(navigator = navigator, transition = { Transition.OneWayFade })
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // Pop source-related screens when incognito mode is turned off
 | 
			
		||||
                    LaunchedEffect(Unit) {
 | 
			
		||||
                        preferences.incognitoMode().changes()
 | 
			
		||||
                            .drop(1)
 | 
			
		||||
                            .onEach {
 | 
			
		||||
                                if (!it) {
 | 
			
		||||
                                    val currentScreen = navigator.lastItem
 | 
			
		||||
                                    if (currentScreen is BrowseSourceScreen ||
 | 
			
		||||
                                        (currentScreen is MangaScreen && currentScreen.fromSource)
 | 
			
		||||
                                    ) {
 | 
			
		||||
                                        navigator.popUntilRoot()
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        .launchIn(this)
 | 
			
		||||
                }
 | 
			
		||||
                            .launchIn(this)
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                CheckForUpdate()
 | 
			
		||||
                    CheckForUpdate()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var showChangelog by remember { mutableStateOf(didMigration && !BuildConfig.DEBUG) }
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,6 @@ import eu.kanade.core.prefs.CheckboxState
 | 
			
		||||
import eu.kanade.core.prefs.mapAsCheckboxState
 | 
			
		||||
import eu.kanade.core.util.addOrRemove
 | 
			
		||||
import eu.kanade.data.chapter.NoChaptersException
 | 
			
		||||
import eu.kanade.domain.base.BasePreferences
 | 
			
		||||
import eu.kanade.domain.category.interactor.GetCategories
 | 
			
		||||
import eu.kanade.domain.category.interactor.SetMangaCategories
 | 
			
		||||
import eu.kanade.domain.category.model.Category
 | 
			
		||||
@@ -53,7 +52,6 @@ import eu.kanade.tachiyomi.util.lang.launchNonCancellable
 | 
			
		||||
import eu.kanade.tachiyomi.util.lang.toRelativeString
 | 
			
		||||
import eu.kanade.tachiyomi.util.lang.withIOContext
 | 
			
		||||
import eu.kanade.tachiyomi.util.lang.withUIContext
 | 
			
		||||
import eu.kanade.tachiyomi.util.preference.asHotFlow
 | 
			
		||||
import eu.kanade.tachiyomi.util.removeCovers
 | 
			
		||||
import eu.kanade.tachiyomi.util.shouldDownloadNewChapters
 | 
			
		||||
import eu.kanade.tachiyomi.util.system.logcat
 | 
			
		||||
@@ -64,7 +62,6 @@ import kotlinx.coroutines.flow.collectLatest
 | 
			
		||||
import kotlinx.coroutines.flow.combine
 | 
			
		||||
import kotlinx.coroutines.flow.distinctUntilChanged
 | 
			
		||||
import kotlinx.coroutines.flow.filter
 | 
			
		||||
import kotlinx.coroutines.flow.launchIn
 | 
			
		||||
import kotlinx.coroutines.flow.map
 | 
			
		||||
import kotlinx.coroutines.flow.update
 | 
			
		||||
import kotlinx.coroutines.isActive
 | 
			
		||||
@@ -81,7 +78,6 @@ class MangaInfoScreenModel(
 | 
			
		||||
    val context: Context,
 | 
			
		||||
    val mangaId: Long,
 | 
			
		||||
    private val isFromSource: Boolean,
 | 
			
		||||
    basePreferences: BasePreferences = Injekt.get(),
 | 
			
		||||
    private val downloadPreferences: DownloadPreferences = Injekt.get(),
 | 
			
		||||
    private val libraryPreferences: LibraryPreferences = Injekt.get(),
 | 
			
		||||
    private val uiPreferences: UiPreferences = Injekt.get(),
 | 
			
		||||
@@ -130,17 +126,6 @@ class MangaInfoScreenModel(
 | 
			
		||||
        mutableState.update { if (it is MangaScreenState.Success) func(it) else it }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private var incognitoMode = false
 | 
			
		||||
        set(value) {
 | 
			
		||||
            updateSuccessState { it.copy(isIncognitoMode = value) }
 | 
			
		||||
            field = value
 | 
			
		||||
        }
 | 
			
		||||
    private var downloadedOnlyMode = false
 | 
			
		||||
        set(value) {
 | 
			
		||||
            updateSuccessState { it.copy(isDownloadedOnlyMode = value) }
 | 
			
		||||
            field = value
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        val toChapterItemsParams: List<Chapter>.(manga: Manga) -> List<ChapterItem> = { manga ->
 | 
			
		||||
            toChapterItems(
 | 
			
		||||
@@ -189,8 +174,6 @@ class MangaInfoScreenModel(
 | 
			
		||||
                    isFromSource = isFromSource,
 | 
			
		||||
                    chapters = chapters,
 | 
			
		||||
                    isRefreshingData = needRefreshInfo || needRefreshChapter,
 | 
			
		||||
                    isIncognitoMode = incognitoMode,
 | 
			
		||||
                    isDownloadedOnlyMode = downloadedOnlyMode,
 | 
			
		||||
                    dialog = null,
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
@@ -210,14 +193,6 @@ class MangaInfoScreenModel(
 | 
			
		||||
            // Initial loading finished
 | 
			
		||||
            updateSuccessState { it.copy(isRefreshingData = false) }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        basePreferences.incognitoMode()
 | 
			
		||||
            .asHotFlow { incognitoMode = it }
 | 
			
		||||
            .launchIn(coroutineScope)
 | 
			
		||||
 | 
			
		||||
        basePreferences.downloadedOnly()
 | 
			
		||||
            .asHotFlow { downloadedOnlyMode = it }
 | 
			
		||||
            .launchIn(coroutineScope)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun fetchAllFromSource(manualFetch: Boolean = true) {
 | 
			
		||||
@@ -1037,8 +1012,6 @@ sealed class MangaScreenState {
 | 
			
		||||
        val chapters: List<ChapterItem>,
 | 
			
		||||
        val trackItems: List<TrackItem> = emptyList(),
 | 
			
		||||
        val isRefreshingData: Boolean = false,
 | 
			
		||||
        val isIncognitoMode: Boolean = false,
 | 
			
		||||
        val isDownloadedOnlyMode: Boolean = false,
 | 
			
		||||
        val dialog: MangaInfoScreenModel.Dialog? = null,
 | 
			
		||||
    ) : MangaScreenState() {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,6 @@ import cafe.adriel.voyager.core.model.coroutineScope
 | 
			
		||||
import eu.kanade.core.prefs.asState
 | 
			
		||||
import eu.kanade.core.util.addOrRemove
 | 
			
		||||
import eu.kanade.core.util.insertSeparators
 | 
			
		||||
import eu.kanade.domain.base.BasePreferences
 | 
			
		||||
import eu.kanade.domain.chapter.interactor.GetChapter
 | 
			
		||||
import eu.kanade.domain.chapter.interactor.SetReadStatus
 | 
			
		||||
import eu.kanade.domain.chapter.interactor.UpdateChapter
 | 
			
		||||
@@ -62,16 +61,12 @@ class UpdatesScreenModel(
 | 
			
		||||
    private val getChapter: GetChapter = Injekt.get(),
 | 
			
		||||
    private val libraryPreferences: LibraryPreferences = Injekt.get(),
 | 
			
		||||
    val snackbarHostState: SnackbarHostState = SnackbarHostState(),
 | 
			
		||||
    basePreferences: BasePreferences = Injekt.get(),
 | 
			
		||||
    uiPreferences: UiPreferences = Injekt.get(),
 | 
			
		||||
) : StateScreenModel<UpdatesState>(UpdatesState()) {
 | 
			
		||||
 | 
			
		||||
    private val _events: Channel<Event> = Channel(Int.MAX_VALUE)
 | 
			
		||||
    val events: Flow<Event> = _events.receiveAsFlow()
 | 
			
		||||
 | 
			
		||||
    val isDownloadOnly: Boolean by basePreferences.downloadedOnly().asState(coroutineScope)
 | 
			
		||||
    val isIncognitoMode: Boolean by basePreferences.incognitoMode().asState(coroutineScope)
 | 
			
		||||
 | 
			
		||||
    val lastUpdated by libraryPreferences.libraryUpdateLastTimestamp().asState(coroutineScope)
 | 
			
		||||
 | 
			
		||||
    val relativeTime: Int by uiPreferences.relativeTime().asState(coroutineScope)
 | 
			
		||||
 
 | 
			
		||||
@@ -56,8 +56,6 @@ object UpdatesTab : Tab {
 | 
			
		||||
        UpdateScreen(
 | 
			
		||||
            state = state,
 | 
			
		||||
            snackbarHostState = screenModel.snackbarHostState,
 | 
			
		||||
            incognitoMode = screenModel.isIncognitoMode,
 | 
			
		||||
            downloadedOnlyMode = screenModel.isDownloadOnly,
 | 
			
		||||
            lastUpdated = screenModel.lastUpdated,
 | 
			
		||||
            relativeTime = screenModel.relativeTime,
 | 
			
		||||
            onClickCover = { item -> navigator.push(MangaScreen(item.update.mangaId)) },
 | 
			
		||||
 
 | 
			
		||||
@@ -23,4 +23,5 @@ material-core = { module = "androidx.compose.material:material", version = "1.4.
 | 
			
		||||
accompanist-webview = { module = "com.google.accompanist:accompanist-webview", version.ref = "accompanist" }
 | 
			
		||||
accompanist-flowlayout = { module = "com.google.accompanist:accompanist-flowlayout", version.ref = "accompanist" }
 | 
			
		||||
accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanist" }
 | 
			
		||||
accompanist-themeadapter = { module = "com.google.accompanist:accompanist-themeadapter-material3", version.ref = "accompanist" }
 | 
			
		||||
accompanist-themeadapter = { module = "com.google.accompanist:accompanist-themeadapter-material3", version.ref = "accompanist" }
 | 
			
		||||
accompanist-systemuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanist" }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user