Consistent labeled checkbox composable

(cherry picked from commit c53172265b4dfba380a096c8d9107358515bf0e1)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateDialog.kt
This commit is contained in:
arkon 2023-10-21 09:42:12 -04:00 committed by Jobobby04
parent 19e37454c6
commit ada9239c11
11 changed files with 186 additions and 304 deletions

View File

@ -3,7 +3,6 @@ package eu.kanade.presentation.browse
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
@ -13,7 +12,6 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.PushPin import androidx.compose.material.icons.filled.PushPin
import androidx.compose.material.icons.outlined.PushPin import androidx.compose.material.icons.outlined.PushPin
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Checkbox
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.LocalTextStyle
@ -23,7 +21,6 @@ import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@ -35,6 +32,7 @@ import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreenModel.Listi
import eu.kanade.tachiyomi.util.system.LocaleHelper import eu.kanade.tachiyomi.util.system.LocaleHelper
import tachiyomi.domain.source.model.Pin import tachiyomi.domain.source.model.Pin
import tachiyomi.domain.source.model.Source import tachiyomi.domain.source.model.Source
import tachiyomi.presentation.core.components.LabeledCheckbox
import tachiyomi.presentation.core.components.ScrollbarLazyColumn import tachiyomi.presentation.core.components.ScrollbarLazyColumn
import tachiyomi.presentation.core.components.material.SecondaryItemAlpha import tachiyomi.presentation.core.components.material.SecondaryItemAlpha
import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.components.material.padding
@ -273,29 +271,18 @@ fun SourceCategoriesDialog(
}, },
text = { text = {
Column(Modifier.verticalScroll(rememberScrollState())) { Column(Modifier.verticalScroll(rememberScrollState())) {
categories.forEach { categories.forEach { category ->
Row( LabeledCheckbox(
modifier = Modifier label = category,
.fillMaxWidth() checked = category in newCategories,
.clickable { onCheckedChange = {
if (it in newCategories) { if (it) {
newCategories -= it newCategories += category
} else { } else {
newCategories += it newCategories -= category
} }
}, },
verticalAlignment = Alignment.CenterVertically,
) {
Checkbox(
checked = it in newCategories,
onCheckedChange = null,
) )
Text(
text = it,
modifier = Modifier.padding(horizontal = MaterialTheme.padding.medium),
)
}
} }
} }
}, },

View File

@ -1,12 +1,8 @@
package eu.kanade.presentation.history.components package eu.kanade.presentation.history.components
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.selection.toggleable
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Checkbox
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -14,12 +10,11 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import tachiyomi.presentation.core.components.LabeledCheckbox
import tachiyomi.presentation.core.util.ThemePreviews import tachiyomi.presentation.core.util.ThemePreviews
@Composable @Composable
@ -34,28 +29,16 @@ fun HistoryDeleteDialog(
Text(text = stringResource(R.string.action_remove)) Text(text = stringResource(R.string.action_remove))
}, },
text = { text = {
Column { Column(
Text(text = stringResource(R.string.dialog_with_checkbox_remove_description)) verticalArrangement = Arrangement.spacedBy(8.dp),
Row(
modifier = Modifier
.padding(top = 16.dp)
.toggleable(
interactionSource = remember { MutableInteractionSource() },
indication = null,
value = removeEverything,
onValueChange = { removeEverything = it },
),
verticalAlignment = Alignment.CenterVertically,
) { ) {
Checkbox( Text(text = stringResource(R.string.dialog_with_checkbox_remove_description))
LabeledCheckbox(
label = stringResource(R.string.dialog_with_checkbox_reset),
checked = removeEverything, checked = removeEverything,
onCheckedChange = null, onCheckedChange = { removeEverything = it },
) )
Text(
modifier = Modifier.padding(start = 4.dp),
text = stringResource(R.string.dialog_with_checkbox_reset),
)
}
} }
}, },
onDismissRequest = onDismissRequest, onDismissRequest = onDismissRequest,

View File

@ -1,11 +1,7 @@
package eu.kanade.presentation.library package eu.kanade.presentation.library
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Checkbox
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -13,11 +9,10 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import tachiyomi.core.preference.CheckboxState import tachiyomi.core.preference.CheckboxState
import tachiyomi.presentation.core.components.LabeledCheckbox
@Composable @Composable
fun DeleteLibraryMangaDialog( fun DeleteLibraryMangaDialog(
@ -62,27 +57,18 @@ fun DeleteLibraryMangaDialog(
text = { text = {
Column { Column {
list.forEach { state -> list.forEach { state ->
val onCheck = { LabeledCheckbox(
label = stringResource(state.value),
checked = state.isChecked,
onCheckedChange = {
val index = list.indexOf(state) val index = list.indexOf(state)
if (index != -1) { if (index != -1) {
val mutableList = list.toMutableList() val mutableList = list.toMutableList()
mutableList[index] = state.next() as CheckboxState.State<Int> mutableList[index] = state.next() as CheckboxState.State<Int>
list = mutableList.toList() list = mutableList.toList()
} }
} },
Row(
modifier = Modifier
.fillMaxWidth()
.clickable { onCheck() },
verticalAlignment = Alignment.CenterVertically,
) {
Checkbox(
checked = state.isChecked,
onCheckedChange = { onCheck() },
) )
Text(text = stringResource(state.value))
}
} }
} }
}, },

View File

@ -12,7 +12,6 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.PeopleAlt import androidx.compose.material.icons.outlined.PeopleAlt
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Checkbox
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
@ -34,6 +33,7 @@ import eu.kanade.presentation.components.TabbedDialogPaddings
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import tachiyomi.core.preference.TriState import tachiyomi.core.preference.TriState
import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.manga.model.Manga
import tachiyomi.presentation.core.components.LabeledCheckbox
import tachiyomi.presentation.core.components.RadioItem import tachiyomi.presentation.core.components.RadioItem
import tachiyomi.presentation.core.components.SortItem import tachiyomi.presentation.core.components.SortItem
import tachiyomi.presentation.core.components.TriStateItem import tachiyomi.presentation.core.components.TriStateItem
@ -215,6 +215,7 @@ private fun SetAsDefaultDialog(
onConfirmed: (optionalChecked: Boolean) -> Unit, onConfirmed: (optionalChecked: Boolean) -> Unit,
) { ) {
var optionalChecked by rememberSaveable { mutableStateOf(false) } var optionalChecked by rememberSaveable { mutableStateOf(false) }
AlertDialog( AlertDialog(
onDismissRequest = onDismissRequest, onDismissRequest = onDismissRequest,
title = { Text(text = stringResource(R.string.chapter_settings)) }, title = { Text(text = stringResource(R.string.chapter_settings)) },
@ -224,20 +225,11 @@ private fun SetAsDefaultDialog(
) { ) {
Text(text = stringResource(R.string.confirm_set_chapter_settings)) Text(text = stringResource(R.string.confirm_set_chapter_settings))
Row( LabeledCheckbox(
modifier = Modifier label = stringResource(R.string.also_set_chapter_settings_for_library),
.clickable { optionalChecked = !optionalChecked }
.padding(vertical = 8.dp)
.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Checkbox(
checked = optionalChecked, checked = optionalChecked,
onCheckedChange = null, onCheckedChange = { optionalChecked = it },
) )
Text(text = stringResource(R.string.also_set_chapter_settings_for_library))
}
} }
}, },
dismissButton = { dismissButton = {

View File

@ -1,17 +1,11 @@
package eu.kanade.presentation.manga.components package eu.kanade.presentation.manga.components
import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.selection.selectable
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Checkbox
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.minimumInteractiveComponentSize
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
@ -21,13 +15,13 @@ import androidx.compose.runtime.setValue
import androidx.compose.runtime.toMutableStateList import androidx.compose.runtime.toMutableStateList
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties import androidx.compose.ui.window.DialogProperties
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import tachiyomi.domain.manga.interactor.FetchInterval import tachiyomi.domain.manga.interactor.FetchInterval
import tachiyomi.presentation.core.components.LabeledCheckbox
import tachiyomi.presentation.core.components.WheelTextPicker import tachiyomi.presentation.core.components.WheelTextPicker
@Composable @Composable
@ -128,33 +122,16 @@ fun SelectScanlatorsDialog(
availableScanlators.forEach { current -> availableScanlators.forEach { current ->
item { item {
val isSelected = selected.contains(current) val isSelected = selected.contains(current)
val onSelectionChanged = { LabeledCheckbox(
when (!isSelected) { label = current,
checked = isSelected,
onCheckedChange = {
when (it) {
true -> selected.add(current) true -> selected.add(current)
false -> selected.remove(current) false -> selected.remove(current)
} }
} },
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.clip(MaterialTheme.shapes.small)
.selectable(
selected = isSelected,
onClick = { onSelectionChanged() },
) )
.minimumInteractiveComponentSize()
.fillMaxWidth(),
) {
Checkbox(
checked = isSelected,
onCheckedChange = null,
)
Text(
text = current,
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(start = 24.dp),
)
}
} }
} }
} }

View File

@ -9,14 +9,8 @@ import android.webkit.WebStorage
import android.webkit.WebView import android.webkit.WebView
import android.widget.Toast import android.widget.Toast
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Checkbox
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -29,12 +23,9 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.runtime.toMutableStateList import androidx.compose.runtime.toMutableStateList
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties import androidx.compose.ui.window.DialogProperties
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.core.text.HtmlCompat import androidx.core.text.HtmlCompat
@ -95,6 +86,7 @@ import tachiyomi.domain.library.service.LibraryPreferences
import tachiyomi.domain.manga.interactor.GetAllManga import tachiyomi.domain.manga.interactor.GetAllManga
import tachiyomi.domain.manga.repository.MangaRepository import tachiyomi.domain.manga.repository.MangaRepository
import tachiyomi.domain.source.service.SourceManager import tachiyomi.domain.source.service.SourceManager
import tachiyomi.presentation.core.components.LabeledCheckbox
import tachiyomi.presentation.core.util.collectAsState import tachiyomi.presentation.core.util.collectAsState
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
@ -499,29 +491,16 @@ object SettingsAdvancedScreen : SearchableSettings {
LazyColumn { LazyColumn {
options.forEachIndexed { index, option -> options.forEachIndexed { index, option ->
item { item {
val isSelected = index == 0 || selection.contains(option) LabeledCheckbox(
val onSelectionChanged = { label = option,
when (!isSelected) { checked = index == 0 || selection.contains(option),
onCheckedChange = {
when (it) {
true -> selection.add(option) true -> selection.add(option)
false -> selection.remove(option) false -> selection.remove(option)
} }
} },
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clickable { onSelectionChanged() },
) {
Checkbox(
checked = isSelected,
onCheckedChange = { onSelectionChanged() },
) )
Text(
text = option,
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(start = 12.dp),
)
}
} }
} }
} }

View File

@ -8,20 +8,13 @@ import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Checkbox
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -38,7 +31,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.core.net.toUri import androidx.core.net.toUri
import com.hippo.unifile.UniFile import com.hippo.unifile.UniFile
import eu.kanade.presentation.extensions.RequestStoragePermission import eu.kanade.presentation.extensions.RequestStoragePermission
@ -55,6 +47,7 @@ import eu.kanade.tachiyomi.util.system.copyToClipboard
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import tachiyomi.domain.backup.service.BackupPreferences import tachiyomi.domain.backup.service.BackupPreferences
import tachiyomi.presentation.core.components.LabeledCheckbox
import tachiyomi.presentation.core.components.ScrollbarLazyColumn import tachiyomi.presentation.core.components.ScrollbarLazyColumn
import tachiyomi.presentation.core.util.collectAsState import tachiyomi.presentation.core.util.collectAsState
import tachiyomi.presentation.core.util.isScrolledToEnd import tachiyomi.presentation.core.util.isScrolledToEnd
@ -164,22 +157,23 @@ object SettingsBackupScreen : SearchableSettings {
val state = rememberLazyListState() val state = rememberLazyListState()
ScrollbarLazyColumn(state = state) { ScrollbarLazyColumn(state = state) {
item { item {
CreateBackupDialogItem( LabeledCheckbox(
isSelected = true, label = stringResource(R.string.manga),
title = stringResource(R.string.manga), checked = true,
onCheckedChange = {},
) )
} }
choices.forEach { (k, v) -> choices.forEach { (k, v) ->
item { item {
val isSelected = flags.contains(k) val isSelected = flags.contains(k)
CreateBackupDialogItem( LabeledCheckbox(
isSelected = isSelected, label = stringResource(v),
title = stringResource(v), checked = isSelected,
modifier = Modifier.clickable { onCheckedChange = {
if (isSelected) { if (it) {
flags.remove(k)
} else {
flags.add(k) flags.add(k)
} else {
flags.remove(k)
} }
}, },
) )
@ -208,29 +202,6 @@ object SettingsBackupScreen : SearchableSettings {
) )
} }
@Composable
private fun CreateBackupDialogItem(
modifier: Modifier = Modifier,
isSelected: Boolean,
title: String,
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = modifier.fillMaxWidth(),
) {
Checkbox(
modifier = Modifier.heightIn(min = 48.dp),
checked = isSelected,
onCheckedChange = null,
)
Text(
text = title,
style = MaterialTheme.typography.bodyMedium.merge(),
modifier = Modifier.padding(start = 24.dp),
)
}
}
@Composable @Composable
private fun getRestoreBackupPref(): Preference.PreferenceItem.TextPreference { private fun getRestoreBackupPref(): Preference.PreferenceItem.TextPreference {
val context = LocalContext.current val context = LocalContext.current

View File

@ -1,7 +1,6 @@
package eu.kanade.presentation.more.settings.screen.advanced package eu.kanade.presentation.more.settings.screen.advanced
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
@ -54,6 +53,7 @@ import tachiyomi.data.Database
import tachiyomi.domain.source.interactor.GetSourcesWithNonLibraryManga import tachiyomi.domain.source.interactor.GetSourcesWithNonLibraryManga
import tachiyomi.domain.source.model.Source import tachiyomi.domain.source.model.Source
import tachiyomi.domain.source.model.SourceWithCount import tachiyomi.domain.source.model.SourceWithCount
import tachiyomi.presentation.core.components.LabeledCheckbox
import tachiyomi.presentation.core.components.material.Scaffold import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.screens.EmptyScreen import tachiyomi.presentation.core.screens.EmptyScreen
import tachiyomi.presentation.core.screens.LoadingScreen import tachiyomi.presentation.core.screens.LoadingScreen
@ -107,21 +107,12 @@ class ClearDatabaseScreen : Screen() {
// SY <-- // SY <--
Text(text = stringResource(R.string.clear_database_confirmation)) Text(text = stringResource(R.string.clear_database_confirmation))
// SY --> // SY -->
Row( LabeledCheckbox(
Modifier label = stringResource(R.string.clear_db_exclude_read),
.fillMaxWidth()
.height(56.dp)
.clickable(onClick = { keepReadManga = !keepReadManga }),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) {
Text(stringResource(R.string.clear_db_exclude_read))
Checkbox(
checked = keepReadManga, checked = keepReadManga,
onCheckedChange = null, onCheckedChange = { keepReadManga = it },
) )
} }
}
// SY <-- // SY <--
}, },
) )

View File

@ -1,30 +1,20 @@
package eu.kanade.presentation.more.settings.widget package eu.kanade.presentation.more.settings.widget
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.selection.selectable
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Checkbox
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.minimumInteractiveComponentSize
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.runtime.toMutableStateList import androidx.compose.runtime.toMutableStateList
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties import androidx.compose.ui.window.DialogProperties
import eu.kanade.presentation.more.settings.Preference import eu.kanade.presentation.more.settings.Preference
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import tachiyomi.presentation.core.components.LabeledCheckbox
@Composable @Composable
fun MultiSelectListPreferenceWidget( fun MultiSelectListPreferenceWidget(
@ -55,33 +45,17 @@ fun MultiSelectListPreferenceWidget(
preference.entries.forEach { current -> preference.entries.forEach { current ->
item { item {
val isSelected = selected.contains(current.key) val isSelected = selected.contains(current.key)
val onSelectionChanged = { LabeledCheckbox(
when (!isSelected) { label = current.value,
true -> selected.add(current.key)
false -> selected.remove(current.key)
}
}
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.clip(MaterialTheme.shapes.small)
.selectable(
selected = isSelected,
onClick = { onSelectionChanged() },
)
.minimumInteractiveComponentSize()
.fillMaxWidth(),
) {
Checkbox(
checked = isSelected, checked = isSelected,
onCheckedChange = null, onCheckedChange = {
) if (it) {
Text( selected.add(current.key)
text = current.value, } else {
style = MaterialTheme.typography.bodyMedium, selected.remove(current.key)
modifier = Modifier.padding(start = 24.dp),
)
} }
},
)
} }
} }
} }

View File

@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.ui.manga.track
import android.app.Application import android.app.Application
import android.content.Context import android.content.Context
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
@ -13,7 +12,6 @@ import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Delete
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Checkbox
import androidx.compose.material3.FilledTonalButton import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
@ -33,6 +31,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.core.model.ScreenModel import cafe.adriel.voyager.core.model.ScreenModel
import cafe.adriel.voyager.core.model.StateScreenModel import cafe.adriel.voyager.core.model.StateScreenModel
import cafe.adriel.voyager.core.model.coroutineScope import cafe.adriel.voyager.core.model.coroutineScope
@ -75,6 +74,7 @@ import tachiyomi.domain.source.service.SourceManager
import tachiyomi.domain.track.interactor.DeleteTrack import tachiyomi.domain.track.interactor.DeleteTrack
import tachiyomi.domain.track.interactor.GetTracks import tachiyomi.domain.track.interactor.GetTracks
import tachiyomi.domain.track.model.Track import tachiyomi.domain.track.model.Track
import tachiyomi.presentation.core.components.LabeledCheckbox
import tachiyomi.presentation.core.components.material.AlertDialogContent import tachiyomi.presentation.core.components.material.AlertDialogContent
import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.components.material.padding
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
@ -94,10 +94,10 @@ data class TrackInfoDialogHomeScreen(
override fun Content() { override fun Content() {
val navigator = LocalNavigator.currentOrThrow val navigator = LocalNavigator.currentOrThrow
val context = LocalContext.current val context = LocalContext.current
val sm = rememberScreenModel { Model(mangaId, sourceId) } val screenModel = rememberScreenModel { Model(mangaId, sourceId) }
val dateFormat = remember { UiPreferences.dateFormat(Injekt.get<UiPreferences>().dateFormat().get()) } val dateFormat = remember { UiPreferences.dateFormat(Injekt.get<UiPreferences>().dateFormat().get()) }
val state by sm.state.collectAsState() val state by screenModel.state.collectAsState()
TrackInfoDialogHome( TrackInfoDialogHome(
trackItems = state.trackItems, trackItems = state.trackItems,
@ -146,7 +146,7 @@ data class TrackInfoDialogHomeScreen(
}, },
onNewSearch = { onNewSearch = {
if (it.tracker is EnhancedTracker) { if (it.tracker is EnhancedTracker) {
sm.registerEnhancedTracking(it) screenModel.registerEnhancedTracking(it)
} else { } else {
navigator.push( navigator.push(
TrackerSearchScreen( TrackerSearchScreen(
@ -261,19 +261,19 @@ private data class TrackStatusSelectorScreen(
@Composable @Composable
override fun Content() { override fun Content() {
val navigator = LocalNavigator.currentOrThrow val navigator = LocalNavigator.currentOrThrow
val sm = rememberScreenModel { val screenModel = rememberScreenModel {
Model( Model(
track = track, track = track,
tracker = Injekt.get<TrackerManager>().get(serviceId)!!, tracker = Injekt.get<TrackerManager>().get(serviceId)!!,
) )
} }
val state by sm.state.collectAsState() val state by screenModel.state.collectAsState()
TrackStatusSelector( TrackStatusSelector(
selection = state.selection, selection = state.selection,
onSelectionChange = sm::setSelection, onSelectionChange = screenModel::setSelection,
selections = remember { sm.getSelections() }, selections = remember { screenModel.getSelections() },
onConfirm = { onConfirm = {
sm.setStatus() screenModel.setStatus()
navigator.pop() navigator.pop()
}, },
onDismissRequest = navigator::pop, onDismissRequest = navigator::pop,
@ -314,20 +314,20 @@ private data class TrackChapterSelectorScreen(
@Composable @Composable
override fun Content() { override fun Content() {
val navigator = LocalNavigator.currentOrThrow val navigator = LocalNavigator.currentOrThrow
val sm = rememberScreenModel { val screenModel = rememberScreenModel {
Model( Model(
track = track, track = track,
tracker = Injekt.get<TrackerManager>().get(serviceId)!!, tracker = Injekt.get<TrackerManager>().get(serviceId)!!,
) )
} }
val state by sm.state.collectAsState() val state by screenModel.state.collectAsState()
TrackChapterSelector( TrackChapterSelector(
selection = state.selection, selection = state.selection,
onSelectionChange = sm::setSelection, onSelectionChange = screenModel::setSelection,
range = remember { sm.getRange() }, range = remember { screenModel.getRange() },
onConfirm = { onConfirm = {
sm.setChapter() screenModel.setChapter()
navigator.pop() navigator.pop()
}, },
onDismissRequest = navigator::pop, onDismissRequest = navigator::pop,
@ -373,20 +373,20 @@ private data class TrackScoreSelectorScreen(
@Composable @Composable
override fun Content() { override fun Content() {
val navigator = LocalNavigator.currentOrThrow val navigator = LocalNavigator.currentOrThrow
val sm = rememberScreenModel { val screenModel = rememberScreenModel {
Model( Model(
track = track, track = track,
tracker = Injekt.get<TrackerManager>().get(serviceId)!!, tracker = Injekt.get<TrackerManager>().get(serviceId)!!,
) )
} }
val state by sm.state.collectAsState() val state by screenModel.state.collectAsState()
TrackScoreSelector( TrackScoreSelector(
selection = state.selection, selection = state.selection,
onSelectionChange = sm::setSelection, onSelectionChange = screenModel::setSelection,
selections = remember { sm.getSelections() }, selections = remember { screenModel.getSelections() },
onConfirm = { onConfirm = {
sm.setScore() screenModel.setScore()
navigator.pop() navigator.pop()
}, },
onDismissRequest = navigator::pop, onDismissRequest = navigator::pop,
@ -484,7 +484,7 @@ private data class TrackDateSelectorScreen(
@Composable @Composable
override fun Content() { override fun Content() {
val navigator = LocalNavigator.currentOrThrow val navigator = LocalNavigator.currentOrThrow
val sm = rememberScreenModel { val screenModel = rememberScreenModel {
Model( Model(
track = track, track = track,
tracker = Injekt.get<TrackerManager>().get(serviceId)!!, tracker = Injekt.get<TrackerManager>().get(serviceId)!!,
@ -503,13 +503,13 @@ private data class TrackDateSelectorScreen(
} else { } else {
stringResource(R.string.track_finished_reading_date) stringResource(R.string.track_finished_reading_date)
}, },
initialSelectedDateMillis = sm.initialSelection, initialSelectedDateMillis = screenModel.initialSelection,
selectableDates = selectableDates, selectableDates = selectableDates,
onConfirm = { onConfirm = {
sm.setDate(it) screenModel.setDate(it)
navigator.pop() navigator.pop()
}, },
onRemove = { sm.confirmRemoveDate(navigator) }.takeIf { canRemove }, onRemove = { screenModel.confirmRemoveDate(navigator) }.takeIf { canRemove },
onDismissRequest = navigator::pop, onDismissRequest = navigator::pop,
) )
} }
@ -557,7 +557,7 @@ private data class TrackDateRemoverScreen(
@Composable @Composable
override fun Content() { override fun Content() {
val navigator = LocalNavigator.currentOrThrow val navigator = LocalNavigator.currentOrThrow
val sm = rememberScreenModel { val screenModel = rememberScreenModel {
Model( Model(
track = track, track = track,
tracker = Injekt.get<TrackerManager>().get(serviceId)!!, tracker = Injekt.get<TrackerManager>().get(serviceId)!!,
@ -579,7 +579,7 @@ private data class TrackDateRemoverScreen(
) )
}, },
text = { text = {
val serviceName = sm.getServiceName() val serviceName = screenModel.getServiceName()
Text( Text(
text = if (start) { text = if (start) {
stringResource(R.string.track_remove_start_date_conf_text, serviceName) stringResource(R.string.track_remove_start_date_conf_text, serviceName)
@ -598,7 +598,7 @@ private data class TrackDateRemoverScreen(
} }
FilledTonalButton( FilledTonalButton(
onClick = { onClick = {
sm.removeDate() screenModel.removeDate()
navigator.popUntil { it is TrackInfoDialogHomeScreen } navigator.popUntil { it is TrackInfoDialogHomeScreen }
}, },
colors = ButtonDefaults.filledTonalButtonColors( colors = ButtonDefaults.filledTonalButtonColors(
@ -643,7 +643,7 @@ data class TrackerSearchScreen(
@Composable @Composable
override fun Content() { override fun Content() {
val navigator = LocalNavigator.currentOrThrow val navigator = LocalNavigator.currentOrThrow
val sm = rememberScreenModel { val screenModel = rememberScreenModel {
Model( Model(
mangaId = mangaId, mangaId = mangaId,
currentUrl = currentUrl, currentUrl = currentUrl,
@ -652,18 +652,18 @@ data class TrackerSearchScreen(
) )
} }
val state by sm.state.collectAsState() val state by screenModel.state.collectAsState()
var textFieldValue by remember { mutableStateOf(TextFieldValue(initialQuery)) } var textFieldValue by remember { mutableStateOf(TextFieldValue(initialQuery)) }
TrackerSearch( TrackerSearch(
query = textFieldValue, query = textFieldValue,
onQueryChange = { textFieldValue = it }, onQueryChange = { textFieldValue = it },
onDispatchQuery = { sm.trackingSearch(textFieldValue.text) }, onDispatchQuery = { screenModel.trackingSearch(textFieldValue.text) },
queryResult = state.queryResult, queryResult = state.queryResult,
selected = state.selected, selected = state.selected,
onSelectedChange = sm::updateSelection, onSelectedChange = screenModel::updateSelection,
onConfirmSelection = { onConfirmSelection = {
sm.registerTracking(state.selected!!) screenModel.registerTracking(state.selected!!)
navigator.pop() navigator.pop()
}, },
onDismissRequest = navigator::pop, onDismissRequest = navigator::pop,
@ -731,14 +731,14 @@ private data class TrackerRemoveScreen(
@Composable @Composable
override fun Content() { override fun Content() {
val navigator = LocalNavigator.currentOrThrow val navigator = LocalNavigator.currentOrThrow
val sm = rememberScreenModel { val screenModel = rememberScreenModel {
Model( Model(
mangaId = mangaId, mangaId = mangaId,
track = track, track = track,
tracker = Injekt.get<TrackerManager>().get(serviceId)!!, tracker = Injekt.get<TrackerManager>().get(serviceId)!!,
) )
} }
val serviceName = sm.getName() val serviceName = screenModel.getName()
var removeRemoteTrack by remember { mutableStateOf(false) } var removeRemoteTrack by remember { mutableStateOf(false) }
AlertDialogContent( AlertDialogContent(
modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars), modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars),
@ -755,21 +755,19 @@ private data class TrackerRemoveScreen(
) )
}, },
text = { text = {
Column { Column(
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
Text( Text(
text = stringResource(R.string.track_delete_text, serviceName), text = stringResource(R.string.track_delete_text, serviceName),
) )
if (sm.isDeletable()) {
val onChange = { removeRemoteTrack = !removeRemoteTrack } if (screenModel.isDeletable()) {
Row( LabeledCheckbox(
modifier = Modifier label = stringResource(R.string.track_delete_remote_text, serviceName),
.fillMaxWidth() checked = removeRemoteTrack,
.clickable(onClick = onChange), onCheckedChange = { removeRemoteTrack = it },
verticalAlignment = Alignment.CenterVertically, )
) {
Checkbox(checked = removeRemoteTrack, onCheckedChange = { onChange() })
Text(text = stringResource(R.string.track_delete_remote_text, serviceName))
}
} }
} }
}, },
@ -786,8 +784,8 @@ private data class TrackerRemoveScreen(
} }
FilledTonalButton( FilledTonalButton(
onClick = { onClick = {
sm.unregisterTracking(serviceId) screenModel.unregisterTracking(serviceId)
if (removeRemoteTrack) sm.deleteMangaFromService() if (removeRemoteTrack) screenModel.deleteMangaFromService()
navigator.pop() navigator.pop()
}, },
colors = ButtonDefaults.filledTonalButtonColors( colors = ButtonDefaults.filledTonalButtonColors(

View File

@ -0,0 +1,44 @@
package tachiyomi.presentation.core.components
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.material3.Checkbox
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.dp
@Composable
fun LabeledCheckbox(
modifier: Modifier = Modifier,
label: String,
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
) {
Row(
modifier = modifier
.clip(MaterialTheme.shapes.small)
.fillMaxWidth()
.heightIn(min = 48.dp)
.clickable(
role = Role.Checkbox,
onClick = { onCheckedChange(!checked) },
),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp),
) {
Checkbox(
checked = checked,
onCheckedChange = null,
)
Text(text = label)
}
}