New Feature: Introduce Upcoming page to Mihon (#420)
* Work in progress upcoming feature * Checkpointing WIP upcoming feature * Functional Upcoming Screen * Rename UpdateCalendar to UpdateUpcoming * Converted Strings to resources * Cleanup * Fixed detekt issues * Removed Link icon per @AntsyLich's suggestion. * Detekt * Fixed Calendar display on wide form factor devices * Added Key to upcoming lazycolumn * Updated tablet mode UI to support two column view * Updated header creation logic * Updated header creation logic... again * Moved stray string to resources * Fixed PR Comments and query refactor * Tweaks to query, refactored to flow, comments on calendar * Switched to Date Formatter * Cleaned up date formatter * More Refactor work * Updated Calendar to support localized week formats * Fixed year format * Refactored Header animation * Moved upcoming FAQ * Completed YearMonth Migration * Replaced currentYearMonth with delegate * Even more cleanup * cleaned up alignment modifiers * Click Handler and other refactors * Removed Wrapped Content Height/Size/extra clips * Huge Refactor for CalendarDay * Another cleanup attempt * Migrated to new mihon.feature.* module pattern * changed access modifier * A Bunch of changes from the next round of reviews * Cleanups * Cleanup 2 --------- Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
package mihon.feature.upcoming
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.HelpOutline
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.components.relativeDateText
|
||||
import eu.kanade.presentation.util.isTabletUi
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.ImmutableMap
|
||||
import kotlinx.coroutines.launch
|
||||
import mihon.feature.upcoming.components.UpcomingItem
|
||||
import mihon.feature.upcoming.components.calendar.Calendar
|
||||
import tachiyomi.core.common.Constants
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.FastScrollLazyColumn
|
||||
import tachiyomi.presentation.core.components.ListGroupHeader
|
||||
import tachiyomi.presentation.core.components.TwoPanelBox
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.i18n.stringResource
|
||||
import java.time.LocalDate
|
||||
import java.time.YearMonth
|
||||
|
||||
@Composable
|
||||
fun UpcomingScreenContent(
|
||||
state: UpcomingScreenModel.State,
|
||||
setSelectedYearMonth: (YearMonth) -> Unit,
|
||||
onClickUpcoming: (manga: Manga) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
val listState = rememberLazyListState()
|
||||
val onClickDay: (LocalDate, Int) -> Unit = { date, offset ->
|
||||
state.headerIndexes[date]?.let {
|
||||
scope.launch {
|
||||
listState.animateScrollToItem(it + offset)
|
||||
}
|
||||
}
|
||||
}
|
||||
Scaffold(
|
||||
topBar = { UpcomingToolbar() },
|
||||
modifier = modifier,
|
||||
) { paddingValues ->
|
||||
if (isTabletUi()) {
|
||||
UpcomingScreenLargeImpl(
|
||||
listState = listState,
|
||||
items = state.items,
|
||||
events = state.events,
|
||||
paddingValues = paddingValues,
|
||||
selectedYearMonth = state.selectedYearMonth,
|
||||
setSelectedYearMonth = setSelectedYearMonth,
|
||||
onClickDay = { onClickDay(it, 0) },
|
||||
onClickUpcoming = onClickUpcoming,
|
||||
)
|
||||
} else {
|
||||
UpcomingScreenSmallImpl(
|
||||
listState = listState,
|
||||
items = state.items,
|
||||
events = state.events,
|
||||
paddingValues = paddingValues,
|
||||
selectedYearMonth = state.selectedYearMonth,
|
||||
setSelectedYearMonth = setSelectedYearMonth,
|
||||
onClickDay = { onClickDay(it, 1) },
|
||||
onClickUpcoming = onClickUpcoming,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun UpcomingToolbar() {
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
val uriHandler = LocalUriHandler.current
|
||||
|
||||
AppBar(
|
||||
title = stringResource(MR.strings.label_upcoming),
|
||||
navigateUp = navigator::pop,
|
||||
actions = {
|
||||
IconButton(onClick = { uriHandler.openUri(Constants.URL_HELP_UPCOMING) }) {
|
||||
Icon(
|
||||
imageVector = Icons.AutoMirrored.Outlined.HelpOutline,
|
||||
contentDescription = stringResource(MR.strings.upcoming_guide),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun UpcomingScreenSmallImpl(
|
||||
listState: LazyListState,
|
||||
items: ImmutableList<UpcomingUIModel>,
|
||||
events: ImmutableMap<LocalDate, Int>,
|
||||
paddingValues: PaddingValues,
|
||||
selectedYearMonth: YearMonth,
|
||||
setSelectedYearMonth: (YearMonth) -> Unit,
|
||||
onClickDay: (LocalDate) -> Unit,
|
||||
onClickUpcoming: (manga: Manga) -> Unit,
|
||||
) {
|
||||
FastScrollLazyColumn(
|
||||
contentPadding = paddingValues,
|
||||
state = listState,
|
||||
) {
|
||||
item(key = "upcoming-calendar") {
|
||||
Calendar(
|
||||
selectedYearMonth = selectedYearMonth,
|
||||
events = events,
|
||||
setSelectedYearMonth = setSelectedYearMonth,
|
||||
onClickDay = onClickDay,
|
||||
)
|
||||
}
|
||||
items(
|
||||
items = items,
|
||||
key = { "upcoming-${it.hashCode()}" },
|
||||
contentType = {
|
||||
when (it) {
|
||||
is UpcomingUIModel.Header -> "header"
|
||||
is UpcomingUIModel.Item -> "item"
|
||||
}
|
||||
},
|
||||
) { item ->
|
||||
when (item) {
|
||||
is UpcomingUIModel.Item -> {
|
||||
UpcomingItem(
|
||||
upcoming = item.manga,
|
||||
onClick = { onClickUpcoming(item.manga) },
|
||||
)
|
||||
}
|
||||
is UpcomingUIModel.Header -> {
|
||||
ListGroupHeader(text = relativeDateText(item.date))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun UpcomingScreenLargeImpl(
|
||||
listState: LazyListState,
|
||||
items: ImmutableList<UpcomingUIModel>,
|
||||
events: ImmutableMap<LocalDate, Int>,
|
||||
paddingValues: PaddingValues,
|
||||
selectedYearMonth: YearMonth,
|
||||
setSelectedYearMonth: (YearMonth) -> Unit,
|
||||
onClickDay: (LocalDate) -> Unit,
|
||||
onClickUpcoming: (manga: Manga) -> Unit,
|
||||
) {
|
||||
TwoPanelBox(
|
||||
modifier = Modifier.padding(paddingValues),
|
||||
startContent = {
|
||||
Calendar(
|
||||
selectedYearMonth = selectedYearMonth,
|
||||
events = events,
|
||||
setSelectedYearMonth = setSelectedYearMonth,
|
||||
onClickDay = onClickDay,
|
||||
)
|
||||
},
|
||||
endContent = {
|
||||
FastScrollLazyColumn(state = listState) {
|
||||
items(
|
||||
items = items,
|
||||
key = { "upcoming-${it.hashCode()}" },
|
||||
contentType = {
|
||||
when (it) {
|
||||
is UpcomingUIModel.Header -> "header"
|
||||
is UpcomingUIModel.Item -> "item"
|
||||
}
|
||||
},
|
||||
) { item ->
|
||||
when (item) {
|
||||
is UpcomingUIModel.Item -> {
|
||||
UpcomingItem(
|
||||
upcoming = item.manga,
|
||||
onClick = { onClickUpcoming(item.manga) },
|
||||
)
|
||||
}
|
||||
is UpcomingUIModel.Header -> {
|
||||
ListGroupHeader(text = relativeDateText(item.date))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user