mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-03 23:58:55 +01:00 
			
		
		
		
	Dedupe common LazyColumn with action at bottom layout
This commit is contained in:
		@@ -3,19 +3,14 @@ package eu.kanade.presentation.more.settings.screen.advanced
 | 
			
		||||
import androidx.compose.foundation.clickable
 | 
			
		||||
import androidx.compose.foundation.layout.Column
 | 
			
		||||
import androidx.compose.foundation.layout.Row
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxSize
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxWidth
 | 
			
		||||
import androidx.compose.foundation.layout.height
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.foundation.lazy.LazyColumn
 | 
			
		||||
import androidx.compose.foundation.lazy.items
 | 
			
		||||
import androidx.compose.material.icons.Icons
 | 
			
		||||
import androidx.compose.material.icons.outlined.FlipToBack
 | 
			
		||||
import androidx.compose.material.icons.outlined.SelectAll
 | 
			
		||||
import androidx.compose.material3.AlertDialog
 | 
			
		||||
import androidx.compose.material3.Button
 | 
			
		||||
import androidx.compose.material3.Checkbox
 | 
			
		||||
import androidx.compose.material3.HorizontalDivider
 | 
			
		||||
import androidx.compose.material3.MaterialTheme
 | 
			
		||||
import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.material3.TextButton
 | 
			
		||||
@@ -50,6 +45,7 @@ import tachiyomi.domain.source.interactor.GetSourcesWithNonLibraryManga
 | 
			
		||||
import tachiyomi.domain.source.model.Source
 | 
			
		||||
import tachiyomi.domain.source.model.SourceWithCount
 | 
			
		||||
import tachiyomi.i18n.MR
 | 
			
		||||
import tachiyomi.presentation.core.components.LazyColumnWithAction
 | 
			
		||||
import tachiyomi.presentation.core.components.material.Scaffold
 | 
			
		||||
import tachiyomi.presentation.core.i18n.stringResource
 | 
			
		||||
import tachiyomi.presentation.core.screens.EmptyScreen
 | 
			
		||||
@@ -114,7 +110,7 @@ class ClearDatabaseScreen : Screen() {
 | 
			
		||||
                                                onClick = model::selectAll,
 | 
			
		||||
                                            ),
 | 
			
		||||
                                            AppBar.Action(
 | 
			
		||||
                                                title = stringResource(MR.strings.action_select_all),
 | 
			
		||||
                                                title = stringResource(MR.strings.action_select_inverse),
 | 
			
		||||
                                                icon = Icons.Outlined.FlipToBack,
 | 
			
		||||
                                                onClick = model::invertSelection,
 | 
			
		||||
                                            ),
 | 
			
		||||
@@ -132,36 +128,18 @@ class ClearDatabaseScreen : Screen() {
 | 
			
		||||
                            modifier = Modifier.padding(contentPadding),
 | 
			
		||||
                        )
 | 
			
		||||
                    } else {
 | 
			
		||||
                        Column(
 | 
			
		||||
                            modifier = Modifier
 | 
			
		||||
                                .padding(contentPadding)
 | 
			
		||||
                                .fillMaxSize(),
 | 
			
		||||
                        LazyColumnWithAction(
 | 
			
		||||
                            contentPadding = contentPadding,
 | 
			
		||||
                            actionLabel = stringResource(MR.strings.action_delete),
 | 
			
		||||
                            actionEnabled = s.selection.isNotEmpty(),
 | 
			
		||||
                            onClickAction = model::showConfirmation,
 | 
			
		||||
                        ) {
 | 
			
		||||
                            LazyColumn(
 | 
			
		||||
                                modifier = Modifier.weight(1f),
 | 
			
		||||
                            ) {
 | 
			
		||||
                                items(s.items) { sourceWithCount ->
 | 
			
		||||
                                    ClearDatabaseItem(
 | 
			
		||||
                                        source = sourceWithCount.source,
 | 
			
		||||
                                        count = sourceWithCount.count,
 | 
			
		||||
                                        isSelected = s.selection.contains(sourceWithCount.id),
 | 
			
		||||
                                        onClickSelect = { model.toggleSelection(sourceWithCount.source) },
 | 
			
		||||
                                    )
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            HorizontalDivider()
 | 
			
		||||
 | 
			
		||||
                            Button(
 | 
			
		||||
                                modifier = Modifier
 | 
			
		||||
                                    .padding(horizontal = 16.dp, vertical = 8.dp)
 | 
			
		||||
                                    .fillMaxWidth(),
 | 
			
		||||
                                onClick = model::showConfirmation,
 | 
			
		||||
                                enabled = s.selection.isNotEmpty(),
 | 
			
		||||
                            ) {
 | 
			
		||||
                                Text(
 | 
			
		||||
                                    text = stringResource(MR.strings.action_delete),
 | 
			
		||||
                                    color = MaterialTheme.colorScheme.onPrimary,
 | 
			
		||||
                            items(s.items) { sourceWithCount ->
 | 
			
		||||
                                ClearDatabaseItem(
 | 
			
		||||
                                    source = sourceWithCount.source,
 | 
			
		||||
                                    count = sourceWithCount.count,
 | 
			
		||||
                                    isSelected = s.selection.contains(sourceWithCount.id),
 | 
			
		||||
                                    onClickSelect = { model.toggleSelection(sourceWithCount.source) },
 | 
			
		||||
                                )
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
 
 | 
			
		||||
@@ -6,23 +6,12 @@ import android.content.Intent
 | 
			
		||||
import android.net.Uri
 | 
			
		||||
import androidx.activity.compose.rememberLauncherForActivityResult
 | 
			
		||||
import androidx.activity.result.contract.ActivityResultContracts
 | 
			
		||||
import androidx.compose.foundation.layout.Column
 | 
			
		||||
import androidx.compose.foundation.layout.ColumnScope
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxSize
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxWidth
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.foundation.lazy.LazyColumn
 | 
			
		||||
import androidx.compose.material3.Button
 | 
			
		||||
import androidx.compose.material3.HorizontalDivider
 | 
			
		||||
import androidx.compose.material3.MaterialTheme
 | 
			
		||||
import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.Immutable
 | 
			
		||||
import androidx.compose.runtime.collectAsState
 | 
			
		||||
import androidx.compose.runtime.getValue
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.platform.LocalContext
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import cafe.adriel.voyager.core.model.StateScreenModel
 | 
			
		||||
import cafe.adriel.voyager.core.model.rememberScreenModel
 | 
			
		||||
import cafe.adriel.voyager.navigator.LocalNavigator
 | 
			
		||||
@@ -39,9 +28,9 @@ import kotlinx.collections.immutable.ImmutableList
 | 
			
		||||
import kotlinx.coroutines.flow.update
 | 
			
		||||
import tachiyomi.i18n.MR
 | 
			
		||||
import tachiyomi.presentation.core.components.LabeledCheckbox
 | 
			
		||||
import tachiyomi.presentation.core.components.LazyColumnWithAction
 | 
			
		||||
import tachiyomi.presentation.core.components.SectionCard
 | 
			
		||||
import tachiyomi.presentation.core.components.material.Scaffold
 | 
			
		||||
import tachiyomi.presentation.core.components.material.padding
 | 
			
		||||
import tachiyomi.presentation.core.i18n.stringResource
 | 
			
		||||
 | 
			
		||||
class CreateBackupScreen : Screen() {
 | 
			
		||||
@@ -76,55 +65,37 @@ class CreateBackupScreen : Screen() {
 | 
			
		||||
                )
 | 
			
		||||
            },
 | 
			
		||||
        ) { contentPadding ->
 | 
			
		||||
            Column(
 | 
			
		||||
                modifier = Modifier
 | 
			
		||||
                    .padding(contentPadding)
 | 
			
		||||
                    .fillMaxSize(),
 | 
			
		||||
            LazyColumnWithAction(
 | 
			
		||||
                contentPadding = contentPadding,
 | 
			
		||||
                actionLabel = stringResource(MR.strings.action_create),
 | 
			
		||||
                onClickAction = {
 | 
			
		||||
                    if (!BackupCreateJob.isManualJobRunning(context)) {
 | 
			
		||||
                        try {
 | 
			
		||||
                            chooseBackupDir.launch(BackupCreator.getFilename())
 | 
			
		||||
                        } catch (e: ActivityNotFoundException) {
 | 
			
		||||
                            context.toast(MR.strings.file_picker_error)
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        context.toast(MR.strings.backup_in_progress)
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
            ) {
 | 
			
		||||
                LazyColumn(
 | 
			
		||||
                    modifier = Modifier.weight(1f),
 | 
			
		||||
                ) {
 | 
			
		||||
                    if (DeviceUtil.isMiui && DeviceUtil.isMiuiOptimizationDisabled()) {
 | 
			
		||||
                        item {
 | 
			
		||||
                            WarningBanner(MR.strings.restore_miui_warning)
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                if (DeviceUtil.isMiui && DeviceUtil.isMiuiOptimizationDisabled()) {
 | 
			
		||||
                    item {
 | 
			
		||||
                        SectionCard(MR.strings.label_library) {
 | 
			
		||||
                            Options(BackupOptions.libraryOptions, state, model)
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    item {
 | 
			
		||||
                        SectionCard(MR.strings.label_settings) {
 | 
			
		||||
                            Options(BackupOptions.settingsOptions, state, model)
 | 
			
		||||
                        }
 | 
			
		||||
                        WarningBanner(MR.strings.restore_miui_warning)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                HorizontalDivider()
 | 
			
		||||
                item {
 | 
			
		||||
                    SectionCard(MR.strings.label_library) {
 | 
			
		||||
                        Options(BackupOptions.libraryOptions, state, model)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                Button(
 | 
			
		||||
                    modifier = Modifier
 | 
			
		||||
                        .padding(horizontal = 16.dp, vertical = 8.dp)
 | 
			
		||||
                        .fillMaxWidth(),
 | 
			
		||||
                    onClick = {
 | 
			
		||||
                        if (!BackupCreateJob.isManualJobRunning(context)) {
 | 
			
		||||
                            try {
 | 
			
		||||
                                chooseBackupDir.launch(BackupCreator.getFilename())
 | 
			
		||||
                            } catch (e: ActivityNotFoundException) {
 | 
			
		||||
                                context.toast(MR.strings.file_picker_error)
 | 
			
		||||
                            }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            context.toast(MR.strings.backup_in_progress)
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                ) {
 | 
			
		||||
                    Text(
 | 
			
		||||
                        text = stringResource(MR.strings.action_create),
 | 
			
		||||
                        color = MaterialTheme.colorScheme.onPrimary,
 | 
			
		||||
                    )
 | 
			
		||||
                item {
 | 
			
		||||
                    SectionCard(MR.strings.label_settings) {
 | 
			
		||||
                        Options(BackupOptions.settingsOptions, state, model)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -144,7 +115,6 @@ class CreateBackupScreen : Screen() {
 | 
			
		||||
                    model.toggle(option.setter, it)
 | 
			
		||||
                },
 | 
			
		||||
                enabled = option.enabled(state.options),
 | 
			
		||||
                modifier = Modifier.padding(horizontal = MaterialTheme.padding.medium),
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -4,14 +4,9 @@ import android.content.Context
 | 
			
		||||
import android.net.Uri
 | 
			
		||||
import androidx.compose.foundation.layout.Arrangement
 | 
			
		||||
import androidx.compose.foundation.layout.Column
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxSize
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxWidth
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.foundation.lazy.LazyColumn
 | 
			
		||||
import androidx.compose.foundation.lazy.LazyListScope
 | 
			
		||||
import androidx.compose.foundation.text.selection.SelectionContainer
 | 
			
		||||
import androidx.compose.material3.Button
 | 
			
		||||
import androidx.compose.material3.HorizontalDivider
 | 
			
		||||
import androidx.compose.material3.MaterialTheme
 | 
			
		||||
import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
@@ -24,7 +19,6 @@ import androidx.compose.ui.text.SpanStyle
 | 
			
		||||
import androidx.compose.ui.text.buildAnnotatedString
 | 
			
		||||
import androidx.compose.ui.text.font.FontWeight
 | 
			
		||||
import androidx.compose.ui.text.withStyle
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import androidx.core.net.toUri
 | 
			
		||||
import cafe.adriel.voyager.core.model.StateScreenModel
 | 
			
		||||
import cafe.adriel.voyager.core.model.rememberScreenModel
 | 
			
		||||
@@ -41,6 +35,7 @@ import kotlinx.coroutines.flow.update
 | 
			
		||||
import tachiyomi.core.util.lang.anyEnabled
 | 
			
		||||
import tachiyomi.i18n.MR
 | 
			
		||||
import tachiyomi.presentation.core.components.LabeledCheckbox
 | 
			
		||||
import tachiyomi.presentation.core.components.LazyColumnWithAction
 | 
			
		||||
import tachiyomi.presentation.core.components.SectionCard
 | 
			
		||||
import tachiyomi.presentation.core.components.material.Scaffold
 | 
			
		||||
import tachiyomi.presentation.core.components.material.padding
 | 
			
		||||
@@ -66,58 +61,39 @@ class RestoreBackupScreen(
 | 
			
		||||
                )
 | 
			
		||||
            },
 | 
			
		||||
        ) { contentPadding ->
 | 
			
		||||
            Column(
 | 
			
		||||
                modifier = Modifier
 | 
			
		||||
                    .padding(contentPadding)
 | 
			
		||||
                    .fillMaxSize(),
 | 
			
		||||
            LazyColumnWithAction(
 | 
			
		||||
                contentPadding = contentPadding,
 | 
			
		||||
                actionLabel = stringResource(MR.strings.action_restore),
 | 
			
		||||
                actionEnabled = state.canRestore && state.options.anyEnabled(),
 | 
			
		||||
                onClickAction = {
 | 
			
		||||
                    model.startRestore()
 | 
			
		||||
                    navigator.pop()
 | 
			
		||||
                },
 | 
			
		||||
            ) {
 | 
			
		||||
                LazyColumn(
 | 
			
		||||
                    modifier = Modifier.weight(1f),
 | 
			
		||||
                ) {
 | 
			
		||||
                    if (DeviceUtil.isMiui && DeviceUtil.isMiuiOptimizationDisabled()) {
 | 
			
		||||
                        item {
 | 
			
		||||
                            WarningBanner(MR.strings.restore_miui_warning)
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (state.canRestore) {
 | 
			
		||||
                        item {
 | 
			
		||||
                            SectionCard {
 | 
			
		||||
                                RestoreOptions.options.forEach { option ->
 | 
			
		||||
                                    LabeledCheckbox(
 | 
			
		||||
                                        label = stringResource(option.label),
 | 
			
		||||
                                        checked = option.getter(state.options),
 | 
			
		||||
                                        onCheckedChange = {
 | 
			
		||||
                                            model.toggle(option.setter, it)
 | 
			
		||||
                                        },
 | 
			
		||||
                                        modifier = Modifier.padding(horizontal = MaterialTheme.padding.medium),
 | 
			
		||||
                                    )
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (state.error != null) {
 | 
			
		||||
                        errorMessageItem(state.error)
 | 
			
		||||
                if (DeviceUtil.isMiui && DeviceUtil.isMiuiOptimizationDisabled()) {
 | 
			
		||||
                    item {
 | 
			
		||||
                        WarningBanner(MR.strings.restore_miui_warning)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                HorizontalDivider()
 | 
			
		||||
                if (state.canRestore) {
 | 
			
		||||
                    item {
 | 
			
		||||
                        SectionCard {
 | 
			
		||||
                            RestoreOptions.options.forEach { option ->
 | 
			
		||||
                                LabeledCheckbox(
 | 
			
		||||
                                    label = stringResource(option.label),
 | 
			
		||||
                                    checked = option.getter(state.options),
 | 
			
		||||
                                    onCheckedChange = {
 | 
			
		||||
                                        model.toggle(option.setter, it)
 | 
			
		||||
                                    },
 | 
			
		||||
                                )
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                Button(
 | 
			
		||||
                    modifier = Modifier
 | 
			
		||||
                        .padding(horizontal = 16.dp, vertical = 8.dp)
 | 
			
		||||
                        .fillMaxWidth(),
 | 
			
		||||
                    enabled = state.canRestore && state.options.anyEnabled(),
 | 
			
		||||
                    onClick = {
 | 
			
		||||
                        model.startRestore()
 | 
			
		||||
                        navigator.pop()
 | 
			
		||||
                    },
 | 
			
		||||
                ) {
 | 
			
		||||
                    Text(
 | 
			
		||||
                        text = stringResource(MR.strings.action_restore),
 | 
			
		||||
                        color = MaterialTheme.colorScheme.onPrimary,
 | 
			
		||||
                    )
 | 
			
		||||
                if (state.error != null) {
 | 
			
		||||
                    errorMessageItem(state.error)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,52 @@
 | 
			
		||||
package tachiyomi.presentation.core.components
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.layout.Column
 | 
			
		||||
import androidx.compose.foundation.layout.PaddingValues
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxSize
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxWidth
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.foundation.lazy.LazyColumn
 | 
			
		||||
import androidx.compose.foundation.lazy.LazyListScope
 | 
			
		||||
import androidx.compose.material3.Button
 | 
			
		||||
import androidx.compose.material3.HorizontalDivider
 | 
			
		||||
import androidx.compose.material3.MaterialTheme
 | 
			
		||||
import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun LazyColumnWithAction(
 | 
			
		||||
    contentPadding: PaddingValues,
 | 
			
		||||
    actionLabel: String,
 | 
			
		||||
    onClickAction: () -> Unit,
 | 
			
		||||
    modifier: Modifier = Modifier,
 | 
			
		||||
    actionEnabled: Boolean = true,
 | 
			
		||||
    content: LazyListScope.() -> Unit,
 | 
			
		||||
) {
 | 
			
		||||
    Column(
 | 
			
		||||
        modifier = modifier
 | 
			
		||||
            .padding(contentPadding)
 | 
			
		||||
            .fillMaxSize(),
 | 
			
		||||
    ) {
 | 
			
		||||
        LazyColumn(
 | 
			
		||||
            modifier = Modifier.weight(1f),
 | 
			
		||||
            content = content,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        HorizontalDivider()
 | 
			
		||||
 | 
			
		||||
        Button(
 | 
			
		||||
            modifier = Modifier
 | 
			
		||||
                .padding(horizontal = 16.dp, vertical = 8.dp)
 | 
			
		||||
                .fillMaxWidth(),
 | 
			
		||||
            enabled = actionEnabled,
 | 
			
		||||
            onClick = onClickAction,
 | 
			
		||||
        ) {
 | 
			
		||||
            Text(
 | 
			
		||||
                text = actionLabel,
 | 
			
		||||
                color = MaterialTheme.colorScheme.onPrimary,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package tachiyomi.presentation.core.components
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.layout.Column
 | 
			
		||||
import androidx.compose.foundation.layout.ColumnScope
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxWidth
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.foundation.lazy.LazyItemScope
 | 
			
		||||
@@ -16,7 +17,7 @@ import tachiyomi.presentation.core.i18n.stringResource
 | 
			
		||||
@Composable
 | 
			
		||||
fun LazyItemScope.SectionCard(
 | 
			
		||||
    titleRes: StringResource? = null,
 | 
			
		||||
    content: @Composable () -> Unit,
 | 
			
		||||
    content: @Composable ColumnScope.() -> Unit,
 | 
			
		||||
) {
 | 
			
		||||
    if (titleRes != null) {
 | 
			
		||||
        Text(
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user