From 66094f8075081db50b3ba9ebe2df3af7fff0791a Mon Sep 17 00:00:00 2001 From: Ash Date: Tue, 24 May 2022 17:47:24 +0800 Subject: [PATCH] Optimize the flow page --- .../reader/data/constant/ElevationTokens.kt | 10 +++++ .../java/me/ash/reader/data/entity/Article.kt | 10 ++--- .../FeedsFilterBarTonalElevationPreference.kt | 40 ++++++++++--------- .../FeedsGroupListTonalElevationPreference.kt | 37 ++++++++--------- .../FeedsTopBarTonalElevationPreference.kt | 37 ++++++++--------- ...FlowArticleListTonalElevationPreference.kt | 37 ++++++++--------- .../FlowFilterBarTonalElevationPreference.kt | 37 ++++++++--------- .../FlowTopBarTonalElevationPreference.kt | 37 ++++++++--------- .../reader/data/repository/OpmlRepository.kt | 2 +- .../ash/reader/data/repository/RssHelper.kt | 13 +++--- .../data/repository/StringsRepository.kt | 11 ++++- .../reader/ui/component/base/RYAsyncImage.kt | 2 +- .../ash/reader/ui/page/home/HomeViewModel.kt | 16 +++++++- .../feeds/subscribe/SubscribeViewModel.kt | 16 ++------ .../reader/ui/page/home/flow/ArticleItem.kt | 27 ++++++------- .../reader/ui/page/home/flow/ArticleList.kt | 10 ++--- .../ash/reader/ui/page/home/flow/FlowPage.kt | 32 +++++---------- .../reader/ui/page/home/flow/FlowViewModel.kt | 4 -- .../ash/reader/ui/page/home/flow/SearchBar.kt | 17 ++++---- .../reader/ui/page/home/flow/StickyHeader.kt | 8 ++-- .../ui/page/home/reading/ReadingViewModel.kt | 2 +- .../java/me/ash/reader/ui/theme/Shapes.kt | 15 +++++++ .../main/java/me/ash/reader/ui/theme/Theme.kt | 3 +- .../drawable/ic_broken_image_black_24dp.xml | 3 +- .../ic_hourglass_empty_black_24dp.xml | 3 +- 25 files changed, 230 insertions(+), 199 deletions(-) create mode 100644 app/src/main/java/me/ash/reader/data/constant/ElevationTokens.kt create mode 100644 app/src/main/java/me/ash/reader/ui/theme/Shapes.kt diff --git a/app/src/main/java/me/ash/reader/data/constant/ElevationTokens.kt b/app/src/main/java/me/ash/reader/data/constant/ElevationTokens.kt new file mode 100644 index 0000000..4c240e1 --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/constant/ElevationTokens.kt @@ -0,0 +1,10 @@ +package me.ash.reader.data.constant + +object ElevationTokens { + const val Level0 = 0 + const val Level1 = 1 + const val Level2 = 3 + const val Level3 = 6 + const val Level4 = 8 + const val Level5 = 12 +} \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/entity/Article.kt b/app/src/main/java/me/ash/reader/data/entity/Article.kt index c18859e..30086fc 100644 --- a/app/src/main/java/me/ash/reader/data/entity/Article.kt +++ b/app/src/main/java/me/ash/reader/data/entity/Article.kt @@ -1,9 +1,6 @@ package me.ash.reader.data.entity -import androidx.room.ColumnInfo -import androidx.room.Entity -import androidx.room.ForeignKey -import androidx.room.PrimaryKey +import androidx.room.* import java.util.* @Entity( @@ -45,4 +42,7 @@ data class Article( var isStarred: Boolean = false, @ColumnInfo(defaultValue = "false") var isReadLater: Boolean = false, -) \ No newline at end of file +) { + @Ignore + var dateString: String? = null +} \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarTonalElevationPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarTonalElevationPreference.kt index ba08eb3..ecdd1cc 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarTonalElevationPreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarTonalElevationPreference.kt @@ -4,17 +4,18 @@ import android.content.Context import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch +import me.ash.reader.data.constant.ElevationTokens import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.put sealed class FeedsFilterBarTonalElevationPreference(val value: Int) : Preference() { - object Level0 : FeedsFilterBarTonalElevationPreference(0) - object Level1 : FeedsFilterBarTonalElevationPreference(1) - object Level2 : FeedsFilterBarTonalElevationPreference(3) - object Level3 : FeedsFilterBarTonalElevationPreference(6) - object Level4 : FeedsFilterBarTonalElevationPreference(8) - object Level5 : FeedsFilterBarTonalElevationPreference(12) + object Level0 : FeedsFilterBarTonalElevationPreference(ElevationTokens.Level0) + object Level1 : FeedsFilterBarTonalElevationPreference(ElevationTokens.Level1) + object Level2 : FeedsFilterBarTonalElevationPreference(ElevationTokens.Level2) + object Level3 : FeedsFilterBarTonalElevationPreference(ElevationTokens.Level3) + object Level4 : FeedsFilterBarTonalElevationPreference(ElevationTokens.Level4) + object Level5 : FeedsFilterBarTonalElevationPreference(ElevationTokens.Level5) override fun put(context: Context, scope: CoroutineScope) { scope.launch { @@ -27,12 +28,12 @@ sealed class FeedsFilterBarTonalElevationPreference(val value: Int) : Preference fun getDesc(context: Context): String = when (this) { - Level0 -> "Level 0 (0dp)" - Level1 -> "Level 1 (1dp)" - Level2 -> "Level 2 (3dp)" - Level3 -> "Level 3 (6dp)" - Level4 -> "Level 4 (8dp)" - Level5 -> "Level 5 (12dp)" + Level0 -> "Level 0 (${ElevationTokens.Level0}dp)" + Level1 -> "Level 1 (${ElevationTokens.Level1}dp)" + Level2 -> "Level 2 (${ElevationTokens.Level2}dp)" + Level3 -> "Level 3 (${ElevationTokens.Level3}dp)" + Level4 -> "Level 4 (${ElevationTokens.Level4}dp)" + Level5 -> "Level 5 (${ElevationTokens.Level5}dp)" } companion object { @@ -41,13 +42,14 @@ sealed class FeedsFilterBarTonalElevationPreference(val value: Int) : Preference fun fromPreferences(preferences: Preferences) = when (preferences[DataStoreKeys.FeedsFilterBarTonalElevation.key]) { - 0 -> Level0 - 1 -> Level1 - 3 -> Level2 - 6 -> Level3 - 8 -> Level4 - 12 -> Level5 + ElevationTokens.Level0 -> Level0 + ElevationTokens.Level1 -> Level1 + ElevationTokens.Level2 -> Level2 + ElevationTokens.Level3 -> Level3 + ElevationTokens.Level4 -> Level4 + ElevationTokens.Level5 -> Level5 else -> default } } -} \ No newline at end of file +} + diff --git a/app/src/main/java/me/ash/reader/data/preference/FeedsGroupListTonalElevationPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FeedsGroupListTonalElevationPreference.kt index c65afe0..0fbea55 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FeedsGroupListTonalElevationPreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FeedsGroupListTonalElevationPreference.kt @@ -4,17 +4,18 @@ import android.content.Context import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch +import me.ash.reader.data.constant.ElevationTokens import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.put sealed class FeedsGroupListTonalElevationPreference(val value: Int) : Preference() { - object Level0 : FeedsGroupListTonalElevationPreference(0) - object Level1 : FeedsGroupListTonalElevationPreference(1) - object Level2 : FeedsGroupListTonalElevationPreference(3) - object Level3 : FeedsGroupListTonalElevationPreference(6) - object Level4 : FeedsGroupListTonalElevationPreference(8) - object Level5 : FeedsGroupListTonalElevationPreference(12) + object Level0 : FeedsGroupListTonalElevationPreference(ElevationTokens.Level0) + object Level1 : FeedsGroupListTonalElevationPreference(ElevationTokens.Level1) + object Level2 : FeedsGroupListTonalElevationPreference(ElevationTokens.Level2) + object Level3 : FeedsGroupListTonalElevationPreference(ElevationTokens.Level3) + object Level4 : FeedsGroupListTonalElevationPreference(ElevationTokens.Level4) + object Level5 : FeedsGroupListTonalElevationPreference(ElevationTokens.Level5) override fun put(context: Context, scope: CoroutineScope) { scope.launch { @@ -27,12 +28,12 @@ sealed class FeedsGroupListTonalElevationPreference(val value: Int) : Preference fun getDesc(context: Context): String = when (this) { - Level0 -> "Level 0 (0dp)" - Level1 -> "Level 1 (1dp)" - Level2 -> "Level 2 (3dp)" - Level3 -> "Level 3 (6dp)" - Level4 -> "Level 4 (8dp)" - Level5 -> "Level 5 (12dp)" + Level0 -> "Level 0 (${ElevationTokens.Level0}dp)" + Level1 -> "Level 1 (${ElevationTokens.Level1}dp)" + Level2 -> "Level 2 (${ElevationTokens.Level2}dp)" + Level3 -> "Level 3 (${ElevationTokens.Level3}dp)" + Level4 -> "Level 4 (${ElevationTokens.Level4}dp)" + Level5 -> "Level 5 (${ElevationTokens.Level5}dp)" } companion object { @@ -41,12 +42,12 @@ sealed class FeedsGroupListTonalElevationPreference(val value: Int) : Preference fun fromPreferences(preferences: Preferences) = when (preferences[DataStoreKeys.FeedsGroupListTonalElevation.key]) { - 0 -> Level0 - 1 -> Level1 - 3 -> Level2 - 6 -> Level3 - 8 -> Level4 - 12 -> Level5 + ElevationTokens.Level0 -> Level0 + ElevationTokens.Level1 -> Level1 + ElevationTokens.Level2 -> Level2 + ElevationTokens.Level3 -> Level3 + ElevationTokens.Level4 -> Level4 + ElevationTokens.Level5 -> Level5 else -> default } } diff --git a/app/src/main/java/me/ash/reader/data/preference/FeedsTopBarTonalElevationPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FeedsTopBarTonalElevationPreference.kt index b541b4c..9769340 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FeedsTopBarTonalElevationPreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FeedsTopBarTonalElevationPreference.kt @@ -4,17 +4,18 @@ import android.content.Context import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch +import me.ash.reader.data.constant.ElevationTokens import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.put sealed class FeedsTopBarTonalElevationPreference(val value: Int) : Preference() { - object Level0 : FeedsTopBarTonalElevationPreference(0) - object Level1 : FeedsTopBarTonalElevationPreference(1) - object Level2 : FeedsTopBarTonalElevationPreference(3) - object Level3 : FeedsTopBarTonalElevationPreference(6) - object Level4 : FeedsTopBarTonalElevationPreference(8) - object Level5 : FeedsTopBarTonalElevationPreference(12) + object Level0 : FeedsTopBarTonalElevationPreference(ElevationTokens.Level0) + object Level1 : FeedsTopBarTonalElevationPreference(ElevationTokens.Level1) + object Level2 : FeedsTopBarTonalElevationPreference(ElevationTokens.Level2) + object Level3 : FeedsTopBarTonalElevationPreference(ElevationTokens.Level3) + object Level4 : FeedsTopBarTonalElevationPreference(ElevationTokens.Level4) + object Level5 : FeedsTopBarTonalElevationPreference(ElevationTokens.Level5) override fun put(context: Context, scope: CoroutineScope) { scope.launch { @@ -27,12 +28,12 @@ sealed class FeedsTopBarTonalElevationPreference(val value: Int) : Preference() fun getDesc(context: Context): String = when (this) { - Level0 -> "Level 0 (0dp)" - Level1 -> "Level 1 (1dp)" - Level2 -> "Level 2 (3dp)" - Level3 -> "Level 3 (6dp)" - Level4 -> "Level 4 (8dp)" - Level5 -> "Level 5 (12dp)" + Level0 -> "Level 0 (${ElevationTokens.Level0}dp)" + Level1 -> "Level 1 (${ElevationTokens.Level1}dp)" + Level2 -> "Level 2 (${ElevationTokens.Level2}dp)" + Level3 -> "Level 3 (${ElevationTokens.Level3}dp)" + Level4 -> "Level 4 (${ElevationTokens.Level4}dp)" + Level5 -> "Level 5 (${ElevationTokens.Level5}dp)" } companion object { @@ -41,12 +42,12 @@ sealed class FeedsTopBarTonalElevationPreference(val value: Int) : Preference() fun fromPreferences(preferences: Preferences) = when (preferences[DataStoreKeys.FeedsTopBarTonalElevation.key]) { - 0 -> Level0 - 1 -> Level1 - 3 -> Level2 - 6 -> Level3 - 8 -> Level4 - 12 -> Level5 + ElevationTokens.Level0 -> Level0 + ElevationTokens.Level1 -> Level1 + ElevationTokens.Level2 -> Level2 + ElevationTokens.Level3 -> Level3 + ElevationTokens.Level4 -> Level4 + ElevationTokens.Level5 -> Level5 else -> default } } diff --git a/app/src/main/java/me/ash/reader/data/preference/FlowArticleListTonalElevationPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListTonalElevationPreference.kt index 2d3dd1b..3ff0592 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FlowArticleListTonalElevationPreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListTonalElevationPreference.kt @@ -4,17 +4,18 @@ import android.content.Context import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch +import me.ash.reader.data.constant.ElevationTokens import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.put sealed class FlowArticleListTonalElevationPreference(val value: Int) : Preference() { - object Level0 : FlowArticleListTonalElevationPreference(0) - object Level1 : FlowArticleListTonalElevationPreference(1) - object Level2 : FlowArticleListTonalElevationPreference(3) - object Level3 : FlowArticleListTonalElevationPreference(6) - object Level4 : FlowArticleListTonalElevationPreference(8) - object Level5 : FlowArticleListTonalElevationPreference(12) + object Level0 : FlowArticleListTonalElevationPreference(ElevationTokens.Level0) + object Level1 : FlowArticleListTonalElevationPreference(ElevationTokens.Level1) + object Level2 : FlowArticleListTonalElevationPreference(ElevationTokens.Level2) + object Level3 : FlowArticleListTonalElevationPreference(ElevationTokens.Level3) + object Level4 : FlowArticleListTonalElevationPreference(ElevationTokens.Level4) + object Level5 : FlowArticleListTonalElevationPreference(ElevationTokens.Level5) override fun put(context: Context, scope: CoroutineScope) { scope.launch { @@ -27,12 +28,12 @@ sealed class FlowArticleListTonalElevationPreference(val value: Int) : Preferenc fun getDesc(context: Context): String = when (this) { - Level0 -> "Level 0 (0dp)" - Level1 -> "Level 1 (1dp)" - Level2 -> "Level 2 (3dp)" - Level3 -> "Level 3 (6dp)" - Level4 -> "Level 4 (8dp)" - Level5 -> "Level 5 (12dp)" + Level0 -> "Level 0 (${ElevationTokens.Level0}dp)" + Level1 -> "Level 1 (${ElevationTokens.Level1}dp)" + Level2 -> "Level 2 (${ElevationTokens.Level2}dp)" + Level3 -> "Level 3 (${ElevationTokens.Level3}dp)" + Level4 -> "Level 4 (${ElevationTokens.Level4}dp)" + Level5 -> "Level 5 (${ElevationTokens.Level5}dp)" } companion object { @@ -41,12 +42,12 @@ sealed class FlowArticleListTonalElevationPreference(val value: Int) : Preferenc fun fromPreferences(preferences: Preferences) = when (preferences[DataStoreKeys.FlowArticleListTonalElevation.key]) { - 0 -> Level0 - 1 -> Level1 - 3 -> Level2 - 6 -> Level3 - 8 -> Level4 - 12 -> Level5 + ElevationTokens.Level0 -> Level0 + ElevationTokens.Level1 -> Level1 + ElevationTokens.Level2 -> Level2 + ElevationTokens.Level3 -> Level3 + ElevationTokens.Level4 -> Level4 + ElevationTokens.Level5 -> Level5 else -> default } } diff --git a/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarTonalElevationPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarTonalElevationPreference.kt index 067d58c..45fcc5c 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarTonalElevationPreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarTonalElevationPreference.kt @@ -4,17 +4,18 @@ import android.content.Context import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch +import me.ash.reader.data.constant.ElevationTokens import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.put sealed class FlowFilterBarTonalElevationPreference(val value: Int) : Preference() { - object Level0 : FlowFilterBarTonalElevationPreference(0) - object Level1 : FlowFilterBarTonalElevationPreference(1) - object Level2 : FlowFilterBarTonalElevationPreference(3) - object Level3 : FlowFilterBarTonalElevationPreference(6) - object Level4 : FlowFilterBarTonalElevationPreference(8) - object Level5 : FlowFilterBarTonalElevationPreference(12) + object Level0 : FlowFilterBarTonalElevationPreference(ElevationTokens.Level0) + object Level1 : FlowFilterBarTonalElevationPreference(ElevationTokens.Level1) + object Level2 : FlowFilterBarTonalElevationPreference(ElevationTokens.Level2) + object Level3 : FlowFilterBarTonalElevationPreference(ElevationTokens.Level3) + object Level4 : FlowFilterBarTonalElevationPreference(ElevationTokens.Level4) + object Level5 : FlowFilterBarTonalElevationPreference(ElevationTokens.Level5) override fun put(context: Context, scope: CoroutineScope) { scope.launch { @@ -27,12 +28,12 @@ sealed class FlowFilterBarTonalElevationPreference(val value: Int) : Preference( fun getDesc(context: Context): String = when (this) { - Level0 -> "Level 0 (0dp)" - Level1 -> "Level 1 (1dp)" - Level2 -> "Level 2 (3dp)" - Level3 -> "Level 3 (6dp)" - Level4 -> "Level 4 (8dp)" - Level5 -> "Level 5 (12dp)" + Level0 -> "Level 0 (${ElevationTokens.Level0}dp)" + Level1 -> "Level 1 (${ElevationTokens.Level1}dp)" + Level2 -> "Level 2 (${ElevationTokens.Level2}dp)" + Level3 -> "Level 3 (${ElevationTokens.Level3}dp)" + Level4 -> "Level 4 (${ElevationTokens.Level4}dp)" + Level5 -> "Level 5 (${ElevationTokens.Level5}dp)" } companion object { @@ -41,12 +42,12 @@ sealed class FlowFilterBarTonalElevationPreference(val value: Int) : Preference( fun fromPreferences(preferences: Preferences) = when (preferences[DataStoreKeys.FlowFilterBarTonalElevation.key]) { - 0 -> Level0 - 1 -> Level1 - 3 -> Level2 - 6 -> Level3 - 8 -> Level4 - 12 -> Level5 + ElevationTokens.Level0 -> Level0 + ElevationTokens.Level1 -> Level1 + ElevationTokens.Level2 -> Level2 + ElevationTokens.Level3 -> Level3 + ElevationTokens.Level4 -> Level4 + ElevationTokens.Level5 -> Level5 else -> default } } diff --git a/app/src/main/java/me/ash/reader/data/preference/FlowTopBarTonalElevationPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowTopBarTonalElevationPreference.kt index 90938dc..20ad859 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FlowTopBarTonalElevationPreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FlowTopBarTonalElevationPreference.kt @@ -4,17 +4,18 @@ import android.content.Context import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch +import me.ash.reader.data.constant.ElevationTokens import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.put sealed class FlowTopBarTonalElevationPreference(val value: Int) : Preference() { - object Level0 : FlowTopBarTonalElevationPreference(0) - object Level1 : FlowTopBarTonalElevationPreference(1) - object Level2 : FlowTopBarTonalElevationPreference(3) - object Level3 : FlowTopBarTonalElevationPreference(6) - object Level4 : FlowTopBarTonalElevationPreference(8) - object Level5 : FlowTopBarTonalElevationPreference(12) + object Level0 : FlowTopBarTonalElevationPreference(ElevationTokens.Level0) + object Level1 : FlowTopBarTonalElevationPreference(ElevationTokens.Level1) + object Level2 : FlowTopBarTonalElevationPreference(ElevationTokens.Level2) + object Level3 : FlowTopBarTonalElevationPreference(ElevationTokens.Level3) + object Level4 : FlowTopBarTonalElevationPreference(ElevationTokens.Level4) + object Level5 : FlowTopBarTonalElevationPreference(ElevationTokens.Level5) override fun put(context: Context, scope: CoroutineScope) { scope.launch { @@ -27,12 +28,12 @@ sealed class FlowTopBarTonalElevationPreference(val value: Int) : Preference() { fun getDesc(context: Context): String = when (this) { - Level0 -> "Level 0 (0dp)" - Level1 -> "Level 1 (1dp)" - Level2 -> "Level 2 (3dp)" - Level3 -> "Level 3 (6dp)" - Level4 -> "Level 4 (8dp)" - Level5 -> "Level 5 (12dp)" + Level0 -> "Level 0 (${ElevationTokens.Level0}dp)" + Level1 -> "Level 1 (${ElevationTokens.Level1}dp)" + Level2 -> "Level 2 (${ElevationTokens.Level2}dp)" + Level3 -> "Level 3 (${ElevationTokens.Level3}dp)" + Level4 -> "Level 4 (${ElevationTokens.Level4}dp)" + Level5 -> "Level 5 (${ElevationTokens.Level5}dp)" } companion object { @@ -41,12 +42,12 @@ sealed class FlowTopBarTonalElevationPreference(val value: Int) : Preference() { fun fromPreferences(preferences: Preferences) = when (preferences[DataStoreKeys.FlowTopBarTonalElevation.key]) { - 0 -> Level0 - 1 -> Level1 - 3 -> Level2 - 6 -> Level3 - 8 -> Level4 - 12 -> Level5 + ElevationTokens.Level0 -> Level0 + ElevationTokens.Level1 -> Level1 + ElevationTokens.Level2 -> Level2 + ElevationTokens.Level3 -> Level3 + ElevationTokens.Level4 -> Level4 + ElevationTokens.Level5 -> Level5 else -> default } } diff --git a/app/src/main/java/me/ash/reader/data/repository/OpmlRepository.kt b/app/src/main/java/me/ash/reader/data/repository/OpmlRepository.kt index 7af9c0e..774be76 100644 --- a/app/src/main/java/me/ash/reader/data/repository/OpmlRepository.kt +++ b/app/src/main/java/me/ash/reader/data/repository/OpmlRepository.kt @@ -54,7 +54,7 @@ class OpmlRepository @Inject constructor( Opml( "2.0", Head( - accountDao.queryById(context.currentAccountId).name, + accountDao.queryById(context.currentAccountId)?.name, Date().toString(), null, null, null, null, null, null, null, null, null, null, null, diff --git a/app/src/main/java/me/ash/reader/data/repository/RssHelper.kt b/app/src/main/java/me/ash/reader/data/repository/RssHelper.kt index 584fa48..25528d0 100644 --- a/app/src/main/java/me/ash/reader/data/repository/RssHelper.kt +++ b/app/src/main/java/me/ash/reader/data/repository/RssHelper.kt @@ -21,8 +21,6 @@ import net.dankito.readability4j.extended.Readability4JExtended import okhttp3.OkHttpClient import okhttp3.Request import java.net.URL -import java.text.ParsePosition -import java.text.SimpleDateFormat import java.util.* import javax.inject.Inject @@ -86,7 +84,12 @@ class RssHelper @Inject constructor( return withContext(dispatcherIO) { val a = mutableListOf
() val accountId = context.currentAccountId - val parseRss: SyndFeed = SyndFeedInput().build(XmlReader(URL(feed.url))) + val parseRss: SyndFeed = SyndFeedInput().build( + XmlReader(URL(feed.url).openConnection().apply { + connectTimeout = 5000 + readTimeout = 5000 + }) + ) parseRss.entries.forEach { if (latestLink != null && latestLink == it.link) return@withContext a val desc = it.description?.value @@ -111,13 +114,13 @@ class RssHelper @Inject constructor( date = it.publishedDate ?: it.updatedDate ?: Date(), title = Html.fromHtml(it.title.toString()).toString(), author = it.author, - rawDescription = (desc ?: content) ?: "", + rawDescription = (content ?: desc) ?: "", shortDescription = (Readability4JExtended("", desc ?: content ?: "") .parse().textContent ?: "") .take(100) .trim(), fullContent = content, - img = findImg((desc ?: content) ?: ""), + img = findImg((content ?: desc) ?: ""), link = it.link ?: "", ) ) diff --git a/app/src/main/java/me/ash/reader/data/repository/StringsRepository.kt b/app/src/main/java/me/ash/reader/data/repository/StringsRepository.kt index fa8d76b..5497c77 100644 --- a/app/src/main/java/me/ash/reader/data/repository/StringsRepository.kt +++ b/app/src/main/java/me/ash/reader/data/repository/StringsRepository.kt @@ -11,6 +11,13 @@ class StringsRepository @Inject constructor( private val context: Context, ) { fun getString(resId: Int, vararg formatArgs: Any) = context.getString(resId, *formatArgs) - fun getQuantityString(resId: Int, quantity: Int, vararg formatArgs: Any) = context.resources.getQuantityString(resId, quantity, *formatArgs) - fun formatAsString(date: Date?) = date?.formatAsString(context) + + fun getQuantityString(resId: Int, quantity: Int, vararg formatArgs: Any) = + context.resources.getQuantityString(resId, quantity, *formatArgs) + + fun formatAsString( + date: Date?, + onlyHourMinute: Boolean? = false, + atHourMinute: Boolean? = false + ) = date?.formatAsString(context, onlyHourMinute, atHourMinute) } diff --git a/app/src/main/java/me/ash/reader/ui/component/base/RYAsyncImage.kt b/app/src/main/java/me/ash/reader/ui/component/base/RYAsyncImage.kt index bd86c62..cfd4959 100644 --- a/app/src/main/java/me/ash/reader/ui/component/base/RYAsyncImage.kt +++ b/app/src/main/java/me/ash/reader/ui/component/base/RYAsyncImage.kt @@ -16,7 +16,7 @@ import coil.size.Scale import coil.size.Size import me.ash.reader.R -val Size_1000 = Size(1000, 1000) +val SIZE_1000 = Size(1000, 1000) @Composable fun RYAsyncImage( diff --git a/app/src/main/java/me/ash/reader/ui/page/home/HomeViewModel.kt b/app/src/main/java/me/ash/reader/ui/page/home/HomeViewModel.kt index a250c56..56bebff 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/HomeViewModel.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/HomeViewModel.kt @@ -50,7 +50,12 @@ class HomeViewModel @Inject constructor( fun fetchArticles() { _homeUiState.update { it.copy( - pagingData = Pager(PagingConfig(pageSize = 50)) { + pagingData = Pager( + config = PagingConfig( + pageSize = 100, + enablePlaceholders = false, + ) + ) { if (_homeUiState.value.searchContent.isNotBlank()) { rssRepository.get().searchArticles( content = _homeUiState.value.searchContent.trim(), @@ -68,7 +73,14 @@ class HomeViewModel @Inject constructor( ) } }.flow.map { - it.map { FlowItemView.Article(it) }.insertSeparators { before, after -> + it.map { + FlowItemView.Article(it.apply { + article.dateString = stringsRepository.formatAsString( + date = article.date, + onlyHourMinute = true + ) + }) + }.insertSeparators { before, after -> val beforeDate = stringsRepository.formatAsString(before?.articleWithFeed?.article?.date) val afterDate = diff --git a/app/src/main/java/me/ash/reader/ui/page/home/feeds/subscribe/SubscribeViewModel.kt b/app/src/main/java/me/ash/reader/ui/page/home/feeds/subscribe/SubscribeViewModel.kt index df4e143..a891ff4 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/feeds/subscribe/SubscribeViewModel.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/feeds/subscribe/SubscribeViewModel.kt @@ -4,16 +4,13 @@ import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Job -import kotlinx.coroutines.async import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import me.ash.reader.R import me.ash.reader.data.entity.Article import me.ash.reader.data.entity.Feed import me.ash.reader.data.entity.Group -import me.ash.reader.data.module.DispatcherIO import me.ash.reader.data.repository.OpmlRepository import me.ash.reader.data.repository.RssHelper import me.ash.reader.data.repository.RssRepository @@ -28,8 +25,6 @@ class SubscribeViewModel @Inject constructor( private val rssRepository: RssRepository, private val rssHelper: RssHelper, private val stringsRepository: StringsRepository, - @DispatcherIO - private val dispatcherIO: CoroutineDispatcher, ) : ViewModel() { private val _subscribeUiState = MutableStateFlow(SubscribeUiState()) val subscribeUiState: StateFlow = _subscribeUiState.asStateFlow() @@ -55,7 +50,7 @@ class SubscribeViewModel @Inject constructor( } fun importFromInputStream(inputStream: InputStream) { - viewModelScope.launch(dispatcherIO) { + viewModelScope.launch { try { opmlRepository.saveToDatabase(inputStream) rssRepository.get().doSync() @@ -68,13 +63,10 @@ class SubscribeViewModel @Inject constructor( fun subscribe() { val feed = _subscribeUiState.value.feed ?: return val articles = _subscribeUiState.value.articles - viewModelScope.launch(dispatcherIO) { - val groupId = async { - _subscribeUiState.value.selectedGroupId - } + viewModelScope.launch { rssRepository.get().subscribe( feed.copy( - groupId = groupId.await(), + groupId = _subscribeUiState.value.selectedGroupId, isNotification = _subscribeUiState.value.allowNotificationPreset, isFullContent = _subscribeUiState.value.parseFullContentPreset, ), articles @@ -123,7 +115,7 @@ class SubscribeViewModel @Inject constructor( fun search() { searchJob?.cancel() - viewModelScope.launch(dispatcherIO) { + viewModelScope.launch { try { _subscribeUiState.update { it.copy( diff --git a/app/src/main/java/me/ash/reader/ui/page/home/flow/ArticleItem.kt b/app/src/main/java/me/ash/reader/ui/page/home/flow/ArticleItem.kt index 819b0ca..d741d1c 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/flow/ArticleItem.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/flow/ArticleItem.kt @@ -2,7 +2,6 @@ package me.ash.reader.ui.page.home.flow import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.Star import androidx.compose.material3.Icon @@ -23,10 +22,10 @@ import coil.size.Scale import me.ash.reader.R import me.ash.reader.data.entity.ArticleWithFeed import me.ash.reader.data.preference.* -import me.ash.reader.ui.component.base.RYAsyncImage -import me.ash.reader.ui.ext.formatAsString import me.ash.reader.ui.component.FeedIcon -import me.ash.reader.ui.component.base.Size_1000 +import me.ash.reader.ui.component.base.RYAsyncImage +import me.ash.reader.ui.component.base.SIZE_1000 +import me.ash.reader.ui.theme.SHAPE_20 @Composable fun ArticleItem( @@ -43,7 +42,7 @@ fun ArticleItem( Column( modifier = Modifier .padding(horizontal = 12.dp) - .clip(RoundedCornerShape(20.dp)) + .clip(SHAPE_20) .clickable { onClick(articleWithFeed) } .padding(horizontal = 12.dp, vertical = 12.dp) .alpha(if (articleWithFeed.article.isStarred || articleWithFeed.article.isUnread) 1f else 0.5f), @@ -80,21 +79,20 @@ fun ArticleItem( if (articleWithFeed.article.isStarred) { Icon( modifier = Modifier + .alpha(0.7f) .size(14.dp) .padding(end = 2.dp), imageVector = Icons.Rounded.Star, contentDescription = stringResource(R.string.starred), - tint = MaterialTheme.colorScheme.outline.copy(alpha = 0.7f), + tint = MaterialTheme.colorScheme.outline, ) } // Date Text( - text = articleWithFeed.article.date.formatAsString( - context, - onlyHourMinute = true - ), - color = MaterialTheme.colorScheme.outline.copy(alpha = 0.7f), + modifier = Modifier.alpha(0.7f), + text = articleWithFeed.article.dateString ?: "", + color = MaterialTheme.colorScheme.outline, style = MaterialTheme.typography.labelMedium, ) } @@ -128,8 +126,9 @@ fun ArticleItem( // Description if (articleListDesc.value && articleWithFeed.article.shortDescription.isNotBlank()) { Text( + modifier = Modifier.alpha(0.7f), text = articleWithFeed.article.shortDescription, - color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f), + color = MaterialTheme.colorScheme.onSurfaceVariant, style = MaterialTheme.typography.bodySmall, maxLines = 2, overflow = TextOverflow.Ellipsis, @@ -143,11 +142,11 @@ fun ArticleItem( modifier = Modifier .padding(start = 10.dp) .size(80.dp) - .clip(RoundedCornerShape(20.dp)), + .clip(SHAPE_20), data = articleWithFeed.article.img, scale = Scale.FILL, precision = Precision.INEXACT, - size = Size_1000, + size = SIZE_1000, contentScale = ContentScale.Crop, ) } diff --git a/app/src/main/java/me/ash/reader/ui/page/home/flow/ArticleList.kt b/app/src/main/java/me/ash/reader/ui/page/home/flow/ArticleList.kt index c0aaf27..6483ede 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/flow/ArticleList.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/flow/ArticleList.kt @@ -13,8 +13,8 @@ import me.ash.reader.data.entity.ArticleWithFeed @OptIn(ExperimentalFoundationApi::class) fun LazyListScope.ArticleList( pagingItems: LazyPagingItems, - articleListFeedIcon: Boolean, - articleListDateStickyHeader: Boolean, + isShowFeedIcon: Boolean, + isShowStickyHeader: Boolean, articleListTonalElevation: Int, onClick: (ArticleWithFeed) -> Unit = {}, ) { @@ -31,13 +31,13 @@ fun LazyListScope.ArticleList( } is FlowItemView.Date -> { if (item.showSpacer) item { Spacer(modifier = Modifier.height(40.dp)) } - if (articleListDateStickyHeader) { + if (isShowStickyHeader) { stickyHeader(key = item.date) { - StickyHeader(item.date, articleListFeedIcon, articleListTonalElevation) + StickyHeader(item.date, isShowFeedIcon, articleListTonalElevation) } } else { item(key = item.date) { - StickyHeader(item.date, articleListFeedIcon, articleListTonalElevation) + StickyHeader(item.date, isShowFeedIcon, articleListTonalElevation) } } } diff --git a/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt b/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt index 2b243ea..231dbed 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt @@ -33,7 +33,6 @@ import me.ash.reader.ui.component.base.RYScaffold import me.ash.reader.ui.component.base.SwipeRefresh import me.ash.reader.ui.ext.collectAsStateValue import me.ash.reader.ui.page.common.RouteName -import me.ash.reader.ui.page.home.FilterState import me.ash.reader.ui.page.home.HomeViewModel @OptIn( @@ -165,7 +164,15 @@ fun FlowPage( state = listState, ) { item { - DisplayTextHeader(filterUiState, isSyncing, articleListFeedIcon.value) + DisplayText( + modifier = Modifier.padding(start = if (articleListFeedIcon.value) 30.dp else 0.dp), + text = when { + filterUiState.group != null -> filterUiState.group.name + filterUiState.feed != null -> filterUiState.feed.name + else -> filterUiState.filter.getName() + }, + desc = if (isSyncing) stringResource(R.string.syncing) else "", + ) RYExtensibleVisibility(visible = markAsRead) { Spacer(modifier = Modifier.height((56 + 24 + 10).dp)) } @@ -217,8 +224,8 @@ fun FlowPage( } ArticleList( pagingItems = pagingItems, - articleListFeedIcon = articleListFeedIcon.value, - articleListDateStickyHeader = articleListDateStickyHeader.value, + isShowFeedIcon = articleListFeedIcon.value, + isShowStickyHeader = articleListDateStickyHeader.value, articleListTonalElevation = articleListTonalElevation.value, ) { onSearch = false @@ -248,20 +255,3 @@ fun FlowPage( } ) } - -@Composable -private fun DisplayTextHeader( - filterState: FilterState, - isSyncing: Boolean, - articleListFeedIcon: Boolean, -) { - DisplayText( - modifier = Modifier.padding(start = if (articleListFeedIcon) 30.dp else 0.dp), - text = when { - filterState.group != null -> filterState.group.name - filterState.feed != null -> filterState.feed.name - else -> filterState.filter.getName() - }, - desc = if (isSyncing) stringResource(R.string.syncing) else "", - ) -} diff --git a/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowViewModel.kt b/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowViewModel.kt index 4144f9d..392045f 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowViewModel.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowViewModel.kt @@ -11,7 +11,6 @@ import kotlinx.coroutines.launch import me.ash.reader.data.entity.ArticleWithFeed import me.ash.reader.data.repository.RssRepository import java.util.* -import javax.annotation.concurrent.Immutable import javax.inject.Inject @HiltViewModel @@ -77,10 +76,7 @@ enum class MarkAsReadBefore { All, } -@Immutable sealed class FlowItemView { - @Immutable class Article(val articleWithFeed: ArticleWithFeed) : FlowItemView() - @Immutable class Date(val date: String, val showSpacer: Boolean) : FlowItemView() } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/ui/page/home/flow/SearchBar.kt b/app/src/main/java/me/ash/reader/ui/page/home/flow/SearchBar.kt index 9c6e0b6..9d07147 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/flow/SearchBar.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/flow/SearchBar.kt @@ -12,19 +12,19 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction -import androidx.compose.ui.text.style.BaselineShift import androidx.compose.ui.unit.dp import me.ash.reader.R +import me.ash.reader.data.constant.ElevationTokens @Composable fun SearchBar( - modifier: Modifier = Modifier, value: String, placeholder: String = "", focusRequester: FocusRequester = remember { FocusRequester() }, @@ -39,7 +39,7 @@ fun SearchBar( .padding(horizontal = 24.dp) .fillMaxWidth(), shape = CircleShape, - tonalElevation = 3.dp + tonalElevation = ElevationTokens.Level2.dp ) { Row( modifier = Modifier.fillMaxSize(), @@ -62,6 +62,7 @@ fun SearchBar( .fillMaxWidth() .focusRequester(focusRequester), colors = TextFieldDefaults.textFieldColors( + textColor = MaterialTheme.colorScheme.onSurfaceVariant, containerColor = Color.Transparent, focusedIndicatorColor = Color.Transparent, unfocusedIndicatorColor = Color.Transparent, @@ -70,17 +71,13 @@ fun SearchBar( onValueChange = { onValueChange(it) }, placeholder = { Text( + modifier = Modifier.alpha(0.7f), text = placeholder, style = MaterialTheme.typography.bodyLarge, - color = MaterialTheme.colorScheme.onSurfaceVariant.copy( - alpha = 0.7f - ), + color = MaterialTheme.colorScheme.onSurfaceVariant, ) }, - textStyle = MaterialTheme.typography.bodyLarge.copy( - color = MaterialTheme.colorScheme.onSurfaceVariant, - baselineShift = BaselineShift(0.1f) - ), + textStyle = MaterialTheme.typography.bodyLarge, singleLine = true, keyboardOptions = KeyboardOptions( imeAction = ImeAction.Done diff --git a/app/src/main/java/me/ash/reader/ui/page/home/flow/StickyHeader.kt b/app/src/main/java/me/ash/reader/ui/page/home/flow/StickyHeader.kt index dcda056..3f8518b 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/flow/StickyHeader.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/flow/StickyHeader.kt @@ -15,8 +15,8 @@ import me.ash.reader.ui.theme.palette.onDark @Composable fun StickyHeader( - currentItemDay: String, - articleListFeedIcon: Boolean, + dateString: String, + isShowFeedIcon: Boolean, articleListTonalElevation: Int, ) { Row( @@ -30,10 +30,10 @@ fun StickyHeader( ) { Text( modifier = Modifier.padding( - start = if (articleListFeedIcon) 54.dp else 24.dp, + start = if (isShowFeedIcon) 54.dp else 24.dp, bottom = 4.dp ), - text = currentItemDay, + text = dateString, color = MaterialTheme.colorScheme.primary, style = MaterialTheme.typography.labelLarge, ) diff --git a/app/src/main/java/me/ash/reader/ui/page/home/reading/ReadingViewModel.kt b/app/src/main/java/me/ash/reader/ui/page/home/reading/ReadingViewModel.kt index e2ca168..8095268 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/reading/ReadingViewModel.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/reading/ReadingViewModel.kt @@ -18,7 +18,7 @@ import javax.inject.Inject @HiltViewModel class ReadingViewModel @Inject constructor( - val rssRepository: RssRepository, + private val rssRepository: RssRepository, private val rssHelper: RssHelper, ) : ViewModel() { private val _readingUiState = MutableStateFlow(ReadingUiState()) diff --git a/app/src/main/java/me/ash/reader/ui/theme/Shapes.kt b/app/src/main/java/me/ash/reader/ui/theme/Shapes.kt new file mode 100644 index 0000000..670cab2 --- /dev/null +++ b/app/src/main/java/me/ash/reader/ui/theme/Shapes.kt @@ -0,0 +1,15 @@ +package me.ash.reader.ui.theme + +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Shapes +import androidx.compose.ui.unit.dp + +val Shapes = Shapes( + extraSmall = RoundedCornerShape(4.0.dp), + small = RoundedCornerShape(8.0.dp), + medium = RoundedCornerShape(12.0.dp), + large = RoundedCornerShape(16.0.dp), + extraLarge = RoundedCornerShape(28.0.dp) +) + +val SHAPE_20 = RoundedCornerShape(20.0.dp) \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/ui/theme/Theme.kt b/app/src/main/java/me/ash/reader/ui/theme/Theme.kt index f09a07d..0696c1a 100644 --- a/app/src/main/java/me/ash/reader/ui/theme/Theme.kt +++ b/app/src/main/java/me/ash/reader/ui/theme/Theme.kt @@ -40,7 +40,8 @@ fun AppTheme( if (useDarkTheme) dynamicDarkColorScheme() else dynamicLightColorScheme(), typography = AppTypography, - content = content + shapes = Shapes, + content = content, ) } } diff --git a/app/src/main/res/drawable/ic_broken_image_black_24dp.xml b/app/src/main/res/drawable/ic_broken_image_black_24dp.xml index 6872d2e..aa7e72d 100644 --- a/app/src/main/res/drawable/ic_broken_image_black_24dp.xml +++ b/app/src/main/res/drawable/ic_broken_image_black_24dp.xml @@ -5,5 +5,6 @@ android:viewportHeight="24"> + android:fillColor="#000000" + android:fillAlpha="0.3"/> diff --git a/app/src/main/res/drawable/ic_hourglass_empty_black_24dp.xml b/app/src/main/res/drawable/ic_hourglass_empty_black_24dp.xml index ca58686..5f4bd70 100644 --- a/app/src/main/res/drawable/ic_hourglass_empty_black_24dp.xml +++ b/app/src/main/res/drawable/ic_hourglass_empty_black_24dp.xml @@ -5,5 +5,6 @@ android:viewportHeight="24"> + android:fillColor="#000000" + android:fillAlpha="0.3"/>