Consistent labeled checkbox composable

This commit is contained in:
arkon 2023-10-21 09:42:12 -04:00
parent 8626a55fe4
commit c53172265b
8 changed files with 151 additions and 216 deletions

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(
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
Text(text = stringResource(R.string.dialog_with_checkbox_remove_description)) Text(text = stringResource(R.string.dialog_with_checkbox_remove_description))
Row(
modifier = Modifier LabeledCheckbox(
.padding(top = 16.dp) label = stringResource(R.string.dialog_with_checkbox_reset),
.toggleable( checked = removeEverything,
interactionSource = remember { MutableInteractionSource() }, onCheckedChange = { removeEverything = it },
indication = null, )
value = removeEverything,
onValueChange = { removeEverything = it },
),
verticalAlignment = Alignment.CenterVertically,
) {
Checkbox(
checked = removeEverything,
onCheckedChange = null,
)
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(
val index = list.indexOf(state) label = stringResource(state.value),
if (index != -1) { checked = state.isChecked,
val mutableList = list.toMutableList() onCheckedChange = {
mutableList[index] = state.next() as CheckboxState.State<Int> val index = list.indexOf(state)
list = mutableList.toList() if (index != -1) {
} val mutableList = list.toMutableList()
} mutableList[index] = state.next() as CheckboxState.State<Int>
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

@ -1,16 +1,12 @@
package eu.kanade.presentation.manga package eu.kanade.presentation.manga
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.ColumnScope import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
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.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
@ -19,7 +15,6 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
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.ui.Alignment
import androidx.compose.ui.Modifier 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
@ -30,6 +25,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
@ -172,6 +168,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)) },
@ -181,20 +178,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 } checked = optionalChecked,
.padding(vertical = 8.dp) onCheckedChange = { optionalChecked = it },
.fillMaxWidth(), )
horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Checkbox(
checked = optionalChecked,
onCheckedChange = null,
)
Text(text = stringResource(R.string.also_set_chapter_settings_for_library))
}
} }
}, },
dismissButton = { dismissButton = {

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
@ -160,22 +153,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)
} }
}, },
) )
@ -204,29 +198,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,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) checked = isSelected,
false -> selected.remove(current.key) onCheckedChange = {
} if (it) {
} selected.add(current.key)
Row( } else {
verticalAlignment = Alignment.CenterVertically, selected.remove(current.key)
modifier = Modifier }
.clip(MaterialTheme.shapes.small) },
.selectable( )
selected = isSelected,
onClick = { onSelectionChanged() },
)
.minimumInteractiveComponentSize()
.fillMaxWidth(),
) {
Checkbox(
checked = isSelected,
onCheckedChange = null,
)
Text(
text = current.value,
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(start = 24.dp),
)
}
} }
} }
} }

View File

@ -1,17 +1,13 @@
package eu.kanade.tachiyomi.ui.browse.migration.search package eu.kanade.tachiyomi.ui.browse.migration.search
import androidx.compose.foundation.background import androidx.compose.foundation.background
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.FlowRow import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
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.MaterialTheme 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
@ -22,7 +18,6 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.toMutableStateList import androidx.compose.runtime.toMutableStateList
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
@ -55,6 +50,7 @@ import tachiyomi.domain.manga.model.MangaUpdate
import tachiyomi.domain.source.service.SourceManager import tachiyomi.domain.source.service.SourceManager
import tachiyomi.domain.track.interactor.GetTracks import tachiyomi.domain.track.interactor.GetTracks
import tachiyomi.domain.track.interactor.InsertTrack import tachiyomi.domain.track.interactor.InsertTrack
import tachiyomi.presentation.core.components.LabeledCheckbox
import tachiyomi.presentation.core.screens.LoadingScreen import tachiyomi.presentation.core.screens.LoadingScreen
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
@ -92,16 +88,11 @@ internal fun MigrateDialog(
modifier = Modifier.verticalScroll(rememberScrollState()), modifier = Modifier.verticalScroll(rememberScrollState()),
) { ) {
flags.forEachIndexed { index, flag -> flags.forEachIndexed { index, flag ->
val onChange = { selectedFlags[index] = !selectedFlags[index] } LabeledCheckbox(
Row( label = stringResource(flag.titleId),
modifier = Modifier checked = selectedFlags[index],
.fillMaxWidth() onCheckedChange = { selectedFlags[index] = it },
.clickable(onClick = onChange), )
verticalAlignment = Alignment.CenterVertically,
) {
Checkbox(checked = selectedFlags[index], onCheckedChange = { onChange() })
Text(text = context.getString(flag.titleId))
}
} }
} }
}, },

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)
}
}