From 5824ac81c2b5085317114cd882473d8891c75048 Mon Sep 17 00:00:00 2001 From: Ahmad Ansori Palembani Date: Mon, 23 Dec 2024 20:58:30 +0700 Subject: [PATCH] refactor: Use Compose for EmptyView --- .../ui/download/DownloadBottomSheet.kt | 4 +- .../tachiyomi/ui/library/LibraryController.kt | 4 +- .../ui/manga/track/TrackingBottomSheet.kt | 7 +- .../stats/details/StatsDetailsController.kt | 7 +- .../tachiyomi/ui/recents/RecentsController.kt | 7 +- .../tachiyomi/ui/recents/RecentsPresenter.kt | 4 +- .../database/ClearDatabaseController.kt | 4 +- .../source/browse/BrowseSourceController.kt | 11 +- .../eu/kanade/tachiyomi/util/WindowSize.kt | 12 ++ .../util/system/ContextExtensions.kt | 5 +- .../eu/kanade/tachiyomi/widget/EmptyView.kt | 113 ++++++++------ .../presentation/component/EmptyScreen.kt | 143 ++++++++++++++---- .../extension/repo/ExtensionRepoScreen.kt | 2 + 13 files changed, 228 insertions(+), 95 deletions(-) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/util/WindowSize.kt diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadBottomSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadBottomSheet.kt index ef9a074b29..0afa1b2af0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadBottomSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/download/DownloadBottomSheet.kt @@ -5,6 +5,8 @@ import android.content.Context import android.util.AttributeSet import android.view.MenuItem import android.widget.LinearLayout +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.FileDownloadOff import androidx.core.view.WindowInsetsCompat.Type.systemBars import androidx.core.view.isInvisible import androidx.core.view.updateLayoutParams @@ -212,7 +214,7 @@ class DownloadBottomSheet @JvmOverloads constructor( setBottomSheet() if (presenter.downloadQueueState.value.isEmpty()) { binding.emptyView.show( - R.drawable.ic_download_off_24dp, + Icons.Filled.FileDownloadOff, MR.strings.nothing_is_downloading, ) } else { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt index bf10138a82..393fe3244d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt @@ -28,6 +28,8 @@ import android.widget.ImageView import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.view.ActionMode +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.HeartBroken import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.animation.doOnEnd import androidx.core.view.ViewCompat @@ -1135,7 +1137,7 @@ open class LibraryController( binding.emptyView.hide() } else { binding.emptyView.show( - R.drawable.ic_heart_off_24dp, + Icons.Filled.HeartBroken, if (hasActiveFilters) { MR.strings.no_matches_for_filters } else { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackingBottomSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackingBottomSheet.kt index 5fcdb7a29b..b8b6e8479e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackingBottomSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackingBottomSheet.kt @@ -18,6 +18,8 @@ import android.widget.TextView import androidx.activity.OnBackPressedCallback import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.PopupMenu +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.SearchOff import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.net.toUri import androidx.core.view.WindowInsetsCompat.Type.systemBars @@ -31,7 +33,6 @@ import com.google.android.material.datepicker.MaterialDatePicker import com.mikepenz.fastadapter.FastAdapter import com.mikepenz.fastadapter.adapters.ItemAdapter import com.mikepenz.fastadapter.listeners.addClickListener -import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.track.EnhancedTrackService import eu.kanade.tachiyomi.data.track.TrackService import eu.kanade.tachiyomi.data.track.model.TrackSearch @@ -317,7 +318,7 @@ class TrackingBottomSheet(private val controller: MangaDetailsController) : if (results.isEmpty()) { setMiddleTrackView(binding.searchEmptyView.id) binding.searchEmptyView.show( - R.drawable.ic_search_off_24dp, + Icons.Filled.SearchOff, MR.strings.no_results_found, ) } else { @@ -338,7 +339,7 @@ class TrackingBottomSheet(private val controller: MangaDetailsController) : binding.trackSearchRecycler.isVisible = false searchItemAdapter.clear() binding.searchEmptyView.show( - R.drawable.ic_search_off_24dp, + Icons.Filled.SearchOff, error.message ?: "", ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/more/stats/details/StatsDetailsController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/more/stats/details/StatsDetailsController.kt index 7636389cee..c9d366fb39 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/more/stats/details/StatsDetailsController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/more/stats/details/StatsDetailsController.kt @@ -12,6 +12,8 @@ import android.view.View import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.SearchView +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.HeartBroken import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.graphics.ColorUtils import androidx.core.util.Pair @@ -458,7 +460,10 @@ class StatsDetailsController : with(binding ?: headerBinding) { val hasNoData = currentStats.isNullOrEmpty() || currentStats.all { it.count == 0 } if (hasNoData) { - this@StatsDetailsController.binding.noChartData.show(R.drawable.ic_heart_off_24dp, MR.strings.no_data_for_filters) + this@StatsDetailsController.binding.noChartData.show( + Icons.Filled.HeartBroken, + MR.strings.no_data_for_filters, + ) presenter.currentStats?.removeAll { it.count == 0 } handleNoChartLayout() this?.statsPieChart?.isVisible = false diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsController.kt index 022d491fd4..b4ec025691 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsController.kt @@ -12,6 +12,9 @@ import android.view.RoundedCorner import android.view.View import android.view.ViewGroup import androidx.activity.BackEventCompat +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.HistoryToggleOff +import androidx.compose.material.icons.filled.SearchOff import androidx.core.view.WindowInsetsCompat.Type.systemBars import androidx.core.view.isInvisible import androidx.core.view.isVisible @@ -596,9 +599,9 @@ class RecentsController(bundle: Bundle? = null) : if (recents.isEmpty()) { binding.recentsEmptyView.show( if (!isSearching()) { - R.drawable.ic_history_off_24dp + Icons.Filled.HistoryToggleOff } else { - R.drawable.ic_search_off_24dp + Icons.Filled.SearchOff }, if (isSearching()) { MR.strings.no_results_found diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsPresenter.kt index 138df111a7..24a5f4ca7c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recents/RecentsPresenter.kt @@ -75,8 +75,8 @@ class RecentsPresenter( } private val newAdditionsHeader = RecentMangaHeaderItem(RecentMangaHeaderItem.NEWLY_ADDED) private val newChaptersHeader = RecentMangaHeaderItem(RecentMangaHeaderItem.NEW_CHAPTERS) - private val continueReadingHeader = - RecentMangaHeaderItem(RecentMangaHeaderItem.CONTINUE_READING) + private val continueReadingHeader = RecentMangaHeaderItem(RecentMangaHeaderItem.CONTINUE_READING) + var finished = false private var shouldMoveToTop = false var viewType: RecentsViewType = RecentsViewType.valueOf(uiPreferences.recentsViewType().get()) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/controllers/database/ClearDatabaseController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/controllers/database/ClearDatabaseController.kt index 5c74237139..316589f6cd 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/controllers/database/ClearDatabaseController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/controllers/database/ClearDatabaseController.kt @@ -7,6 +7,8 @@ import android.view.MenuInflater import android.view.MenuItem import android.view.View import android.view.ViewGroup +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Book import androidx.core.view.WindowInsetsCompat.Type.systemBars import androidx.core.view.forEach import androidx.core.view.isInvisible @@ -193,7 +195,7 @@ class ClearDatabaseController : binding.emptyView.hide() } else { binding.emptyView.show( - R.drawable.ic_book_24dp, + Icons.Filled.Book, MR.strings.database_clean, ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/BrowseSourceController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/BrowseSourceController.kt index 8eb367d84b..cbf0973b0c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/BrowseSourceController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/source/browse/BrowseSourceController.kt @@ -8,6 +8,8 @@ import android.view.MenuInflater import android.view.MenuItem import android.view.View import android.view.ViewGroup +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ExploreOff import androidx.core.view.WindowInsetsCompat.Type.ime import androidx.core.view.WindowInsetsCompat.Type.systemBars import androidx.core.view.isVisible @@ -62,7 +64,6 @@ import eu.kanade.tachiyomi.widget.EmptyView import eu.kanade.tachiyomi.widget.LinearLayoutManagerAccurateOffset import kotlin.math.roundToInt import kotlinx.coroutines.Job -import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch import uy.kohesive.injekt.injectLazy @@ -577,7 +578,7 @@ open class BrowseSourceController(bundle: Bundle) : snack?.dismiss() val message = getErrorMessage(error) - val retryAction = View.OnClickListener { + val retryAction = { // If not the first page, show bottom binding.progress bar. if (adapter.mainItemCount > 0 && progressItem != null) { adapter.addScrollableFooterWithDelay(progressItem!!, 0, true) @@ -606,16 +607,16 @@ open class BrowseSourceController(bundle: Bundle) : binding.emptyView.show( if (presenter.source is HttpSource) { - R.drawable.ic_browse_off_24dp + EmptyView.Image.Vector(Icons.Filled.ExploreOff) } else { - R.drawable.ic_local_library_24dp + EmptyView.Image.ResourceVector(R.drawable.ic_local_library_24dp) }, message, actions, ) } else { snack = binding.sourceLayout.snack(message, Snackbar.LENGTH_INDEFINITE) { - setAction(MR.strings.retry, retryAction) + setAction(MR.strings.retry) { retryAction() } } } if (isControllerVisible) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/WindowSize.kt b/app/src/main/java/eu/kanade/tachiyomi/util/WindowSize.kt new file mode 100644 index 0000000000..311c1f34fd --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/util/WindowSize.kt @@ -0,0 +1,12 @@ +package eu.kanade.tachiyomi.util + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.ReadOnlyComposable +import androidx.compose.ui.platform.LocalConfiguration +import eu.kanade.tachiyomi.util.system.isTablet + +@Composable +@ReadOnlyComposable +fun isTablet(): Boolean { + return LocalConfiguration.current.isTablet() +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt index e0dfd4e2f3..91943b465d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/system/ContextExtensions.kt @@ -54,6 +54,8 @@ import yokai.i18n.MR private const val TABLET_UI_MIN_SCREEN_WIDTH_DP = 720 +private const val TABLET_UI_MIN_SCREEN_WIDTH_LANDSCAPE_DP = 600 + /** * Helper method to create a notification. * @@ -113,7 +115,8 @@ fun Float.dpToPxEnd(resources: Resources): Float { val Resources.isLTR get() = configuration.layoutDirection == View.LAYOUT_DIRECTION_LTR -fun Context.isTablet() = resources.configuration.smallestScreenWidthDp >= 600 +fun Configuration.isTablet() = smallestScreenWidthDp >= TABLET_UI_MIN_SCREEN_WIDTH_LANDSCAPE_DP +fun Context.isTablet() = resources.configuration.isTablet() val displayMaxHeightInPx: Int get() = Resources.getSystem().displayMetrics.let { max(it.heightPixels, it.widthPixels) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/EmptyView.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/EmptyView.kt index 6bbaa86939..7a419059d3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/EmptyView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/EmptyView.kt @@ -2,28 +2,60 @@ package eu.kanade.tachiyomi.widget import android.content.Context import android.util.AttributeSet -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.RelativeLayout -import androidx.annotation.DrawableRes +import android.view.Gravity +import android.widget.FrameLayout import androidx.annotation.StringRes +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Download +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.AbstractComposeView +import androidx.compose.ui.platform.ViewCompositionStrategy +import androidx.compose.ui.res.vectorResource import androidx.core.view.isVisible -import androidx.core.view.updateLayoutParams -import com.google.android.material.button.MaterialButton import dev.icerock.moko.resources.StringResource -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.databinding.CommonViewEmptyBinding -import eu.kanade.tachiyomi.util.view.setText -import eu.kanade.tachiyomi.util.view.setVectorCompat +import eu.kanade.tachiyomi.util.isTablet +import yokai.presentation.component.EmptyScreen +import yokai.presentation.theme.YokaiTheme import yokai.util.lang.getString -import android.R as AR -class EmptyView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : - RelativeLayout(context, attrs) { +class EmptyView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, +) : AbstractComposeView(context, attrs, defStyleAttr) { - private val binding: CommonViewEmptyBinding = - CommonViewEmptyBinding.inflate(LayoutInflater.from(context), this, true) + private var image by mutableStateOf(Image.Vector(Icons.Filled.Download)) + private var message by mutableStateOf("") + private var actions by mutableStateOf(emptyList()) + + init { + layoutParams = FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, Gravity.CENTER) + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnDetachedFromWindowOrReleasedFromPool) + } + + @Composable + fun image(): ImageVector { + return when (image) { + is Image.Vector -> (image as Image.Vector).image + is Image.ResourceVector -> ImageVector.vectorResource((image as Image.ResourceVector).id) + } + } + + @Composable + override fun Content() { + YokaiTheme { + EmptyScreen( + image = image(), + message = message, + isTablet = isTablet(), + actions = actions, + ) + } + } /** * Hide the information view @@ -36,16 +68,21 @@ class EmptyView @JvmOverloads constructor(context: Context, attrs: AttributeSet? * Show the information view * @param textResource text of information view */ - fun show(@DrawableRes drawable: Int, textResource: StringResource, actions: List? = null) { - show(drawable, context.getString(textResource), actions) + fun show(image: ImageVector, textResource: StringResource, actions: List = emptyList()) { + show(Image.Vector(image), context.getString(textResource), actions) } /** * Show the information view * @param textResource text of information view */ - fun show(@DrawableRes drawable: Int, @StringRes textResource: Int, actions: List? = null) { - show(drawable, context.getString(textResource), actions) + fun show(image: ImageVector, @StringRes textResource: Int, actions: List = emptyList()) { + show(Image.Vector(image), context.getString(textResource), actions) + } + + @Deprecated("Use EmptyView.Image instead of passing ImageVector directly") + fun show(image: ImageVector, message: String, actions: List = emptyList()) { + show(Image.Vector(image), message, actions) } /** @@ -53,36 +90,20 @@ class EmptyView @JvmOverloads constructor(context: Context, attrs: AttributeSet? * @param drawable icon of information view * @param textResource text of information view */ - fun show(@DrawableRes drawable: Int, message: String, actions: List? = null) { - binding.imageView.setVectorCompat(drawable, AR.attr.textColorHint) - binding.textLabel.text = message - - binding.actionsContainer.removeAllViews() - binding.actionsContainer.isVisible = !actions.isNullOrEmpty() - if (!actions.isNullOrEmpty()) { - actions.forEach { - val button = - (inflate(context, R.layout.material_text_button, null) as MaterialButton) - .apply { - setText(it.resId) - setOnClickListener(it.listener) - } - binding.actionsContainer.addView(button) - if (context.resources.configuration.screenHeightDp < 600) { - button.textAlignment = View.TEXT_ALIGNMENT_TEXT_START - button.updateLayoutParams { - width = ViewGroup.LayoutParams.WRAP_CONTENT - height = ViewGroup.LayoutParams.WRAP_CONTENT - } - } - } - } - + fun show(image: Image, message: String, actions: List = emptyList()) { + this.image = image + this.message = message + this.actions = actions this.isVisible = true } data class Action( val resId: StringResource, - val listener: OnClickListener, + val listener: () -> Unit, ) + + sealed class Image { + data class Vector(val image: ImageVector) : Image() + data class ResourceVector(val id: Int) : Image() + } } diff --git a/app/src/main/java/yokai/presentation/component/EmptyScreen.kt b/app/src/main/java/yokai/presentation/component/EmptyScreen.kt index dc9d4c66df..2d5925a6a9 100644 --- a/app/src/main/java/yokai/presentation/component/EmptyScreen.kt +++ b/app/src/main/java/yokai/presentation/component/EmptyScreen.kt @@ -4,6 +4,8 @@ import android.content.res.Configuration import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -13,6 +15,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Download import androidx.compose.material3.MaterialTheme 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 @@ -21,7 +24,11 @@ import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import dev.icerock.moko.resources.compose.stringResource import eu.kanade.tachiyomi.util.compose.textHint +import eu.kanade.tachiyomi.widget.EmptyView +import yokai.i18n.MR private val defaultIconModifier = Modifier.size(128.dp) @@ -34,8 +41,9 @@ fun EmptyScreen( modifier: Modifier = Modifier, image: ImageVector, message: String, - actions: @Composable () -> Unit = {}, -) = EmptyScreen( + isTablet: Boolean, + actions: List = emptyList(), +) = EmptyScreenImpl( modifier = modifier, image = { Image( @@ -46,7 +54,8 @@ fun EmptyScreen( ) }, message = message, - actions = actions, + actions = { EmptyScreenActions(actions, isTablet) }, + isTablet = isTablet, ) @Composable @@ -54,8 +63,9 @@ fun EmptyScreen( modifier: Modifier = Modifier, image: ImageBitmap, message: String, - actions: @Composable () -> Unit = {}, -) = EmptyScreen( + isTablet: Boolean, + actions: List = emptyList(), +) = EmptyScreenImpl( modifier = modifier, image = { Image( @@ -65,35 +75,104 @@ fun EmptyScreen( ) }, message = message, - actions = actions, + actions = { EmptyScreenActions(actions, isTablet) }, + isTablet = isTablet, ) -@Preview(name = "Light", uiMode = Configuration.UI_MODE_NIGHT_NO, showBackground = true) @Composable -private fun EmptyScreen( - modifier: Modifier = Modifier, - image: @Composable () -> Unit = { - Image(modifier = defaultIconModifier, imageVector = Icons.Filled.Download, contentDescription = null) - }, - message: String = "Something went wrong", - actions: @Composable () -> Unit = {}, -) { - Column( - modifier = modifier - .fillMaxSize() - .verticalScroll(rememberScrollState()) - .padding(16.dp), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, - ) { - image() - Text( - modifier = Modifier - .padding(top = 16.dp), - text = message, - color = MaterialTheme.colorScheme.textHint, - style = MaterialTheme.typography.labelMedium, - ) - actions() +private fun EmptyScreenActions(actions: List, isTablet: Boolean) { + if (isTablet) { + FlowRow { + actions.forEach { action -> + TextButton(onClick = { action.listener() }) { + Text( + text = stringResource(action.resId), + fontSize = 14.sp, + ) + } + } + } + } else { + Column( + verticalArrangement = Arrangement.spacedBy(4.dp), + ) { + actions.forEach { action -> + TextButton(onClick = { action.listener() }) { + Text( + text = stringResource(action.resId), + fontSize = 14.sp, + ) + } + } + } } } + +@Composable +private fun EmptyScreenImpl( + modifier: Modifier = Modifier, + image: @Composable () -> Unit, + message: String, + actions: @Composable () -> Unit, + isTablet: Boolean, +) { + if (isTablet) { + Column( + modifier = modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()) + .padding(8.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { + Row { + image() + Text( + modifier = Modifier + .padding(vertical = 4.dp), + text = message, + color = MaterialTheme.colorScheme.textHint, + style = MaterialTheme.typography.labelMedium, + ) + } + actions() + } + } else { + Column( + modifier = modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()) + .padding(16.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { + image() + Text( + modifier = Modifier + .padding(vertical = 16.dp), + text = message, + color = MaterialTheme.colorScheme.textHint, + style = MaterialTheme.typography.labelMedium, + ) + actions() + } + } +} + +@Preview(name = "Dark", uiMode = Configuration.UI_MODE_NIGHT_YES, showBackground = true) +@Preview(name = "Light", uiMode = Configuration.UI_MODE_NIGHT_NO, showBackground = true) +@Composable +private fun EmptyScreenPreview() { + EmptyScreen( + image = Icons.Filled.Download, + message = "Something went wrong", + actions = listOf( + EmptyView.Action(MR.strings.download) {}, + EmptyView.Action(MR.strings.download) {}, + EmptyView.Action(MR.strings.download) {}, + EmptyView.Action(MR.strings.download) {}, + EmptyView.Action(MR.strings.download) {}, + ), + isTablet = false, + ) +} diff --git a/app/src/main/java/yokai/presentation/extension/repo/ExtensionRepoScreen.kt b/app/src/main/java/yokai/presentation/extension/repo/ExtensionRepoScreen.kt index 47a756a7bb..ed93b2b846 100644 --- a/app/src/main/java/yokai/presentation/extension/repo/ExtensionRepoScreen.kt +++ b/app/src/main/java/yokai/presentation/extension/repo/ExtensionRepoScreen.kt @@ -29,6 +29,7 @@ import dev.icerock.moko.resources.compose.stringResource import eu.kanade.tachiyomi.util.compose.LocalAlertDialog import eu.kanade.tachiyomi.util.compose.LocalBackPress import eu.kanade.tachiyomi.util.compose.currentOrThrow +import eu.kanade.tachiyomi.util.isTablet import eu.kanade.tachiyomi.util.system.toast import kotlinx.coroutines.flow.collectLatest import yokai.domain.ComposableAlertDialog @@ -101,6 +102,7 @@ fun ExtensionRepoScreen( modifier = Modifier.fillParentMaxSize(), image = Icons.Filled.ExtensionOff, message = stringResource(MR.strings.information_empty_repos), + isTablet = isTablet(), ) } return@LazyColumn