From 210da5db8aaa07aa1d072eb36d773a2236f5dc54 Mon Sep 17 00:00:00 2001 From: Zakhar Timoshenko Date: Mon, 15 Apr 2024 02:47:09 +0300 Subject: [PATCH] Add new manga screen variant --- .../shirizu/core/components/DetailsToolbar.kt | 80 +++++- .../shirizu/core/components/SettingItem.kt | 4 +- .../shirizu/core/components/TopAppBar.kt | 155 +++++++---- .../xtimms/shirizu/core/prefs/AppSettings.kt | 3 + .../core/{ => ui}/screens/EmptyScreen.kt | 2 +- .../core/{ => ui}/screens/InfoScreen.kt | 2 +- .../core/{ => ui}/screens/LoadingScreen.kt | 2 +- .../org/xtimms/shirizu/crash/CrashScreen.kt | 2 +- .../sections/details/ClassicDetailsInfoBox.kt | 244 ++++++++++++++++++ .../sections/details/DetailsInfoHeader.kt | 153 +---------- .../shirizu/sections/details/DetailsView.kt | 132 ++++++---- .../sections/details/ModernDetailsInfoBox.kt | 129 +++++++++ .../xtimms/shirizu/sections/feed/FeedView.kt | 2 +- .../shirizu/sections/history/HistoryView.kt | 13 +- .../shirizu/sections/search/SearchView.kt | 2 +- .../shirizu/sections/settings/SettingsView.kt | 36 ++- .../settings/appearance/AppearanceView.kt | 26 +- .../sections/settings/network/NetworkView.kt | 9 +- .../sources/catalog/SourceCatalogItem.kt | 54 ++-- .../sources/catalog/SourcesCatalogPager.kt | 8 +- .../shirizu/sections/shelf/ShelfPager.kt | 2 +- app/src/main/res/values/strings.xml | 2 + 22 files changed, 744 insertions(+), 318 deletions(-) rename app/src/main/java/org/xtimms/shirizu/core/{ => ui}/screens/EmptyScreen.kt (98%) rename app/src/main/java/org/xtimms/shirizu/core/{ => ui}/screens/InfoScreen.kt (99%) rename app/src/main/java/org/xtimms/shirizu/core/{ => ui}/screens/LoadingScreen.kt (91%) create mode 100644 app/src/main/java/org/xtimms/shirizu/sections/details/ClassicDetailsInfoBox.kt create mode 100644 app/src/main/java/org/xtimms/shirizu/sections/details/ModernDetailsInfoBox.kt diff --git a/app/src/main/java/org/xtimms/shirizu/core/components/DetailsToolbar.kt b/app/src/main/java/org/xtimms/shirizu/core/components/DetailsToolbar.kt index 1c81644..e594eaf 100644 --- a/app/src/main/java/org/xtimms/shirizu/core/components/DetailsToolbar.kt +++ b/app/src/main/java/org/xtimms/shirizu/core/components/DetailsToolbar.kt @@ -1,14 +1,9 @@ package org.xtimms.shirizu.core.components import androidx.compose.animation.core.animateDpAsState -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.FavoriteBorder import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material.icons.filled.Share import androidx.compose.material.icons.outlined.Download @@ -32,13 +27,12 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clipToBounds import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @OptIn(ExperimentalMaterial3Api::class) @Composable -fun DetailsToolbar( +fun ModernDetailsToolbar( title: String, titleAlphaProvider: () -> Float, navigateBack: () -> Unit, @@ -118,4 +112,76 @@ fun DetailsToolbar( ) ) } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ClassicDetailsToolbar( + title: String, + titleAlphaProvider: () -> Float, + navigateBack: () -> Unit, + navigateToWebBrowser: () -> Unit, + modifier: Modifier = Modifier, + backgroundAlphaProvider: () -> Float = titleAlphaProvider +) { + + var expanded by remember { mutableStateOf(false) } + + Column( + modifier = modifier + ) { + TopAppBar( + navigationIcon = { + BackIconButton( + onClick = navigateBack + ) + }, + title = { + Text( + text = title, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + color = LocalContentColor.current.copy(alpha = titleAlphaProvider()), + ) + }, + actions = { + IconButton( + onClick = { expanded = true } + ) { + Icon(imageVector = Icons.Default.MoreVert, contentDescription = null) + } + DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) { + DropdownMenuItem( + text = { Text("Share") }, + onClick = { /*TODO*/ }, + leadingIcon = { + Icon(imageVector = Icons.Default.Share, contentDescription = null) + } + ) + DropdownMenuItem( + text = { Text("Download") }, + onClick = { /*TODO*/ }, + leadingIcon = { + Icon(imageVector = Icons.Outlined.Download, contentDescription = null) + } + ) + DropdownMenuItem( + text = { Text("Open in web browser") }, + onClick = { + navigateToWebBrowser() + expanded = false + }, + leadingIcon = { + Icon(imageVector = Icons.Outlined.Language, contentDescription = null) + } + ) + } + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme + .surfaceColorAtElevation(3.dp) + .copy(alpha = backgroundAlphaProvider()) + ) + ) + } } \ No newline at end of file diff --git a/app/src/main/java/org/xtimms/shirizu/core/components/SettingItem.kt b/app/src/main/java/org/xtimms/shirizu/core/components/SettingItem.kt index d8a1507..0f53d93 100644 --- a/app/src/main/java/org/xtimms/shirizu/core/components/SettingItem.kt +++ b/app/src/main/java/org/xtimms/shirizu/core/components/SettingItem.kt @@ -27,9 +27,9 @@ fun SettingTitle(text: String) { Text( modifier = Modifier .padding(top = 32.dp) - .padding(horizontal = 20.dp, vertical = 16.dp), + .padding(horizontal = 16.dp, vertical = 16.dp), text = text, - style = MaterialTheme.typography.displaySmall + style = MaterialTheme.typography.headlineLarge ) } diff --git a/app/src/main/java/org/xtimms/shirizu/core/components/TopAppBar.kt b/app/src/main/java/org/xtimms/shirizu/core/components/TopAppBar.kt index 6c2c80c..592b7be 100644 --- a/app/src/main/java/org/xtimms/shirizu/core/components/TopAppBar.kt +++ b/app/src/main/java/org/xtimms/shirizu/core/components/TopAppBar.kt @@ -22,8 +22,8 @@ import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.QueryStats import androidx.compose.material.icons.outlined.MoreVert +import androidx.compose.material.icons.outlined.QueryStats import androidx.compose.material.icons.outlined.RssFeed import androidx.compose.material.icons.outlined.Search import androidx.compose.material.icons.outlined.SentimentSatisfiedAlt @@ -41,6 +41,7 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MediumTopAppBar import androidx.compose.material3.SuggestionChip import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.runtime.Composable @@ -63,6 +64,7 @@ import org.xtimms.shirizu.R import org.xtimms.shirizu.core.DURATION_ENTER import org.xtimms.shirizu.core.DURATION_EXIT import org.xtimms.shirizu.core.initialOffset +import org.xtimms.shirizu.core.prefs.AppSettings import org.xtimms.shirizu.core.toEasing import org.xtimms.shirizu.sections.explore.EXPLORE_DESTINATION import org.xtimms.shirizu.sections.feed.FEED_DESTINATION @@ -167,53 +169,76 @@ fun TopAppBar( Row( modifier = modifier.padding(end = 16.dp), ) { - IconButton( - onClick = { navController.navigate(FEED_DESTINATION) }, - modifier = Modifier.padding(0.dp), - ) { - Icon( - Icons.Outlined.RssFeed, - contentDescription = stringResource(id = R.string.feed), - tint = MaterialTheme.colorScheme.outline - ) - } - IconButton( - onClick = { expanded = true }, - modifier = Modifier.padding(0.dp), - ) { - Icon( - Icons.Outlined.MoreVert, - contentDescription = stringResource(id = R.string.open_menu), - tint = MaterialTheme.colorScheme.outline - ) - } - DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) { - DropdownMenuItem( - text = { Text(text = stringResource(id = R.string.statistics)) }, - onClick = { - navController.navigate(STATS_DESTINATION) - expanded = false - }, - leadingIcon = { - Icon( - imageVector = Icons.Default.QueryStats, - contentDescription = stringResource(id = R.string.statistics) - ) - } - ) - DropdownMenuItem( - text = { Text(text = stringResource(id = R.string.settings)) }, - onClick = { - navController.navigate(SETTINGS_DESTINATION) - expanded = false - }, - leadingIcon = { - Icon( - imageVector = Icons.Outlined.Settings, - contentDescription = stringResource(id = R.string.settings) - ) - } - ) + if (AppSettings.isTrackerEnabled()) { + IconButton( + onClick = { navController.navigate(FEED_DESTINATION) }, + modifier = Modifier.padding(0.dp), + ) { + Icon( + Icons.Outlined.RssFeed, + contentDescription = stringResource(id = R.string.feed), + tint = MaterialTheme.colorScheme.outline + ) + } + IconButton( + onClick = { expanded = true }, + modifier = Modifier.padding(0.dp), + ) { + Icon( + Icons.Outlined.MoreVert, + contentDescription = stringResource(id = R.string.open_menu), + tint = MaterialTheme.colorScheme.outline + ) + } + DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) { + DropdownMenuItem( + text = { Text(text = stringResource(id = R.string.statistics)) }, + onClick = { + navController.navigate(STATS_DESTINATION) + expanded = false + }, + leadingIcon = { + Icon( + imageVector = Icons.Outlined.QueryStats, + contentDescription = stringResource(id = R.string.statistics) + ) + } + ) + DropdownMenuItem( + text = { Text(text = stringResource(id = R.string.settings)) }, + onClick = { + navController.navigate(SETTINGS_DESTINATION) + expanded = false + }, + leadingIcon = { + Icon( + imageVector = Icons.Outlined.Settings, + contentDescription = stringResource(id = R.string.settings) + ) + } + ) + } + } else { + IconButton( + onClick = { navController.navigate(STATS_DESTINATION) }, + modifier = Modifier.padding(0.dp), + ) { + Icon( + Icons.Outlined.QueryStats, + contentDescription = stringResource(id = R.string.statistics), + tint = MaterialTheme.colorScheme.outline + ) + } + IconButton( + onClick = { navController.navigate(SETTINGS_DESTINATION) }, + modifier = Modifier.padding(0.dp), + ) { + Icon( + Icons.Outlined.Settings, + contentDescription = stringResource(id = R.string.settings), + tint = MaterialTheme.colorScheme.outline + ) + } } } } @@ -271,18 +296,36 @@ fun SmallTopAppBarWithChips( } } +private val path = Path().apply { + moveTo(0f,0f) + lineTo(0.7f, 0.1f) + cubicTo(0.7f, 0.1f, .95F, .5F, 1F, 1F) + moveTo(1f,1f) +} + +val fraction: (Float) -> Float = { PathInterpolator(path).getInterpolation(it) } + @OptIn(ExperimentalMaterial3Api::class) @Composable fun SmallTopAppBar( - title: String, - scrollBehavior: TopAppBarScrollBehavior? = null, - navigateBack: () -> Unit, + modifier: Modifier = Modifier, + titleText: String = "", + scrollBehavior: TopAppBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(), + title: @Composable () -> Unit = { + Text( + text = titleText, + color = MaterialTheme.colorScheme.onSurface.copy(alpha = fraction(scrollBehavior.state.overlappedFraction)), + maxLines = 1 + ) + }, + navigationIcon: @Composable () -> Unit = {}, + actions: @Composable RowScope.() -> Unit = {}, ) { - MediumTopAppBar( - title = { Text(text = title) }, - navigationIcon = { - BackIconButton(onClick = navigateBack) - }, + androidx.compose.material3.TopAppBar( + modifier = modifier, + title = title, + navigationIcon = navigationIcon, + actions = actions, scrollBehavior = scrollBehavior ) } diff --git a/app/src/main/java/org/xtimms/shirizu/core/prefs/AppSettings.kt b/app/src/main/java/org/xtimms/shirizu/core/prefs/AppSettings.kt index 8ca43f7..a571d5b 100644 --- a/app/src/main/java/org/xtimms/shirizu/core/prefs/AppSettings.kt +++ b/app/src/main/java/org/xtimms/shirizu/core/prefs/AppSettings.kt @@ -59,6 +59,7 @@ const val RELATED = "related" const val TRACKER = "tracker" const val CELLULAR_DOWNLOAD = "cellular_download" const val STATISTICS = "statistics" +const val MODERN_VIEW = "modern_view" const val PROXY_TYPE = "proxy_type" const val PROXY_ADDRESS = "proxy_address" @@ -170,6 +171,8 @@ object AppSettings { fun isStatisticsEnabled() = STATISTICS.getBoolean() + fun isModernViewEnabled() = MODERN_VIEW.getBoolean(true) + fun getGridColumnsCount(columns: Int = GRID_COLUMNS.getInt()): Float { return when (columns) { 1 -> 1f diff --git a/app/src/main/java/org/xtimms/shirizu/core/screens/EmptyScreen.kt b/app/src/main/java/org/xtimms/shirizu/core/ui/screens/EmptyScreen.kt similarity index 98% rename from app/src/main/java/org/xtimms/shirizu/core/screens/EmptyScreen.kt rename to app/src/main/java/org/xtimms/shirizu/core/ui/screens/EmptyScreen.kt index aca305e..45ef28d 100644 --- a/app/src/main/java/org/xtimms/shirizu/core/screens/EmptyScreen.kt +++ b/app/src/main/java/org/xtimms/shirizu/core/ui/screens/EmptyScreen.kt @@ -1,4 +1,4 @@ -package org.xtimms.shirizu.core.screens +package org.xtimms.shirizu.core.ui.screens import androidx.annotation.StringRes import androidx.compose.foundation.layout.Arrangement diff --git a/app/src/main/java/org/xtimms/shirizu/core/screens/InfoScreen.kt b/app/src/main/java/org/xtimms/shirizu/core/ui/screens/InfoScreen.kt similarity index 99% rename from app/src/main/java/org/xtimms/shirizu/core/screens/InfoScreen.kt rename to app/src/main/java/org/xtimms/shirizu/core/ui/screens/InfoScreen.kt index 91d9603..61d6997 100644 --- a/app/src/main/java/org/xtimms/shirizu/core/screens/InfoScreen.kt +++ b/app/src/main/java/org/xtimms/shirizu/core/ui/screens/InfoScreen.kt @@ -1,4 +1,4 @@ -package org.xtimms.shirizu.core.screens +package org.xtimms.shirizu.core.ui.screens import androidx.compose.animation.AnimatedContent import androidx.compose.animation.core.RepeatMode diff --git a/app/src/main/java/org/xtimms/shirizu/core/screens/LoadingScreen.kt b/app/src/main/java/org/xtimms/shirizu/core/ui/screens/LoadingScreen.kt similarity index 91% rename from app/src/main/java/org/xtimms/shirizu/core/screens/LoadingScreen.kt rename to app/src/main/java/org/xtimms/shirizu/core/ui/screens/LoadingScreen.kt index 0997c41..49347e7 100644 --- a/app/src/main/java/org/xtimms/shirizu/core/screens/LoadingScreen.kt +++ b/app/src/main/java/org/xtimms/shirizu/core/ui/screens/LoadingScreen.kt @@ -1,4 +1,4 @@ -package org.xtimms.shirizu.core.screens +package org.xtimms.shirizu.core.ui.screens import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize diff --git a/app/src/main/java/org/xtimms/shirizu/crash/CrashScreen.kt b/app/src/main/java/org/xtimms/shirizu/crash/CrashScreen.kt index 92213aa..bb53a38 100644 --- a/app/src/main/java/org/xtimms/shirizu/crash/CrashScreen.kt +++ b/app/src/main/java/org/xtimms/shirizu/crash/CrashScreen.kt @@ -19,7 +19,7 @@ import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.unit.dp import org.acra.ktx.sendWithAcra import org.xtimms.shirizu.R -import org.xtimms.shirizu.core.screens.InfoScreen +import org.xtimms.shirizu.core.ui.screens.InfoScreen import org.xtimms.shirizu.ui.theme.ShirizuTheme import org.xtimms.shirizu.utils.system.toast diff --git a/app/src/main/java/org/xtimms/shirizu/sections/details/ClassicDetailsInfoBox.kt b/app/src/main/java/org/xtimms/shirizu/sections/details/ClassicDetailsInfoBox.kt new file mode 100644 index 0000000..03a2e6d --- /dev/null +++ b/app/src/main/java/org/xtimms/shirizu/sections/details/ClassicDetailsInfoBox.kt @@ -0,0 +1,244 @@ +package org.xtimms.shirizu.sections.details + +import android.net.Uri +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.sizeIn +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.LocalContentColor +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.blur +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.drawWithContent +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import coil.ImageLoader +import org.koitharu.kotatsu.parsers.model.MangaSource +import org.koitharu.kotatsu.parsers.model.MangaState +import org.xtimms.shirizu.R +import org.xtimms.shirizu.core.AsyncImageImpl +import org.xtimms.shirizu.core.components.MangaCover +import org.xtimms.shirizu.sections.details.data.ReadingTime +import org.xtimms.shirizu.sections.details.model.HistoryInfo + +@Composable +fun ClassicDetailsInfoBox( + coil: ImageLoader, + imageUrl: String, + favicon: Uri, + title: String, + altTitle: String, + author: String, + isNsfw: Boolean, + state: MangaState?, + source: MangaSource, + historyInfo: HistoryInfo, + readingTime: ReadingTime?, + isTabletUi: Boolean, + appBarPadding: Dp, + modifier: Modifier = Modifier, + onCoverClick: () -> Unit, + isInShelf: Boolean, + onAddToShelfClicked: () -> Unit, + onSourceClicked: () -> Unit, + onDownloadClick: () -> Unit, +) { + + Box(modifier = modifier) { + // Backdrop + val backdropGradientColors = listOf( + Color.Transparent, + MaterialTheme.colorScheme.background, + ) + AsyncImageImpl( + coil = coil, + model = imageUrl, + contentDescription = null, + contentScale = ContentScale.Crop, + modifier = Modifier + .matchParentSize() + .drawWithContent { + drawContent() + drawRect( + brush = Brush.verticalGradient(colors = backdropGradientColors), + ) + } + .blur(3.dp) + .alpha(0.33f), + ) + + // Manga & source info + CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurface) { + if (!isTabletUi) { + MangaInfoSmall( + coil = coil, + appBarPadding = appBarPadding, + imageUrl = imageUrl, + favicon = favicon, + title = title, + altTitle = altTitle, + author = author, + state = state, + source = source, + isInShelf = isInShelf, + onAddToShelfClicked = onAddToShelfClicked, + onCoverClick = onCoverClick, + onSourceClicked = onSourceClicked, + historyInfo = historyInfo, + readingTime = readingTime, + onDownloadClick = onDownloadClick + ) + } else { + MangaInfoLarge( + coil = coil, + appBarPadding = appBarPadding, + imageUrl = imageUrl, + favicon = favicon, + title = title, + altTitle = altTitle, + author = author, + state = state, + source = source, + isInShelf = isInShelf, + onAddToShelfClicked = onAddToShelfClicked, + onCoverClick = onCoverClick, + onSourceClicked = onSourceClicked, + historyInfo = historyInfo, + readingTime = readingTime, + onDownloadClick = onDownloadClick + ) + } + } + } +} + +@Composable +fun MangaInfoLarge( + coil: ImageLoader, + appBarPadding: Dp, + imageUrl: String, + favicon: Uri, + title: String, + altTitle: String, + author: String, + source: MangaSource, + state: MangaState?, + historyInfo: HistoryInfo, + readingTime: ReadingTime?, + isInShelf: Boolean, + onAddToShelfClicked: () -> Unit, + onCoverClick: () -> Unit, + onSourceClicked: () -> Unit, + onDownloadClick: () -> Unit, +) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(start = 16.dp, top = appBarPadding + 16.dp, end = 16.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + MangaCover.Book( + coil = coil, + modifier = Modifier + .fillMaxWidth(0.65f) + .clickable( + role = Role.Button, + onClick = onCoverClick + ), + data = imageUrl, + contentDescription = stringResource(R.string.manga_cover), + ) + Spacer(modifier = Modifier.height(16.dp)) + DetailsContentInfo( + coil = coil, + favicon = favicon, + title = title, + altTitle = altTitle, + author = author, + state = state, + source = source.title, + isInShelf = isInShelf, + onAddToShelfClicked = onAddToShelfClicked, + onSourceClicked = onSourceClicked, + historyInfo = historyInfo, + readingTime = readingTime, + onDownloadClick = onDownloadClick + ) + } +} + +@Composable +fun MangaInfoSmall( + coil: ImageLoader, + appBarPadding: Dp, + imageUrl: String, + favicon: Uri, + title: String, + altTitle: String, + author: String, + state: MangaState?, + source: MangaSource, + historyInfo: HistoryInfo, + readingTime: ReadingTime?, + isInShelf: Boolean, + onAddToShelfClicked: () -> Unit, + onCoverClick: () -> Unit, + onSourceClicked: () -> Unit, + onDownloadClick: () -> Unit, +) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(top = appBarPadding + 32.dp), + verticalArrangement = Arrangement.spacedBy(8.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + AsyncImageImpl( + coil = coil, + modifier = Modifier + .padding(horizontal = 16.dp) + .sizeIn(maxWidth = 54.dp) + .align(Alignment.Start) + .aspectRatio(1f) + .clip(CircleShape) + .clickable( + role = Role.Button, + onClick = onCoverClick + ), + model = imageUrl, + contentDescription = stringResource(R.string.manga_cover), + ) + DetailsContentInfo( + coil = coil, + favicon = favicon, + title = title, + altTitle = altTitle, + author = author, + state = state, + source = source.title, + isInShelf = isInShelf, + onAddToShelfClicked = onAddToShelfClicked, + onSourceClicked = onSourceClicked, + historyInfo = historyInfo, + readingTime = readingTime, + onDownloadClick = onDownloadClick + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/xtimms/shirizu/sections/details/DetailsInfoHeader.kt b/app/src/main/java/org/xtimms/shirizu/sections/details/DetailsInfoHeader.kt index d21a165..dd3c3ba 100644 --- a/app/src/main/java/org/xtimms/shirizu/sections/details/DetailsInfoHeader.kt +++ b/app/src/main/java/org/xtimms/shirizu/sections/details/DetailsInfoHeader.kt @@ -15,33 +15,26 @@ import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter import androidx.compose.animation.graphics.vector.AnimatedImageVector import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.background -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.foundation.layout.wrapContentSize -import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.outlined.MenuBook import androidx.compose.material.icons.outlined.Block import androidx.compose.material.icons.outlined.Close import androidx.compose.material.icons.outlined.DoneAll import androidx.compose.material.icons.outlined.FileDownload import androidx.compose.material.icons.outlined.KeyboardArrowDown -import androidx.compose.material.icons.outlined.Language import androidx.compose.material.icons.outlined.LocalLibrary import androidx.compose.material.icons.outlined.Pause import androidx.compose.material.icons.outlined.Person @@ -49,20 +42,16 @@ import androidx.compose.material.icons.outlined.Schedule import androidx.compose.material.icons.outlined.Sync import androidx.compose.material.icons.outlined.Upcoming import androidx.compose.material3.AssistChip -import androidx.compose.material3.AssistChipDefaults import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.ElevatedAssistChip import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.InputChip -import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalMinimumInteractiveComponentEnforcement import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedIconButton -import androidx.compose.material3.ProvideTextStyle import androidx.compose.material3.SuggestionChip import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -82,14 +71,11 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.Layout import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.stringResource -import androidx.compose.ui.semantics.Role import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp @@ -105,10 +91,8 @@ import org.xtimms.shirizu.core.components.ButtonType import org.xtimms.shirizu.core.components.HtmlTextField import org.xtimms.shirizu.core.components.MangaCover import org.xtimms.shirizu.core.components.ReadButton -import org.xtimms.shirizu.core.parser.favicon.faviconUri import org.xtimms.shirizu.sections.details.data.ReadingTime import org.xtimms.shirizu.sections.details.model.HistoryInfo -import org.xtimms.shirizu.ui.theme.ShirizuTheme import org.xtimms.shirizu.utils.composable.clickableNoIndication import org.xtimms.shirizu.utils.composable.secondaryItemAlpha import kotlin.math.roundToInt @@ -116,106 +100,7 @@ import kotlin.math.roundToInt private val whitespaceLineRegex = Regex("[\\r\\n]{2,}", setOf(RegexOption.MULTILINE)) @Composable -fun DetailsInfoBox( - coil: ImageLoader, - imageUrl: String, - favicon: Uri, - title: String, - altTitle: String, - author: String, - isNsfw: Boolean, - state: MangaState?, - source: MangaSource, - historyInfo: HistoryInfo, - readingTime: ReadingTime?, - isTabletUi: Boolean, - appBarPadding: Dp, - modifier: Modifier = Modifier, - onCoverClick: () -> Unit, - isInShelf: Boolean, - onAddToShelfClicked: () -> Unit, - onSourceClicked: () -> Unit, - onDownloadClick: () -> Unit, -) { - Column(modifier = modifier) { - Box( - modifier = Modifier - .fillMaxWidth(), - contentAlignment = Alignment.BottomEnd, - ) { - AsyncImageImpl( - coil = coil, - model = imageUrl, - contentDescription = null, - contentScale = ContentScale.Crop, - modifier = Modifier - .padding(start = 16.dp, end = 16.dp) - .aspectRatio(1f) - .clickable( - role = Role.Button, - onClick = onCoverClick - ) - .clip(MaterialTheme.shapes.large) - ) - if (isNsfw) { - ElevatedAssistChip( - modifier = Modifier.padding(end = 32.dp, bottom = 8.dp), - onClick = { /*TODO*/ }, - label = { - Text( - text = "18+", - color = MaterialTheme.colorScheme.onErrorContainer - ) - }, - border = BorderStroke(1.dp, MaterialTheme.colorScheme.errorContainer), - colors = AssistChipDefaults.elevatedAssistChipColors() - .copy(containerColor = MaterialTheme.colorScheme.errorContainer) - ) - } - } - - CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurface) { - if (!isTabletUi) { - MangaAndSourceTitlesSmall( - coil = coil, - favicon = favicon, - title = title, - altTitle = altTitle, - author = author, - state = state, - source = source, - isInShelf = isInShelf, - onAddToShelfClicked = onAddToShelfClicked, - onSourceClicked = onSourceClicked, - historyInfo = historyInfo, - readingTime = readingTime, - onDownloadClick = onDownloadClick - ) - } else { - MangaAndSourceTitlesLarge( - coil = coil, - appBarPadding = appBarPadding, - imageUrl = imageUrl, - favicon = favicon, - title = title, - altTitle = altTitle, - author = author, - state = state, - source = source, - isInShelf = isInShelf, - onAddToShelfClicked = onAddToShelfClicked, - onSourceClicked = onSourceClicked, - historyInfo = historyInfo, - readingTime = readingTime, - onDownloadClick = onDownloadClick - ) - } - } - } -} - -@Composable -private fun MangaAndSourceTitlesLarge( +fun MangaAndSourceTitlesLarge( coil: ImageLoader, appBarPadding: Dp, imageUrl: String, @@ -264,7 +149,7 @@ private fun MangaAndSourceTitlesLarge( } @Composable -private fun MangaAndSourceTitlesSmall( +fun MangaAndSourceTitlesSmall( coil: ImageLoader, favicon: Uri, title: String, @@ -288,15 +173,6 @@ private fun MangaAndSourceTitlesSmall( .padding(top = 8.dp), verticalArrangement = Arrangement.spacedBy(2.dp), ) { - /*AsyncImage( - model = imageUrl, - contentDescription = null, - contentScale = ContentScale.Crop, - modifier = Modifier - .padding(PaddingValues(bottom = 8.dp)) - .clip(RoundedCornerShape(100)) - .size(48.dp), - )*/ DetailsContentInfo( coil = coil, favicon = favicon, @@ -321,7 +197,7 @@ private fun MangaAndSourceTitlesSmall( ExperimentalMaterial3Api::class ) @Composable -private fun DetailsContentInfo( +fun DetailsContentInfo( coil: ImageLoader, favicon: Uri, title: String, @@ -528,23 +404,6 @@ private fun DetailsContentInfo( } HorizontalDivider(modifier = Modifier.padding(vertical = 16.dp)) } - - /*Row(modifier = Modifier - .weight(.5f) - .padding(start = 4.dp, end = 16.dp), horizontalArrangement = Arrangement.spacedBy(8.dp)) { - AnimatedButton( - modifier = Modifier.size(54.dp), - type = KeyboardButtonType.PRIMARY, - icon = Icons.Outlined.FavoriteBorder - ) - AnimatedButton( - modifier = Modifier - .height(54.dp) - .fillMaxWidth(), - type = KeyboardButtonType.TERTIARY, - icon = Icons.Outlined.PlayArrow - ) - }*/ } } @@ -621,7 +480,7 @@ fun ExpandableMangaDescription( ) { tags.forEach { TagsChip( - modifier = DefaultTagChipModifier, + modifier = modifier.padding(vertical = 4.dp), tag = it, onClick = { tagSelected = it.title @@ -645,8 +504,6 @@ private fun MangaSummary( modifier: Modifier = Modifier, ) { - val uriHandler = LocalUriHandler.current - val animProgress by animateFloatAsState( targetValue = if (expanded) 1f else 0f, label = "summary", @@ -728,8 +585,6 @@ private fun MangaSummary( } } -private val DefaultTagChipModifier = Modifier.padding(vertical = 4.dp) - @OptIn(ExperimentalMaterial3Api::class) @Composable private fun TagsChip( diff --git a/app/src/main/java/org/xtimms/shirizu/sections/details/DetailsView.kt b/app/src/main/java/org/xtimms/shirizu/sections/details/DetailsView.kt index e83fa99..cd49765 100644 --- a/app/src/main/java/org/xtimms/shirizu/sections/details/DetailsView.kt +++ b/app/src/main/java/org/xtimms/shirizu/sections/details/DetailsView.kt @@ -15,8 +15,6 @@ import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.calculateEndPadding import androidx.compose.foundation.layout.calculateStartPadding import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.sizeIn @@ -62,12 +60,12 @@ import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaState -import org.koitharu.kotatsu.parsers.model.RATING_UNKNOWN import org.xtimms.shirizu.LocalWindowWidthState import org.xtimms.shirizu.R import org.xtimms.shirizu.core.HapticFeedback.slightHapticFeedback -import org.xtimms.shirizu.core.components.DetailsToolbar +import org.xtimms.shirizu.core.components.ClassicDetailsToolbar import org.xtimms.shirizu.core.components.MangaHorizontalItem +import org.xtimms.shirizu.core.components.ModernDetailsToolbar import org.xtimms.shirizu.core.parser.favicon.faviconUri import org.xtimms.shirizu.core.prefs.AppSettings import org.xtimms.shirizu.core.prefs.AppSettings.getBoolean @@ -115,6 +113,7 @@ fun DetailsView( } } } else null + val isModernView = AppSettings.isModernViewEnabled() val checkNetworkOrDownload = { if (!AppSettings.isNetworkAvailableForDownload()) { @@ -224,13 +223,23 @@ fun DetailsView( if (!isFirstItemVisible || isFirstItemScrolled) 1f else 0f, label = "Top Bar Background", ) - DetailsToolbar( - title = viewModel.details.value?.toManga()?.title.orEmpty(), - titleAlphaProvider = { animatedTitleAlpha }, - backgroundAlphaProvider = { animatedBgAlpha }, - navigateBack = { navigateBack() }, - navigateToWebBrowser = { openUrl(viewModel.details.value?.toManga()?.publicUrl.orEmpty()) }, - ) + if (isModernView) { + ModernDetailsToolbar( + title = viewModel.details.value?.toManga()?.title.orEmpty(), + titleAlphaProvider = { animatedTitleAlpha }, + backgroundAlphaProvider = { animatedBgAlpha }, + navigateBack = { navigateBack() }, + navigateToWebBrowser = { openUrl(viewModel.details.value?.toManga()?.publicUrl.orEmpty()) }, + ) + } else { + ClassicDetailsToolbar( + title = viewModel.details.value?.toManga()?.title.orEmpty(), + titleAlphaProvider = { animatedTitleAlpha }, + backgroundAlphaProvider = { animatedBgAlpha }, + navigateBack = { navigateBack() }, + navigateToWebBrowser = { openUrl(viewModel.details.value?.toManga()?.publicUrl.orEmpty()) }, + ) + } }, snackbarHost = { SnackbarHost( @@ -245,7 +254,7 @@ fun DetailsView( modifier = Modifier.fillMaxHeight(), state = chapterListState, contentPadding = PaddingValues( - top = contentPadding.calculateTopPadding() - 60.dp, + top = if (isModernView) contentPadding.calculateTopPadding() - 60.dp else 0.dp, start = contentPadding.calculateStartPadding(layoutDirection), end = contentPadding.calculateEndPadding(layoutDirection), bottom = contentPadding.calculateBottomPadding(), @@ -256,38 +265,73 @@ fun DetailsView( key = DetailsViewItem.INFO_BOX, contentType = DetailsViewItem.INFO_BOX ) { - DetailsInfoBox( - coil = coil, - imageUrl = manga?.largeCoverUrl ?: manga?.coverUrl.orEmpty(), - favicon = manga?.source?.faviconUri() ?: Uri.EMPTY, - title = manga?.title.orEmpty(), - altTitle = manga?.altTitle.orEmpty(), - author = manga?.author.orEmpty(), - isNsfw = manga?.isNsfw ?: true, - state = manga?.state ?: MangaState.FINISHED, - source = manga?.source ?: MangaSource.DUMMY, - isTabletUi = false, - appBarPadding = topPadding, - onCoverClick = { - navigateToFullImage( - arrayOf( - manga?.largeCoverUrl ?: manga?.coverUrl.orEmpty(), - ).toNavArgument() - ) - }, - historyInfo = historyInfo, - readingTime = readingTime, - isInShelf = favouriteCategories, - onAddToShelfClicked = { - openCategoriesBottomSheet = !openCategoriesBottomSheet - }, - onSourceClicked = { - navigateToSource( - manga?.source ?: MangaSource.DUMMY - ) - }, - onDownloadClick = downloadCallback - ) + if (isModernView) { + ModernDetailsInfoBox( + coil = coil, + imageUrl = manga?.largeCoverUrl ?: manga?.coverUrl.orEmpty(), + favicon = manga?.source?.faviconUri() ?: Uri.EMPTY, + title = manga?.title.orEmpty(), + altTitle = manga?.altTitle.orEmpty(), + author = manga?.author.orEmpty(), + isNsfw = manga?.isNsfw ?: true, + state = manga?.state ?: MangaState.FINISHED, + source = manga?.source ?: MangaSource.DUMMY, + isTabletUi = false, + appBarPadding = topPadding, + onCoverClick = { + navigateToFullImage( + arrayOf( + manga?.largeCoverUrl ?: manga?.coverUrl.orEmpty(), + ).toNavArgument() + ) + }, + historyInfo = historyInfo, + readingTime = readingTime, + isInShelf = favouriteCategories, + onAddToShelfClicked = { + openCategoriesBottomSheet = !openCategoriesBottomSheet + }, + onSourceClicked = { + navigateToSource( + manga?.source ?: MangaSource.DUMMY + ) + }, + onDownloadClick = downloadCallback + ) + } else { + ClassicDetailsInfoBox( + coil = coil, + imageUrl = manga?.largeCoverUrl ?: manga?.coverUrl.orEmpty(), + favicon = manga?.source?.faviconUri() ?: Uri.EMPTY, + title = manga?.title.orEmpty(), + altTitle = manga?.altTitle.orEmpty(), + author = manga?.author.orEmpty(), + isNsfw = manga?.isNsfw ?: true, + state = manga?.state ?: MangaState.FINISHED, + source = manga?.source ?: MangaSource.DUMMY, + isTabletUi = false, + appBarPadding = topPadding, + onCoverClick = { + navigateToFullImage( + arrayOf( + manga?.largeCoverUrl ?: manga?.coverUrl.orEmpty(), + ).toNavArgument() + ) + }, + historyInfo = historyInfo, + readingTime = readingTime, + isInShelf = favouriteCategories, + onAddToShelfClicked = { + openCategoriesBottomSheet = !openCategoriesBottomSheet + }, + onSourceClicked = { + navigateToSource( + manga?.source ?: MangaSource.DUMMY + ) + }, + onDownloadClick = downloadCallback + ) + } } item( diff --git a/app/src/main/java/org/xtimms/shirizu/sections/details/ModernDetailsInfoBox.kt b/app/src/main/java/org/xtimms/shirizu/sections/details/ModernDetailsInfoBox.kt new file mode 100644 index 0000000..bec4719 --- /dev/null +++ b/app/src/main/java/org/xtimms/shirizu/sections/details/ModernDetailsInfoBox.kt @@ -0,0 +1,129 @@ +package org.xtimms.shirizu.sections.details + +import android.net.Uri +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.AssistChipDefaults +import androidx.compose.material3.ElevatedAssistChip +import androidx.compose.material3.LocalContentColor +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import coil.ImageLoader +import org.koitharu.kotatsu.parsers.model.MangaSource +import org.koitharu.kotatsu.parsers.model.MangaState +import org.xtimms.shirizu.core.AsyncImageImpl +import org.xtimms.shirizu.sections.details.data.ReadingTime +import org.xtimms.shirizu.sections.details.model.HistoryInfo + +@Composable +fun ModernDetailsInfoBox( + coil: ImageLoader, + imageUrl: String, + favicon: Uri, + title: String, + altTitle: String, + author: String, + isNsfw: Boolean, + state: MangaState?, + source: MangaSource, + historyInfo: HistoryInfo, + readingTime: ReadingTime?, + isTabletUi: Boolean, + appBarPadding: Dp, + modifier: Modifier = Modifier, + onCoverClick: () -> Unit, + isInShelf: Boolean, + onAddToShelfClicked: () -> Unit, + onSourceClicked: () -> Unit, + onDownloadClick: () -> Unit, +) { + Column(modifier = modifier) { + Box( + modifier = Modifier + .fillMaxWidth(), + contentAlignment = Alignment.BottomEnd, + ) { + AsyncImageImpl( + coil = coil, + model = imageUrl, + contentDescription = null, + contentScale = ContentScale.Crop, + modifier = Modifier + .padding(start = 16.dp, end = 16.dp) + .aspectRatio(1f) + .clickable( + role = Role.Button, + onClick = onCoverClick + ) + .clip(MaterialTheme.shapes.large) + ) + if (isNsfw) { + ElevatedAssistChip( + modifier = Modifier.padding(end = 32.dp, bottom = 8.dp), + onClick = { /*TODO*/ }, + label = { + Text( + text = "18+", + color = MaterialTheme.colorScheme.onErrorContainer + ) + }, + border = BorderStroke(1.dp, MaterialTheme.colorScheme.errorContainer), + colors = AssistChipDefaults.elevatedAssistChipColors() + .copy(containerColor = MaterialTheme.colorScheme.errorContainer) + ) + } + } + + CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurface) { + if (!isTabletUi) { + MangaAndSourceTitlesSmall( + coil = coil, + favicon = favicon, + title = title, + altTitle = altTitle, + author = author, + state = state, + source = source, + isInShelf = isInShelf, + onAddToShelfClicked = onAddToShelfClicked, + onSourceClicked = onSourceClicked, + historyInfo = historyInfo, + readingTime = readingTime, + onDownloadClick = onDownloadClick + ) + } else { + MangaAndSourceTitlesLarge( + coil = coil, + appBarPadding = appBarPadding, + imageUrl = imageUrl, + favicon = favicon, + title = title, + altTitle = altTitle, + author = author, + state = state, + source = source, + isInShelf = isInShelf, + onAddToShelfClicked = onAddToShelfClicked, + onSourceClicked = onSourceClicked, + historyInfo = historyInfo, + readingTime = readingTime, + onDownloadClick = onDownloadClick + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/xtimms/shirizu/sections/feed/FeedView.kt b/app/src/main/java/org/xtimms/shirizu/sections/feed/FeedView.kt index f7b13a3..00e1a2f 100644 --- a/app/src/main/java/org/xtimms/shirizu/sections/feed/FeedView.kt +++ b/app/src/main/java/org/xtimms/shirizu/sections/feed/FeedView.kt @@ -45,7 +45,7 @@ import org.xtimms.shirizu.core.components.effects.RowEntity import org.xtimms.shirizu.core.components.effects.RowEntityType import org.xtimms.shirizu.core.components.effects.animatedItemsIndexed import org.xtimms.shirizu.core.components.effects.updateAnimatedItemsState -import org.xtimms.shirizu.core.screens.EmptyScreen +import org.xtimms.shirizu.core.ui.screens.EmptyScreen import org.xtimms.shirizu.core.tracker.model.TrackingLogItem import org.xtimms.shirizu.sections.feed.model.toFeedItem import org.xtimms.shirizu.utils.lang.calculateTimeAgo diff --git a/app/src/main/java/org/xtimms/shirizu/sections/history/HistoryView.kt b/app/src/main/java/org/xtimms/shirizu/sections/history/HistoryView.kt index 6bf5fac..633518e 100644 --- a/app/src/main/java/org/xtimms/shirizu/sections/history/HistoryView.kt +++ b/app/src/main/java/org/xtimms/shirizu/sections/history/HistoryView.kt @@ -1,24 +1,17 @@ package org.xtimms.shirizu.sections.history //noinspection UsingMaterialAndMaterial3Libraries -import androidx.compose.animation.core.Animatable -import androidx.compose.animation.core.AnimationVector1D import androidx.compose.animation.core.animateDpAsState -import androidx.compose.foundation.gestures.ScrollableState import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.calculateEndPadding -import androidx.compose.foundation.layout.calculateStartPadding import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListState -import androidx.compose.foundation.lazy.rememberLazyListState -import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.DismissDirection import androidx.compose.material.ExperimentalMaterialApi @@ -43,14 +36,12 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.min import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import coil.ImageLoader import org.xtimms.shirizu.R -import org.xtimms.shirizu.core.collapsable import org.xtimms.shirizu.core.components.ListGroupHeader import org.xtimms.shirizu.core.components.effects.RowEntity import org.xtimms.shirizu.core.components.effects.RowEntityType @@ -58,8 +49,8 @@ import org.xtimms.shirizu.core.components.effects.animatedItemsIndexed import org.xtimms.shirizu.core.components.effects.updateAnimatedItemsState import org.xtimms.shirizu.core.prefs.AppSettings import org.xtimms.shirizu.core.prefs.SWIPE_TUTORIAL -import org.xtimms.shirizu.core.screens.EmptyScreen -import org.xtimms.shirizu.core.screens.LoadingScreen +import org.xtimms.shirizu.core.ui.screens.EmptyScreen +import org.xtimms.shirizu.core.ui.screens.LoadingScreen import org.xtimms.shirizu.utils.lang.calculateTimeAgo import org.xtimms.shirizu.utils.lang.isSameDay import java.time.Instant diff --git a/app/src/main/java/org/xtimms/shirizu/sections/search/SearchView.kt b/app/src/main/java/org/xtimms/shirizu/sections/search/SearchView.kt index ba763f6..9cb8192 100644 --- a/app/src/main/java/org/xtimms/shirizu/sections/search/SearchView.kt +++ b/app/src/main/java/org/xtimms/shirizu/sections/search/SearchView.kt @@ -34,7 +34,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import org.xtimms.shirizu.R import org.xtimms.shirizu.core.components.BackIconButton -import org.xtimms.shirizu.core.screens.EmptyScreen +import org.xtimms.shirizu.core.ui.screens.EmptyScreen import org.xtimms.shirizu.ui.theme.ShirizuTheme const val SEARCH_DESTINATION = "search" diff --git a/app/src/main/java/org/xtimms/shirizu/sections/settings/SettingsView.kt b/app/src/main/java/org/xtimms/shirizu/sections/settings/SettingsView.kt index edc7ca3..c5db7c5 100644 --- a/app/src/main/java/org/xtimms/shirizu/sections/settings/SettingsView.kt +++ b/app/src/main/java/org/xtimms/shirizu/sections/settings/SettingsView.kt @@ -15,8 +15,11 @@ import androidx.compose.animation.fadeOut import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.navigationBars +import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.icons.Icons @@ -30,6 +33,9 @@ import androidx.compose.material.icons.outlined.Palette import androidx.compose.material.icons.outlined.SettingsBackupRestore import androidx.compose.material.icons.outlined.Storage import androidx.compose.material.icons.outlined.Wifi +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Scaffold +import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue @@ -37,18 +43,22 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import org.xtimms.shirizu.R +import org.xtimms.shirizu.core.components.BackIconButton import org.xtimms.shirizu.core.components.PreferencesHintCard -import org.xtimms.shirizu.core.components.ScaffoldWithTopAppBar import org.xtimms.shirizu.core.components.SettingItem +import org.xtimms.shirizu.core.components.SettingTitle +import org.xtimms.shirizu.core.components.SmallTopAppBar import org.xtimms.shirizu.utils.FileSize const val SETTINGS_DESTINATION = "settings" +@OptIn(ExperimentalMaterial3Api::class) @SuppressLint("BatteryLife") @Composable fun SettingsView( @@ -76,6 +86,8 @@ fun SettingsView( mutableStateOf(!pm.isIgnoringBatteryOptimizations(context.packageName)) } + val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() + val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS).apply { data = Uri.parse("package:${context.packageName}") @@ -96,9 +108,22 @@ fun SettingsView( showBatteryHint = !pm.isIgnoringBatteryOptimizations(context.packageName) } - ScaffoldWithTopAppBar( - title = stringResource(R.string.settings), - navigateBack = navigateBack + Scaffold( + modifier = Modifier + .fillMaxSize() + .nestedScroll(scrollBehavior.nestedScrollConnection), + topBar = { + SmallTopAppBar( + titleText = stringResource(id = R.string.settings), + navigationIcon = { + BackIconButton { + navigateBack() + } + }, + scrollBehavior = scrollBehavior + ) + }, + contentWindowInsets = WindowInsets.navigationBars.only(WindowInsetsSides.Horizontal), ) { padding -> LazyColumn( modifier = Modifier.padding(padding), @@ -106,6 +131,9 @@ fun SettingsView( bottom = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() ) ) { + item { + SettingTitle(text = stringResource(id = R.string.settings)) + } item { AnimatedVisibility( visible = showBatteryHint && isActivityAvailable, diff --git a/app/src/main/java/org/xtimms/shirizu/sections/settings/appearance/AppearanceView.kt b/app/src/main/java/org/xtimms/shirizu/sections/settings/appearance/AppearanceView.kt index 29b6768..999dad1 100644 --- a/app/src/main/java/org/xtimms/shirizu/sections/settings/appearance/AppearanceView.kt +++ b/app/src/main/java/org/xtimms/shirizu/sections/settings/appearance/AppearanceView.kt @@ -31,8 +31,8 @@ import androidx.compose.material.icons.outlined.Check import androidx.compose.material.icons.outlined.ColorLens import androidx.compose.material.icons.outlined.DarkMode import androidx.compose.material.icons.outlined.Language +import androidx.compose.material.icons.outlined.Layers import androidx.compose.material.icons.outlined.LightMode -import androidx.compose.material.icons.outlined.Timelapse import androidx.compose.material3.Card import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme @@ -72,7 +72,7 @@ import org.xtimms.shirizu.core.components.ScaffoldWithTopAppBar import org.xtimms.shirizu.core.prefs.AppSettings import org.xtimms.shirizu.core.prefs.DarkThemePreference.Companion.OFF import org.xtimms.shirizu.core.prefs.DarkThemePreference.Companion.ON -import org.xtimms.shirizu.core.prefs.READING_TIME +import org.xtimms.shirizu.core.prefs.MODERN_VIEW import org.xtimms.shirizu.core.prefs.STYLE_MONOCHROME import org.xtimms.shirizu.core.prefs.STYLE_TONAL_SPOT import org.xtimms.shirizu.core.prefs.paletteStyles @@ -85,7 +85,6 @@ import org.xtimms.shirizu.ui.monet.TonalPalettes.Companion.toTonalPalettes import org.xtimms.shirizu.ui.monet.a1 import org.xtimms.shirizu.ui.monet.a2 import org.xtimms.shirizu.ui.monet.a3 -import org.xtimms.shirizu.utils.material.combineColors import org.xtimms.shirizu.utils.system.toDisplayName import java.util.Locale @@ -101,6 +100,10 @@ fun AppearanceView( ) { val localDensity = LocalDensity.current + var isModernViewEnabled by remember { + mutableStateOf(AppSettings.isModernViewEnabled()) + } + ScaffoldWithTopAppBar( title = stringResource(R.string.appearance), navigateBack = navigateBack @@ -246,6 +249,15 @@ fun AppearanceView( icon = Icons.Outlined.Language, description = Locale.getDefault().toDisplayName(), onClick = { navigateToLanguages() }) + PreferenceSubtitle(text = stringResource(id = R.string.user_interface)) + PreferenceSwitch( + icon = Icons.Outlined.Layers, + title = stringResource(id = R.string.details_modern_look), + isChecked = isModernViewEnabled, + ) { + isModernViewEnabled = !isModernViewEnabled + AppSettings.updateValue(MODERN_VIEW, isModernViewEnabled) + } } } } @@ -286,8 +298,12 @@ fun RowScope.ColorButtonImpl( onClick: () -> Unit = {} ) { - val containerSize by animateDpAsState(targetValue = if (isSelected.invoke()) 28.dp else 0.dp) - val iconSize by animateDpAsState(targetValue = if (isSelected.invoke()) 16.dp else 0.dp) + val containerSize by animateDpAsState(targetValue = if (isSelected.invoke()) 28.dp else 0.dp, + label = "containerSize" + ) + val iconSize by animateDpAsState(targetValue = if (isSelected.invoke()) 16.dp else 0.dp, + label = "iconSize" + ) Surface( modifier = modifier diff --git a/app/src/main/java/org/xtimms/shirizu/sections/settings/network/NetworkView.kt b/app/src/main/java/org/xtimms/shirizu/sections/settings/network/NetworkView.kt index e2b052a..feb2dd6 100644 --- a/app/src/main/java/org/xtimms/shirizu/sections/settings/network/NetworkView.kt +++ b/app/src/main/java/org/xtimms/shirizu/sections/settings/network/NetworkView.kt @@ -66,6 +66,7 @@ import org.xtimms.shirizu.utils.MaskVisualTransformation import org.xtimms.shirizu.utils.NumberDefaults.INPUT_LENGTH import org.xtimms.shirizu.utils.NumberDefaults.MASK import org.xtimms.shirizu.utils.NumberDefaults.MAX_PORT +import org.xtimms.shirizu.utils.lang.ifNullOrEmpty import org.xtimms.shirizu.utils.lang.intState import java.net.Proxy @@ -175,14 +176,14 @@ fun NetworkView( PreferenceItem( enabled = proxy != Proxy.Type.DIRECT.ordinal, title = stringResource(id = R.string.proxy_address), - description = address, + description = address.ifNullOrEmpty { stringResource(id = R.string.not_set) }, ) { showProxyAddressDialog = true } } item { PreferenceItem( enabled = proxy != Proxy.Type.DIRECT.ordinal, title = stringResource(id = R.string.proxy_port), - description = port.toString() + description = if (port == 0) stringResource(id = R.string.not_set) else port.toString() ) { showProxyPortDialog = true } } item { @@ -192,14 +193,14 @@ fun NetworkView( PreferenceItem( enabled = proxy != Proxy.Type.DIRECT.ordinal, title = stringResource(id = R.string.proxy_username), - description = username, + description = username.ifNullOrEmpty { stringResource(id = R.string.not_set) }, ) { showProxyUsernameDialog = true } } item { PreferenceItem( enabled = proxy != Proxy.Type.DIRECT.ordinal, title = stringResource(id = R.string.proxy_password), - description = String(CharArray(password.length) { '\u2022' }), + description = String(CharArray(password.length) { '\u2022' }).ifNullOrEmpty { stringResource(id = R.string.not_set) }, ) { showProxyPasswordDialog = true } } } diff --git a/app/src/main/java/org/xtimms/shirizu/sections/settings/sources/catalog/SourceCatalogItem.kt b/app/src/main/java/org/xtimms/shirizu/sections/settings/sources/catalog/SourceCatalogItem.kt index d96289c..c701735 100644 --- a/app/src/main/java/org/xtimms/shirizu/sections/settings/sources/catalog/SourceCatalogItem.kt +++ b/app/src/main/java/org/xtimms/shirizu/sections/settings/sources/catalog/SourceCatalogItem.kt @@ -3,50 +3,60 @@ package org.xtimms.shirizu.sections.settings.sources.catalog import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.outlined.Label +import androidx.compose.material.icons.outlined.Add import androidx.compose.material3.Card import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import coil.ImageLoader import org.koitharu.kotatsu.parsers.model.MangaSource import org.xtimms.shirizu.core.AsyncImageImpl import org.xtimms.shirizu.core.parser.favicon.faviconUri +import org.xtimms.shirizu.ui.theme.ShirizuTheme @Composable fun SourceCatalogItem( coil: ImageLoader, source: MangaSource, - modifier: Modifier = Modifier, ) { - Card( - modifier = modifier, + Row( + modifier = Modifier + .fillMaxWidth() + .padding(8.dp), + verticalAlignment = Alignment.CenterVertically, ) { - Row( + AsyncImageImpl( + modifier = Modifier.size(42.dp), + coil = coil, + contentDescription = null, + model = source.faviconUri() + ) + Text( + text = source.title, modifier = Modifier - .fillMaxWidth() - .padding( - start = 16.dp, - top = 16.dp, - end = 16.dp, - ), - verticalAlignment = Alignment.CenterVertically, - ) { - AsyncImageImpl( - coil = coil, - contentDescription = null, - model = source.faviconUri() - ) - Text( - text = source.title, - modifier = Modifier - .padding(start = 16.dp), - ) + .padding(start = 16.dp) + .weight(1f), + ) + IconButton(onClick = { /*TODO*/ }) { + Icon(imageVector = Icons.Outlined.Add, contentDescription = null) } } +} + +@Preview +@Composable +fun SourceCatalogItemPreview() { + ShirizuTheme { + SourceCatalogItem(coil = ImageLoader(LocalContext.current), source = MangaSource.MANGADEX) + } } \ No newline at end of file diff --git a/app/src/main/java/org/xtimms/shirizu/sections/settings/sources/catalog/SourcesCatalogPager.kt b/app/src/main/java/org/xtimms/shirizu/sections/settings/sources/catalog/SourcesCatalogPager.kt index 3ec825f..f92795c 100644 --- a/app/src/main/java/org/xtimms/shirizu/sections/settings/sources/catalog/SourcesCatalogPager.kt +++ b/app/src/main/java/org/xtimms/shirizu/sections/settings/sources/catalog/SourcesCatalogPager.kt @@ -5,7 +5,6 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.lazy.items import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.PagerState @@ -17,14 +16,9 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import androidx.compose.ui.util.fastAny import coil.ImageLoader import org.xtimms.shirizu.R -import org.xtimms.shirizu.core.components.MangaGridItem -import org.xtimms.shirizu.core.screens.EmptyScreen -import org.xtimms.shirizu.sections.shelf.LazyShelfGrid -import org.xtimms.shirizu.sections.shelf.ShelfGrid -import org.xtimms.shirizu.sections.shelf.ShelfManga +import org.xtimms.shirizu.core.ui.screens.EmptyScreen import org.xtimms.shirizu.utils.system.plus @Composable diff --git a/app/src/main/java/org/xtimms/shirizu/sections/shelf/ShelfPager.kt b/app/src/main/java/org/xtimms/shirizu/sections/shelf/ShelfPager.kt index 55a1f7d..8c96334 100644 --- a/app/src/main/java/org/xtimms/shirizu/sections/shelf/ShelfPager.kt +++ b/app/src/main/java/org/xtimms/shirizu/sections/shelf/ShelfPager.kt @@ -17,7 +17,7 @@ import androidx.compose.ui.unit.dp import coil.ImageLoader import org.xtimms.shirizu.R import org.xtimms.shirizu.core.prefs.AppSettings -import org.xtimms.shirizu.core.screens.EmptyScreen +import org.xtimms.shirizu.core.ui.screens.EmptyScreen import org.xtimms.shirizu.utils.system.plus @Composable diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cb8e228..56060b3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -306,4 +306,6 @@ Open menu My bad… Logs about this bug have been sent to the developers, thank you. + User interface + Modern look of the manga information screen \ No newline at end of file