mirror of
https://github.com/mihonapp/mihon.git
synced 2024-12-26 10:58:24 +01:00
EmptyScreen: Compose-ify and apply content padding (#8177)
* Apply content padding to empty screen except the empty screens in browse * compose-ify EmptyScreen * center face when action show * fix padding * apply content padding to browse tabs * fix duplicate bottom insets
This commit is contained in:
parent
23bfa1f18f
commit
8500add09f
@ -13,6 +13,9 @@ import androidx.compose.foundation.layout.size
|
|||||||
import androidx.compose.foundation.lazy.grid.GridCells
|
import androidx.compose.foundation.lazy.grid.GridCells
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.HelpOutline
|
||||||
|
import androidx.compose.material.icons.filled.Public
|
||||||
|
import androidx.compose.material.icons.filled.Refresh
|
||||||
import androidx.compose.material.icons.outlined.Favorite
|
import androidx.compose.material.icons.outlined.Favorite
|
||||||
import androidx.compose.material.icons.outlined.FilterList
|
import androidx.compose.material.icons.outlined.FilterList
|
||||||
import androidx.compose.material.icons.outlined.NewReleases
|
import androidx.compose.material.icons.outlined.NewReleases
|
||||||
@ -49,6 +52,7 @@ import eu.kanade.presentation.browse.components.BrowseSourceToolbar
|
|||||||
import eu.kanade.presentation.components.AppStateBanners
|
import eu.kanade.presentation.components.AppStateBanners
|
||||||
import eu.kanade.presentation.components.Divider
|
import eu.kanade.presentation.components.Divider
|
||||||
import eu.kanade.presentation.components.EmptyScreen
|
import eu.kanade.presentation.components.EmptyScreen
|
||||||
|
import eu.kanade.presentation.components.EmptyScreenAction
|
||||||
import eu.kanade.presentation.components.ExtendedFloatingActionButton
|
import eu.kanade.presentation.components.ExtendedFloatingActionButton
|
||||||
import eu.kanade.presentation.components.LoadingScreen
|
import eu.kanade.presentation.components.LoadingScreen
|
||||||
import eu.kanade.presentation.components.Scaffold
|
import eu.kanade.presentation.components.Scaffold
|
||||||
@ -56,7 +60,6 @@ import eu.kanade.tachiyomi.R
|
|||||||
import eu.kanade.tachiyomi.source.LocalSource
|
import eu.kanade.tachiyomi.source.LocalSource
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
||||||
import eu.kanade.tachiyomi.ui.more.MoreController
|
import eu.kanade.tachiyomi.ui.more.MoreController
|
||||||
import eu.kanade.tachiyomi.widget.EmptyView
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BrowseSourceScreen(
|
fun BrowseSourceScreen(
|
||||||
@ -248,13 +251,29 @@ fun BrowseSourceContent(
|
|||||||
message = getErrorMessage(errorState),
|
message = getErrorMessage(errorState),
|
||||||
actions = if (state.source is LocalSource) {
|
actions = if (state.source is LocalSource) {
|
||||||
listOf(
|
listOf(
|
||||||
EmptyView.Action(R.string.local_source_help_guide, R.drawable.ic_help_24dp) { onLocalSourceHelpClick() },
|
EmptyScreenAction(
|
||||||
|
stringResId = R.string.local_source_help_guide,
|
||||||
|
icon = Icons.Default.HelpOutline,
|
||||||
|
onClick = onLocalSourceHelpClick,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
listOf(
|
listOf(
|
||||||
EmptyView.Action(R.string.action_retry, R.drawable.ic_refresh_24dp) { mangaList.refresh() },
|
EmptyScreenAction(
|
||||||
EmptyView.Action(R.string.action_open_in_web_view, R.drawable.ic_public_24dp) { onWebViewClick() },
|
stringResId = R.string.action_retry,
|
||||||
EmptyView.Action(R.string.label_help, R.drawable.ic_help_24dp) { onHelpClick() },
|
icon = Icons.Default.Refresh,
|
||||||
|
onClick = mangaList::refresh,
|
||||||
|
),
|
||||||
|
EmptyScreenAction(
|
||||||
|
stringResId = R.string.action_open_in_web_view,
|
||||||
|
icon = Icons.Default.Public,
|
||||||
|
onClick = onWebViewClick,
|
||||||
|
),
|
||||||
|
EmptyScreenAction(
|
||||||
|
stringResId = R.string.label_help,
|
||||||
|
icon = Icons.Default.HelpOutline,
|
||||||
|
onClick = onHelpClick,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -133,7 +133,10 @@ private fun ExtensionDetails(
|
|||||||
) {
|
) {
|
||||||
when {
|
when {
|
||||||
presenter.isLoading -> LoadingScreen()
|
presenter.isLoading -> LoadingScreen()
|
||||||
presenter.extension == null -> EmptyScreen(textResource = R.string.empty_screen)
|
presenter.extension == null -> EmptyScreen(
|
||||||
|
textResource = R.string.empty_screen,
|
||||||
|
modifier = Modifier.padding(contentPadding),
|
||||||
|
)
|
||||||
else -> {
|
else -> {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val extension = presenter.extension
|
val extension = presenter.extension
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package eu.kanade.presentation.browse
|
package eu.kanade.presentation.browse
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material3.Switch
|
import androidx.compose.material3.Switch
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@ -37,7 +38,10 @@ fun ExtensionFilterScreen(
|
|||||||
) { contentPadding ->
|
) { contentPadding ->
|
||||||
when {
|
when {
|
||||||
presenter.isLoading -> LoadingScreen()
|
presenter.isLoading -> LoadingScreen()
|
||||||
presenter.isEmpty -> EmptyScreen(textResource = R.string.empty_screen)
|
presenter.isEmpty -> EmptyScreen(
|
||||||
|
textResource = R.string.empty_screen,
|
||||||
|
modifier = Modifier.padding(contentPadding),
|
||||||
|
)
|
||||||
else -> {
|
else -> {
|
||||||
SourceFilterContent(
|
SourceFilterContent(
|
||||||
contentPadding = contentPadding,
|
contentPadding = contentPadding,
|
||||||
|
@ -5,11 +5,9 @@ import androidx.compose.animation.core.animateDpAsState
|
|||||||
import androidx.compose.foundation.combinedClickable
|
import androidx.compose.foundation.combinedClickable
|
||||||
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.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.RowScope
|
import androidx.compose.foundation.layout.RowScope
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
|
||||||
import androidx.compose.foundation.layout.asPaddingValues
|
|
||||||
import androidx.compose.foundation.layout.navigationBars
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
@ -55,11 +53,11 @@ import eu.kanade.tachiyomi.extension.model.InstallStep
|
|||||||
import eu.kanade.tachiyomi.ui.browse.extension.ExtensionUiModel
|
import eu.kanade.tachiyomi.ui.browse.extension.ExtensionUiModel
|
||||||
import eu.kanade.tachiyomi.ui.browse.extension.ExtensionsPresenter
|
import eu.kanade.tachiyomi.ui.browse.extension.ExtensionsPresenter
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
import eu.kanade.tachiyomi.widget.TachiyomiBottomNavigationView.Companion.bottomNavPadding
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ExtensionScreen(
|
fun ExtensionScreen(
|
||||||
presenter: ExtensionsPresenter,
|
presenter: ExtensionsPresenter,
|
||||||
|
contentPadding: PaddingValues,
|
||||||
onLongClickItem: (Extension) -> Unit,
|
onLongClickItem: (Extension) -> Unit,
|
||||||
onClickItemCancel: (Extension) -> Unit,
|
onClickItemCancel: (Extension) -> Unit,
|
||||||
onInstallExtension: (Extension.Available) -> Unit,
|
onInstallExtension: (Extension.Available) -> Unit,
|
||||||
@ -77,10 +75,14 @@ fun ExtensionScreen(
|
|||||||
) {
|
) {
|
||||||
when {
|
when {
|
||||||
presenter.isLoading -> LoadingScreen()
|
presenter.isLoading -> LoadingScreen()
|
||||||
presenter.isEmpty -> EmptyScreen(R.string.empty_screen)
|
presenter.isEmpty -> EmptyScreen(
|
||||||
|
textResource = R.string.empty_screen,
|
||||||
|
modifier = Modifier.padding(contentPadding),
|
||||||
|
)
|
||||||
else -> {
|
else -> {
|
||||||
ExtensionContent(
|
ExtensionContent(
|
||||||
state = presenter,
|
state = presenter,
|
||||||
|
contentPadding = contentPadding,
|
||||||
onLongClickItem = onLongClickItem,
|
onLongClickItem = onLongClickItem,
|
||||||
onClickItemCancel = onClickItemCancel,
|
onClickItemCancel = onClickItemCancel,
|
||||||
onInstallExtension = onInstallExtension,
|
onInstallExtension = onInstallExtension,
|
||||||
@ -98,6 +100,7 @@ fun ExtensionScreen(
|
|||||||
@Composable
|
@Composable
|
||||||
private fun ExtensionContent(
|
private fun ExtensionContent(
|
||||||
state: ExtensionsState,
|
state: ExtensionsState,
|
||||||
|
contentPadding: PaddingValues,
|
||||||
onLongClickItem: (Extension) -> Unit,
|
onLongClickItem: (Extension) -> Unit,
|
||||||
onClickItemCancel: (Extension) -> Unit,
|
onClickItemCancel: (Extension) -> Unit,
|
||||||
onInstallExtension: (Extension.Available) -> Unit,
|
onInstallExtension: (Extension.Available) -> Unit,
|
||||||
@ -110,7 +113,7 @@ private fun ExtensionContent(
|
|||||||
var trustState by remember { mutableStateOf<Extension.Untrusted?>(null) }
|
var trustState by remember { mutableStateOf<Extension.Untrusted?>(null) }
|
||||||
|
|
||||||
FastScrollLazyColumn(
|
FastScrollLazyColumn(
|
||||||
contentPadding = bottomNavPadding + WindowInsets.navigationBars.asPaddingValues() + topPaddingValues,
|
contentPadding = contentPadding + topPaddingValues,
|
||||||
) {
|
) {
|
||||||
items(
|
items(
|
||||||
items = state.items,
|
items = state.items,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package eu.kanade.presentation.browse
|
package eu.kanade.presentation.browse
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
@ -39,7 +40,10 @@ fun MigrateMangaScreen(
|
|||||||
) { contentPadding ->
|
) { contentPadding ->
|
||||||
when {
|
when {
|
||||||
presenter.isLoading -> LoadingScreen()
|
presenter.isLoading -> LoadingScreen()
|
||||||
presenter.isEmpty -> EmptyScreen(textResource = R.string.empty_screen)
|
presenter.isEmpty -> EmptyScreen(
|
||||||
|
textResource = R.string.empty_screen,
|
||||||
|
modifier = Modifier.padding(contentPadding),
|
||||||
|
)
|
||||||
else -> {
|
else -> {
|
||||||
MigrateMangaContent(
|
MigrateMangaContent(
|
||||||
contentPadding = contentPadding,
|
contentPadding = contentPadding,
|
||||||
|
@ -3,10 +3,8 @@ package eu.kanade.presentation.browse
|
|||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
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.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
|
||||||
import androidx.compose.foundation.layout.asPaddingValues
|
|
||||||
import androidx.compose.foundation.layout.navigationBars
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
@ -42,20 +40,24 @@ import eu.kanade.presentation.util.topPaddingValues
|
|||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.ui.browse.migration.sources.MigrationSourcesPresenter
|
import eu.kanade.tachiyomi.ui.browse.migration.sources.MigrationSourcesPresenter
|
||||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||||
import eu.kanade.tachiyomi.widget.TachiyomiBottomNavigationView.Companion.bottomNavPadding
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MigrateSourceScreen(
|
fun MigrateSourceScreen(
|
||||||
presenter: MigrationSourcesPresenter,
|
presenter: MigrationSourcesPresenter,
|
||||||
|
contentPadding: PaddingValues,
|
||||||
onClickItem: (Source) -> Unit,
|
onClickItem: (Source) -> Unit,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
when {
|
when {
|
||||||
presenter.isLoading -> LoadingScreen()
|
presenter.isLoading -> LoadingScreen()
|
||||||
presenter.isEmpty -> EmptyScreen(textResource = R.string.information_empty_library)
|
presenter.isEmpty -> EmptyScreen(
|
||||||
|
textResource = R.string.information_empty_library,
|
||||||
|
modifier = Modifier.padding(contentPadding),
|
||||||
|
)
|
||||||
else ->
|
else ->
|
||||||
MigrateSourceList(
|
MigrateSourceList(
|
||||||
list = presenter.items,
|
list = presenter.items,
|
||||||
|
contentPadding = contentPadding,
|
||||||
onClickItem = onClickItem,
|
onClickItem = onClickItem,
|
||||||
onLongClickItem = { source ->
|
onLongClickItem = { source ->
|
||||||
val sourceId = source.id.toString()
|
val sourceId = source.id.toString()
|
||||||
@ -72,6 +74,7 @@ fun MigrateSourceScreen(
|
|||||||
@Composable
|
@Composable
|
||||||
private fun MigrateSourceList(
|
private fun MigrateSourceList(
|
||||||
list: List<Pair<Source, Long>>,
|
list: List<Pair<Source, Long>>,
|
||||||
|
contentPadding: PaddingValues,
|
||||||
onClickItem: (Source) -> Unit,
|
onClickItem: (Source) -> Unit,
|
||||||
onLongClickItem: (Source) -> Unit,
|
onLongClickItem: (Source) -> Unit,
|
||||||
sortingMode: SetMigrateSorting.Mode,
|
sortingMode: SetMigrateSorting.Mode,
|
||||||
@ -80,7 +83,7 @@ private fun MigrateSourceList(
|
|||||||
onToggleSortingDirection: () -> Unit,
|
onToggleSortingDirection: () -> Unit,
|
||||||
) {
|
) {
|
||||||
ScrollbarLazyColumn(
|
ScrollbarLazyColumn(
|
||||||
contentPadding = bottomNavPadding + WindowInsets.navigationBars.asPaddingValues() + topPaddingValues,
|
contentPadding = contentPadding + topPaddingValues,
|
||||||
) {
|
) {
|
||||||
stickyHeader(key = "header") {
|
stickyHeader(key = "header") {
|
||||||
Row(
|
Row(
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package eu.kanade.presentation.browse
|
package eu.kanade.presentation.browse
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material3.Checkbox
|
import androidx.compose.material3.Checkbox
|
||||||
import androidx.compose.material3.Switch
|
import androidx.compose.material3.Switch
|
||||||
@ -43,7 +44,10 @@ fun SourcesFilterScreen(
|
|||||||
) { contentPadding ->
|
) { contentPadding ->
|
||||||
when {
|
when {
|
||||||
presenter.isLoading -> LoadingScreen()
|
presenter.isLoading -> LoadingScreen()
|
||||||
presenter.isEmpty -> EmptyScreen(textResource = R.string.source_filter_empty_screen)
|
presenter.isEmpty -> EmptyScreen(
|
||||||
|
textResource = R.string.source_filter_empty_screen,
|
||||||
|
modifier = Modifier.padding(contentPadding),
|
||||||
|
)
|
||||||
else -> {
|
else -> {
|
||||||
SourcesFilterContent(
|
SourcesFilterContent(
|
||||||
contentPadding = contentPadding,
|
contentPadding = contentPadding,
|
||||||
|
@ -2,10 +2,8 @@ package eu.kanade.presentation.browse
|
|||||||
|
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.asPaddingValues
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.navigationBars
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
@ -40,12 +38,12 @@ import eu.kanade.tachiyomi.source.LocalSource
|
|||||||
import eu.kanade.tachiyomi.ui.browse.source.SourcesPresenter
|
import eu.kanade.tachiyomi.ui.browse.source.SourcesPresenter
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import eu.kanade.tachiyomi.widget.TachiyomiBottomNavigationView.Companion.bottomNavPadding
|
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SourcesScreen(
|
fun SourcesScreen(
|
||||||
presenter: SourcesPresenter,
|
presenter: SourcesPresenter,
|
||||||
|
contentPadding: PaddingValues,
|
||||||
onClickItem: (Source, String) -> Unit,
|
onClickItem: (Source, String) -> Unit,
|
||||||
onClickDisable: (Source) -> Unit,
|
onClickDisable: (Source) -> Unit,
|
||||||
onClickPin: (Source) -> Unit,
|
onClickPin: (Source) -> Unit,
|
||||||
@ -53,10 +51,14 @@ fun SourcesScreen(
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
when {
|
when {
|
||||||
presenter.isLoading -> LoadingScreen()
|
presenter.isLoading -> LoadingScreen()
|
||||||
presenter.isEmpty -> EmptyScreen(R.string.source_empty_screen)
|
presenter.isEmpty -> EmptyScreen(
|
||||||
|
textResource = R.string.source_empty_screen,
|
||||||
|
modifier = Modifier.padding(contentPadding),
|
||||||
|
)
|
||||||
else -> {
|
else -> {
|
||||||
SourceList(
|
SourceList(
|
||||||
state = presenter,
|
state = presenter,
|
||||||
|
contentPadding = contentPadding,
|
||||||
onClickItem = onClickItem,
|
onClickItem = onClickItem,
|
||||||
onClickDisable = onClickDisable,
|
onClickDisable = onClickDisable,
|
||||||
onClickPin = onClickPin,
|
onClickPin = onClickPin,
|
||||||
@ -77,12 +79,13 @@ fun SourcesScreen(
|
|||||||
@Composable
|
@Composable
|
||||||
private fun SourceList(
|
private fun SourceList(
|
||||||
state: SourcesState,
|
state: SourcesState,
|
||||||
|
contentPadding: PaddingValues,
|
||||||
onClickItem: (Source, String) -> Unit,
|
onClickItem: (Source, String) -> Unit,
|
||||||
onClickDisable: (Source) -> Unit,
|
onClickDisable: (Source) -> Unit,
|
||||||
onClickPin: (Source) -> Unit,
|
onClickPin: (Source) -> Unit,
|
||||||
) {
|
) {
|
||||||
ScrollbarLazyColumn(
|
ScrollbarLazyColumn(
|
||||||
contentPadding = bottomNavPadding + WindowInsets.navigationBars.asPaddingValues() + topPaddingValues,
|
contentPadding = contentPadding + topPaddingValues,
|
||||||
) {
|
) {
|
||||||
items(
|
items(
|
||||||
items = state.items,
|
items = state.items,
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
package eu.kanade.presentation.category
|
package eu.kanade.presentation.category
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
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 eu.kanade.presentation.category.components.CategoryContent
|
import eu.kanade.presentation.category.components.CategoryContent
|
||||||
@ -48,7 +50,10 @@ fun CategoryScreen(
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
when {
|
when {
|
||||||
presenter.isLoading -> LoadingScreen()
|
presenter.isLoading -> LoadingScreen()
|
||||||
presenter.isEmpty -> EmptyScreen(textResource = R.string.information_empty_category)
|
presenter.isEmpty -> EmptyScreen(
|
||||||
|
textResource = R.string.information_empty_category,
|
||||||
|
modifier = Modifier.padding(paddingValues),
|
||||||
|
)
|
||||||
else -> {
|
else -> {
|
||||||
CategoryContent(
|
CategoryContent(
|
||||||
state = presenter,
|
state = presenter,
|
||||||
|
@ -1,23 +1,49 @@
|
|||||||
package eu.kanade.presentation.components
|
package eu.kanade.presentation.components
|
||||||
|
|
||||||
import android.view.ViewGroup
|
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.compose.foundation.layout.Box
|
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.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.paddingFromBaseline
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.HelpOutline
|
||||||
|
import androidx.compose.material.icons.filled.Refresh
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.layout.Layout
|
||||||
|
import androidx.compose.ui.layout.layoutId
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.viewinterop.AndroidView
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
import eu.kanade.tachiyomi.widget.EmptyView
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||||
|
import eu.kanade.presentation.util.secondaryItemAlpha
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun EmptyScreen(
|
fun EmptyScreen(
|
||||||
@StringRes textResource: Int,
|
@StringRes textResource: Int,
|
||||||
actions: List<EmptyView.Action>? = null,
|
modifier: Modifier = Modifier,
|
||||||
|
actions: List<EmptyScreenAction>? = null,
|
||||||
) {
|
) {
|
||||||
EmptyScreen(
|
EmptyScreen(
|
||||||
message = stringResource(textResource),
|
message = stringResource(textResource),
|
||||||
|
modifier = modifier,
|
||||||
actions = actions,
|
actions = actions,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -25,24 +51,174 @@ fun EmptyScreen(
|
|||||||
@Composable
|
@Composable
|
||||||
fun EmptyScreen(
|
fun EmptyScreen(
|
||||||
message: String,
|
message: String,
|
||||||
actions: List<EmptyView.Action>? = null,
|
modifier: Modifier = Modifier,
|
||||||
|
actions: List<EmptyScreenAction>? = null,
|
||||||
) {
|
) {
|
||||||
Box(
|
val face = remember { getRandomErrorFace() }
|
||||||
modifier = Modifier
|
Layout(
|
||||||
.fillMaxSize(),
|
content = {
|
||||||
) {
|
Column(
|
||||||
AndroidView(
|
modifier = Modifier
|
||||||
factory = { context ->
|
.layoutId("face")
|
||||||
EmptyView(context).apply {
|
.padding(horizontal = 24.dp),
|
||||||
layoutParams = ViewGroup.LayoutParams(
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
) {
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
Text(
|
||||||
)
|
text = face,
|
||||||
show(message, actions)
|
modifier = Modifier.secondaryItemAlpha(),
|
||||||
|
fontFamily = FontFamily.Monospace,
|
||||||
|
style = MaterialTheme.typography.displayMedium,
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = message,
|
||||||
|
modifier = Modifier.paddingFromBaseline(top = 24.dp),
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (!actions.isNullOrEmpty()) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.layoutId("actions")
|
||||||
|
.padding(
|
||||||
|
top = 24.dp,
|
||||||
|
start = horizontalPadding,
|
||||||
|
end = horizontalPadding,
|
||||||
|
),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
|
||||||
|
) {
|
||||||
|
actions.forEach {
|
||||||
|
ActionButton(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
title = stringResource(id = it.stringResId),
|
||||||
|
icon = it.icon,
|
||||||
|
onClick = it.onClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
modifier = Modifier
|
},
|
||||||
.align(Alignment.Center),
|
modifier = modifier.fillMaxSize(),
|
||||||
)
|
) { measurables, constraints ->
|
||||||
|
val looseConstraints = constraints.copy(minWidth = 0, minHeight = 0)
|
||||||
|
val facePlaceable = measurables.first { it.layoutId == "face" }
|
||||||
|
.measure(looseConstraints)
|
||||||
|
val actionsPlaceable = measurables.firstOrNull { it.layoutId == "actions" }
|
||||||
|
?.measure(looseConstraints)
|
||||||
|
|
||||||
|
layout(constraints.maxWidth, constraints.maxHeight) {
|
||||||
|
val faceY = (constraints.maxHeight - facePlaceable.height) / 2
|
||||||
|
facePlaceable.placeRelative(
|
||||||
|
x = (constraints.maxWidth - facePlaceable.width) / 2,
|
||||||
|
y = faceY,
|
||||||
|
)
|
||||||
|
|
||||||
|
actionsPlaceable?.placeRelative(
|
||||||
|
x = (constraints.maxWidth - actionsPlaceable.width) / 2,
|
||||||
|
y = faceY + facePlaceable.height,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(
|
||||||
|
name = "Light",
|
||||||
|
widthDp = 400,
|
||||||
|
heightDp = 400,
|
||||||
|
)
|
||||||
|
@Preview(
|
||||||
|
name = "Dark",
|
||||||
|
widthDp = 400,
|
||||||
|
heightDp = 400,
|
||||||
|
uiMode = UI_MODE_NIGHT_YES,
|
||||||
|
)
|
||||||
|
@Composable
|
||||||
|
private fun NoActionPreview() {
|
||||||
|
TachiyomiTheme {
|
||||||
|
Surface {
|
||||||
|
EmptyScreen(
|
||||||
|
textResource = R.string.empty_screen,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(
|
||||||
|
name = "Light",
|
||||||
|
widthDp = 400,
|
||||||
|
heightDp = 400,
|
||||||
|
)
|
||||||
|
@Preview(
|
||||||
|
name = "Dark",
|
||||||
|
widthDp = 400,
|
||||||
|
heightDp = 400,
|
||||||
|
uiMode = UI_MODE_NIGHT_YES,
|
||||||
|
)
|
||||||
|
@Composable
|
||||||
|
private fun WithActionPreview() {
|
||||||
|
TachiyomiTheme {
|
||||||
|
Surface {
|
||||||
|
EmptyScreen(
|
||||||
|
textResource = R.string.empty_screen,
|
||||||
|
actions = listOf(
|
||||||
|
EmptyScreenAction(
|
||||||
|
stringResId = R.string.action_retry,
|
||||||
|
icon = Icons.Default.Refresh,
|
||||||
|
onClick = {},
|
||||||
|
),
|
||||||
|
EmptyScreenAction(
|
||||||
|
stringResId = R.string.getting_started_guide,
|
||||||
|
icon = Icons.Default.HelpOutline,
|
||||||
|
onClick = {},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class EmptyScreenAction(
|
||||||
|
@StringRes val stringResId: Int,
|
||||||
|
val icon: ImageVector,
|
||||||
|
val onClick: () -> Unit,
|
||||||
|
)
|
||||||
|
|
||||||
|
private val horizontalPadding = 24.dp
|
||||||
|
|
||||||
|
private val ERROR_FACES = listOf(
|
||||||
|
"(・o・;)",
|
||||||
|
"Σ(ಠ_ಠ)",
|
||||||
|
"ಥ_ಥ",
|
||||||
|
"(˘・_・˘)",
|
||||||
|
"(; ̄Д ̄)",
|
||||||
|
"(・Д・。",
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun getRandomErrorFace(): String {
|
||||||
|
return ERROR_FACES[Random.nextInt(ERROR_FACES.size)]
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@ package eu.kanade.presentation.components
|
|||||||
|
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.calculateEndPadding
|
import androidx.compose.foundation.layout.calculateEndPadding
|
||||||
import androidx.compose.foundation.layout.calculateStartPadding
|
import androidx.compose.foundation.layout.calculateStartPadding
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
@ -17,6 +18,7 @@ import androidx.compose.ui.platform.LocalLayoutDirection
|
|||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import com.google.accompanist.pager.HorizontalPager
|
import com.google.accompanist.pager.HorizontalPager
|
||||||
import com.google.accompanist.pager.rememberPagerState
|
import com.google.accompanist.pager.rememberPagerState
|
||||||
|
import eu.kanade.tachiyomi.widget.TachiyomiBottomNavigationView
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -95,7 +97,11 @@ fun TabbedScreen(
|
|||||||
state = state,
|
state = state,
|
||||||
verticalAlignment = Alignment.Top,
|
verticalAlignment = Alignment.Top,
|
||||||
) { page ->
|
) { page ->
|
||||||
tabs[page].content()
|
tabs[page].content(
|
||||||
|
TachiyomiBottomNavigationView.withBottomNavPadding(
|
||||||
|
PaddingValues(bottom = contentPadding.calculateBottomPadding()),
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,5 +111,5 @@ data class TabContent(
|
|||||||
@StringRes val titleRes: Int,
|
@StringRes val titleRes: Int,
|
||||||
val badgeNumber: Int? = null,
|
val badgeNumber: Int? = null,
|
||||||
val actions: List<AppBar.Action> = emptyList(),
|
val actions: List<AppBar.Action> = emptyList(),
|
||||||
val content: @Composable () -> Unit,
|
val content: @Composable (contentPadding: PaddingValues) -> Unit,
|
||||||
)
|
)
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
package eu.kanade.presentation.history
|
package eu.kanade.presentation.history
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import eu.kanade.domain.history.model.HistoryWithRelations
|
import eu.kanade.domain.history.model.HistoryWithRelations
|
||||||
import eu.kanade.presentation.components.EmptyScreen
|
import eu.kanade.presentation.components.EmptyScreen
|
||||||
@ -19,6 +21,7 @@ import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
|||||||
import eu.kanade.tachiyomi.ui.recent.history.HistoryPresenter
|
import eu.kanade.tachiyomi.ui.recent.history.HistoryPresenter
|
||||||
import eu.kanade.tachiyomi.ui.recent.history.HistoryPresenter.Dialog
|
import eu.kanade.tachiyomi.ui.recent.history.HistoryPresenter.Dialog
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
|
import eu.kanade.tachiyomi.widget.TachiyomiBottomNavigationView
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
@ -41,15 +44,19 @@ fun HistoryScreen(
|
|||||||
},
|
},
|
||||||
) { contentPadding ->
|
) { contentPadding ->
|
||||||
val items by presenter.getHistory().collectAsState(initial = null)
|
val items by presenter.getHistory().collectAsState(initial = null)
|
||||||
|
val contentPaddingWithNavBar = TachiyomiBottomNavigationView.withBottomNavPadding(contentPadding)
|
||||||
items.let {
|
items.let {
|
||||||
if (it == null) {
|
if (it == null) {
|
||||||
LoadingScreen()
|
LoadingScreen()
|
||||||
} else if (it.isEmpty()) {
|
} else if (it.isEmpty()) {
|
||||||
EmptyScreen(textResource = R.string.information_no_recent_manga)
|
EmptyScreen(
|
||||||
|
textResource = R.string.information_no_recent_manga,
|
||||||
|
modifier = Modifier.padding(contentPaddingWithNavBar),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
HistoryContent(
|
HistoryContent(
|
||||||
history = it,
|
history = it,
|
||||||
contentPadding = contentPadding,
|
contentPadding = contentPaddingWithNavBar,
|
||||||
onClickCover = onClickCover,
|
onClickCover = onClickCover,
|
||||||
onClickResume = onClickResume,
|
onClickResume = onClickResume,
|
||||||
onClickDelete = { item -> presenter.dialog = Dialog.Delete(item) },
|
onClickDelete = { item -> presenter.dialog = Dialog.Delete(item) },
|
||||||
|
@ -11,8 +11,6 @@ import eu.kanade.presentation.components.RelativeDateHeader
|
|||||||
import eu.kanade.presentation.components.ScrollbarLazyColumn
|
import eu.kanade.presentation.components.ScrollbarLazyColumn
|
||||||
import eu.kanade.presentation.history.HistoryUiModel
|
import eu.kanade.presentation.history.HistoryUiModel
|
||||||
import eu.kanade.presentation.util.plus
|
import eu.kanade.presentation.util.plus
|
||||||
import eu.kanade.presentation.util.topPaddingValues
|
|
||||||
import eu.kanade.tachiyomi.widget.TachiyomiBottomNavigationView.Companion.bottomNavPadding
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
@ -30,7 +28,7 @@ fun HistoryContent(
|
|||||||
val dateFormat: DateFormat = remember { UiPreferences.dateFormat(preferences.dateFormat().get()) }
|
val dateFormat: DateFormat = remember { UiPreferences.dateFormat(preferences.dateFormat().get()) }
|
||||||
|
|
||||||
ScrollbarLazyColumn(
|
ScrollbarLazyColumn(
|
||||||
contentPadding = contentPadding + bottomNavPadding + topPaddingValues,
|
contentPadding = contentPadding,
|
||||||
) {
|
) {
|
||||||
items(
|
items(
|
||||||
items = history,
|
items = history,
|
||||||
|
@ -1,17 +1,26 @@
|
|||||||
package eu.kanade.presentation.library
|
package eu.kanade.presentation.library
|
||||||
|
|
||||||
import androidx.compose.animation.Crossfade
|
import androidx.compose.animation.Crossfade
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.HelpOutline
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
import eu.kanade.domain.category.model.Category
|
import eu.kanade.domain.category.model.Category
|
||||||
import eu.kanade.domain.library.model.display
|
import eu.kanade.domain.library.model.display
|
||||||
|
import eu.kanade.presentation.components.EmptyScreen
|
||||||
|
import eu.kanade.presentation.components.EmptyScreenAction
|
||||||
import eu.kanade.presentation.components.LibraryBottomActionMenu
|
import eu.kanade.presentation.components.LibraryBottomActionMenu
|
||||||
import eu.kanade.presentation.components.LoadingScreen
|
import eu.kanade.presentation.components.LoadingScreen
|
||||||
import eu.kanade.presentation.components.Scaffold
|
import eu.kanade.presentation.components.Scaffold
|
||||||
import eu.kanade.presentation.library.components.LibraryContent
|
import eu.kanade.presentation.library.components.LibraryContent
|
||||||
import eu.kanade.presentation.library.components.LibraryToolbar
|
import eu.kanade.presentation.library.components.LibraryToolbar
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.LocalSource
|
import eu.kanade.tachiyomi.source.LocalSource
|
||||||
import eu.kanade.tachiyomi.ui.library.LibraryPresenter
|
import eu.kanade.tachiyomi.ui.library.LibraryPresenter
|
||||||
|
import eu.kanade.tachiyomi.widget.TachiyomiBottomNavigationView
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LibraryScreen(
|
fun LibraryScreen(
|
||||||
@ -60,9 +69,26 @@ fun LibraryScreen(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
|
val contentPadding = TachiyomiBottomNavigationView.withBottomNavPadding(paddingValues)
|
||||||
|
if (presenter.searchQuery.isNullOrEmpty() && presenter.isLibraryEmpty) {
|
||||||
|
val handler = LocalUriHandler.current
|
||||||
|
EmptyScreen(
|
||||||
|
textResource = R.string.information_empty_library,
|
||||||
|
modifier = Modifier.padding(contentPadding),
|
||||||
|
actions = listOf(
|
||||||
|
EmptyScreenAction(
|
||||||
|
stringResId = R.string.getting_started_guide,
|
||||||
|
icon = Icons.Default.HelpOutline,
|
||||||
|
onClick = { handler.openUri("https://tachiyomi.org/help/guides/getting-started") },
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return@Scaffold
|
||||||
|
}
|
||||||
|
|
||||||
LibraryContent(
|
LibraryContent(
|
||||||
state = presenter,
|
state = presenter,
|
||||||
contentPadding = paddingValues,
|
contentPadding = contentPadding,
|
||||||
currentPage = { presenter.activeCategory },
|
currentPage = { presenter.activeCategory },
|
||||||
isLibraryEmpty = presenter.isLibraryEmpty,
|
isLibraryEmpty = presenter.isLibraryEmpty,
|
||||||
showPageTabs = presenter.tabVisibility,
|
showPageTabs = presenter.tabVisibility,
|
||||||
|
@ -15,7 +15,6 @@ import androidx.compose.ui.zIndex
|
|||||||
import eu.kanade.presentation.components.FastScrollLazyVerticalGrid
|
import eu.kanade.presentation.components.FastScrollLazyVerticalGrid
|
||||||
import eu.kanade.presentation.util.plus
|
import eu.kanade.presentation.util.plus
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.widget.TachiyomiBottomNavigationView.Companion.bottomNavPadding
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LazyLibraryGrid(
|
fun LazyLibraryGrid(
|
||||||
@ -27,7 +26,7 @@ fun LazyLibraryGrid(
|
|||||||
FastScrollLazyVerticalGrid(
|
FastScrollLazyVerticalGrid(
|
||||||
columns = if (columns == 0) GridCells.Adaptive(128.dp) else GridCells.Fixed(columns),
|
columns = if (columns == 0) GridCells.Adaptive(128.dp) else GridCells.Fixed(columns),
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
contentPadding = contentPadding + bottomNavPadding + PaddingValues(12.dp),
|
contentPadding = contentPadding + PaddingValues(12.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||||
content = content,
|
content = content,
|
||||||
|
@ -15,18 +15,15 @@ import androidx.compose.runtime.rememberCoroutineScope
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||||
import androidx.compose.ui.platform.LocalUriHandler
|
|
||||||
import com.google.accompanist.pager.rememberPagerState
|
import com.google.accompanist.pager.rememberPagerState
|
||||||
import eu.kanade.core.prefs.PreferenceMutableState
|
import eu.kanade.core.prefs.PreferenceMutableState
|
||||||
import eu.kanade.domain.category.model.Category
|
import eu.kanade.domain.category.model.Category
|
||||||
import eu.kanade.domain.library.model.LibraryDisplayMode
|
import eu.kanade.domain.library.model.LibraryDisplayMode
|
||||||
import eu.kanade.domain.library.model.LibraryManga
|
import eu.kanade.domain.library.model.LibraryManga
|
||||||
import eu.kanade.presentation.components.EmptyScreen
|
|
||||||
import eu.kanade.presentation.components.SwipeRefresh
|
import eu.kanade.presentation.components.SwipeRefresh
|
||||||
import eu.kanade.presentation.library.LibraryState
|
import eu.kanade.presentation.library.LibraryState
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.presentation.util.plus
|
||||||
import eu.kanade.tachiyomi.ui.library.LibraryItem
|
import eu.kanade.tachiyomi.ui.library.LibraryItem
|
||||||
import eu.kanade.tachiyomi.widget.EmptyView
|
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@ -100,19 +97,6 @@ fun LibraryContent(
|
|||||||
},
|
},
|
||||||
enabled = state.selectionMode.not(),
|
enabled = state.selectionMode.not(),
|
||||||
) {
|
) {
|
||||||
if (state.searchQuery.isNullOrEmpty() && isLibraryEmpty) {
|
|
||||||
val handler = LocalUriHandler.current
|
|
||||||
EmptyScreen(
|
|
||||||
R.string.information_empty_library,
|
|
||||||
listOf(
|
|
||||||
EmptyView.Action(R.string.getting_started_guide, R.drawable.ic_help_24dp) {
|
|
||||||
handler.openUri("https://tachiyomi.org/help/guides/getting-started")
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
return@SwipeRefresh
|
|
||||||
}
|
|
||||||
|
|
||||||
LibraryPager(
|
LibraryPager(
|
||||||
state = pagerState,
|
state = pagerState,
|
||||||
contentPadding = PaddingValues(bottom = contentPadding.calculateBottomPadding()),
|
contentPadding = PaddingValues(bottom = contentPadding.calculateBottomPadding()),
|
||||||
|
@ -31,7 +31,6 @@ import eu.kanade.presentation.util.selectedBackground
|
|||||||
import eu.kanade.presentation.util.verticalPadding
|
import eu.kanade.presentation.util.verticalPadding
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.ui.library.LibraryItem
|
import eu.kanade.tachiyomi.ui.library.LibraryItem
|
||||||
import eu.kanade.tachiyomi.widget.TachiyomiBottomNavigationView.Companion.bottomNavPadding
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LibraryList(
|
fun LibraryList(
|
||||||
@ -45,7 +44,7 @@ fun LibraryList(
|
|||||||
) {
|
) {
|
||||||
FastScrollLazyColumn(
|
FastScrollLazyColumn(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
contentPadding = bottomNavPadding + contentPadding,
|
contentPadding = contentPadding,
|
||||||
) {
|
) {
|
||||||
item {
|
item {
|
||||||
if (searchQuery.isNullOrEmpty().not()) {
|
if (searchQuery.isNullOrEmpty().not()) {
|
||||||
|
@ -27,7 +27,7 @@ import eu.kanade.tachiyomi.R
|
|||||||
import eu.kanade.tachiyomi.ui.more.DownloadQueueState
|
import eu.kanade.tachiyomi.ui.more.DownloadQueueState
|
||||||
import eu.kanade.tachiyomi.ui.more.MoreController
|
import eu.kanade.tachiyomi.ui.more.MoreController
|
||||||
import eu.kanade.tachiyomi.ui.more.MorePresenter
|
import eu.kanade.tachiyomi.ui.more.MorePresenter
|
||||||
import eu.kanade.tachiyomi.widget.TachiyomiBottomNavigationView.Companion.bottomNavPadding
|
import eu.kanade.tachiyomi.widget.TachiyomiBottomNavigationView
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MoreScreen(
|
fun MoreScreen(
|
||||||
@ -43,7 +43,7 @@ fun MoreScreen(
|
|||||||
|
|
||||||
ScrollbarLazyColumn(
|
ScrollbarLazyColumn(
|
||||||
modifier = Modifier.statusBarsPadding(),
|
modifier = Modifier.statusBarsPadding(),
|
||||||
contentPadding = bottomNavPadding,
|
contentPadding = TachiyomiBottomNavigationView.withBottomNavPadding(),
|
||||||
) {
|
) {
|
||||||
item {
|
item {
|
||||||
LogoHeader()
|
LogoHeader()
|
||||||
|
@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.PaddingValues
|
|||||||
import androidx.compose.foundation.layout.calculateEndPadding
|
import androidx.compose.foundation.layout.calculateEndPadding
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.FlipToBack
|
import androidx.compose.material.icons.filled.FlipToBack
|
||||||
@ -33,7 +34,6 @@ import eu.kanade.presentation.components.MangaBottomActionMenu
|
|||||||
import eu.kanade.presentation.components.Scaffold
|
import eu.kanade.presentation.components.Scaffold
|
||||||
import eu.kanade.presentation.components.SwipeRefresh
|
import eu.kanade.presentation.components.SwipeRefresh
|
||||||
import eu.kanade.presentation.components.VerticalFastScroller
|
import eu.kanade.presentation.components.VerticalFastScroller
|
||||||
import eu.kanade.presentation.util.plus
|
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
||||||
@ -43,7 +43,7 @@ import eu.kanade.tachiyomi.ui.recent.updates.UpdatesPresenter
|
|||||||
import eu.kanade.tachiyomi.ui.recent.updates.UpdatesPresenter.Dialog
|
import eu.kanade.tachiyomi.ui.recent.updates.UpdatesPresenter.Dialog
|
||||||
import eu.kanade.tachiyomi.ui.recent.updates.UpdatesPresenter.Event
|
import eu.kanade.tachiyomi.ui.recent.updates.UpdatesPresenter.Event
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import eu.kanade.tachiyomi.widget.TachiyomiBottomNavigationView.Companion.bottomNavPadding
|
import eu.kanade.tachiyomi.widget.TachiyomiBottomNavigationView
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -96,13 +96,17 @@ fun UpdateScreen(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
) { contentPadding ->
|
) { contentPadding ->
|
||||||
|
val contentPaddingWithNavBar = TachiyomiBottomNavigationView.withBottomNavPadding(contentPadding)
|
||||||
when {
|
when {
|
||||||
presenter.isLoading -> LoadingScreen()
|
presenter.isLoading -> LoadingScreen()
|
||||||
presenter.uiModels.isEmpty() -> EmptyScreen(textResource = R.string.information_no_recent)
|
presenter.uiModels.isEmpty() -> EmptyScreen(
|
||||||
|
textResource = R.string.information_no_recent,
|
||||||
|
modifier = Modifier.padding(contentPaddingWithNavBar),
|
||||||
|
)
|
||||||
else -> {
|
else -> {
|
||||||
UpdateScreenContent(
|
UpdateScreenContent(
|
||||||
presenter = presenter,
|
presenter = presenter,
|
||||||
contentPadding = contentPadding,
|
contentPadding = contentPaddingWithNavBar,
|
||||||
onUpdateLibrary = onUpdateLibrary,
|
onUpdateLibrary = onUpdateLibrary,
|
||||||
onClickCover = onClickCover,
|
onClickCover = onClickCover,
|
||||||
)
|
)
|
||||||
@ -120,10 +124,6 @@ private fun UpdateScreenContent(
|
|||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val updatesListState = rememberLazyListState()
|
val updatesListState = rememberLazyListState()
|
||||||
|
|
||||||
// During selection mode bottom nav is not visible
|
|
||||||
val contentPaddingWithNavBar = contentPadding + bottomNavPadding
|
|
||||||
|
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
var isRefreshing by remember { mutableStateOf(false) }
|
var isRefreshing by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
@ -140,39 +140,35 @@ private fun UpdateScreenContent(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
enabled = presenter.selectionMode.not(),
|
enabled = presenter.selectionMode.not(),
|
||||||
indicatorPadding = contentPaddingWithNavBar,
|
indicatorPadding = contentPadding,
|
||||||
) {
|
) {
|
||||||
if (presenter.uiModels.isEmpty()) {
|
VerticalFastScroller(
|
||||||
EmptyScreen(textResource = R.string.information_no_recent)
|
listState = updatesListState,
|
||||||
} else {
|
topContentPadding = contentPadding.calculateTopPadding(),
|
||||||
VerticalFastScroller(
|
endContentPadding = contentPadding.calculateEndPadding(LocalLayoutDirection.current),
|
||||||
listState = updatesListState,
|
) {
|
||||||
topContentPadding = contentPaddingWithNavBar.calculateTopPadding(),
|
LazyColumn(
|
||||||
endContentPadding = contentPaddingWithNavBar.calculateEndPadding(LocalLayoutDirection.current),
|
modifier = Modifier.fillMaxHeight(),
|
||||||
|
state = updatesListState,
|
||||||
|
contentPadding = contentPadding,
|
||||||
) {
|
) {
|
||||||
LazyColumn(
|
if (presenter.lastUpdated > 0L) {
|
||||||
modifier = Modifier.fillMaxHeight(),
|
updatesLastUpdatedItem(presenter.lastUpdated)
|
||||||
state = updatesListState,
|
|
||||||
contentPadding = contentPaddingWithNavBar,
|
|
||||||
) {
|
|
||||||
if (presenter.lastUpdated > 0L) {
|
|
||||||
updatesLastUpdatedItem(presenter.lastUpdated)
|
|
||||||
}
|
|
||||||
|
|
||||||
updatesUiItems(
|
|
||||||
uiModels = presenter.uiModels,
|
|
||||||
selectionMode = presenter.selectionMode,
|
|
||||||
onUpdateSelected = presenter::toggleSelection,
|
|
||||||
onClickCover = onClickCover,
|
|
||||||
onClickUpdate = {
|
|
||||||
val intent = ReaderActivity.newIntent(context, it.update.mangaId, it.update.chapterId)
|
|
||||||
context.startActivity(intent)
|
|
||||||
},
|
|
||||||
onDownloadChapter = presenter::downloadChapters,
|
|
||||||
relativeTime = presenter.relativeTime,
|
|
||||||
dateFormat = presenter.dateFormat,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updatesUiItems(
|
||||||
|
uiModels = presenter.uiModels,
|
||||||
|
selectionMode = presenter.selectionMode,
|
||||||
|
onUpdateSelected = presenter::toggleSelection,
|
||||||
|
onClickCover = onClickCover,
|
||||||
|
onClickUpdate = {
|
||||||
|
val intent = ReaderActivity.newIntent(context, it.update.mangaId, it.update.chapterId)
|
||||||
|
context.startActivity(intent)
|
||||||
|
},
|
||||||
|
onDownloadChapter = presenter::downloadChapters,
|
||||||
|
relativeTime = presenter.relativeTime,
|
||||||
|
dateFormat = presenter.dateFormat,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,9 +34,10 @@ fun extensionsTab(
|
|||||||
onClick = { router?.pushController(ExtensionFilterController()) },
|
onClick = { router?.pushController(ExtensionFilterController()) },
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
content = {
|
content = { contentPadding ->
|
||||||
ExtensionScreen(
|
ExtensionScreen(
|
||||||
presenter = presenter,
|
presenter = presenter,
|
||||||
|
contentPadding = contentPadding,
|
||||||
onLongClickItem = { extension ->
|
onLongClickItem = { extension ->
|
||||||
when (extension) {
|
when (extension) {
|
||||||
is Extension.Available -> presenter.installExtension(extension)
|
is Extension.Available -> presenter.installExtension(extension)
|
||||||
|
@ -31,9 +31,10 @@ fun migrateSourcesTab(
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
content = {
|
content = { contentPadding ->
|
||||||
MigrateSourceScreen(
|
MigrateSourceScreen(
|
||||||
presenter = presenter,
|
presenter = presenter,
|
||||||
|
contentPadding = contentPadding,
|
||||||
onClickItem = { source ->
|
onClickItem = { source ->
|
||||||
router?.pushController(
|
router?.pushController(
|
||||||
MigrationMangaController(
|
MigrationMangaController(
|
||||||
|
@ -32,9 +32,10 @@ fun sourcesTab(
|
|||||||
onClick = { router?.pushController(SourceFilterController()) },
|
onClick = { router?.pushController(SourceFilterController()) },
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
content = {
|
content = { contentPadding ->
|
||||||
SourcesScreen(
|
SourcesScreen(
|
||||||
presenter = presenter,
|
presenter = presenter,
|
||||||
|
contentPadding = contentPadding,
|
||||||
onClickItem = { source, query ->
|
onClickItem = { source, query ->
|
||||||
presenter.onOpenSource(source)
|
presenter.onOpenSource(source)
|
||||||
router?.pushController(BrowseSourceController(source, query))
|
router?.pushController(BrowseSourceController(source, query))
|
||||||
|
@ -256,7 +256,10 @@ class DownloadController :
|
|||||||
},
|
},
|
||||||
) { contentPadding ->
|
) { contentPadding ->
|
||||||
if (downloadList.isEmpty()) {
|
if (downloadList.isEmpty()) {
|
||||||
EmptyScreen(textResource = R.string.information_no_downloads)
|
EmptyScreen(
|
||||||
|
textResource = R.string.information_no_downloads,
|
||||||
|
modifier = Modifier.padding(contentPadding),
|
||||||
|
)
|
||||||
return@Scaffold
|
return@Scaffold
|
||||||
}
|
}
|
||||||
val density = LocalDensity.current
|
val density = LocalDensity.current
|
||||||
|
@ -1,26 +1,24 @@
|
|||||||
package eu.kanade.tachiyomi.widget
|
package eu.kanade.tachiyomi.widget
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.ColorStateList
|
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.RelativeLayout
|
|
||||||
import androidx.annotation.DrawableRes
|
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.appcompat.view.ContextThemeWrapper
|
import androidx.compose.material3.LocalContentColor
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.platform.AbstractComposeView
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import com.google.android.material.button.MaterialButton
|
import eu.kanade.presentation.components.EmptyScreen
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||||
import eu.kanade.tachiyomi.databinding.CommonViewEmptyBinding
|
|
||||||
import eu.kanade.tachiyomi.util.system.getThemeColor
|
|
||||||
import kotlin.random.Random
|
|
||||||
|
|
||||||
class EmptyView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
class EmptyView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
||||||
RelativeLayout(context, attrs) {
|
AbstractComposeView(context, attrs) {
|
||||||
|
|
||||||
private val binding: CommonViewEmptyBinding =
|
var message by mutableStateOf("")
|
||||||
CommonViewEmptyBinding.inflate(LayoutInflater.from(context), this, true)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hide the information view
|
* Hide the information view
|
||||||
@ -33,62 +31,17 @@ class EmptyView @JvmOverloads constructor(context: Context, attrs: AttributeSet?
|
|||||||
* Show the information view
|
* Show the information view
|
||||||
* @param textResource text of information view
|
* @param textResource text of information view
|
||||||
*/
|
*/
|
||||||
fun show(@StringRes textResource: Int, actions: List<Action>? = null) {
|
fun show(@StringRes textResource: Int) {
|
||||||
show(context.getString(textResource), actions)
|
message = context.getString(textResource)
|
||||||
}
|
|
||||||
|
|
||||||
fun show(message: String, actions: List<Action>? = null) {
|
|
||||||
binding.textFace.text = getRandomErrorFace()
|
|
||||||
binding.textLabel.text = message
|
|
||||||
|
|
||||||
binding.actionsContainer.removeAllViews()
|
|
||||||
val buttonContext = ContextThemeWrapper(context, R.style.Widget_Tachiyomi_Button_ActionButton)
|
|
||||||
val buttonColor = ColorStateList.valueOf(context.getThemeColor(R.attr.colorOnBackground))
|
|
||||||
actions?.forEach {
|
|
||||||
val button = MaterialButton(
|
|
||||||
buttonContext,
|
|
||||||
null,
|
|
||||||
R.attr.borderlessButtonStyle,
|
|
||||||
).apply {
|
|
||||||
layoutParams = LinearLayout.LayoutParams(
|
|
||||||
0,
|
|
||||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
|
||||||
1f / actions.size,
|
|
||||||
)
|
|
||||||
|
|
||||||
setTextColor(buttonColor)
|
|
||||||
iconTint = buttonColor
|
|
||||||
|
|
||||||
setIconResource(it.iconResId)
|
|
||||||
setText(it.stringResId)
|
|
||||||
|
|
||||||
setOnClickListener(it.listener)
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.actionsContainer.addView(button)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isVisible = true
|
this.isVisible = true
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
@Composable
|
||||||
private val ERROR_FACES = listOf(
|
override fun Content() {
|
||||||
"(・o・;)",
|
TachiyomiTheme {
|
||||||
"Σ(ಠ_ಠ)",
|
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onBackground) {
|
||||||
"ಥ_ಥ",
|
EmptyScreen(message = message)
|
||||||
"(˘・_・˘)",
|
}
|
||||||
"(; ̄Д ̄)",
|
|
||||||
"(・Д・。",
|
|
||||||
)
|
|
||||||
|
|
||||||
fun getRandomErrorFace(): String {
|
|
||||||
return ERROR_FACES[Random.nextInt(ERROR_FACES.size)]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Action(
|
|
||||||
@StringRes val stringResId: Int,
|
|
||||||
@DrawableRes val iconResId: Int,
|
|
||||||
val listener: OnClickListener,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
@ -9,10 +9,16 @@ import android.os.Parcelable
|
|||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.ViewPropertyAnimator
|
import android.view.ViewPropertyAnimator
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.calculateEndPadding
|
||||||
|
import androidx.compose.foundation.layout.calculateStartPadding
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.ReadOnlyComposable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.max
|
||||||
import androidx.customview.view.AbsSavedState
|
import androidx.customview.view.AbsSavedState
|
||||||
import androidx.interpolator.view.animation.FastOutLinearInInterpolator
|
import androidx.interpolator.view.animation.FastOutLinearInInterpolator
|
||||||
import androidx.interpolator.view.animation.LinearOutSlowInInterpolator
|
import androidx.interpolator.view.animation.LinearOutSlowInInterpolator
|
||||||
@ -58,7 +64,7 @@ class TachiyomiBottomNavigationView @JvmOverloads constructor(
|
|||||||
|
|
||||||
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
||||||
super.onSizeChanged(w, h, oldw, oldh)
|
super.onSizeChanged(w, h, oldw, oldh)
|
||||||
bottomNavPadding = PaddingValues(bottom = h.pxToDp.dp)
|
bottomNavPadding = h.pxToDp.dp
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -74,6 +80,7 @@ class TachiyomiBottomNavigationView @JvmOverloads constructor(
|
|||||||
SLIDE_UP_ANIMATION_DURATION,
|
SLIDE_UP_ANIMATION_DURATION,
|
||||||
LinearOutSlowInInterpolator(),
|
LinearOutSlowInInterpolator(),
|
||||||
)
|
)
|
||||||
|
bottomNavPadding = height.pxToDp.dp
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -89,6 +96,7 @@ class TachiyomiBottomNavigationView @JvmOverloads constructor(
|
|||||||
SLIDE_DOWN_ANIMATION_DURATION,
|
SLIDE_DOWN_ANIMATION_DURATION,
|
||||||
FastOutLinearInInterpolator(),
|
FastOutLinearInInterpolator(),
|
||||||
)
|
)
|
||||||
|
bottomNavPadding = 0.dp
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun animateTranslation(targetY: Float, duration: Long, interpolator: TimeInterpolator) {
|
private fun animateTranslation(targetY: Float, duration: Long, interpolator: TimeInterpolator) {
|
||||||
@ -149,7 +157,21 @@ class TachiyomiBottomNavigationView @JvmOverloads constructor(
|
|||||||
private const val SLIDE_UP_ANIMATION_DURATION = 225L
|
private const val SLIDE_UP_ANIMATION_DURATION = 225L
|
||||||
private const val SLIDE_DOWN_ANIMATION_DURATION = 175L
|
private const val SLIDE_DOWN_ANIMATION_DURATION = 175L
|
||||||
|
|
||||||
var bottomNavPadding by mutableStateOf(PaddingValues())
|
private var bottomNavPadding by mutableStateOf(0.dp)
|
||||||
private set
|
|
||||||
|
/**
|
||||||
|
* Merges [bottomNavPadding] to the origin's [PaddingValues] bottom side.
|
||||||
|
*/
|
||||||
|
@ReadOnlyComposable
|
||||||
|
@Composable
|
||||||
|
fun withBottomNavPadding(origin: PaddingValues = PaddingValues()): PaddingValues {
|
||||||
|
val layoutDirection = LocalLayoutDirection.current
|
||||||
|
return PaddingValues(
|
||||||
|
start = origin.calculateStartPadding(layoutDirection),
|
||||||
|
top = origin.calculateTopPadding(),
|
||||||
|
end = origin.calculateEndPadding(layoutDirection),
|
||||||
|
bottom = max(origin.calculateBottomPadding(), bottomNavPadding),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="16dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/text_face"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center"
|
|
||||||
android:textAppearance="?attr/textAppearanceBodyMedium"
|
|
||||||
android:textColor="?android:attr/textColorSecondary"
|
|
||||||
android:textSize="48sp"
|
|
||||||
tools:text="-_-" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/text_label"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_margin="16dp"
|
|
||||||
android:gravity="center"
|
|
||||||
android:textAppearance="?attr/textAppearanceBodyMedium"
|
|
||||||
android:textColor="?android:attr/textColorSecondary"
|
|
||||||
tools:text="Label" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/actions_container"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
@ -81,16 +81,6 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
<!--==============-->
|
|
||||||
<!--Widgets.Button-->
|
|
||||||
<!--==============-->
|
|
||||||
<style name="Widget.Tachiyomi.Button.ActionButton" parent="Widget.Material3.Button.TextButton.Icon">
|
|
||||||
<item name="iconGravity">top</item>
|
|
||||||
<item name="iconTint">@color/button_action_selector</item>
|
|
||||||
<item name="iconPadding">4dp</item>
|
|
||||||
<item name="android:textColor">@color/button_action_selector</item>
|
|
||||||
<item name="android:textSize">12sp</item>
|
|
||||||
</style>
|
|
||||||
<!--=======================-->
|
<!--=======================-->
|
||||||
<!--Widgets.MaterialDivider-->
|
<!--Widgets.MaterialDivider-->
|
||||||
<!--=======================-->
|
<!--=======================-->
|
||||||
|
Loading…
Reference in New Issue
Block a user