Minor tweaks to download custom dialog

- Allow large decrements (just goes to 0)
- Use Material3 text field for proper theming
- Move dialog composable to presentation package
This commit is contained in:
arkon 2022-08-26 09:16:26 -04:00
parent 2453d1a886
commit 03b9950fa1
19 changed files with 189 additions and 180 deletions

View file

@ -9,7 +9,7 @@ import eu.kanade.tachiyomi.R
val Category.visualName: String val Category.visualName: String
@Composable @Composable
get() = when { get() = when {
isSystemCategory -> stringResource(id = R.string.label_default) isSystemCategory -> stringResource(R.string.label_default)
else -> name else -> name
} }

View file

@ -110,7 +110,7 @@ fun AppBar(
IconButton(onClick = onCancelActionMode) { IconButton(onClick = onCancelActionMode) {
Icon( Icon(
imageVector = Icons.Default.Close, imageVector = Icons.Default.Close,
contentDescription = stringResource(id = R.string.action_cancel), contentDescription = stringResource(R.string.action_cancel),
) )
} }
} else { } else {

View file

@ -39,14 +39,14 @@ fun ChangeCategoryDialog(
onEditCategories() onEditCategories()
}, },
) { ) {
Text(text = stringResource(id = R.string.action_edit_categories)) Text(text = stringResource(R.string.action_edit_categories))
} }
}, },
title = { title = {
Text(text = stringResource(id = R.string.action_move_category)) Text(text = stringResource(R.string.action_move_category))
}, },
text = { text = {
Text(text = stringResource(id = R.string.information_empty_category_dialog)) Text(text = stringResource(R.string.information_empty_category_dialog))
}, },
) )
return return
@ -60,11 +60,11 @@ fun ChangeCategoryDialog(
onDismissRequest() onDismissRequest()
onEditCategories() onEditCategories()
},) { },) {
Text(text = stringResource(id = R.string.action_edit)) Text(text = stringResource(R.string.action_edit))
} }
Spacer(modifier = Modifier.weight(1f)) Spacer(modifier = Modifier.weight(1f))
TextButton(onClick = onDismissRequest) { TextButton(onClick = onDismissRequest) {
Text(text = stringResource(id = android.R.string.cancel)) Text(text = stringResource(android.R.string.cancel))
} }
TextButton( TextButton(
onClick = { onClick = {
@ -75,12 +75,12 @@ fun ChangeCategoryDialog(
) )
}, },
) { ) {
Text(text = stringResource(id = R.string.action_add)) Text(text = stringResource(R.string.action_add))
} }
} }
}, },
title = { title = {
Text(text = stringResource(id = R.string.action_move_category)) Text(text = stringResource(R.string.action_move_category))
}, },
text = { text = {
Column { Column {

View file

@ -36,7 +36,7 @@ fun DeleteLibraryMangaDialog(
onDismissRequest = onDismissRequest, onDismissRequest = onDismissRequest,
dismissButton = { dismissButton = {
TextButton(onClick = onDismissRequest) { TextButton(onClick = onDismissRequest) {
Text(text = stringResource(id = android.R.string.cancel)) Text(text = stringResource(android.R.string.cancel))
} }
}, },
confirmButton = { confirmButton = {
@ -49,11 +49,11 @@ fun DeleteLibraryMangaDialog(
) )
}, },
) { ) {
Text(text = stringResource(id = android.R.string.ok)) Text(text = stringResource(android.R.string.ok))
} }
}, },
title = { title = {
Text(text = stringResource(id = R.string.action_remove)) Text(text = stringResource(R.string.action_remove))
}, },
text = { text = {
Column { Column {
@ -69,7 +69,7 @@ fun DeleteLibraryMangaDialog(
list = mutableList.toList() list = mutableList.toList()
}, },
) )
Text(text = stringResource(id = state.value)) Text(text = stringResource(state.value))
} }
} }
} }

View file

@ -62,7 +62,7 @@ fun HistoryRegularToolbar(
scrollBehavior: TopAppBarScrollBehavior, scrollBehavior: TopAppBarScrollBehavior,
) { ) {
AppBar( AppBar(
title = stringResource(id = R.string.history), title = stringResource(R.string.history),
actions = { actions = {
IconButton(onClick = onClickSearch) { IconButton(onClick = onClickSearch) {
Icon(Icons.Outlined.Search, contentDescription = stringResource(R.string.action_search)) Icon(Icons.Outlined.Search, contentDescription = stringResource(R.string.action_search))
@ -105,7 +105,7 @@ fun HistorySearchToolbar(
actions = { actions = {
AnimatedVisibility(visible = searchQuery.isNotEmpty()) { AnimatedVisibility(visible = searchQuery.isNotEmpty()) {
IconButton(onClick = onClickResetSearch) { IconButton(onClick = onClickResetSearch) {
Icon(Icons.Outlined.Close, contentDescription = stringResource(id = R.string.action_reset)) Icon(Icons.Outlined.Close, contentDescription = stringResource(R.string.action_reset))
} }
} }
}, },

View file

@ -193,7 +193,7 @@ fun LibrarySearchToolbar(
actions = { actions = {
AnimatedVisibility(visible = searchQuery.isNotEmpty()) { AnimatedVisibility(visible = searchQuery.isNotEmpty()) {
IconButton(onClick = onClickResetSearch) { IconButton(onClick = onClickResetSearch) {
Icon(Icons.Outlined.Close, contentDescription = stringResource(id = R.string.action_reset)) Icon(Icons.Outlined.Close, contentDescription = stringResource(R.string.action_reset))
} }
} }
}, },

View file

@ -1,7 +1,6 @@
package eu.kanade.tachiyomi.ui.manga.chapter package eu.kanade.presentation.manga.components
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.ChevronLeft import androidx.compose.material.icons.outlined.ChevronLeft
@ -11,6 +10,8 @@ import androidx.compose.material.icons.outlined.KeyboardDoubleArrowRight
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
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.OutlinedTextField
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
@ -19,8 +20,10 @@ 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.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
@Composable @Composable
@ -34,7 +37,7 @@ fun DownloadCustomAmountDialog(
onDismissRequest = onDismissRequest, onDismissRequest = onDismissRequest,
dismissButton = { dismissButton = {
TextButton(onClick = onDismissRequest) { TextButton(onClick = onDismissRequest) {
Text(text = stringResource(id = android.R.string.cancel)) Text(text = stringResource(android.R.string.cancel))
} }
}, },
confirmButton = { confirmButton = {
@ -44,11 +47,11 @@ fun DownloadCustomAmountDialog(
onConfirm(amount.coerceIn(0, maxAmount)) onConfirm(amount.coerceIn(0, maxAmount))
}, },
) { ) {
Text(text = stringResource(id = android.R.string.ok)) Text(text = stringResource(R.string.action_download))
} }
}, },
title = { title = {
Text(text = stringResource(id = R.string.custom_download)) Text(text = stringResource(R.string.custom_download))
}, },
text = { text = {
val onChangeAmount: (Int) -> Unit = { amount = (amount + it).coerceIn(0, maxAmount) } val onChangeAmount: (Int) -> Unit = { amount = (amount + it).coerceIn(0, maxAmount) }
@ -57,7 +60,7 @@ fun DownloadCustomAmountDialog(
) { ) {
IconButton( IconButton(
onClick = { onChangeAmount(-10) }, onClick = { onChangeAmount(-10) },
enabled = amount > 10, enabled = amount > 0,
) { ) {
Icon(imageVector = Icons.Outlined.KeyboardDoubleArrowLeft, contentDescription = "") Icon(imageVector = Icons.Outlined.KeyboardDoubleArrowLeft, contentDescription = "")
} }
@ -67,10 +70,12 @@ fun DownloadCustomAmountDialog(
) { ) {
Icon(imageVector = Icons.Outlined.ChevronLeft, contentDescription = "") Icon(imageVector = Icons.Outlined.ChevronLeft, contentDescription = "")
} }
BasicTextField( OutlinedTextField(
modifier = Modifier.weight(1f),
value = amount.toString(), value = amount.toString(),
onValueChange = { onChangeAmount(it.toIntOrNull() ?: 0) }, onValueChange = { onChangeAmount(it.toIntOrNull() ?: 0) },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
textStyle = LocalTextStyle.current.copy(textAlign = TextAlign.Center),
) )
IconButton( IconButton(
onClick = { onChangeAmount(1) }, onClick = { onChangeAmount(1) },

View file

@ -0,0 +1,57 @@
package eu.kanade.presentation.manga.components
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.source.Source
@Composable
fun DuplicateMangaDialog(
onDismissRequest: () -> Unit,
onConfirm: () -> Unit,
onOpenManga: () -> Unit,
duplicateFrom: Source,
) {
AlertDialog(
onDismissRequest = onDismissRequest,
confirmButton = {
Row {
TextButton(onClick = {
onDismissRequest()
onOpenManga()
},) {
Text(text = stringResource(R.string.action_show_manga))
}
Spacer(modifier = Modifier.weight(1f))
TextButton(onClick = onDismissRequest) {
Text(text = stringResource(android.R.string.cancel))
}
TextButton(
onClick = {
onDismissRequest()
onConfirm()
},
) {
Text(text = stringResource(R.string.action_add))
}
}
},
title = {
Text(text = stringResource(R.string.are_you_sure))
},
text = {
Text(
text = stringResource(
id = R.string.confirm_manga_add_duplicate,
duplicateFrom.name,
),
)
},
)
}

View file

@ -16,7 +16,7 @@ fun DeleteChaptersDialog(
onDismissRequest = onDismissRequest, onDismissRequest = onDismissRequest,
dismissButton = { dismissButton = {
TextButton(onClick = onDismissRequest) { TextButton(onClick = onDismissRequest) {
Text(text = stringResource(id = android.R.string.cancel)) Text(text = stringResource(android.R.string.cancel))
} }
}, },
confirmButton = { confirmButton = {
@ -26,14 +26,14 @@ fun DeleteChaptersDialog(
onConfirm() onConfirm()
}, },
) { ) {
Text(text = stringResource(id = android.R.string.ok)) Text(text = stringResource(android.R.string.ok))
} }
}, },
title = { title = {
Text(text = stringResource(id = R.string.are_you_sure)) Text(text = stringResource(R.string.are_you_sure))
}, },
text = { text = {
Text(text = stringResource(id = R.string.confirm_delete_chapters)) Text(text = stringResource(R.string.confirm_delete_chapters))
}, },
) )
} }

View file

@ -35,7 +35,7 @@ fun ClearDatabaseContent(
) )
} }
} }
false -> EmptyScreen(message = stringResource(id = R.string.database_clean)) false -> EmptyScreen(message = stringResource(R.string.database_clean))
} }
} }
} }

View file

@ -16,16 +16,16 @@ fun ClearDatabaseDeleteDialog(
onDismissRequest = onDismissRequest, onDismissRequest = onDismissRequest,
confirmButton = { confirmButton = {
TextButton(onClick = onDelete) { TextButton(onClick = onDelete) {
Text(text = stringResource(id = android.R.string.ok)) Text(text = stringResource(android.R.string.ok))
} }
}, },
dismissButton = { dismissButton = {
TextButton(onClick = onDismissRequest) { TextButton(onClick = onDismissRequest) {
Text(text = stringResource(id = android.R.string.cancel)) Text(text = stringResource(android.R.string.cancel))
} }
}, },
text = { text = {
Text(text = stringResource(id = R.string.clear_database_confirmation)) Text(text = stringResource(R.string.clear_database_confirmation))
}, },
) )
} }

View file

@ -27,7 +27,7 @@ fun ClearDatabaseFloatingActionButton(
ExtendedFloatingActionButton( ExtendedFloatingActionButton(
modifier = Modifier.navigationBarsPadding(), modifier = Modifier.navigationBarsPadding(),
text = { text = {
Text(text = stringResource(id = R.string.action_delete)) Text(text = stringResource(R.string.action_delete))
}, },
icon = { icon = {
Icon(Icons.Outlined.Delete, contentDescription = "") Icon(Icons.Outlined.Delete, contentDescription = "")

View file

@ -43,7 +43,7 @@ fun ClearDatabaseItem(
text = source.visualName, text = source.visualName,
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
) )
Text(text = stringResource(id = R.string.clear_database_source_item_count, count)) Text(text = stringResource(R.string.clear_database_source_item_count, count))
} }
Checkbox( Checkbox(
checked = isSelected, checked = isSelected,

View file

@ -18,19 +18,19 @@ fun ClearDatabaseToolbar(
onClickInvertSelection: () -> Unit, onClickInvertSelection: () -> Unit,
) { ) {
AppBar( AppBar(
title = stringResource(id = R.string.pref_clear_database), title = stringResource(R.string.pref_clear_database),
navigateUp = navigateUp, navigateUp = navigateUp,
actions = { actions = {
if (state.isEmpty.not()) { if (state.isEmpty.not()) {
AppBarActions( AppBarActions(
actions = listOf( actions = listOf(
AppBar.Action( AppBar.Action(
title = stringResource(id = R.string.action_select_all), title = stringResource(R.string.action_select_all),
icon = Icons.Outlined.SelectAll, icon = Icons.Outlined.SelectAll,
onClick = onClickSelectAll, onClick = onClickSelectAll,
), ),
AppBar.Action( AppBar.Action(
title = stringResource(id = R.string.action_select_all), title = stringResource(R.string.action_select_all),
icon = Icons.Outlined.FlipToBack, icon = Icons.Outlined.FlipToBack,
onClick = onClickInvertSelection, onClick = onClickInvertSelection,
), ),

View file

@ -92,7 +92,7 @@ class UpdatesGridGlanceWidget : GlanceAppWidget() {
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
) { ) {
Text( Text(
text = stringResource(id = R.string.appwidget_unavailable_locked), text = stringResource(R.string.appwidget_unavailable_locked),
style = TextStyle( style = TextStyle(
color = ColorProvider(R.color.appwidget_on_secondary_container), color = ColorProvider(R.color.appwidget_on_secondary_container),
fontSize = 12.sp, fontSize = 12.sp,
@ -114,7 +114,7 @@ class UpdatesGridGlanceWidget : GlanceAppWidget() {
if (inData == null) { if (inData == null) {
CircularProgressIndicator() CircularProgressIndicator()
} else if (inData.isEmpty()) { } else if (inData.isEmpty()) {
Text(text = stringResource(id = R.string.information_no_recent)) Text(text = stringResource(R.string.information_no_recent))
} else { } else {
(0 until rowCount).forEach { i -> (0 until rowCount).forEach { i ->
val coverRow = (0 until columnCount).mapNotNull { j -> val coverRow = (0 until columnCount).mapNotNull { j ->

View file

@ -641,7 +641,7 @@ class LibraryPresenter(
fun getToolbarTitle(): androidx.compose.runtime.State<LibraryToolbarTitle> { fun getToolbarTitle(): androidx.compose.runtime.State<LibraryToolbarTitle> {
val category = categories.getOrNull(activeCategory) val category = categories.getOrNull(activeCategory)
val defaultTitle = stringResource(id = R.string.label_library) val defaultTitle = stringResource(R.string.label_library)
val categoryName = category?.visualName ?: defaultTitle val categoryName = category?.visualName ?: defaultTitle
val default = remember { LibraryToolbarTitle(defaultTitle) } val default = remember { LibraryToolbarTitle(defaultTitle) }

View file

@ -2,19 +2,10 @@ package eu.kanade.tachiyomi.ui.manga
import android.app.Dialog import android.app.Dialog
import android.os.Bundle import android.os.Bundle
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import com.bluelinelabs.conductor.Controller import com.bluelinelabs.conductor.Controller
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import eu.kanade.domain.manga.model.Manga import eu.kanade.domain.manga.model.Manga
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.ui.base.controller.DialogController import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.ui.base.controller.pushController import eu.kanade.tachiyomi.ui.base.controller.pushController
@ -55,48 +46,3 @@ class AddDuplicateMangaDialog(bundle: Bundle? = null) : DialogController(bundle)
.create() .create()
} }
} }
@Composable
fun DuplicateDialog(
onDismissRequest: () -> Unit,
onConfirm: () -> Unit,
onOpenManga: () -> Unit,
duplicateFrom: Source,
) {
AlertDialog(
onDismissRequest = onDismissRequest,
confirmButton = {
Row {
TextButton(onClick = {
onDismissRequest()
onOpenManga()
},) {
Text(text = stringResource(id = R.string.action_show_manga))
}
Spacer(modifier = Modifier.weight(1f))
TextButton(onClick = onDismissRequest) {
Text(text = stringResource(id = android.R.string.cancel))
}
TextButton(
onClick = {
onDismissRequest()
onConfirm()
},
) {
Text(text = stringResource(id = R.string.action_add))
}
}
},
title = {
Text(text = stringResource(id = R.string.are_you_sure))
},
text = {
Text(
text = stringResource(
id = R.string.confirm_manga_add_duplicate,
duplicateFrom.name,
),
)
},
)
}

View file

@ -26,6 +26,8 @@ import eu.kanade.presentation.components.LoadingScreen
import eu.kanade.presentation.manga.DownloadAction import eu.kanade.presentation.manga.DownloadAction
import eu.kanade.presentation.manga.MangaScreen import eu.kanade.presentation.manga.MangaScreen
import eu.kanade.presentation.manga.components.DeleteChaptersDialog import eu.kanade.presentation.manga.components.DeleteChaptersDialog
import eu.kanade.presentation.manga.components.DownloadCustomAmountDialog
import eu.kanade.presentation.manga.components.DuplicateMangaDialog
import eu.kanade.presentation.util.calculateWindowWidthSizeClass import eu.kanade.presentation.util.calculateWindowWidthSizeClass
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.download.DownloadService import eu.kanade.tachiyomi.data.download.DownloadService
@ -46,7 +48,6 @@ import eu.kanade.tachiyomi.ui.library.LibraryController
import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.manga.MangaPresenter.Dialog import eu.kanade.tachiyomi.ui.manga.MangaPresenter.Dialog
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersSettingsSheet import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersSettingsSheet
import eu.kanade.tachiyomi.ui.manga.chapter.DownloadCustomAmountDialog
import eu.kanade.tachiyomi.ui.manga.info.MangaFullCoverDialog import eu.kanade.tachiyomi.ui.manga.info.MangaFullCoverDialog
import eu.kanade.tachiyomi.ui.manga.track.TrackItem import eu.kanade.tachiyomi.ui.manga.track.TrackItem
import eu.kanade.tachiyomi.ui.manga.track.TrackSearchDialog import eu.kanade.tachiyomi.ui.manga.track.TrackSearchDialog
@ -105,6 +106,12 @@ class MangaController : FullComposeController<MangaPresenter> {
@Composable @Composable
override fun ComposeContent() { override fun ComposeContent() {
val state by presenter.state.collectAsState() val state by presenter.state.collectAsState()
if (state is MangaScreenState.Loading) {
LoadingScreen()
return
}
val dialog by derivedStateOf { val dialog by derivedStateOf {
when (val state = state) { when (val state = state) {
MangaScreenState.Loading -> null MangaScreenState.Loading -> null
@ -112,10 +119,8 @@ class MangaController : FullComposeController<MangaPresenter> {
} }
} }
if (state is MangaScreenState.Success) {
val successState = state as MangaScreenState.Success val successState = state as MangaScreenState.Success
val isHttpSource = remember { successState.source is HttpSource } val isHttpSource = remember { successState.source is HttpSource }
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
MangaScreen( MangaScreen(
@ -182,7 +187,7 @@ class MangaController : FullComposeController<MangaPresenter> {
) )
} }
is Dialog.DuplicateManga -> { is Dialog.DuplicateManga -> {
DuplicateDialog( DuplicateMangaDialog(
onDismissRequest = onDismissRequest, onDismissRequest = onDismissRequest,
onConfirm = { onConfirm = {
presenter.toggleFavorite( presenter.toggleFavorite(
@ -197,9 +202,6 @@ class MangaController : FullComposeController<MangaPresenter> {
} }
null -> {} null -> {}
} }
} else {
LoadingScreen()
}
} }
// Let compose view handle this // Let compose view handle this
@ -427,7 +429,7 @@ class MangaController : FullComposeController<MangaPresenter> {
} }
} }
fun deleteChapters(chapters: List<DomainChapter>) { private fun deleteChapters(chapters: List<DomainChapter>) {
if (chapters.isEmpty()) return if (chapters.isEmpty()) return
presenter.deleteChapters(chapters) presenter.deleteChapters(chapters)
} }

View file

@ -26,7 +26,6 @@ subprojects {
kotlinter { kotlinter {
experimentalRules = true experimentalRules = true
disabledRules = arrayOf( disabledRules = arrayOf(
"experimental:argument-list-wrapping", // Doesn't play well with Android Studio "experimental:argument-list-wrapping", // Doesn't play well with Android Studio
"filename", // Often broken to give a more general name "filename", // Often broken to give a more general name