From 2ee3bda87ac949a431662b58031f40328a8c9a19 Mon Sep 17 00:00:00 2001 From: SkyD666 Date: Sun, 7 Jul 2024 23:41:49 +0800 Subject: [PATCH] [feature|fix] Support configuring the min-width of item for article list screen and search list screen (#63); fix crash caused by SwipeToDismissBox (#62); support verifying if a link is a torrent resource via mime type (#67) --- app/build.gradle.kts | 2 +- .../java/com/skyd/anivu/ext/PreferenceExt.kt | 4 + .../skyd/anivu/model/preference/Settings.kt | 8 ++ .../article/ArticleItemMinWidthPreference.kt | 26 ++++++ .../search/SearchItemMinWidthPreference.kt | 26 ++++++ .../worker/download/DownloadTorrentWorker.kt | 8 +- .../skyd/anivu/model/worker/download/Util.kt | 37 +++++++-- .../adapter/variety/proxy/Enclosure1Proxy.kt | 1 + .../anivu/ui/component/SwipeToDismissBox.kt | 29 ------- .../adapter/proxy/Article1Proxy.kt | 27 +++++-- .../ui/fragment/article/ArticleFragment.kt | 3 +- .../ui/fragment/search/SearchFragment.kt | 3 +- .../article/ArticleStyleFragment.kt | 79 +++++++++++++++++++ .../appearance/search/SearchStyleFragment.kt | 31 ++++++++ .../com/skyd/anivu/ui/local/LocalValue.kt | 4 + app/src/main/res/values-zh-rCN/strings.xml | 3 +- app/src/main/res/values/strings.xml | 2 + 17 files changed, 242 insertions(+), 51 deletions(-) create mode 100644 app/src/main/java/com/skyd/anivu/model/preference/appearance/article/ArticleItemMinWidthPreference.kt create mode 100644 app/src/main/java/com/skyd/anivu/model/preference/appearance/search/SearchItemMinWidthPreference.kt delete mode 100644 app/src/main/java/com/skyd/anivu/ui/component/SwipeToDismissBox.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1f4d89a8..527d3e61 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -22,7 +22,7 @@ android { minSdk = 24 targetSdk = 34 versionCode = 18 - versionName = "1.1-beta50" + versionName = "1.1-beta51" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/java/com/skyd/anivu/ext/PreferenceExt.kt b/app/src/main/java/com/skyd/anivu/ext/PreferenceExt.kt index 4b7a463d..10430526 100644 --- a/app/src/main/java/com/skyd/anivu/ext/PreferenceExt.kt +++ b/app/src/main/java/com/skyd/anivu/ext/PreferenceExt.kt @@ -8,6 +8,7 @@ import com.skyd.anivu.model.preference.appearance.DateStylePreference import com.skyd.anivu.model.preference.appearance.NavigationBarLabelPreference import com.skyd.anivu.model.preference.appearance.TextFieldStylePreference import com.skyd.anivu.model.preference.appearance.ThemePreference +import com.skyd.anivu.model.preference.appearance.article.ArticleItemMinWidthPreference import com.skyd.anivu.model.preference.appearance.article.ArticleItemTonalElevationPreference import com.skyd.anivu.model.preference.appearance.article.ArticleListTonalElevationPreference import com.skyd.anivu.model.preference.appearance.article.ArticleTopBarTonalElevationPreference @@ -16,6 +17,7 @@ import com.skyd.anivu.model.preference.appearance.article.ShowArticleTopBarRefre import com.skyd.anivu.model.preference.appearance.feed.FeedGroupExpandPreference import com.skyd.anivu.model.preference.appearance.feed.FeedListTonalElevationPreference import com.skyd.anivu.model.preference.appearance.feed.FeedTopBarTonalElevationPreference +import com.skyd.anivu.model.preference.appearance.search.SearchItemMinWidthPreference import com.skyd.anivu.model.preference.appearance.search.SearchListTonalElevationPreference import com.skyd.anivu.model.preference.appearance.search.SearchTopBarTonalElevationPreference import com.skyd.anivu.model.preference.behavior.PickImageMethodPreference @@ -52,6 +54,8 @@ fun Preferences.toSettings(): Settings { searchTopBarTonalElevation = SearchTopBarTonalElevationPreference.fromPreferences(this), showArticleTopBarRefresh = ShowArticleTopBarRefreshPreference.fromPreferences(this), showArticlePullRefresh = ShowArticlePullRefreshPreference.fromPreferences(this), + articleItemMinWidth = ArticleItemMinWidthPreference.fromPreferences(this), + searchItemMinWidth = SearchItemMinWidthPreference.fromPreferences(this), // Update ignoreUpdateVersion = IgnoreUpdateVersionPreference.fromPreferences(this), diff --git a/app/src/main/java/com/skyd/anivu/model/preference/Settings.kt b/app/src/main/java/com/skyd/anivu/model/preference/Settings.kt index 6fbd26bd..e073ee7d 100644 --- a/app/src/main/java/com/skyd/anivu/model/preference/Settings.kt +++ b/app/src/main/java/com/skyd/anivu/model/preference/Settings.kt @@ -13,6 +13,7 @@ import com.skyd.anivu.model.preference.appearance.DateStylePreference import com.skyd.anivu.model.preference.appearance.NavigationBarLabelPreference import com.skyd.anivu.model.preference.appearance.TextFieldStylePreference import com.skyd.anivu.model.preference.appearance.ThemePreference +import com.skyd.anivu.model.preference.appearance.article.ArticleItemMinWidthPreference import com.skyd.anivu.model.preference.appearance.article.ArticleItemTonalElevationPreference import com.skyd.anivu.model.preference.appearance.article.ArticleListTonalElevationPreference import com.skyd.anivu.model.preference.appearance.article.ArticleTopBarTonalElevationPreference @@ -21,6 +22,7 @@ import com.skyd.anivu.model.preference.appearance.article.ShowArticleTopBarRefre import com.skyd.anivu.model.preference.appearance.feed.FeedGroupExpandPreference import com.skyd.anivu.model.preference.appearance.feed.FeedListTonalElevationPreference import com.skyd.anivu.model.preference.appearance.feed.FeedTopBarTonalElevationPreference +import com.skyd.anivu.model.preference.appearance.search.SearchItemMinWidthPreference import com.skyd.anivu.model.preference.appearance.search.SearchListTonalElevationPreference import com.skyd.anivu.model.preference.appearance.search.SearchTopBarTonalElevationPreference import com.skyd.anivu.model.preference.behavior.PickImageMethodPreference @@ -38,6 +40,7 @@ import com.skyd.anivu.model.preference.player.HardwareDecodePreference import com.skyd.anivu.model.preference.player.PlayerDoubleTapPreference import com.skyd.anivu.model.preference.player.PlayerShow85sButtonPreference import com.skyd.anivu.model.preference.player.PlayerShowScreenshotButtonPreference +import com.skyd.anivu.ui.local.LocalArticleItemMinWidth import com.skyd.anivu.ui.local.LocalArticleItemTonalElevation import com.skyd.anivu.ui.local.LocalArticleListTonalElevation import com.skyd.anivu.ui.local.LocalArticleSwipeLeftAction @@ -62,6 +65,7 @@ import com.skyd.anivu.ui.local.LocalPickImageMethod import com.skyd.anivu.ui.local.LocalPlayerDoubleTap import com.skyd.anivu.ui.local.LocalPlayerShow85sButton import com.skyd.anivu.ui.local.LocalPlayerShowScreenshotButton +import com.skyd.anivu.ui.local.LocalSearchItemMinWidth import com.skyd.anivu.ui.local.LocalSearchListTonalElevation import com.skyd.anivu.ui.local.LocalSearchTopBarTonalElevation import com.skyd.anivu.ui.local.LocalShowArticlePullRefresh @@ -89,6 +93,8 @@ data class Settings( val searchTopBarTonalElevation: Float = SearchTopBarTonalElevationPreference.default, val showArticleTopBarRefresh: Boolean = ShowArticleTopBarRefreshPreference.default, val showArticlePullRefresh: Boolean = ShowArticlePullRefreshPreference.default, + val articleItemMinWidth: Float = ArticleItemMinWidthPreference.default, + val searchItemMinWidth: Float = SearchItemMinWidthPreference.default, // Update val ignoreUpdateVersion: Long = IgnoreUpdateVersionPreference.default, // Behavior @@ -136,6 +142,8 @@ fun SettingsProvider( LocalSearchTopBarTonalElevation provides settings.searchTopBarTonalElevation, LocalShowArticleTopBarRefresh provides settings.showArticleTopBarRefresh, LocalShowArticlePullRefresh provides settings.showArticlePullRefresh, + LocalArticleItemMinWidth provides settings.articleItemMinWidth, + LocalSearchItemMinWidth provides settings.searchItemMinWidth, // Update LocalIgnoreUpdateVersion provides settings.ignoreUpdateVersion, // Behavior diff --git a/app/src/main/java/com/skyd/anivu/model/preference/appearance/article/ArticleItemMinWidthPreference.kt b/app/src/main/java/com/skyd/anivu/model/preference/appearance/article/ArticleItemMinWidthPreference.kt new file mode 100644 index 00000000..dd91261d --- /dev/null +++ b/app/src/main/java/com/skyd/anivu/model/preference/appearance/article/ArticleItemMinWidthPreference.kt @@ -0,0 +1,26 @@ +package com.skyd.anivu.model.preference.appearance.article + +import android.content.Context +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.floatPreferencesKey +import com.skyd.anivu.base.BasePreference +import com.skyd.anivu.ext.dataStore +import com.skyd.anivu.ext.put +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch + +object ArticleItemMinWidthPreference : BasePreference { + private const val ARTICLE_ITEM_MIN_WIDTH = "articleItemMinWidth" + override val default = 360f + + val key = floatPreferencesKey(ARTICLE_ITEM_MIN_WIDTH) + + fun put(context: Context, scope: CoroutineScope, value: Float) { + scope.launch(Dispatchers.IO) { + context.dataStore.put(key, value) + } + } + + override fun fromPreferences(preferences: Preferences): Float = preferences[key] ?: default +} \ No newline at end of file diff --git a/app/src/main/java/com/skyd/anivu/model/preference/appearance/search/SearchItemMinWidthPreference.kt b/app/src/main/java/com/skyd/anivu/model/preference/appearance/search/SearchItemMinWidthPreference.kt new file mode 100644 index 00000000..1fef53ef --- /dev/null +++ b/app/src/main/java/com/skyd/anivu/model/preference/appearance/search/SearchItemMinWidthPreference.kt @@ -0,0 +1,26 @@ +package com.skyd.anivu.model.preference.appearance.search + +import android.content.Context +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.floatPreferencesKey +import com.skyd.anivu.base.BasePreference +import com.skyd.anivu.ext.dataStore +import com.skyd.anivu.ext.put +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch + +object SearchItemMinWidthPreference : BasePreference { + private const val SEARCH_ITEM_MIN_WIDTH = "searchItemMinWidth" + override val default = 360f + + val key = floatPreferencesKey(SEARCH_ITEM_MIN_WIDTH) + + fun put(context: Context, scope: CoroutineScope, value: Float) { + scope.launch(Dispatchers.IO) { + context.dataStore.put(key, value) + } + } + + override fun fromPreferences(preferences: Preferences): Float = preferences[key] ?: default +} \ No newline at end of file diff --git a/app/src/main/java/com/skyd/anivu/model/worker/download/DownloadTorrentWorker.kt b/app/src/main/java/com/skyd/anivu/model/worker/download/DownloadTorrentWorker.kt index dddef8e4..c128c7f5 100644 --- a/app/src/main/java/com/skyd/anivu/model/worker/download/DownloadTorrentWorker.kt +++ b/app/src/main/java/com/skyd/anivu/model/worker/download/DownloadTorrentWorker.kt @@ -60,7 +60,6 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withContext import org.libtorrent4j.AlertListener -import org.libtorrent4j.MoveFlags import org.libtorrent4j.SessionManager import org.libtorrent4j.SessionParams import org.libtorrent4j.TorrentHandle @@ -249,12 +248,12 @@ class DownloadTorrentWorker(context: Context, parameters: WorkerParameters) : saveDir: File, flags: torrent_flags_t = torrent_flags_t(), ) { - doIfMagnetOrTorrentLink( + ifMagnetLink( link = link, onMagnet = { sessionManager.download(link, saveDir, flags) }, - onTorrent = { + onUnsupported = { val tempTorrentFile = File( Const.TEMP_TORRENT_DIR, link.substringAfterLast('/').toDecodedUrl().validateFileName() @@ -269,9 +268,6 @@ class DownloadTorrentWorker(context: Context, parameters: WorkerParameters) : flags ) }, - onUnsupported = { - error("Unsupported link: $link") - }, ) } diff --git a/app/src/main/java/com/skyd/anivu/model/worker/download/Util.kt b/app/src/main/java/com/skyd/anivu/model/worker/download/Util.kt index a8813af6..e54bb1ea 100644 --- a/app/src/main/java/com/skyd/anivu/model/worker/download/Util.kt +++ b/app/src/main/java/com/skyd/anivu/model/worker/download/Util.kt @@ -36,22 +36,45 @@ import java.io.FileOutputStream import java.io.IOException +fun isTorrentMimetype(mimetype: String?): Boolean { + return Regex("^application(s)?/x-bittorrent$").matches(mimetype.orEmpty()) +} + fun doIfMagnetOrTorrentLink( link: String, + mimetype: String? = null, onMagnet: ((String) -> Unit)? = null, onTorrent: ((String) -> Unit)? = null, onSupported: ((String) -> Unit)? = null, onUnsupported: ((String) -> Unit)? = null, +) { + ifMagnetLink( + link = link, + onMagnet = { + onMagnet?.invoke(link) + onSupported?.invoke(link) + }, + onUnsupported = { + if ( + isTorrentMimetype(mimetype) || + Regex("^(http|https)://.*\\.torrent$").matches(link) + ) { + onTorrent?.invoke(link) + onSupported?.invoke(link) + } else { + onUnsupported?.invoke(link) + } + }, + ) +} + +fun ifMagnetLink( + link: String, + onMagnet: ((String) -> Unit)? = null, + onUnsupported: ((String) -> Unit)? = null, ) { if (link.startsWith("magnet:")) { onMagnet?.invoke(link) - onSupported?.invoke(link) - } else if ( - (link.startsWith("http:") || link.startsWith("https:")) && - link.endsWith(".torrent") - ) { - onTorrent?.invoke(link) - onSupported?.invoke(link) } else { onUnsupported?.invoke(link) } diff --git a/app/src/main/java/com/skyd/anivu/ui/adapter/variety/proxy/Enclosure1Proxy.kt b/app/src/main/java/com/skyd/anivu/ui/adapter/variety/proxy/Enclosure1Proxy.kt index 096030b3..9726704b 100644 --- a/app/src/main/java/com/skyd/anivu/ui/adapter/variety/proxy/Enclosure1Proxy.kt +++ b/app/src/main/java/com/skyd/anivu/ui/adapter/variety/proxy/Enclosure1Proxy.kt @@ -54,6 +54,7 @@ class Enclosure1Proxy( } doIfMagnetOrTorrentLink( link = data.url, + mimetype = data.type, onSupported = { btnEnclosure1Download.visible() btnEnclosure1Download.setOnClickListener { diff --git a/app/src/main/java/com/skyd/anivu/ui/component/SwipeToDismissBox.kt b/app/src/main/java/com/skyd/anivu/ui/component/SwipeToDismissBox.kt deleted file mode 100644 index d2f0522c..00000000 --- a/app/src/main/java/com/skyd/anivu/ui/component/SwipeToDismissBox.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.skyd.anivu.ui.component - -import androidx.compose.material3.SwipeToDismissBoxDefaults -import androidx.compose.material3.SwipeToDismissBoxState -import androidx.compose.material3.SwipeToDismissBoxValue -import androidx.compose.runtime.Composable -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.ui.platform.LocalDensity - -@Composable -fun rememberSwipeToDismissBoxState( - vararg inputs: Any?, - initialValue: SwipeToDismissBoxValue = SwipeToDismissBoxValue.Settled, - confirmValueChange: (SwipeToDismissBoxValue) -> Boolean = { true }, - positionalThreshold: (totalDistance: Float) -> Float = - SwipeToDismissBoxDefaults.positionalThreshold, -): SwipeToDismissBoxState { - val density = LocalDensity.current - return rememberSaveable( - inputs = inputs, - saver = SwipeToDismissBoxState.Saver( - confirmValueChange = confirmValueChange, - density = density, - positionalThreshold = positionalThreshold - ) - ) { - SwipeToDismissBoxState(initialValue, density, confirmValueChange, positionalThreshold) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/skyd/anivu/ui/component/lazyverticalgrid/adapter/proxy/Article1Proxy.kt b/app/src/main/java/com/skyd/anivu/ui/component/lazyverticalgrid/adapter/proxy/Article1Proxy.kt index 44cabb04..29916910 100644 --- a/app/src/main/java/com/skyd/anivu/ui/component/lazyverticalgrid/adapter/proxy/Article1Proxy.kt +++ b/app/src/main/java/com/skyd/anivu/ui/component/lazyverticalgrid/adapter/proxy/Article1Proxy.kt @@ -39,6 +39,7 @@ import androidx.compose.material3.OutlinedCard import androidx.compose.material3.SwipeToDismissBox import androidx.compose.material3.SwipeToDismissBoxValue import androidx.compose.material3.Text +import androidx.compose.material3.rememberSwipeToDismissBoxState import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider @@ -81,7 +82,6 @@ import com.skyd.anivu.model.preference.behavior.article.ArticleTapActionPreferen import com.skyd.anivu.ui.component.AniVuImage import com.skyd.anivu.ui.component.lazyverticalgrid.adapter.LazyGridAdapter import com.skyd.anivu.ui.component.rememberAniVuImageLoader -import com.skyd.anivu.ui.component.rememberSwipeToDismissBoxState import com.skyd.anivu.ui.fragment.read.EnclosureBottomSheet import com.skyd.anivu.ui.fragment.read.ReadFragment import com.skyd.anivu.ui.local.LocalArticleItemTonalElevation @@ -90,6 +90,7 @@ import com.skyd.anivu.ui.local.LocalArticleSwipeRightAction import com.skyd.anivu.ui.local.LocalArticleTapAction import com.skyd.anivu.ui.local.LocalDeduplicateTitleInDesc import com.skyd.anivu.ui.local.LocalNavController +import java.io.Serializable class Article1Proxy( private val onFavorite: (ArticleWithFeed, Boolean) -> Unit, @@ -101,6 +102,7 @@ class Article1Proxy( } } + @Composable fun Article1Item( data: ArticleWithFeed, @@ -109,11 +111,23 @@ fun Article1Item( ) { val navController = LocalNavController.current val context = LocalContext.current - val articleWithEnclosure = data.articleWithEnclosure var expandMenu by rememberSaveable { mutableStateOf(false) } + /** + * SwipeToDismissBoxState doesn't recompose, + * so we need to pass in a "variable" that points to an object that doesn't change, + * hence the need to wrap the data (DataWrapper). + * When the data changes, we only change the fields inside the DataWrapper object, + * which ensures that SwipeToDismissBoxState gets the latest data from the DataWrapper object. + */ + class DataWrapper( + var data: ArticleWithFeed + ) : Serializable + + val dataWrapper = rememberSaveable { DataWrapper(data) } + LaunchedEffect(data) { dataWrapper.data = data } + val swipeToDismissBoxState = rememberSwipeToDismissBoxState( - inputs = arrayOf(data), confirmValueChange = { dismissValue -> val articleSwipeAction = context.dataStore.getOrDefault( if (dismissValue == SwipeToDismissBoxValue.StartToEnd) { @@ -124,14 +138,17 @@ fun Article1Item( ) when (dismissValue) { SwipeToDismissBoxValue.EndToStart, SwipeToDismissBoxValue.StartToEnd -> { + val articleWithEnclosure = dataWrapper.data.articleWithEnclosure swipeAction( articleSwipeAction = articleSwipeAction, context = context, navController = navController, data = articleWithEnclosure, - onMarkAsRead = { onRead(data, !data.articleWithEnclosure.article.isRead) }, + onMarkAsRead = { + onRead(dataWrapper.data, !articleWithEnclosure.article.isRead) + }, onMarkAsFavorite = { - onFavorite(data, !data.articleWithEnclosure.article.isFavorite) + onFavorite(dataWrapper.data, !articleWithEnclosure.article.isFavorite) }, ) } diff --git a/app/src/main/java/com/skyd/anivu/ui/fragment/article/ArticleFragment.kt b/app/src/main/java/com/skyd/anivu/ui/fragment/article/ArticleFragment.kt index f853200a..21da11b8 100644 --- a/app/src/main/java/com/skyd/anivu/ui/fragment/article/ArticleFragment.kt +++ b/app/src/main/java/com/skyd/anivu/ui/fragment/article/ArticleFragment.kt @@ -80,6 +80,7 @@ import com.skyd.anivu.ui.component.lazyverticalgrid.AniVuLazyVerticalGrid import com.skyd.anivu.ui.component.lazyverticalgrid.adapter.LazyGridAdapter import com.skyd.anivu.ui.component.lazyverticalgrid.adapter.proxy.Article1Proxy import com.skyd.anivu.ui.fragment.search.SearchFragment +import com.skyd.anivu.ui.local.LocalArticleItemMinWidth import com.skyd.anivu.ui.local.LocalArticleListTonalElevation import com.skyd.anivu.ui.local.LocalArticleTopBarTonalElevation import com.skyd.anivu.ui.local.LocalNavController @@ -368,7 +369,7 @@ private fun ArticleList( } AniVuLazyVerticalGrid( modifier = modifier.fillMaxSize(), - columns = GridCells.Adaptive(360.dp), + columns = GridCells.Adaptive(LocalArticleItemMinWidth.current.dp), dataList = articles, listState = listState, adapter = adapter, diff --git a/app/src/main/java/com/skyd/anivu/ui/fragment/search/SearchFragment.kt b/app/src/main/java/com/skyd/anivu/ui/fragment/search/SearchFragment.kt index 02256e57..a3ce6ac4 100644 --- a/app/src/main/java/com/skyd/anivu/ui/fragment/search/SearchFragment.kt +++ b/app/src/main/java/com/skyd/anivu/ui/fragment/search/SearchFragment.kt @@ -81,6 +81,7 @@ import com.skyd.anivu.ui.component.lazyverticalgrid.AniVuLazyVerticalGrid import com.skyd.anivu.ui.component.lazyverticalgrid.adapter.LazyGridAdapter import com.skyd.anivu.ui.component.lazyverticalgrid.adapter.proxy.Article1Proxy import com.skyd.anivu.ui.component.lazyverticalgrid.adapter.proxy.Feed1Proxy +import com.skyd.anivu.ui.local.LocalSearchItemMinWidth import com.skyd.anivu.ui.local.LocalSearchListTonalElevation import com.skyd.anivu.ui.local.LocalSearchTopBarTonalElevation import dagger.hilt.android.AndroidEntryPoint @@ -270,7 +271,7 @@ private fun SearchResultList( } AniVuLazyVerticalGrid( modifier = modifier, - columns = GridCells.Adaptive(360.dp), + columns = GridCells.Adaptive(LocalSearchItemMinWidth.current.dp), dataList = result, listState = listState, adapter = adapter, diff --git a/app/src/main/java/com/skyd/anivu/ui/fragment/settings/appearance/article/ArticleStyleFragment.kt b/app/src/main/java/com/skyd/anivu/ui/fragment/settings/appearance/article/ArticleStyleFragment.kt index 65a71e35..c9ad1c22 100644 --- a/app/src/main/java/com/skyd/anivu/ui/fragment/settings/appearance/article/ArticleStyleFragment.kt +++ b/app/src/main/java/com/skyd/anivu/ui/fragment/settings/appearance/article/ArticleStyleFragment.kt @@ -4,20 +4,30 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.compose.animation.animateContentSize +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Refresh +import androidx.compose.material.icons.outlined.Restore import androidx.compose.material.icons.outlined.Tonality +import androidx.compose.material.icons.outlined.WidthNormal +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.input.nestedscroll.nestedScroll @@ -25,18 +35,22 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import com.skyd.anivu.R import com.skyd.anivu.base.BaseComposeFragment +import com.skyd.anivu.model.preference.appearance.article.ArticleItemMinWidthPreference import com.skyd.anivu.model.preference.appearance.article.ArticleItemTonalElevationPreference import com.skyd.anivu.model.preference.appearance.article.ArticleListTonalElevationPreference import com.skyd.anivu.model.preference.appearance.article.ArticleTopBarTonalElevationPreference import com.skyd.anivu.model.preference.appearance.article.ShowArticlePullRefreshPreference import com.skyd.anivu.model.preference.appearance.article.ShowArticleTopBarRefreshPreference import com.skyd.anivu.model.preference.appearance.feed.TonalElevationPreferenceUtil +import com.skyd.anivu.ui.component.AniVuIconButton import com.skyd.anivu.ui.component.AniVuTopBar import com.skyd.anivu.ui.component.AniVuTopBarStyle import com.skyd.anivu.ui.component.BaseSettingsItem import com.skyd.anivu.ui.component.CategorySettingsItem import com.skyd.anivu.ui.component.SwitchSettingsItem +import com.skyd.anivu.ui.component.dialog.SliderDialog import com.skyd.anivu.ui.fragment.settings.appearance.feed.TonalElevationDialog +import com.skyd.anivu.ui.local.LocalArticleItemMinWidth import com.skyd.anivu.ui.local.LocalArticleItemTonalElevation import com.skyd.anivu.ui.local.LocalArticleListTonalElevation import com.skyd.anivu.ui.local.LocalArticleTopBarTonalElevation @@ -72,6 +86,7 @@ fun ArticleStyleScreen() { var openTopBarTonalElevationDialog by rememberSaveable { mutableStateOf(false) } var openArticleListTonalElevationDialog by rememberSaveable { mutableStateOf(false) } var openArticleItemTonalElevationDialog by rememberSaveable { mutableStateOf(false) } + var openArticleItemMinWidthDialog by rememberSaveable { mutableStateOf(false) } LazyColumn( modifier = Modifier @@ -148,6 +163,14 @@ fun ArticleStyleScreen() { onClick = { openArticleItemTonalElevationDialog = true } ) } + item { + BaseSettingsItem( + icon = rememberVectorPainter(Icons.Outlined.WidthNormal), + text = stringResource(id = R.string.min_width_dp), + descriptionText = "${LocalArticleItemMinWidth.current} dp", + onClick = { openArticleItemMinWidthDialog = true } + ) + } } if (openTopBarTonalElevationDialog) { @@ -195,5 +218,61 @@ fun ArticleStyleScreen() { } ) } + if (openArticleItemMinWidthDialog) { + ItemMinWidthDialog( + onDismissRequest = { openArticleItemMinWidthDialog = false }, + initValue = LocalArticleItemMinWidth.current, + defaultValue = { ArticleItemMinWidthPreference.default }, + onConfirm = { + ArticleItemMinWidthPreference.put( + context = context, + scope = scope, + value = it, + ) + openArticleItemMinWidthDialog = false + } + ) + } } +} + + +@Composable +internal fun ItemMinWidthDialog( + onDismissRequest: () -> Unit, + initValue: Float, + defaultValue: () -> Float, + onConfirm: (Float) -> Unit, +) { + var value by rememberSaveable { mutableFloatStateOf(initValue) } + + SliderDialog( + onDismissRequest = onDismissRequest, + value = value, + onValueChange = { value = it }, + valueRange = 200f..600f, + valueLabel = { + Box(modifier = Modifier.fillMaxWidth()) { + Text( + modifier = Modifier + .align(Alignment.Center) + .animateContentSize(), + text = "$value dp", + style = MaterialTheme.typography.titleMedium, + ) + AniVuIconButton( + modifier = Modifier.align(Alignment.CenterEnd), + onClick = { value = defaultValue() }, + imageVector = Icons.Outlined.Restore, + ) + } + }, + icon = { Icon(imageVector = Icons.Outlined.WidthNormal, contentDescription = null) }, + title = { Text(text = stringResource(id = R.string.min_width_dp)) }, + confirmButton = { + TextButton(onClick = { onConfirm(value) }) { + Text(text = stringResource(id = R.string.ok)) + } + } + ) } \ No newline at end of file diff --git a/app/src/main/java/com/skyd/anivu/ui/fragment/settings/appearance/search/SearchStyleFragment.kt b/app/src/main/java/com/skyd/anivu/ui/fragment/settings/appearance/search/SearchStyleFragment.kt index 2cfa04f9..cc577993 100644 --- a/app/src/main/java/com/skyd/anivu/ui/fragment/settings/appearance/search/SearchStyleFragment.kt +++ b/app/src/main/java/com/skyd/anivu/ui/fragment/settings/appearance/search/SearchStyleFragment.kt @@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Tonality +import androidx.compose.material.icons.outlined.WidthNormal import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults @@ -25,13 +26,16 @@ import androidx.compose.ui.res.stringResource import com.skyd.anivu.R import com.skyd.anivu.base.BaseComposeFragment import com.skyd.anivu.model.preference.appearance.feed.TonalElevationPreferenceUtil +import com.skyd.anivu.model.preference.appearance.search.SearchItemMinWidthPreference import com.skyd.anivu.model.preference.appearance.search.SearchListTonalElevationPreference import com.skyd.anivu.model.preference.appearance.search.SearchTopBarTonalElevationPreference import com.skyd.anivu.ui.component.AniVuTopBar import com.skyd.anivu.ui.component.AniVuTopBarStyle import com.skyd.anivu.ui.component.BaseSettingsItem import com.skyd.anivu.ui.component.CategorySettingsItem +import com.skyd.anivu.ui.fragment.settings.appearance.article.ItemMinWidthDialog import com.skyd.anivu.ui.fragment.settings.appearance.feed.TonalElevationDialog +import com.skyd.anivu.ui.local.LocalSearchItemMinWidth import com.skyd.anivu.ui.local.LocalSearchListTonalElevation import com.skyd.anivu.ui.local.LocalSearchTopBarTonalElevation import dagger.hilt.android.AndroidEntryPoint @@ -63,6 +67,7 @@ fun SearchStyleScreen() { ) { paddingValues -> var openTopBarTonalElevationDialog by rememberSaveable { mutableStateOf(false) } var openSearchListTonalElevationDialog by rememberSaveable { mutableStateOf(false) } + var openSearchItemMinWidthDialog by rememberSaveable { mutableStateOf(false) } LazyColumn( modifier = Modifier @@ -96,6 +101,17 @@ fun SearchStyleScreen() { onClick = { openSearchListTonalElevationDialog = true } ) } + item { + CategorySettingsItem(text = stringResource(id = R.string.search_style_screen_search_item_category)) + } + item { + BaseSettingsItem( + icon = rememberVectorPainter(Icons.Outlined.WidthNormal), + text = stringResource(id = R.string.min_width_dp), + descriptionText = "${LocalSearchItemMinWidth.current} dp", + onClick = { openSearchItemMinWidthDialog = true } + ) + } } if (openTopBarTonalElevationDialog) { @@ -128,5 +144,20 @@ fun SearchStyleScreen() { } ) } + if (openSearchItemMinWidthDialog) { + ItemMinWidthDialog( + onDismissRequest = { openSearchItemMinWidthDialog = false }, + initValue = LocalSearchItemMinWidth.current, + defaultValue = { SearchItemMinWidthPreference.default }, + onConfirm = { + SearchItemMinWidthPreference.put( + context = context, + scope = scope, + value = it, + ) + openSearchItemMinWidthDialog = false + } + ) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/skyd/anivu/ui/local/LocalValue.kt b/app/src/main/java/com/skyd/anivu/ui/local/LocalValue.kt index 3f02a21f..bdd494e5 100644 --- a/app/src/main/java/com/skyd/anivu/ui/local/LocalValue.kt +++ b/app/src/main/java/com/skyd/anivu/ui/local/LocalValue.kt @@ -9,6 +9,7 @@ import com.skyd.anivu.model.preference.appearance.DateStylePreference import com.skyd.anivu.model.preference.appearance.NavigationBarLabelPreference import com.skyd.anivu.model.preference.appearance.TextFieldStylePreference import com.skyd.anivu.model.preference.appearance.ThemePreference +import com.skyd.anivu.model.preference.appearance.article.ArticleItemMinWidthPreference import com.skyd.anivu.model.preference.appearance.article.ArticleItemTonalElevationPreference import com.skyd.anivu.model.preference.appearance.article.ArticleListTonalElevationPreference import com.skyd.anivu.model.preference.appearance.article.ArticleTopBarTonalElevationPreference @@ -17,6 +18,7 @@ import com.skyd.anivu.model.preference.appearance.article.ShowArticleTopBarRefre import com.skyd.anivu.model.preference.appearance.feed.FeedGroupExpandPreference import com.skyd.anivu.model.preference.appearance.feed.FeedListTonalElevationPreference import com.skyd.anivu.model.preference.appearance.feed.FeedTopBarTonalElevationPreference +import com.skyd.anivu.model.preference.appearance.search.SearchItemMinWidthPreference import com.skyd.anivu.model.preference.appearance.search.SearchListTonalElevationPreference import com.skyd.anivu.model.preference.appearance.search.SearchTopBarTonalElevationPreference import com.skyd.anivu.model.preference.behavior.PickImageMethodPreference @@ -66,6 +68,8 @@ val LocalSearchTopBarTonalElevation = val LocalShowArticleTopBarRefresh = compositionLocalOf { ShowArticleTopBarRefreshPreference.default } val LocalShowArticlePullRefresh = compositionLocalOf { ShowArticlePullRefreshPreference.default } +val LocalArticleItemMinWidth = compositionLocalOf { ArticleItemMinWidthPreference.default } +val LocalSearchItemMinWidth = compositionLocalOf { SearchItemMinWidthPreference.default } // Update val LocalIgnoreUpdateVersion = compositionLocalOf { IgnoreUpdateVersionPreference.default } diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 03befbb4..57ecae84 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -299,7 +299,8 @@ 添加分组 移动到 删除“%s”分组及其包含的所有文件和文件夹 - + 最小宽度(dp) + 搜索项 已读 %d 项 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 40f6a77e..3a14eaa4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -306,6 +306,8 @@ Add group Move to Delete the \"%s\" group and all the files it contains + Min width (dp) + Search item Read %d item Read %d items