-
Notifications
You must be signed in to change notification settings - Fork 496
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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>
- Loading branch information
Showing
22 changed files
with
797 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 23 additions & 0 deletions
23
app/src/main/java/mihon/core/designsystem/utils/WindowSize.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package mihon.core.designsystem.utils | ||
|
||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.ReadOnlyComposable | ||
import androidx.compose.ui.platform.LocalConfiguration | ||
import androidx.compose.ui.unit.dp | ||
|
||
@Composable | ||
@ReadOnlyComposable | ||
fun isMediumWidthWindow(): Boolean { | ||
val configuration = LocalConfiguration.current | ||
return configuration.screenWidthDp > MediumWidthWindowSize.value | ||
} | ||
|
||
@Composable | ||
@ReadOnlyComposable | ||
fun isExpandedWidthWindow(): Boolean { | ||
val configuration = LocalConfiguration.current | ||
return configuration.screenWidthDp > ExpandedWidthWindowSize.value | ||
} | ||
|
||
val MediumWidthWindowSize = 600.dp | ||
val ExpandedWidthWindowSize = 840.dp |
27 changes: 27 additions & 0 deletions
27
app/src/main/java/mihon/feature/upcoming/UpcomingScreen.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package mihon.feature.upcoming | ||
|
||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.collectAsState | ||
import androidx.compose.runtime.getValue | ||
import cafe.adriel.voyager.core.model.rememberScreenModel | ||
import cafe.adriel.voyager.navigator.LocalNavigator | ||
import cafe.adriel.voyager.navigator.currentOrThrow | ||
import eu.kanade.presentation.util.Screen | ||
import eu.kanade.tachiyomi.ui.manga.MangaScreen | ||
|
||
class UpcomingScreen : Screen() { | ||
|
||
@Composable | ||
override fun Content() { | ||
val navigator = LocalNavigator.currentOrThrow | ||
|
||
val screenModel = rememberScreenModel { UpcomingScreenModel() } | ||
val state by screenModel.state.collectAsState() | ||
|
||
UpcomingScreenContent( | ||
state = state, | ||
setSelectedYearMonth = screenModel::setSelectedYearMonth, | ||
onClickUpcoming = { navigator.push(MangaScreen(it.id)) }, | ||
) | ||
} | ||
} |
198 changes: 198 additions & 0 deletions
198
app/src/main/java/mihon/feature/upcoming/UpcomingScreenContent.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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)) | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
) | ||
} |
Oops, something went wrong.