Migrate ReaderPageSheet to Compose

(cherry picked from commit f2b0d74b4cd6740b708e587f18c6cc798287dbe8)

# Conflicts:
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPageSheet.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt
#	app/src/main/res/layout/reader_page_sheet.xml
This commit is contained in:
arkon 2023-06-23 23:17:47 -04:00 committed by Jobobby04
parent 43a920bbb9
commit 273951188c
9 changed files with 327 additions and 332 deletions

View File

@ -31,7 +31,6 @@ import android.widget.RelativeLayout
import android.widget.TextView
import android.widget.Toast
import androidx.activity.viewModels
import androidx.annotation.ColorInt
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
@ -96,7 +95,6 @@ import eu.kanade.tachiyomi.util.view.popupMenu
import eu.kanade.tachiyomi.util.view.setComposeContent
import eu.kanade.tachiyomi.util.view.setTooltip
import eu.kanade.tachiyomi.widget.listener.SimpleAnimationListener
import exh.log.xLogE
import exh.source.isEhBasedSource
import exh.util.defaultReaderType
import exh.util.mangaType
@ -530,6 +528,23 @@ class ReaderActivity : BaseActivity() {
)
}
binding.dialogRoot.setComposeContent {
val state by viewModel.state.collectAsState()
when (state.dialog) {
is ReaderViewModel.Dialog.Page -> ReaderPageDialog(
onDismissRequest = viewModel::closeDialog,
onSetAsCover = viewModel::setAsCover,
onShare = viewModel::shareImage,
onSave = viewModel::saveImage,
onShareCombined = viewModel::shareImages,
onSaveCombined = viewModel::saveImages,
hasExtraPage = (state.dialog as? ReaderViewModel.Dialog.Page)?.extraPage != null,
)
null -> {}
}
}
// SY -->
val sliderContent: @Composable (Boolean) -> Unit = a@{ isVertical ->
val state by viewModel.state.collectAsState()
@ -1325,18 +1340,7 @@ class ReaderActivity : BaseActivity() {
*/
fun onPageLongTap(page: ReaderPage, extraPage: ReaderPage? = null) {
// SY -->
try {
val viewer = viewModel.state.value.viewer as? PagerViewer
ReaderPageSheet(
this,
page,
extraPage,
(viewer !is R2LPagerViewer) xor (viewer?.config?.invertDoublePages ?: false),
viewer?.config?.pageCanvasColor,
).show()
} catch (e: WindowManager.BadTokenException) {
xLogE("Caught and ignoring reader page sheet launch exception!", e)
}
viewModel.openPageDialog(page, extraPage)
// SY <--
}
@ -1374,20 +1378,6 @@ class ReaderActivity : BaseActivity() {
}
}
/**
* Called from the page sheet. It delegates the call to the presenter to do some IO, which
* will call [onShareImageResult] with the path the image was saved on when it's ready.
*/
fun shareImage(page: ReaderPage) {
viewModel.shareImage(page)
}
// SY -->
fun shareImages(firstPage: ReaderPage, secondPage: ReaderPage, isLTR: Boolean, @ColorInt bg: Int) {
viewModel.shareImages(firstPage, secondPage, isLTR, bg)
}
// SY <--
/**
* Called from the presenter when a page is ready to be shared. It shows Android's default
* sharing tool.
@ -1411,20 +1401,6 @@ class ReaderActivity : BaseActivity() {
startActivity(Intent.createChooser(intent, getString(R.string.action_share)))
}
/**
* Called from the page sheet. It delegates saving the image of the given [page] on external
* storage to the presenter.
*/
fun saveImage(page: ReaderPage) {
viewModel.saveImage(page)
}
// SY -->
fun saveImages(firstPage: ReaderPage, secondPage: ReaderPage, isLTR: Boolean, @ColorInt bg: Int) {
viewModel.saveImages(firstPage, secondPage, isLTR, bg)
}
// SY <--
/**
* Called from the presenter when a page is saved or fails. It shows a message or logs the
* event depending on the [result].
@ -1440,14 +1416,6 @@ class ReaderActivity : BaseActivity() {
}
}
/**
* Called from the page sheet. It delegates setting the image of the given [page] as the
* cover to the presenter.
*/
fun setAsCover(page: ReaderPage) {
viewModel.setAsCover(page)
}
/**
* Called from the presenter when a page is set as cover or fails. It shows a different message
* depending on the [result].

View File

@ -0,0 +1,198 @@
package eu.kanade.tachiyomi.ui.reader
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Photo
import androidx.compose.material.icons.outlined.Save
import androidx.compose.material.icons.outlined.Share
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import eu.kanade.presentation.components.AdaptiveSheet
import eu.kanade.tachiyomi.R
import tachiyomi.presentation.core.components.ActionButton
import tachiyomi.presentation.core.components.material.padding
@Composable
fun ReaderPageDialog(
onDismissRequest: () -> Unit,
// SY -->
onSetAsCover: (useExtraPage: Boolean) -> Unit,
onShare: (useExtraPage: Boolean) -> Unit,
onSave: (useExtraPage: Boolean) -> Unit,
onShareCombined: () -> Unit,
onSaveCombined: () -> Unit,
hasExtraPage: Boolean,
// SY <--
) {
var showSetCoverDialog by remember { mutableStateOf(false) }
// SY -->
var useExtraPage by remember { mutableStateOf(false) }
// SY <--
AdaptiveSheet(
onDismissRequest = onDismissRequest,
) {
Column(modifier = Modifier.padding(vertical = 16.dp)) {
Row(
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small),
) {
ActionButton(
modifier = Modifier.weight(1f),
title = stringResource(
// SY -->
if (hasExtraPage) {
R.string.action_set_first_page_cover
} else {
R.string.set_as_cover
},
// SY <--
),
icon = Icons.Outlined.Photo,
onClick = { showSetCoverDialog = true },
)
ActionButton(
modifier = Modifier.weight(1f),
title = stringResource(
// SY -->
if (hasExtraPage) {
R.string.action_share_first_page
} else {
R.string.action_share
},
// SY <--
),
icon = Icons.Outlined.Share,
onClick = {
// SY -->
onShare(false)
// SY <--
onDismissRequest()
},
)
ActionButton(
modifier = Modifier.weight(1f),
title = stringResource(
// SY -->
if (hasExtraPage) {
R.string.action_save_first_page
} else {
R.string.action_save
},
// SY <--
),
icon = Icons.Outlined.Save,
onClick = {
// SY -->
onSave(false)
// SY <--
onDismissRequest()
},
)
}
if (hasExtraPage) {
Row(
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small),
) {
ActionButton(
modifier = Modifier.weight(1f),
title = stringResource(R.string.action_set_second_page_cover),
icon = Icons.Outlined.Photo,
onClick = {
showSetCoverDialog = true
},
)
ActionButton(
modifier = Modifier.weight(1f),
title = stringResource(R.string.action_share_second_page),
icon = Icons.Outlined.Share,
onClick = {
onShare(true)
onDismissRequest()
},
)
ActionButton(
modifier = Modifier.weight(1f),
title = stringResource(R.string.action_save_second_page),
icon = Icons.Outlined.Save,
onClick = {
onSave(true)
onDismissRequest()
},
)
}
Row(
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small),
) {
ActionButton(
modifier = Modifier.weight(1f),
title = stringResource(R.string.action_share_combined_page),
icon = Icons.Outlined.Share,
onClick = {
onShareCombined()
onDismissRequest()
},
)
ActionButton(
modifier = Modifier.weight(1f),
title = stringResource(R.string.action_save_combined_page),
icon = Icons.Outlined.Save,
onClick = {
onSaveCombined()
onDismissRequest()
},
)
}
}
}
}
if (showSetCoverDialog) {
SetCoverDialog(
onConfirm = {
// SY -->
onSetAsCover(useExtraPage)
showSetCoverDialog = false
useExtraPage = false
// SY <--
},
onDismiss = { showSetCoverDialog = false },
)
}
}
@Composable
private fun SetCoverDialog(
onConfirm: () -> Unit,
onDismiss: () -> Unit,
) {
AlertDialog(
text = {
Text(stringResource(R.string.confirm_set_image_as_cover))
},
confirmButton = {
TextButton(onClick = onConfirm) {
Text(stringResource(android.R.string.ok))
}
},
dismissButton = {
TextButton(onClick = onDismiss) {
Text(stringResource(R.string.action_cancel))
}
},
onDismissRequest = onDismiss,
)
}

View File

@ -1,94 +0,0 @@
package eu.kanade.tachiyomi.ui.reader
import android.view.LayoutInflater
import android.view.View
import androidx.core.view.isVisible
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.databinding.ReaderPageSheetBinding
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
import eu.kanade.tachiyomi.widget.sheet.BaseBottomSheetDialog
/**
* Sheet to show when a page is long clicked.
*/
class ReaderPageSheet(
private val activity: ReaderActivity,
private val page: ReaderPage,
private val extraPage: ReaderPage? = null,
private val isLTR: Boolean = false,
private val bg: Int? = null,
) : BaseBottomSheetDialog(activity) {
private lateinit var binding: ReaderPageSheetBinding
override fun createView(inflater: LayoutInflater): View {
binding = ReaderPageSheetBinding.inflate(activity.layoutInflater, null, false)
binding.setAsCover.setOnClickListener { setAsCover(page) }
binding.share.setOnClickListener { share(page) }
binding.save.setOnClickListener { save(page) }
if (extraPage != null) {
binding.setAsCover.setText(R.string.action_set_first_page_cover)
binding.share.setText(R.string.action_share_first_page)
binding.save.setText(R.string.action_save_first_page)
binding.setAsCoverExtra.isVisible = true
binding.setAsCoverExtra.setOnClickListener { setAsCover(extraPage) }
binding.shareExtra.isVisible = true
binding.shareExtra.setOnClickListener { share(extraPage) }
binding.saveExtra.isVisible = true
binding.saveExtra.setOnClickListener { save(extraPage) }
binding.shareCombined.isVisible = true
binding.shareCombined.setOnClickListener { shareCombined() }
binding.saveCombined.isVisible = true
binding.saveCombined.setOnClickListener { saveCombined() }
}
return binding.root
}
/**
* Sets the image of this page as the cover of the manga.
*/
private fun setAsCover(page: ReaderPage) {
if (page.status != Page.State.READY) return
MaterialAlertDialogBuilder(activity)
.setMessage(R.string.confirm_set_image_as_cover)
.setPositiveButton(android.R.string.ok) { _, _ ->
activity.setAsCover(page)
}
.setNegativeButton(R.string.action_cancel, null)
.show()
}
/**
* Shares the image of this page with external apps.
*/
private fun share(page: ReaderPage) {
activity.shareImage(page)
dismiss()
}
fun shareCombined() {
activity.shareImages(page, extraPage!!, isLTR, bg!!)
dismiss()
}
/**
* Saves the image of this page on external storage.
*/
private fun save(page: ReaderPage) {
activity.saveImage(page)
dismiss()
}
fun saveCombined() {
activity.saveImages(page, extraPage!!, isLTR, bg!!)
dismiss()
}
}

View File

@ -40,12 +40,15 @@ import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
import eu.kanade.tachiyomi.ui.reader.viewer.Viewer
import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerViewer
import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer
import eu.kanade.tachiyomi.util.chapter.filterDownloaded
import eu.kanade.tachiyomi.util.chapter.removeDuplicates
import eu.kanade.tachiyomi.util.editCover
import eu.kanade.tachiyomi.util.lang.byteSize
import eu.kanade.tachiyomi.util.lang.takeBytes
import eu.kanade.tachiyomi.util.storage.DiskUtil
import eu.kanade.tachiyomi.util.storage.DiskUtil.MAX_FILE_NAME_BYTES
import eu.kanade.tachiyomi.util.storage.cacheImageDir
import eu.kanade.tachiyomi.util.system.isOnline
import exh.md.utils.FollowStatus
@ -192,7 +195,7 @@ class ReaderViewModel(
chapterName = chapter.name,
chapterScanlator = chapter.scanlator,
mangaTitle = chapterManga.ogTitle,
sourceId = chapterManga.source
sourceId = chapterManga.source,
)
}
// SY <--
@ -860,12 +863,27 @@ class ReaderViewModel(
) + filenameSuffix
}
fun openPageDialog(page: ReaderPage/* SY --> */, extraPage: ReaderPage? = null/* SY <-- */) {
mutableState.update { it.copy(dialog = Dialog.Page(page, extraPage)) }
}
fun closeDialog() {
mutableState.update { it.copy(dialog = null) }
}
/**
* Saves the image of this [page] on the pictures directory and notifies the UI of the result.
* Saves the image of the selected page on the pictures directory and notifies the UI of the result.
* There's also a notification to allow sharing the image somewhere else or deleting it.
*/
fun saveImage(page: ReaderPage) {
if (page.status != Page.State.READY) return
fun saveImage(useExtraPage: Boolean) {
// SY -->
val page = if (useExtraPage) {
(state.value.dialog as? Dialog.Page)?.extraPage
} else {
(state.value.dialog as? Dialog.Page)?.page
}
// SY <--
if (page?.status != Page.State.READY) return
val manga = manga ?: return
val context = Injekt.get<Application>()
@ -899,9 +917,15 @@ class ReaderViewModel(
}
// SY -->
fun saveImages(firstPage: ReaderPage, secondPage: ReaderPage, isLTR: Boolean, @ColorInt bg: Int) {
fun saveImages() {
val (firstPage, secondPage) = (state.value.dialog as? Dialog.Page ?: return)
val viewer = state.value.viewer as? PagerViewer ?: return
val isLTR = (viewer !is R2LPagerViewer) xor (viewer.config.invertDoublePages)
val bg = viewer.config.pageCanvasColor
if (firstPage.status != Page.State.READY) return
if (secondPage.status != Page.State.READY) return
if (secondPage?.status != Page.State.READY) return
val manga = manga ?: return
val context = Injekt.get<Application>()
@ -964,14 +988,21 @@ class ReaderViewModel(
// SY <--
/**
* Shares the image of this [page] and notifies the UI with the path of the file to share.
* Shares the image of the selected page and notifies the UI with the path of the file to share.
* The image must be first copied to the internal partition because there are many possible
* formats it can come from, like a zipped chapter, in which case it's not possible to directly
* get a path to the file and it has to be decompressed somewhere first. Only the last shared
* image will be kept so it won't be taking lots of internal disk space.
*/
fun shareImage(page: ReaderPage) {
if (page.status != Page.State.READY) return
fun shareImage(useExtraPage: Boolean) {
// SY -->
val page = if (useExtraPage) {
(state.value.dialog as? Dialog.Page)?.extraPage
} else {
(state.value.dialog as? Dialog.Page)?.page
}
// SY <--
if (page?.status != Page.State.READY) return
val manga = manga ?: return
val context = Injekt.get<Application>()
@ -997,9 +1028,14 @@ class ReaderViewModel(
}
// SY -->
fun shareImages(firstPage: ReaderPage, secondPage: ReaderPage, isLTR: Boolean, @ColorInt bg: Int) {
fun shareImages() {
val (firstPage, secondPage) = (state.value.dialog as? Dialog.Page ?: return)
val viewer = state.value.viewer as? PagerViewer ?: return
val isLTR = (viewer !is R2LPagerViewer) xor (viewer.config.invertDoublePages)
val bg = viewer.config.pageCanvasColor
if (firstPage.status != Page.State.READY) return
if (secondPage.status != Page.State.READY) return
if (secondPage?.status != Page.State.READY) return
val manga = manga ?: return
val context = Injekt.get<Application>()
@ -1025,10 +1061,17 @@ class ReaderViewModel(
// SY <--
/**
* Sets the image of this [page] as cover and notifies the UI of the result.
* Sets the image of the selected page as cover and notifies the UI of the result.
*/
fun setAsCover(page: ReaderPage) {
if (page.status != Page.State.READY) return
fun setAsCover(useExtraPage: Boolean) {
// SY -->
val page = if (useExtraPage) {
(state.value.dialog as? Dialog.Page)?.extraPage
} else {
(state.value.dialog as? Dialog.Page)?.page
}
// SY <--
if (page?.status != Page.State.READY) return
val manga = manga ?: return
val stream = page.stream ?: return
@ -1143,10 +1186,12 @@ class ReaderViewModel(
val viewerChapters: ViewerChapters? = null,
val isLoadingAdjacentChapter: Boolean = false,
val currentPage: Int = -1,
/**
* Viewer used to display the pages (pager, webtoon, ...).
*/
val viewer: Viewer? = null,
val dialog: Dialog? = null,
// SY -->
val currentPageText: String = "",
@ -1158,6 +1203,10 @@ class ReaderViewModel(
get() = viewerChapters?.currChapter?.pages?.size ?: -1
}
sealed class Dialog {
data class Page(val page: ReaderPage/* SY --> */, val extraPage: ReaderPage? = null /* SY <-- */) : Dialog()
}
sealed class Event {
object ReloadViewerChapters : Event()
data class SetOrientation(val orientation: Int) : Event()

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/black"
android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM19,19L5,19L5,5h11.17L19,7.83L19,19zM12,12c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3zM6,6h9v4L6,10z"/>
</vector>

View File

@ -348,4 +348,9 @@
android:layout_height="match_parent"
android:visibility="gone" />
<androidx.compose.ui.platform.ComposeView
android:id="@+id/dialog_root"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>

View File

@ -1,134 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/set_as_cover"
android:layout_width="match_parent"
android:layout_height="56dp"
android:drawablePadding="32dp"
android:gravity="center_vertical"
android:clickable="true"
android:focusable="true"
android:paddingHorizontal="16dp"
android:foreground="?attr/selectableItemBackground"
android:text="@string/set_as_cover"
android:textColor="?attr/colorOnBackground"
app:drawableStartCompat="@drawable/ic_photo_24dp"
app:drawableTint="?attr/colorOnBackground" />
<TextView
android:id="@+id/set_as_cover_extra"
android:layout_width="match_parent"
android:layout_height="56dp"
android:drawablePadding="32dp"
android:gravity="center_vertical"
android:clickable="true"
android:focusable="true"
android:paddingHorizontal="16dp"
android:foreground="?attr/selectableItemBackground"
android:text="@string/action_set_second_page_cover"
android:textColor="?attr/colorOnBackground"
android:visibility="gone"
app:drawableStartCompat="@drawable/ic_photo_24dp"
app:drawableTint="?attr/colorOnBackground" />
<TextView
android:id="@+id/share"
android:layout_width="match_parent"
android:layout_height="56dp"
android:drawablePadding="32dp"
android:gravity="center_vertical"
android:clickable="true"
android:focusable="true"
android:paddingHorizontal="16dp"
android:foreground="?attr/selectableItemBackground"
android:text="@string/action_share"
android:textColor="?attr/colorOnBackground"
app:drawableStartCompat="@drawable/ic_share_24dp"
app:drawableTint="?attr/colorOnBackground" />
<TextView
android:id="@+id/share_extra"
android:layout_width="match_parent"
android:layout_height="56dp"
android:drawablePadding="32dp"
android:gravity="center_vertical"
android:clickable="true"
android:focusable="true"
android:paddingHorizontal="16dp"
android:foreground="?attr/selectableItemBackground"
android:text="@string/action_share_second_page"
android:textColor="?attr/colorOnBackground"
android:visibility="gone"
app:drawableStartCompat="@drawable/ic_share_24dp"
app:drawableTint="?attr/colorOnBackground" />
<TextView
android:id="@+id/share_combined"
android:layout_width="match_parent"
android:layout_height="56dp"
android:drawablePadding="32dp"
android:gravity="center_vertical"
android:clickable="true"
android:focusable="true"
android:paddingHorizontal="16dp"
android:foreground="?attr/selectableItemBackground"
android:text="@string/action_share_combined_page"
android:textColor="?attr/colorOnBackground"
android:visibility="gone"
app:drawableStartCompat="@drawable/ic_share_24dp"
app:drawableTint="?attr/colorOnBackground" />
<TextView
android:id="@+id/save"
android:layout_width="match_parent"
android:layout_height="56dp"
android:drawablePadding="32dp"
android:gravity="center_vertical"
android:clickable="true"
android:focusable="true"
android:paddingHorizontal="16dp"
android:foreground="?attr/selectableItemBackground"
android:text="@string/action_save"
android:textColor="?attr/colorOnBackground"
app:drawableStartCompat="@drawable/ic_save_24dp"
app:drawableTint="?attr/colorOnBackground" />
<TextView
android:id="@+id/save_extra"
android:layout_width="match_parent"
android:layout_height="56dp"
android:drawablePadding="32dp"
android:gravity="center_vertical"
android:clickable="true"
android:focusable="true"
android:paddingHorizontal="16dp"
android:foreground="?attr/selectableItemBackground"
android:text="@string/action_save_second_page"
android:textColor="?attr/colorOnBackground"
android:visibility="gone"
app:drawableStartCompat="@drawable/ic_save_24dp"
app:drawableTint="?attr/colorOnBackground" />
<TextView
android:id="@+id/save_combined"
android:layout_width="match_parent"
android:layout_height="56dp"
android:drawablePadding="32dp"
android:gravity="center_vertical"
android:clickable="true"
android:focusable="true"
android:paddingHorizontal="16dp"
android:foreground="?attr/selectableItemBackground"
android:text="@string/action_save_combined_page"
android:textColor="?attr/colorOnBackground"
android:visibility="gone"
app:drawableStartCompat="@drawable/ic_save_24dp"
app:drawableTint="?attr/colorOnBackground" />
</LinearLayout>

View File

@ -0,0 +1,40 @@
package tachiyomi.presentation.core.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
@Composable
fun ActionButton(
modifier: Modifier = Modifier,
title: String,
icon: ImageVector,
onClick: () -> Unit,
) {
TextButton(
modifier = modifier,
onClick = onClick,
) {
Column(
verticalArrangement = Arrangement.spacedBy(4.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Icon(
imageVector = icon,
contentDescription = null,
)
Text(
text = title,
textAlign = TextAlign.Center,
)
}
}
}

View File

@ -4,17 +4,13 @@ import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.paddingFromBaseline
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
@ -24,6 +20,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEach
import tachiyomi.presentation.core.components.ActionButton
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.util.secondaryItemAlpha
import kotlin.random.Random
@ -96,31 +93,6 @@ fun EmptyScreen(
}
}
@Composable
private fun ActionButton(
modifier: Modifier = Modifier,
title: String,
icon: ImageVector,
onClick: () -> Unit,
) {
TextButton(
modifier = modifier,
onClick = onClick,
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Icon(
imageVector = icon,
contentDescription = null,
)
Spacer(Modifier.height(4.dp))
Text(
text = title,
textAlign = TextAlign.Center,
)
}
}
}
private val ERROR_FACES = listOf(
"(・o・;)",
"Σ(ಠ_ಠ)",