From e85cedc6444572236059d9f61f6a6e7e7be3320f Mon Sep 17 00:00:00 2001 From: SkyD666 Date: Sat, 8 Jun 2024 21:46:05 +0800 Subject: [PATCH] [feature|build] Support right swipe on Article items; support swipe to mark read, favorite (#58); update Kotlin version to 2.0.0; update dependencies --- app/build.gradle.kts | 17 ++- .../java/com/skyd/anivu/ext/PreferenceExt.kt | 2 + .../skyd/anivu/model/preference/Settings.kt | 4 + .../article/ArticleSwipeActionPreference.kt | 47 ++++++++ .../ArticleSwipeLeftActionPreference.kt | 30 +---- .../ArticleSwipeRightActionPreference.kt | 19 +++ .../anivu/ui/component/ColorPaletteView.kt | 11 +- .../anivu/ui/component/SwipeToDismissBox.kt | 29 +++++ .../adapter/proxy/Article1Proxy.kt | 110 +++++++++++++----- .../skyd/anivu/ui/fragment/article/Filter.kt | 23 +++- .../settings/behavior/BehaviorFragment.kt | 62 +++++++--- .../com/skyd/anivu/ui/local/LocalValue.kt | 2 + app/src/main/res/values-zh-rCN/strings.xml | 12 +- app/src/main/res/values/strings.xml | 12 +- build.gradle.kts | 7 +- 15 files changed, 288 insertions(+), 99 deletions(-) create mode 100644 app/src/main/java/com/skyd/anivu/model/preference/behavior/article/ArticleSwipeActionPreference.kt create mode 100644 app/src/main/java/com/skyd/anivu/model/preference/behavior/article/ArticleSwipeRightActionPreference.kt create 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 f6c4a96b..bed25b91 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -4,6 +4,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { id("com.android.application") id("org.jetbrains.kotlin.android") + id("org.jetbrains.kotlin.plugin.compose") id("kotlinx-serialization") id("kotlin-parcelize") id("com.google.devtools.ksp") @@ -21,7 +22,7 @@ android { minSdk = 24 targetSdk = 34 versionCode = 18 - versionName = "1.1-beta47" + versionName = "1.1-beta48" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" @@ -104,9 +105,6 @@ android { viewBinding = true buildConfig = true } - composeOptions { - kotlinCompilerExtensionVersion = "1.5.14" - } packaging { resources.excludes += mutableSetOf( "DebugProbesKt.bin", @@ -130,6 +128,13 @@ android { // ndkVersion = "26.3.11579264" } +composeCompiler { + enableStrongSkippingMode = true + + reportsDestination = layout.buildDirectory.dir("compose_compiler") +// stabilityConfigurationFile = rootProject.layout.projectDirectory.file("stability_config.conf") +} + tasks.withType(KotlinCompile::class.java).configureEach { kotlinOptions { freeCompilerArgs += listOf( @@ -167,7 +172,7 @@ dependencies { implementation("androidx.compose.material3.adaptive:adaptive-layout:1.0.0-beta01") implementation("androidx.compose.material3.adaptive:adaptive-navigation:1.0.0-beta01") implementation("androidx.compose.material:material-icons-extended:1.6.7") - implementation("com.materialkolor:material-kolor:1.6.1") + implementation("com.materialkolor:material-kolor:1.6.2") implementation("androidx.room:room-runtime:2.6.1") implementation("androidx.room:room-ktx:2.6.1") implementation("androidx.room:room-paging:2.6.1") @@ -191,7 +196,7 @@ dependencies { implementation("com.squareup.okhttp3:logging-interceptor:4.12.0") implementation("com.squareup.retrofit2:retrofit:2.11.0") implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-guava:1.8.1") implementation("com.github.aniyomiorg:aniyomi-mpv-lib:1.15.n") 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 e4e473d4..ed83166d 100644 --- a/app/src/main/java/com/skyd/anivu/ext/PreferenceExt.kt +++ b/app/src/main/java/com/skyd/anivu/ext/PreferenceExt.kt @@ -20,6 +20,7 @@ import com.skyd.anivu.model.preference.appearance.search.SearchListTonalElevatio import com.skyd.anivu.model.preference.appearance.search.SearchTopBarTonalElevationPreference import com.skyd.anivu.model.preference.behavior.PickImageMethodPreference import com.skyd.anivu.model.preference.behavior.article.ArticleSwipeLeftActionPreference +import com.skyd.anivu.model.preference.behavior.article.ArticleSwipeRightActionPreference import com.skyd.anivu.model.preference.behavior.article.ArticleTapActionPreference import com.skyd.anivu.model.preference.behavior.article.DeduplicateTitleInDescPreference import com.skyd.anivu.model.preference.behavior.feed.HideEmptyDefaultPreference @@ -58,6 +59,7 @@ fun Preferences.toSettings(): Settings { deduplicateTitleInDesc = DeduplicateTitleInDescPreference.fromPreferences(this), articleTapAction = ArticleTapActionPreference.fromPreferences(this), articleSwipeLeftAction = ArticleSwipeLeftActionPreference.fromPreferences(this), + articleSwipeRightAction = ArticleSwipeRightActionPreference.fromPreferences(this), hideEmptyDefault = HideEmptyDefaultPreference.fromPreferences(this), pickImageMethod = PickImageMethodPreference.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 b6a62294..52285143 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 @@ -25,6 +25,7 @@ import com.skyd.anivu.model.preference.appearance.search.SearchListTonalElevatio import com.skyd.anivu.model.preference.appearance.search.SearchTopBarTonalElevationPreference import com.skyd.anivu.model.preference.behavior.PickImageMethodPreference import com.skyd.anivu.model.preference.behavior.article.ArticleSwipeLeftActionPreference +import com.skyd.anivu.model.preference.behavior.article.ArticleSwipeRightActionPreference import com.skyd.anivu.model.preference.behavior.article.ArticleTapActionPreference import com.skyd.anivu.model.preference.behavior.article.DeduplicateTitleInDescPreference import com.skyd.anivu.model.preference.behavior.feed.HideEmptyDefaultPreference @@ -39,6 +40,7 @@ import com.skyd.anivu.model.preference.player.PlayerShowScreenshotButtonPreferen import com.skyd.anivu.ui.local.LocalArticleItemTonalElevation import com.skyd.anivu.ui.local.LocalArticleListTonalElevation import com.skyd.anivu.ui.local.LocalArticleSwipeLeftAction +import com.skyd.anivu.ui.local.LocalArticleSwipeRightAction import com.skyd.anivu.ui.local.LocalArticleTapAction import com.skyd.anivu.ui.local.LocalArticleTopBarTonalElevation import com.skyd.anivu.ui.local.LocalAutoDeleteArticleBefore @@ -91,6 +93,7 @@ data class Settings( val deduplicateTitleInDesc: Boolean = DeduplicateTitleInDescPreference.default, val articleTapAction: String = ArticleTapActionPreference.default, val articleSwipeLeftAction: String = ArticleSwipeLeftActionPreference.default, + val articleSwipeRightAction: String = ArticleSwipeRightActionPreference.default, val hideEmptyDefault: Boolean = HideEmptyDefaultPreference.default, val pickImageMethod: String = PickImageMethodPreference.default, // Player @@ -136,6 +139,7 @@ fun SettingsProvider( LocalDeduplicateTitleInDesc provides settings.deduplicateTitleInDesc, LocalArticleTapAction provides settings.articleTapAction, LocalArticleSwipeLeftAction provides settings.articleSwipeLeftAction, + LocalArticleSwipeRightAction provides settings.articleSwipeRightAction, LocalHideEmptyDefault provides settings.hideEmptyDefault, LocalPickImageMethod provides settings.pickImageMethod, // Player diff --git a/app/src/main/java/com/skyd/anivu/model/preference/behavior/article/ArticleSwipeActionPreference.kt b/app/src/main/java/com/skyd/anivu/model/preference/behavior/article/ArticleSwipeActionPreference.kt new file mode 100644 index 00000000..41cb1b1a --- /dev/null +++ b/app/src/main/java/com/skyd/anivu/model/preference/behavior/article/ArticleSwipeActionPreference.kt @@ -0,0 +1,47 @@ +package com.skyd.anivu.model.preference.behavior.article + +import android.content.Context +import androidx.datastore.preferences.core.Preferences +import com.skyd.anivu.R +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 + +abstract class ArticleSwipeActionPreference : BasePreference { + + companion object { + const val NONE = "None" + const val READ = "Read" + const val SHOW_ENCLOSURES = "ShowEnclosures" + const val SWITCH_READ_STATE = "SwitchReadState" + const val SWITCH_FAVORITE_STATE = "SwitchFavoriteState" + + fun toDisplayName( + context: Context, + value: String, + ): String = when (value) { + NONE -> context.getString(R.string.none) + READ -> context.getString(R.string.article_action_read) + SHOW_ENCLOSURES -> context.getString(R.string.article_action_show_enclosures) + SWITCH_READ_STATE -> context.getString(R.string.article_action_switch_read_state) + SWITCH_FAVORITE_STATE -> context.getString(R.string.article_action_switch_favorite_state) + else -> context.getString(R.string.unknown) + } + } + + val values = arrayOf(NONE, READ, SHOW_ENCLOSURES, SWITCH_READ_STATE, SWITCH_FAVORITE_STATE) + + abstract val key: Preferences.Key + + fun put(context: Context, scope: CoroutineScope, value: String) { + scope.launch(Dispatchers.IO) { + context.dataStore.put(key, value) + } + } + + override fun fromPreferences(preferences: Preferences): String = preferences[key] ?: default + +} diff --git a/app/src/main/java/com/skyd/anivu/model/preference/behavior/article/ArticleSwipeLeftActionPreference.kt b/app/src/main/java/com/skyd/anivu/model/preference/behavior/article/ArticleSwipeLeftActionPreference.kt index e44c72b0..bfa1b27e 100644 --- a/app/src/main/java/com/skyd/anivu/model/preference/behavior/article/ArticleSwipeLeftActionPreference.kt +++ b/app/src/main/java/com/skyd/anivu/model/preference/behavior/article/ArticleSwipeLeftActionPreference.kt @@ -1,43 +1,19 @@ package com.skyd.anivu.model.preference.behavior.article import android.content.Context -import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.stringPreferencesKey -import com.skyd.anivu.R -import com.skyd.anivu.base.BasePreference import com.skyd.anivu.ext.dataStore import com.skyd.anivu.ext.getOrDefault -import com.skyd.anivu.ext.put -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -object ArticleSwipeLeftActionPreference : BasePreference { +object ArticleSwipeLeftActionPreference : ArticleSwipeActionPreference() { private const val ARTICLE_SWIPE_LEFT_ACTION = "articleSwipeLeftAction" - const val READ = "Read" - const val SHOW_ENCLOSURES = "ShowEnclosures" - - val values = arrayOf(READ, SHOW_ENCLOSURES) - override val default = SHOW_ENCLOSURES - val key = stringPreferencesKey(ARTICLE_SWIPE_LEFT_ACTION) - - fun put(context: Context, scope: CoroutineScope, value: String) { - scope.launch(Dispatchers.IO) { - context.dataStore.put(key, value) - } - } - - override fun fromPreferences(preferences: Preferences): String = preferences[key] ?: default + override val key = stringPreferencesKey(ARTICLE_SWIPE_LEFT_ACTION) fun toDisplayName( context: Context, value: String = context.dataStore.getOrDefault(this), - ): String = when (value) { - READ -> context.getString(R.string.article_action_read) - SHOW_ENCLOSURES -> context.getString(R.string.article_action_show_enclosures) - else -> context.getString(R.string.unknown) - } + ): String = ArticleSwipeActionPreference.toDisplayName(context, value) } diff --git a/app/src/main/java/com/skyd/anivu/model/preference/behavior/article/ArticleSwipeRightActionPreference.kt b/app/src/main/java/com/skyd/anivu/model/preference/behavior/article/ArticleSwipeRightActionPreference.kt new file mode 100644 index 00000000..d512dca7 --- /dev/null +++ b/app/src/main/java/com/skyd/anivu/model/preference/behavior/article/ArticleSwipeRightActionPreference.kt @@ -0,0 +1,19 @@ +package com.skyd.anivu.model.preference.behavior.article + +import android.content.Context +import androidx.datastore.preferences.core.stringPreferencesKey +import com.skyd.anivu.ext.dataStore +import com.skyd.anivu.ext.getOrDefault + +object ArticleSwipeRightActionPreference : ArticleSwipeActionPreference() { + private const val ARTICLE_SWIPE_RIGHT_ACTION = "articleSwipeRightAction" + + override val default = SWITCH_FAVORITE_STATE + + override val key = stringPreferencesKey(ARTICLE_SWIPE_RIGHT_ACTION) + + fun toDisplayName( + context: Context, + value: String = context.dataStore.getOrDefault(this), + ): String = ArticleSwipeActionPreference.toDisplayName(context, value) +} diff --git a/app/src/main/java/com/skyd/anivu/ui/component/ColorPaletteView.kt b/app/src/main/java/com/skyd/anivu/ui/component/ColorPaletteView.kt index 5071994e..bdc8a8ca 100644 --- a/app/src/main/java/com/skyd/anivu/ui/component/ColorPaletteView.kt +++ b/app/src/main/java/com/skyd/anivu/ui/component/ColorPaletteView.kt @@ -22,11 +22,7 @@ import com.skyd.anivu.ext.visible class ColorPaletteView : MaterialCardView { - private val iconImage = ImageView(context).apply { - setBackgroundResource(R.drawable.shape_fill_circle) - setPadding(7.dp) - backgroundTintList = ColorStateList.valueOf(iconBackgroundColor) - } + private val iconImage = ImageView(context) var icon: Drawable? get() = iconImage.drawable set(value) { @@ -72,6 +68,11 @@ class ColorPaletteView : MaterialCardView { attrs, defStyleAttr ) { + with(iconImage) { + setBackgroundResource(R.drawable.shape_fill_circle) + setPadding(7.dp) + backgroundTintList = ColorStateList.valueOf(iconBackgroundColor) + } val a = context.obtainStyledAttributes( attrs, R.styleable.ColorPaletteView, defStyleAttr, 0 ) 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 new file mode 100644 index 00000000..d2f0522c --- /dev/null +++ b/app/src/main/java/com/skyd/anivu/ui/component/SwipeToDismissBox.kt @@ -0,0 +1,29 @@ +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 099e1ca0..44cabb04 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,7 +39,6 @@ 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 @@ -71,18 +70,23 @@ import com.skyd.anivu.ext.dataStore import com.skyd.anivu.ext.getOrDefault import com.skyd.anivu.ext.readable import com.skyd.anivu.ext.toDateTimeString +import com.skyd.anivu.model.bean.ArticleBean import com.skyd.anivu.model.bean.ArticleWithEnclosureBean import com.skyd.anivu.model.bean.ArticleWithFeed import com.skyd.anivu.model.bean.FeedBean +import com.skyd.anivu.model.preference.behavior.article.ArticleSwipeActionPreference import com.skyd.anivu.model.preference.behavior.article.ArticleSwipeLeftActionPreference +import com.skyd.anivu.model.preference.behavior.article.ArticleSwipeRightActionPreference import com.skyd.anivu.model.preference.behavior.article.ArticleTapActionPreference 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 import com.skyd.anivu.ui.local.LocalArticleSwipeLeftAction +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 @@ -105,21 +109,34 @@ fun Article1Item( ) { val navController = LocalNavController.current val context = LocalContext.current - val articleSwipeLeftAction = LocalArticleSwipeLeftAction.current val articleWithEnclosure = data.articleWithEnclosure var expandMenu by rememberSaveable { mutableStateOf(false) } val swipeToDismissBoxState = rememberSwipeToDismissBoxState( + inputs = arrayOf(data), confirmValueChange = { dismissValue -> - if (dismissValue == SwipeToDismissBoxValue.EndToStart) { - swipeLeftAction( - // rememberSwipeToDismissBoxState does not update the variable - // when the outer recompose, so don't use the outer articleSwipeLeftAction - context.dataStore.getOrDefault(ArticleSwipeLeftActionPreference), - context, - navController, - articleWithEnclosure, - ) + val articleSwipeAction = context.dataStore.getOrDefault( + if (dismissValue == SwipeToDismissBoxValue.StartToEnd) { + ArticleSwipeRightActionPreference + } else { + ArticleSwipeLeftActionPreference + } + ) + when (dismissValue) { + SwipeToDismissBoxValue.EndToStart, SwipeToDismissBoxValue.StartToEnd -> { + swipeAction( + articleSwipeAction = articleSwipeAction, + context = context, + navController = navController, + data = articleWithEnclosure, + onMarkAsRead = { onRead(data, !data.articleWithEnclosure.article.isRead) }, + onMarkAsFavorite = { + onFavorite(data, !data.articleWithEnclosure.article.isFavorite) + }, + ) + } + + SwipeToDismissBoxValue.Settled -> Unit } false }, @@ -133,17 +150,22 @@ fun Article1Item( } Box(modifier = Modifier.clip(RoundedCornerShape(12.dp))) { + val enableDismissFromStartToEnd = + LocalArticleSwipeRightAction.current != ArticleSwipeActionPreference.NONE + val enableDismissFromEndToStart = + LocalArticleSwipeLeftAction.current != ArticleSwipeActionPreference.NONE SwipeToDismissBox( state = swipeToDismissBoxState, backgroundContent = { SwipeBackgroundContent( + article = data.articleWithEnclosure.article, direction = swipeToDismissBoxState.dismissDirection, isActive = isSwipeToDismissActive, - articleSwipeLeftAction = articleSwipeLeftAction, - context = context, ) }, - enableDismissFromStartToEnd = false, + enableDismissFromStartToEnd = enableDismissFromStartToEnd, + enableDismissFromEndToStart = enableDismissFromEndToStart, + gesturesEnabled = enableDismissFromStartToEnd || enableDismissFromEndToStart, ) { Article1ItemContent( data = data, @@ -492,14 +514,19 @@ fun FeedIcon(modifier: Modifier = Modifier, data: FeedBean, size: Dp = 22.dp) { @Composable private fun SwipeBackgroundContent( + article: ArticleBean, direction: SwipeToDismissBoxValue, isActive: Boolean, - articleSwipeLeftAction: String, - context: Context, ) { + val context = LocalContext.current val containerColor = MaterialTheme.colorScheme.background val containerColorElevated = MaterialTheme.colorScheme.tertiaryContainer val backgroundColor = remember(isActive) { Animatable(containerColor) } + val articleSwipeAction = if (direction == SwipeToDismissBoxValue.StartToEnd) { + LocalArticleSwipeRightAction.current + } else { + LocalArticleSwipeLeftAction.current + } LaunchedEffect(isActive) { backgroundColor.animateTo(if (isActive) containerColorElevated else containerColor) @@ -510,29 +537,49 @@ private fun SwipeBackgroundContent( .fillMaxSize() .background(backgroundColor.value) .padding(horizontal = 20.dp), - contentAlignment = Alignment.CenterEnd + contentAlignment = if (direction == SwipeToDismissBoxValue.StartToEnd) { + Alignment.CenterStart + } else { + Alignment.CenterEnd + }, ) { val painter = when (direction) { - SwipeToDismissBoxValue.EndToStart -> when (articleSwipeLeftAction) { - ArticleSwipeLeftActionPreference.READ -> { + SwipeToDismissBoxValue.StartToEnd, + SwipeToDismissBoxValue.EndToStart -> when (articleSwipeAction) { + ArticleSwipeActionPreference.READ -> { rememberVectorPainter(image = Icons.Outlined.ImportContacts) } - ArticleSwipeLeftActionPreference.SHOW_ENCLOSURES -> { + ArticleSwipeActionPreference.SHOW_ENCLOSURES -> { painterResource(id = R.drawable.ic_home_storage_24) } + ArticleSwipeActionPreference.SWITCH_READ_STATE -> { + if (article.isRead) { + rememberVectorPainter(image = Icons.Outlined.MarkEmailUnread) + } else { + rememberVectorPainter(image = Icons.Outlined.Drafts) + } + } + + ArticleSwipeActionPreference.SWITCH_FAVORITE_STATE -> { + if (article.isFavorite) { + rememberVectorPainter(image = Icons.Outlined.FavoriteBorder) + } else { + rememberVectorPainter(image = Icons.Outlined.Favorite) + } + } + else -> rememberVectorPainter(image = Icons.Outlined.ImportContacts) } - SwipeToDismissBoxValue.StartToEnd -> null SwipeToDismissBoxValue.Settled -> null } val contentDescription = when (direction) { - SwipeToDismissBoxValue.EndToStart -> ArticleSwipeLeftActionPreference - .toDisplayName(context, articleSwipeLeftAction) + SwipeToDismissBoxValue.StartToEnd, + SwipeToDismissBoxValue.EndToStart -> ArticleSwipeActionPreference + .toDisplayName(context, articleSwipeAction) - SwipeToDismissBoxValue.StartToEnd -> null SwipeToDismissBoxValue.Settled -> null } @@ -546,20 +593,25 @@ private fun SwipeBackgroundContent( } } -private fun swipeLeftAction( - articleSwipeLeftAction: String, +private fun swipeAction( + articleSwipeAction: String, context: Context, navController: NavController, data: ArticleWithEnclosureBean, + onMarkAsRead: () -> Unit, + onMarkAsFavorite: () -> Unit, ) { - when (articleSwipeLeftAction) { - ArticleSwipeLeftActionPreference.READ -> { + when (articleSwipeAction) { + ArticleSwipeActionPreference.READ -> { navigateToReadScreen(navController = navController, data = data) } - ArticleSwipeLeftActionPreference.SHOW_ENCLOSURES -> { + ArticleSwipeActionPreference.SHOW_ENCLOSURES -> { showEnclosureBottomSheet(context = context, data = data) } + + ArticleSwipeActionPreference.SWITCH_READ_STATE -> onMarkAsRead() + ArticleSwipeActionPreference.SWITCH_FAVORITE_STATE -> onMarkAsFavorite() } } diff --git a/app/src/main/java/com/skyd/anivu/ui/fragment/article/Filter.kt b/app/src/main/java/com/skyd/anivu/ui/fragment/article/Filter.kt index 0680e90e..53f577fb 100644 --- a/app/src/main/java/com/skyd/anivu/ui/fragment/article/Filter.kt +++ b/app/src/main/java/com/skyd/anivu/ui/fragment/article/Filter.kt @@ -100,9 +100,20 @@ fun FilterIcon( }, ) DropdownMenuItem( - text = { Text(text = stringResource(id = R.string.article_screen_hide_filter_bar)) }, + text = { + Text( + text = stringResource( + if (showFilterBar) R.string.article_screen_hide_filter_bar + else R.string.article_screen_show_filter_bar + ) + ) + }, leadingIcon = { - Icon(imageVector = Icons.Outlined.FilterAltOff, contentDescription = null) + Icon( + imageVector = if (showFilterBar) Icons.Outlined.FilterAltOff + else Icons.Outlined.FilterAlt, + contentDescription = null, + ) }, onClick = { onFilterBarVisibilityChanged(!showFilterBar) @@ -162,14 +173,14 @@ internal fun SortSetting( context.getString(R.string.article_screen_sort_date_asc), Icons.Outlined.CalendarMonth, ), - ArticleSort.Title(false) to Pair( - context.getString(R.string.article_screen_sort_title_desc), - Icons.Outlined.Title, - ), ArticleSort.Title(true) to Pair( context.getString(R.string.article_screen_sort_title_asc), Icons.Outlined.Title, ), + ArticleSort.Title(false) to Pair( + context.getString(R.string.article_screen_sort_title_desc), + Icons.Outlined.Title, + ), ) } diff --git a/app/src/main/java/com/skyd/anivu/ui/fragment/settings/behavior/BehaviorFragment.kt b/app/src/main/java/com/skyd/anivu/ui/fragment/settings/behavior/BehaviorFragment.kt index c6d32532..453d39f1 100644 --- a/app/src/main/java/com/skyd/anivu/ui/fragment/settings/behavior/BehaviorFragment.kt +++ b/app/src/main/java/com/skyd/anivu/ui/fragment/settings/behavior/BehaviorFragment.kt @@ -10,6 +10,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.outlined.Article import androidx.compose.material.icons.outlined.Done import androidx.compose.material.icons.outlined.SwipeLeft +import androidx.compose.material.icons.outlined.SwipeRight import androidx.compose.material.icons.outlined.Visibility import androidx.compose.material.icons.outlined.VisibilityOff import androidx.compose.material3.DropdownMenu @@ -33,6 +34,7 @@ import androidx.compose.ui.res.stringResource import com.skyd.anivu.R import com.skyd.anivu.base.BaseComposeFragment import com.skyd.anivu.model.preference.behavior.article.ArticleSwipeLeftActionPreference +import com.skyd.anivu.model.preference.behavior.article.ArticleSwipeRightActionPreference import com.skyd.anivu.model.preference.behavior.article.ArticleTapActionPreference import com.skyd.anivu.model.preference.behavior.article.DeduplicateTitleInDescPreference import com.skyd.anivu.model.preference.behavior.feed.HideEmptyDefaultPreference @@ -42,6 +44,7 @@ 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.local.LocalArticleSwipeLeftAction +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.LocalHideEmptyDefault @@ -64,6 +67,7 @@ fun BehaviorScreen() { val scope = rememberCoroutineScope() var expandArticleTapActionMenu by rememberSaveable { mutableStateOf(false) } var expandArticleSwipeLeftActionMenu by rememberSaveable { mutableStateOf(false) } + var expandArticleSwipeRightActionMenu by rememberSaveable { mutableStateOf(false) } Scaffold( topBar = { @@ -146,14 +150,43 @@ fun BehaviorScreen() { value = LocalArticleSwipeLeftAction.current, ), dropdownMenu = { - ArticleSwipeLeftActionMenu( + ArticleSwipeActionMenu( expanded = expandArticleSwipeLeftActionMenu, - onDismissRequest = { expandArticleSwipeLeftActionMenu = false } + onDismissRequest = { expandArticleSwipeLeftActionMenu = false }, + articleSwipeAction = LocalArticleSwipeLeftAction.current, + values = ArticleSwipeLeftActionPreference.values, + toDisplayName = { + ArticleSwipeLeftActionPreference.toDisplayName(context, it) + }, + onClick = { ArticleSwipeLeftActionPreference.put(context, scope, it) }, ) }, onClick = { expandArticleSwipeLeftActionMenu = true }, ) } + item { + BaseSettingsItem( + icon = rememberVectorPainter(image = Icons.Outlined.SwipeRight), + text = stringResource(id = R.string.behavior_screen_article_swipe_right_action), + descriptionText = ArticleSwipeRightActionPreference.toDisplayName( + context = context, + value = LocalArticleSwipeRightAction.current, + ), + dropdownMenu = { + ArticleSwipeActionMenu( + expanded = expandArticleSwipeRightActionMenu, + onDismissRequest = { expandArticleSwipeRightActionMenu = false }, + articleSwipeAction = LocalArticleSwipeRightAction.current, + values = ArticleSwipeRightActionPreference.values, + toDisplayName = { + ArticleSwipeRightActionPreference.toDisplayName(context, it) + }, + onClick = { ArticleSwipeRightActionPreference.put(context, scope, it) }, + ) + }, + onClick = { expandArticleSwipeRightActionMenu = true }, + ) + } } } } @@ -190,31 +223,30 @@ private fun ArticleTapActionMenu(expanded: Boolean, onDismissRequest: () -> Unit } @Composable -private fun ArticleSwipeLeftActionMenu(expanded: Boolean, onDismissRequest: () -> Unit) { - val context = LocalContext.current - val scope = rememberCoroutineScope() - val articleSwipeLeftAction = LocalArticleSwipeLeftAction.current - +private fun ArticleSwipeActionMenu( + expanded: Boolean, + onDismissRequest: () -> Unit, + articleSwipeAction: String, + values: Array, + toDisplayName: (String) -> String, + onClick: (String) -> Unit, +) { DropdownMenu( expanded = expanded, onDismissRequest = onDismissRequest, ) { - ArticleSwipeLeftActionPreference.values.forEach { action -> + values.forEach { action -> DropdownMenuItem( text = { - Text(text = ArticleSwipeLeftActionPreference.toDisplayName(context, action)) + Text(text = toDisplayName(action)) }, leadingIcon = { - if (articleSwipeLeftAction == action) { + if (articleSwipeAction == action) { Icon(imageVector = Icons.Outlined.Done, contentDescription = null) } }, onClick = { - ArticleSwipeLeftActionPreference.put( - context = context, - scope = scope, - value = action, - ) + onClick(action) onDismissRequest() }, ) 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 ecd7d9bb..b77b8c38 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 @@ -21,6 +21,7 @@ import com.skyd.anivu.model.preference.appearance.search.SearchListTonalElevatio import com.skyd.anivu.model.preference.appearance.search.SearchTopBarTonalElevationPreference import com.skyd.anivu.model.preference.behavior.PickImageMethodPreference import com.skyd.anivu.model.preference.behavior.article.ArticleSwipeLeftActionPreference +import com.skyd.anivu.model.preference.behavior.article.ArticleSwipeRightActionPreference import com.skyd.anivu.model.preference.behavior.article.ArticleTapActionPreference import com.skyd.anivu.model.preference.behavior.article.DeduplicateTitleInDescPreference import com.skyd.anivu.model.preference.behavior.feed.HideEmptyDefaultPreference @@ -72,6 +73,7 @@ val LocalIgnoreUpdateVersion = compositionLocalOf { IgnoreUpdateVersionPreferenc val LocalDeduplicateTitleInDesc = compositionLocalOf { DeduplicateTitleInDescPreference.default } val LocalArticleTapAction = compositionLocalOf { ArticleTapActionPreference.default } val LocalArticleSwipeLeftAction = compositionLocalOf { ArticleSwipeLeftActionPreference.default } +val LocalArticleSwipeRightAction = compositionLocalOf { ArticleSwipeRightActionPreference.default } val LocalHideEmptyDefault = compositionLocalOf { HideEmptyDefaultPreference.default } val LocalPickImageMethod = compositionLocalOf { PickImageMethodPreference.default } diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index cd2fc14b..6ed6938b 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -168,6 +168,7 @@ 附件 点击项 左滑 + 右滑 到顶部 默认 分组 @@ -272,12 +273,15 @@ 启用下拉刷新 在标题栏上显示刷新按钮 排序 - 日期 ↑ - 日期 ↓ - 标题 ↑ - 标题 ↓ + 最旧 + 最新 + A 到 Z + Z 到 A 显示过滤条 隐藏过滤条 + 切换已读状态 + 切换收藏状态 + 已读 %d 项 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 54e891d8..04e650aa 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -176,6 +176,7 @@ Show enclosures Tap item Swipe left + Swipe right To top Default Group @@ -280,12 +281,15 @@ Enable pull to refresh Show Refresh button on top bar Sort - Date ↑ - Date ↓ - Title ↑ - Title ↓ + Oldest + Newest + A to Z + Z to A Show filter bar Hide filter bar + Switch read state + Switch favorite state + None Read %d item Read %d items diff --git a/build.gradle.kts b/build.gradle.kts index 3e0c90e5..e20b2605 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,8 +1,9 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { id("com.android.application") version "8.4.0" apply false - id("org.jetbrains.kotlin.android") version "1.9.24" apply false + id("org.jetbrains.kotlin.android") version "2.0.0" apply false + id("org.jetbrains.kotlin.plugin.compose") version "2.0.0" id("com.google.dagger.hilt.android") version "2.51.1" apply false - id("com.google.devtools.ksp") version "1.9.24-1.0.20" apply false - id("org.jetbrains.kotlin.plugin.serialization") version "1.9.24" + id("com.google.devtools.ksp") version "2.0.0-1.0.22" apply false + id("org.jetbrains.kotlin.plugin.serialization") version "2.0.0" } \ No newline at end of file