Optimize the flow page
This commit is contained in:
parent
ba3620d84f
commit
66094f8075
|
@ -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
|
||||
}
|
|
@ -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,
|
||||
)
|
||||
) {
|
||||
@Ignore
|
||||
var dateString: String? = null
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<Article>()
|
||||
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 ?: "",
|
||||
)
|
||||
)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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> = _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(
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -13,8 +13,8 @@ import me.ash.reader.data.entity.ArticleWithFeed
|
|||
@OptIn(ExperimentalFoundationApi::class)
|
||||
fun LazyListScope.ArticleList(
|
||||
pagingItems: LazyPagingItems<FlowItemView>,
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 "",
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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())
|
||||
|
|
15
app/src/main/java/me/ash/reader/ui/theme/Shapes.kt
Normal file
15
app/src/main/java/me/ash/reader/ui/theme/Shapes.kt
Normal file
|
@ -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)
|
|
@ -40,7 +40,8 @@ fun AppTheme(
|
|||
if (useDarkTheme) dynamicDarkColorScheme()
|
||||
else dynamicLightColorScheme(),
|
||||
typography = AppTypography,
|
||||
content = content
|
||||
shapes = Shapes,
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,5 +5,6 @@
|
|||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM19,19L5,19v-4.58l0.99,0.99 4,-4 4,4 4,-3.99L19,12.43L19,19zM19,9.59l-1.01,-1.01 -4,4.01 -4,-4 -4,4 -0.99,-1L5,5h14v4.59z"
|
||||
android:fillColor="#000000"/>
|
||||
android:fillColor="#000000"
|
||||
android:fillAlpha="0.3"/>
|
||||
</vector>
|
||||
|
|
|
@ -5,5 +5,6 @@
|
|||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M8,2c-1.1,0 -2,0.9 -2,2v3.17c0,0.53 0.21,1.04 0.59,1.42L10,12l-3.42,3.42c-0.37,0.38 -0.58,0.89 -0.58,1.42L6,20c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2v-3.16c0,-0.53 -0.21,-1.04 -0.58,-1.41L14,12l3.41,-3.4c0.38,-0.38 0.59,-0.89 0.59,-1.42L18,4c0,-1.1 -0.9,-2 -2,-2L8,2zM16,16.5L16,19c0,0.55 -0.45,1 -1,1L9,20c-0.55,0 -1,-0.45 -1,-1v-2.5l4,-4 4,4zM12,11.5l-4,-4L8,5c0,-0.55 0.45,-1 1,-1h6c0.55,0 1,0.45 1,1v2.5l-4,4z"
|
||||
android:fillColor="#000000"/>
|
||||
android:fillColor="#000000"
|
||||
android:fillAlpha="0.3"/>
|
||||
</vector>
|
||||
|
|
Loading…
Reference in New Issue
Block a user