diff --git a/app/build.gradle b/app/build.gradle
index 16cbc01..fbd5484 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -116,7 +116,7 @@ dependencies {
implementation "org.conscrypt:conscrypt-android:2.5.2"
// https://square.github.io/okhttp/changelogs/changelog/
- implementation "com.squareup.okhttp3:okhttp:5.0.0-alpha.6"
+ implementation "com.squareup.okhttp3:okhttp:$okhttp"
implementation "com.squareup.retrofit2:retrofit:$retrofit2"
implementation "com.squareup.retrofit2:converter-gson:$retrofit2"
@@ -166,9 +166,9 @@ dependencies {
// https://developer.android.com/jetpack/androidx/releases/compose-material
implementation "androidx.compose.material:material:$compose"
implementation "androidx.compose.material:material-icons-extended:$compose"
+ debugImplementation "androidx.compose.ui:ui-tooling:$compose"
implementation "androidx.compose.ui:ui-tooling-preview:$compose"
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose"
- debugImplementation "androidx.compose.ui:ui-tooling:$compose"
// hilt
implementation "androidx.hilt:hilt-work:1.0.0"
diff --git a/app/schemas/me.ash.reader.data.source.RYDatabase/2.json b/app/schemas/me.ash.reader.data.source.RYDatabase/2.json
new file mode 100644
index 0000000..5690ca5
--- /dev/null
+++ b/app/schemas/me.ash.reader.data.source.RYDatabase/2.json
@@ -0,0 +1,321 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 2,
+ "identityHash": "98462c2e9c32394054102313366e7262",
+ "entities": [
+ {
+ "tableName": "account",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT NOT NULL, `type` INTEGER NOT NULL, `updateAt` INTEGER)",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "INTEGER",
+ "notNull": false
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "type",
+ "columnName": "type",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "updateAt",
+ "columnName": "updateAt",
+ "affinity": "INTEGER",
+ "notNull": false
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": true,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [],
+ "foreignKeys": []
+ },
+ {
+ "tableName": "feed",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `icon` TEXT, `url` TEXT NOT NULL, `groupId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `isNotification` INTEGER NOT NULL DEFAULT false, `isFullContent` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`), FOREIGN KEY(`groupId`) REFERENCES `group`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "icon",
+ "columnName": "icon",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "url",
+ "columnName": "url",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "groupId",
+ "columnName": "groupId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isNotification",
+ "columnName": "isNotification",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "false"
+ },
+ {
+ "fieldPath": "isFullContent",
+ "columnName": "isFullContent",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "false"
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_feed_groupId",
+ "unique": false,
+ "columnNames": [
+ "groupId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_feed_groupId` ON `${TABLE_NAME}` (`groupId`)"
+ },
+ {
+ "name": "index_feed_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_feed_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "group",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "groupId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "article",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `date` INTEGER NOT NULL, `title` TEXT NOT NULL, `author` TEXT, `rawDescription` TEXT NOT NULL, `shortDescription` TEXT NOT NULL, `fullContent` TEXT, `img` TEXT, `link` TEXT NOT NULL, `feedId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `isUnread` INTEGER NOT NULL DEFAULT true, `isStarred` INTEGER NOT NULL DEFAULT false, `isReadLater` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`), FOREIGN KEY(`feedId`) REFERENCES `feed`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "title",
+ "columnName": "title",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "author",
+ "columnName": "author",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "rawDescription",
+ "columnName": "rawDescription",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "shortDescription",
+ "columnName": "shortDescription",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "fullContent",
+ "columnName": "fullContent",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "img",
+ "columnName": "img",
+ "affinity": "TEXT",
+ "notNull": false
+ },
+ {
+ "fieldPath": "link",
+ "columnName": "link",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "feedId",
+ "columnName": "feedId",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "isUnread",
+ "columnName": "isUnread",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "true"
+ },
+ {
+ "fieldPath": "isStarred",
+ "columnName": "isStarred",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "false"
+ },
+ {
+ "fieldPath": "isReadLater",
+ "columnName": "isReadLater",
+ "affinity": "INTEGER",
+ "notNull": true,
+ "defaultValue": "false"
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_article_feedId",
+ "unique": false,
+ "columnNames": [
+ "feedId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_article_feedId` ON `${TABLE_NAME}` (`feedId`)"
+ },
+ {
+ "name": "index_article_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_article_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": [
+ {
+ "table": "feed",
+ "onDelete": "CASCADE",
+ "onUpdate": "CASCADE",
+ "columns": [
+ "feedId"
+ ],
+ "referencedColumns": [
+ "id"
+ ]
+ }
+ ]
+ },
+ {
+ "tableName": "group",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT NOT NULL, `accountId` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "name",
+ "columnName": "name",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "accountId",
+ "columnName": "accountId",
+ "affinity": "INTEGER",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_group_accountId",
+ "unique": false,
+ "columnNames": [
+ "accountId"
+ ],
+ "orders": [],
+ "createSql": "CREATE INDEX IF NOT EXISTS `index_group_accountId` ON `${TABLE_NAME}` (`accountId`)"
+ }
+ ],
+ "foreignKeys": []
+ }
+ ],
+ "views": [],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '98462c2e9c32394054102313366e7262')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d275ec0..9976f51 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -5,11 +5,8 @@
-
-
-
+ var articles: List
)
diff --git a/app/src/main/java/me/ash/reader/data/entity/FeedWithGroup.kt b/app/src/main/java/me/ash/reader/data/entity/FeedWithGroup.kt
index 01d4087..bf254b7 100644
--- a/app/src/main/java/me/ash/reader/data/entity/FeedWithGroup.kt
+++ b/app/src/main/java/me/ash/reader/data/entity/FeedWithGroup.kt
@@ -5,7 +5,7 @@ import androidx.room.Relation
data class FeedWithGroup(
@Embedded
- val feed: Feed,
+ var feed: Feed,
@Relation(parentColumn = "groupId", entityColumn = "id")
- val group: Group
+ var group: Group
)
diff --git a/app/src/main/java/me/ash/reader/data/entity/Group.kt b/app/src/main/java/me/ash/reader/data/entity/Group.kt
index 5aa7962..4929d4b 100644
--- a/app/src/main/java/me/ash/reader/data/entity/Group.kt
+++ b/app/src/main/java/me/ash/reader/data/entity/Group.kt
@@ -8,11 +8,11 @@ import androidx.room.PrimaryKey
@Entity(tableName = "group")
data class Group(
@PrimaryKey
- val id: String,
+ var id: String,
@ColumnInfo
- val name: String,
+ var name: String,
@ColumnInfo(index = true)
- val accountId: Int,
+ var accountId: Int,
) {
@Ignore
var important: Int? = 0
diff --git a/app/src/main/java/me/ash/reader/data/entity/GroupWithFeed.kt b/app/src/main/java/me/ash/reader/data/entity/GroupWithFeed.kt
index 28f2c47..f15efdb 100644
--- a/app/src/main/java/me/ash/reader/data/entity/GroupWithFeed.kt
+++ b/app/src/main/java/me/ash/reader/data/entity/GroupWithFeed.kt
@@ -5,7 +5,7 @@ import androidx.room.Relation
data class GroupWithFeed(
@Embedded
- val group: Group,
+ var group: Group,
@Relation(parentColumn = "id", entityColumn = "groupId")
- val feeds: MutableList
+ var feeds: MutableList
)
diff --git a/app/src/main/java/me/ash/reader/data/entity/LatestRelease.kt b/app/src/main/java/me/ash/reader/data/entity/LatestRelease.kt
deleted file mode 100644
index 000e7c9..0000000
--- a/app/src/main/java/me/ash/reader/data/entity/LatestRelease.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-package me.ash.reader.data.entity
-
-data class LatestRelease(
- val html_url: String? = null,
- val tag_name: String? = null,
- val name: String? = null,
- val draft: Boolean? = null,
- val prerelease: Boolean? = null,
- val created_at: String? = null,
- val published_at: String? = null,
- val assets: List? = null,
- val body: String? = null,
-)
-
-data class AssetsItem(
- val name: String? = null,
- val content_type: String? = null,
- val size: Int? = null,
- val download_count: Int? = null,
- val created_at: String? = null,
- val updated_at: String? = null,
- val browser_download_url: String? = null,
-)
\ No newline at end of file
diff --git a/app/src/main/java/me/ash/reader/data/entity/Filter.kt b/app/src/main/java/me/ash/reader/data/model/Filter.kt
similarity index 74%
rename from app/src/main/java/me/ash/reader/data/entity/Filter.kt
rename to app/src/main/java/me/ash/reader/data/model/Filter.kt
index 738ebca..4d1ada5 100644
--- a/app/src/main/java/me/ash/reader/data/entity/Filter.kt
+++ b/app/src/main/java/me/ash/reader/data/model/Filter.kt
@@ -1,4 +1,4 @@
-package me.ash.reader.data.entity
+package me.ash.reader.data.model
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.FiberManualRecord
@@ -6,7 +6,10 @@ import androidx.compose.material.icons.rounded.FiberManualRecord
import androidx.compose.material.icons.rounded.Star
import androidx.compose.material.icons.rounded.StarOutline
import androidx.compose.material.icons.rounded.Subject
+import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.res.stringResource
+import me.ash.reader.R
class Filter(
val index: Int,
@@ -33,5 +36,13 @@ class Filter(
iconOutline = Icons.Rounded.Subject,
iconFilled = Icons.Rounded.Subject,
)
+ val values = listOf(Starred, Unread, All)
}
+}
+
+@Composable
+fun Filter.getName(): String = when (this) {
+ Filter.Unread -> stringResource(R.string.unread)
+ Filter.Starred -> stringResource(R.string.starred)
+ else -> stringResource(R.string.all)
}
\ No newline at end of file
diff --git a/app/src/main/java/me/ash/reader/data/entity/ImportantCount.kt b/app/src/main/java/me/ash/reader/data/model/ImportantCount.kt
similarity index 75%
rename from app/src/main/java/me/ash/reader/data/entity/ImportantCount.kt
rename to app/src/main/java/me/ash/reader/data/model/ImportantCount.kt
index c876bb6..5e6ffc0 100644
--- a/app/src/main/java/me/ash/reader/data/entity/ImportantCount.kt
+++ b/app/src/main/java/me/ash/reader/data/model/ImportantCount.kt
@@ -1,4 +1,4 @@
-package me.ash.reader.data.entity
+package me.ash.reader.data.model
data class ImportantCount(
val important: Int,
diff --git a/app/src/main/java/me/ash/reader/data/model/LatestRelease.kt b/app/src/main/java/me/ash/reader/data/model/LatestRelease.kt
new file mode 100644
index 0000000..ff18b3c
--- /dev/null
+++ b/app/src/main/java/me/ash/reader/data/model/LatestRelease.kt
@@ -0,0 +1,2 @@
+package me.ash.reader.data.model
+
diff --git a/app/src/main/java/me/ash/reader/data/entity/Version.kt b/app/src/main/java/me/ash/reader/data/model/Version.kt
similarity index 96%
rename from app/src/main/java/me/ash/reader/data/entity/Version.kt
rename to app/src/main/java/me/ash/reader/data/model/Version.kt
index 1d8243f..50ef322 100644
--- a/app/src/main/java/me/ash/reader/data/entity/Version.kt
+++ b/app/src/main/java/me/ash/reader/data/model/Version.kt
@@ -1,4 +1,4 @@
-package me.ash.reader.data.entity
+package me.ash.reader.data.model
class Version(identifiers: List) {
private var major: Int = 0
diff --git a/app/src/main/java/me/ash/reader/data/module/DatabaseModule.kt b/app/src/main/java/me/ash/reader/data/module/DatabaseModule.kt
index 6da4d8b..7f215b9 100644
--- a/app/src/main/java/me/ash/reader/data/module/DatabaseModule.kt
+++ b/app/src/main/java/me/ash/reader/data/module/DatabaseModule.kt
@@ -10,7 +10,7 @@ import me.ash.reader.data.dao.AccountDao
import me.ash.reader.data.dao.ArticleDao
import me.ash.reader.data.dao.FeedDao
import me.ash.reader.data.dao.GroupDao
-import me.ash.reader.data.source.ReaderDatabase
+import me.ash.reader.data.source.RYDatabase
import javax.inject.Singleton
@Module
@@ -19,26 +19,26 @@ object DatabaseModule {
@Provides
@Singleton
- fun provideArticleDao(readerDatabase: ReaderDatabase): ArticleDao =
- readerDatabase.articleDao()
+ fun provideArticleDao(RYDatabase: RYDatabase): ArticleDao =
+ RYDatabase.articleDao()
@Provides
@Singleton
- fun provideFeedDao(readerDatabase: ReaderDatabase): FeedDao =
- readerDatabase.feedDao()
+ fun provideFeedDao(RYDatabase: RYDatabase): FeedDao =
+ RYDatabase.feedDao()
@Provides
@Singleton
- fun provideGroupDao(readerDatabase: ReaderDatabase): GroupDao =
- readerDatabase.groupDao()
+ fun provideGroupDao(RYDatabase: RYDatabase): GroupDao =
+ RYDatabase.groupDao()
@Provides
@Singleton
- fun provideAccountDao(readerDatabase: ReaderDatabase): AccountDao =
- readerDatabase.accountDao()
+ fun provideAccountDao(RYDatabase: RYDatabase): AccountDao =
+ RYDatabase.accountDao()
@Provides
@Singleton
- fun provideReaderDatabase(@ApplicationContext context: Context): ReaderDatabase =
- ReaderDatabase.getInstance(context)
+ fun provideReaderDatabase(@ApplicationContext context: Context): RYDatabase =
+ RYDatabase.getInstance(context)
}
\ No newline at end of file
diff --git a/app/src/main/java/me/ash/reader/data/module/ImageLoaderModule.kt b/app/src/main/java/me/ash/reader/data/module/ImageLoaderModule.kt
index bd79879..795c2f1 100644
--- a/app/src/main/java/me/ash/reader/data/module/ImageLoaderModule.kt
+++ b/app/src/main/java/me/ash/reader/data/module/ImageLoaderModule.kt
@@ -15,7 +15,7 @@ import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.Dispatchers
-import me.ash.reader.cachingHttpClient
+import okhttp3.OkHttpClient
import javax.inject.Singleton
@Module
@@ -25,16 +25,11 @@ object ImageLoaderModule {
@Provides
@Singleton
fun provideImageLoader(
- @ApplicationContext context: Context
+ @ApplicationContext context: Context,
+ okHttpClient: OkHttpClient,
): ImageLoader {
return ImageLoader.Builder(context)
- .okHttpClient(
- okHttpClient = cachingHttpClient(
- cacheDirectory = context.cacheDir.resolve("http")
- ).newBuilder()
- //.addNetworkInterceptor(UserAgentInterceptor)
- .build()
- )
+ .okHttpClient(okHttpClient)
.dispatcher(Dispatchers.Default) // This slightly improves scrolling performance
.components{
add(SvgDecoder.Factory())
@@ -59,4 +54,4 @@ object ImageLoaderModule {
)
.build()
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/me/ash/reader/data/module/OkHttpClientModule.kt b/app/src/main/java/me/ash/reader/data/module/OkHttpClientModule.kt
new file mode 100644
index 0000000..279248b
--- /dev/null
+++ b/app/src/main/java/me/ash/reader/data/module/OkHttpClientModule.kt
@@ -0,0 +1,121 @@
+/*
+ * Feeder: Android RSS reader app
+ * https://gitlab.com/spacecowboy/Feeder
+ *
+ * Copyright (C) 2022 Jonas Kalderstam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package me.ash.reader.data.module
+
+import android.content.Context
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.android.qualifiers.ApplicationContext
+import dagger.hilt.components.SingletonComponent
+import me.ash.reader.BuildConfig
+import okhttp3.Cache
+import okhttp3.Interceptor
+import okhttp3.OkHttpClient
+import okhttp3.Response
+import java.io.File
+import java.security.KeyManagementException
+import java.security.NoSuchAlgorithmException
+import java.security.cert.X509Certificate
+import java.util.concurrent.TimeUnit
+import javax.inject.Singleton
+import javax.net.ssl.HostnameVerifier
+import javax.net.ssl.SSLContext
+import javax.net.ssl.TrustManager
+import javax.net.ssl.X509TrustManager
+
+@Module
+@InstallIn(SingletonComponent::class)
+object OkHttpClientModule {
+
+ @Provides
+ @Singleton
+ fun provideOkHttpClient(
+ @ApplicationContext context: Context
+ ): OkHttpClient = cachingHttpClient(
+ cacheDirectory = context.cacheDir.resolve("http")
+ ).newBuilder()
+ .addNetworkInterceptor(UserAgentInterceptor)
+ .build()
+}
+
+fun cachingHttpClient(
+ cacheDirectory: File? = null,
+ cacheSize: Long = 10L * 1024L * 1024L,
+ trustAllCerts: Boolean = true,
+ connectTimeoutSecs: Long = 30L,
+ readTimeoutSecs: Long = 30L
+): OkHttpClient {
+ val builder: OkHttpClient.Builder = OkHttpClient.Builder()
+
+ if (cacheDirectory != null) {
+ builder.cache(Cache(cacheDirectory, cacheSize))
+ }
+
+ builder
+ .connectTimeout(connectTimeoutSecs, TimeUnit.SECONDS)
+ .readTimeout(readTimeoutSecs, TimeUnit.SECONDS)
+ .followRedirects(true)
+
+ if (trustAllCerts) {
+ builder.trustAllCerts()
+ }
+
+ return builder.build()
+}
+
+fun OkHttpClient.Builder.trustAllCerts() {
+ try {
+ val trustManager = object : X509TrustManager {
+ override fun checkClientTrusted(chain: Array?, authType: String?) {
+ }
+
+ override fun checkServerTrusted(chain: Array?, authType: String?) {
+ }
+
+ override fun getAcceptedIssuers(): Array = emptyArray()
+ }
+
+ val sslContext = SSLContext.getInstance("TLS")
+ sslContext.init(null, arrayOf(trustManager), null)
+ val sslSocketFactory = sslContext.socketFactory
+
+ sslSocketFactory(sslSocketFactory, trustManager)
+ .hostnameVerifier(HostnameVerifier { _, _ -> true })
+ } catch (e: NoSuchAlgorithmException) {
+ // ignore
+ } catch (e: KeyManagementException) {
+ // ignore
+ }
+}
+
+object UserAgentInterceptor : Interceptor {
+ override fun intercept(chain: Interceptor.Chain): Response {
+ return chain.proceed(
+ chain.request()
+ .newBuilder()
+ .header("User-Agent", USER_AGENT_STRING)
+ .build()
+ )
+ }
+}
+
+const val USER_AGENT_STRING = "ReadYou / ${BuildConfig.VERSION_NAME}(${BuildConfig.VERSION_CODE})"
\ No newline at end of file
diff --git a/app/src/main/java/me/ash/reader/data/module/RetrofitModule.kt b/app/src/main/java/me/ash/reader/data/module/RetrofitModule.kt
index 2423b02..62ac758 100644
--- a/app/src/main/java/me/ash/reader/data/module/RetrofitModule.kt
+++ b/app/src/main/java/me/ash/reader/data/module/RetrofitModule.kt
@@ -4,7 +4,7 @@ import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
-import me.ash.reader.data.source.AppNetworkDataSource
+import me.ash.reader.data.source.RYNetworkDataSource
import me.ash.reader.data.source.FeverApiDataSource
import me.ash.reader.data.source.GoogleReaderApiDataSource
import javax.inject.Singleton
@@ -15,8 +15,8 @@ object RetrofitModule {
@Provides
@Singleton
- fun provideAppNetworkDataSource(): AppNetworkDataSource =
- AppNetworkDataSource.getInstance()
+ fun provideAppNetworkDataSource(): RYNetworkDataSource =
+ RYNetworkDataSource.getInstance()
@Provides
@Singleton
diff --git a/app/src/main/java/me/ash/reader/data/preference/DarkThemePreference.kt b/app/src/main/java/me/ash/reader/data/preference/DarkThemePreference.kt
index a5329df..4047372 100644
--- a/app/src/main/java/me/ash/reader/data/preference/DarkThemePreference.kt
+++ b/app/src/main/java/me/ash/reader/data/preference/DarkThemePreference.kt
@@ -3,6 +3,7 @@ package me.ash.reader.data.preference
import android.content.Context
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.ReadOnlyComposable
import androidx.datastore.preferences.core.Preferences
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@@ -33,6 +34,7 @@ sealed class DarkThemePreference(val value: Int) : Preference() {
}
@Composable
+ @ReadOnlyComposable
fun isDarkTheme(): Boolean = when (this) {
UseDeviceTheme -> isSystemInDarkTheme()
ON -> true
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/preference/InitialFilterPreference.kt b/app/src/main/java/me/ash/reader/data/preference/InitialFilterPreference.kt
new file mode 100644
index 0000000..4f20d2e
--- /dev/null
+++ b/app/src/main/java/me/ash/reader/data/preference/InitialFilterPreference.kt
@@ -0,0 +1,45 @@
+package me.ash.reader.data.preference
+
+import android.content.Context
+import androidx.datastore.preferences.core.Preferences
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+import me.ash.reader.R
+import me.ash.reader.ui.ext.DataStoreKeys
+import me.ash.reader.ui.ext.dataStore
+import me.ash.reader.ui.ext.put
+
+sealed class InitialFilterPreference(val value: Int) : Preference() {
+ object Starred : InitialFilterPreference(0)
+ object Unread : InitialFilterPreference(1)
+ object All : InitialFilterPreference(2)
+
+ override fun put(context: Context, scope: CoroutineScope) {
+ scope.launch {
+ context.dataStore.put(
+ DataStoreKeys.InitialFilter,
+ value
+ )
+ }
+ }
+
+ fun getDesc(context: Context): String =
+ when (this) {
+ Starred -> context.getString(R.string.starred)
+ Unread -> context.getString(R.string.unread)
+ All -> context.getString(R.string.all)
+ }
+
+ companion object {
+ val default = All
+ val values = listOf(Starred, Unread, All)
+
+ fun fromPreferences(preferences: Preferences) =
+ when (preferences[DataStoreKeys.InitialFilter.key]) {
+ 0 -> Starred
+ 1 -> Unread
+ 2 -> All
+ else -> default
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/me/ash/reader/data/preference/InitialPagePreference.kt b/app/src/main/java/me/ash/reader/data/preference/InitialPagePreference.kt
new file mode 100644
index 0000000..fbf954b
--- /dev/null
+++ b/app/src/main/java/me/ash/reader/data/preference/InitialPagePreference.kt
@@ -0,0 +1,42 @@
+package me.ash.reader.data.preference
+
+import android.content.Context
+import androidx.datastore.preferences.core.Preferences
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+import me.ash.reader.R
+import me.ash.reader.ui.ext.DataStoreKeys
+import me.ash.reader.ui.ext.dataStore
+import me.ash.reader.ui.ext.put
+
+sealed class InitialPagePreference(val value: Int) : Preference() {
+ object FeedsPage : InitialPagePreference(0)
+ object FlowPage : InitialPagePreference(1)
+
+ override fun put(context: Context, scope: CoroutineScope) {
+ scope.launch {
+ context.dataStore.put(
+ DataStoreKeys.InitialPage,
+ value
+ )
+ }
+ }
+
+ fun getDesc(context: Context): String =
+ when (this) {
+ FeedsPage -> context.getString(R.string.feeds_page)
+ FlowPage -> context.getString(R.string.flow_page)
+ }
+
+ companion object {
+ val default = FeedsPage
+ val values = listOf(FeedsPage, FlowPage)
+
+ fun fromPreferences(preferences: Preferences) =
+ when (preferences[DataStoreKeys.InitialPage.key]) {
+ 0 -> FeedsPage
+ 1 -> FlowPage
+ else -> default
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/me/ash/reader/data/preference/NewVersionDownloadUrlPreference.kt b/app/src/main/java/me/ash/reader/data/preference/NewVersionDownloadUrlPreference.kt
new file mode 100644
index 0000000..0b0a5f8
--- /dev/null
+++ b/app/src/main/java/me/ash/reader/data/preference/NewVersionDownloadUrlPreference.kt
@@ -0,0 +1,23 @@
+package me.ash.reader.data.preference
+
+import android.content.Context
+import androidx.datastore.preferences.core.Preferences
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import me.ash.reader.ui.ext.DataStoreKeys
+import me.ash.reader.ui.ext.dataStore
+import me.ash.reader.ui.ext.put
+
+object NewVersionDownloadUrlPreference {
+ const val default = ""
+
+ fun put(context: Context, scope: CoroutineScope, value: String) {
+ scope.launch(Dispatchers.IO) {
+ context.dataStore.put(DataStoreKeys.NewVersionDownloadUrl, value)
+ }
+ }
+
+ fun fromPreferences(preferences: Preferences) =
+ preferences[DataStoreKeys.NewVersionDownloadUrl.key] ?: default
+}
\ No newline at end of file
diff --git a/app/src/main/java/me/ash/reader/data/preference/NewVersionLogPreference.kt b/app/src/main/java/me/ash/reader/data/preference/NewVersionLogPreference.kt
new file mode 100644
index 0000000..151e7bf
--- /dev/null
+++ b/app/src/main/java/me/ash/reader/data/preference/NewVersionLogPreference.kt
@@ -0,0 +1,23 @@
+package me.ash.reader.data.preference
+
+import android.content.Context
+import androidx.datastore.preferences.core.Preferences
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import me.ash.reader.ui.ext.DataStoreKeys
+import me.ash.reader.ui.ext.dataStore
+import me.ash.reader.ui.ext.put
+
+object NewVersionLogPreference {
+ const val default = ""
+
+ fun put(context: Context, scope: CoroutineScope, value: String) {
+ scope.launch(Dispatchers.IO) {
+ context.dataStore.put(DataStoreKeys.NewVersionLog, value)
+ }
+ }
+
+ fun fromPreferences(preferences: Preferences) =
+ preferences[DataStoreKeys.NewVersionLog.key] ?: default
+}
\ No newline at end of file
diff --git a/app/src/main/java/me/ash/reader/data/preference/NewVersionNumberPreference.kt b/app/src/main/java/me/ash/reader/data/preference/NewVersionNumberPreference.kt
new file mode 100644
index 0000000..29424b1
--- /dev/null
+++ b/app/src/main/java/me/ash/reader/data/preference/NewVersionNumberPreference.kt
@@ -0,0 +1,25 @@
+package me.ash.reader.data.preference
+
+import android.content.Context
+import androidx.datastore.preferences.core.Preferences
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import me.ash.reader.data.model.Version
+import me.ash.reader.data.model.toVersion
+import me.ash.reader.ui.ext.DataStoreKeys
+import me.ash.reader.ui.ext.dataStore
+import me.ash.reader.ui.ext.put
+
+object NewVersionNumberPreference {
+ val default = Version()
+
+ fun put(context: Context, scope: CoroutineScope, value: String) {
+ scope.launch(Dispatchers.IO) {
+ context.dataStore.put(DataStoreKeys.NewVersionNumber, value)
+ }
+ }
+
+ fun fromPreferences(preferences: Preferences) =
+ preferences[DataStoreKeys.NewVersionNumber.key].toVersion()
+}
\ No newline at end of file
diff --git a/app/src/main/java/me/ash/reader/data/preference/NewVersionPublishDatePreference.kt b/app/src/main/java/me/ash/reader/data/preference/NewVersionPublishDatePreference.kt
new file mode 100644
index 0000000..b7fd390
--- /dev/null
+++ b/app/src/main/java/me/ash/reader/data/preference/NewVersionPublishDatePreference.kt
@@ -0,0 +1,23 @@
+package me.ash.reader.data.preference
+
+import android.content.Context
+import androidx.datastore.preferences.core.Preferences
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import me.ash.reader.ui.ext.DataStoreKeys
+import me.ash.reader.ui.ext.dataStore
+import me.ash.reader.ui.ext.put
+
+object NewVersionPublishDatePreference {
+ const val default = ""
+
+ fun put(context: Context, scope: CoroutineScope, value: String) {
+ scope.launch(Dispatchers.IO) {
+ context.dataStore.put(DataStoreKeys.NewVersionPublishDate, value)
+ }
+ }
+
+ fun fromPreferences(preferences: Preferences) =
+ preferences[DataStoreKeys.NewVersionPublishDate.key] ?: default
+}
\ No newline at end of file
diff --git a/app/src/main/java/me/ash/reader/data/preference/NewVersionSizePreference.kt b/app/src/main/java/me/ash/reader/data/preference/NewVersionSizePreference.kt
new file mode 100644
index 0000000..eac3dff
--- /dev/null
+++ b/app/src/main/java/me/ash/reader/data/preference/NewVersionSizePreference.kt
@@ -0,0 +1,28 @@
+package me.ash.reader.data.preference
+
+import android.content.Context
+import androidx.datastore.preferences.core.Preferences
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import me.ash.reader.ui.ext.DataStoreKeys
+import me.ash.reader.ui.ext.dataStore
+import me.ash.reader.ui.ext.put
+
+object NewVersionSizePreference {
+ const val default = ""
+
+ fun Int.formatSize(): String =
+ (this / 1024f / 1024f)
+ .takeIf { it > 0f }
+ ?.run { " ${String.format("%.2f", this)} MB" } ?: ""
+
+ fun put(context: Context, scope: CoroutineScope, value: String) {
+ scope.launch(Dispatchers.IO) {
+ context.dataStore.put(DataStoreKeys.NewVersionSize, value)
+ }
+ }
+
+ fun fromPreferences(preferences: Preferences) =
+ preferences[DataStoreKeys.NewVersionSize.key] ?: default
+}
\ No newline at end of file
diff --git a/app/src/main/java/me/ash/reader/data/preference/Preference.kt b/app/src/main/java/me/ash/reader/data/preference/Preference.kt
index cd451da..e4fba2b 100644
--- a/app/src/main/java/me/ash/reader/data/preference/Preference.kt
+++ b/app/src/main/java/me/ash/reader/data/preference/Preference.kt
@@ -1,8 +1,53 @@
package me.ash.reader.data.preference
import android.content.Context
+import androidx.datastore.preferences.core.Preferences
import kotlinx.coroutines.CoroutineScope
sealed class Preference {
abstract fun put(context: Context, scope: CoroutineScope)
+}
+
+fun Preferences.toSettings(): Settings {
+ return Settings(
+ newVersionNumber = NewVersionNumberPreference.fromPreferences(this),
+ skipVersionNumber = SkipVersionNumberPreference.fromPreferences(this),
+ newVersionPublishDate = NewVersionPublishDatePreference.fromPreferences(this),
+ newVersionLog = NewVersionLogPreference.fromPreferences(this),
+ newVersionSize = NewVersionSizePreference.fromPreferences(this),
+ newVersionDownloadUrl = NewVersionDownloadUrlPreference.fromPreferences(this),
+
+ themeIndex = ThemeIndexPreference.fromPreferences(this),
+ customPrimaryColor = CustomPrimaryColorPreference.fromPreferences(this),
+ darkTheme = DarkThemePreference.fromPreferences(this),
+ amoledDarkTheme = AmoledDarkThemePreference.fromPreferences(this),
+
+ feedsFilterBarStyle = FeedsFilterBarStylePreference.fromPreferences(this),
+ feedsFilterBarFilled = FeedsFilterBarFilledPreference.fromPreferences(this),
+ feedsFilterBarPadding = FeedsFilterBarPaddingPreference.fromPreferences(this),
+ feedsFilterBarTonalElevation = FeedsFilterBarTonalElevationPreference.fromPreferences(this),
+ feedsTopBarTonalElevation = FeedsTopBarTonalElevationPreference.fromPreferences(this),
+ feedsGroupListExpand = FeedsGroupListExpandPreference.fromPreferences(this),
+ feedsGroupListTonalElevation = FeedsGroupListTonalElevationPreference.fromPreferences(this),
+
+ flowFilterBarStyle = FlowFilterBarStylePreference.fromPreferences(this),
+ flowFilterBarFilled = FlowFilterBarFilledPreference.fromPreferences(this),
+ flowFilterBarPadding = FlowFilterBarPaddingPreference.fromPreferences(this),
+ flowFilterBarTonalElevation = FlowFilterBarTonalElevationPreference.fromPreferences(this),
+ flowTopBarTonalElevation = FlowTopBarTonalElevationPreference.fromPreferences(this),
+ flowArticleListFeedIcon = FlowArticleListFeedIconPreference.fromPreferences(this),
+ flowArticleListFeedName = FlowArticleListFeedNamePreference.fromPreferences(this),
+ flowArticleListImage = FlowArticleListImagePreference.fromPreferences(this),
+ flowArticleListDesc = FlowArticleListDescPreference.fromPreferences(this),
+ flowArticleListTime = FlowArticleListTimePreference.fromPreferences(this),
+ flowArticleListDateStickyHeader = FlowArticleListDateStickyHeaderPreference.fromPreferences(
+ this
+ ),
+ flowArticleListTonalElevation = FlowArticleListTonalElevationPreference.fromPreferences(this),
+
+ initialPage = InitialPagePreference.fromPreferences(this),
+ initialFilter = InitialFilterPreference.fromPreferences(this),
+
+ languages = LanguagesPreference.fromPreferences(this),
+ )
}
\ No newline at end of file
diff --git a/app/src/main/java/me/ash/reader/data/preference/Settings.kt b/app/src/main/java/me/ash/reader/data/preference/Settings.kt
index 70996c7..b5edcf2 100644
--- a/app/src/main/java/me/ash/reader/data/preference/Settings.kt
+++ b/app/src/main/java/me/ash/reader/data/preference/Settings.kt
@@ -6,12 +6,19 @@ import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
-import androidx.datastore.preferences.core.Preferences
import kotlinx.coroutines.flow.map
+import me.ash.reader.data.model.Version
import me.ash.reader.ui.ext.collectAsStateValue
import me.ash.reader.ui.ext.dataStore
data class Settings(
+ val newVersionNumber: Version = NewVersionNumberPreference.default,
+ val skipVersionNumber: Version = SkipVersionNumberPreference.default,
+ val newVersionPublishDate: String = NewVersionPublishDatePreference.default,
+ val newVersionLog: String = NewVersionLogPreference.default,
+ val newVersionSize: String = NewVersionSizePreference.default,
+ val newVersionDownloadUrl: String = NewVersionDownloadUrlPreference.default,
+
val themeIndex: Int = ThemeIndexPreference.default,
val customPrimaryColor: String = CustomPrimaryColorPreference.default,
val darkTheme: DarkThemePreference = DarkThemePreference.default,
@@ -38,43 +45,12 @@ data class Settings(
val flowArticleListDateStickyHeader: FlowArticleListDateStickyHeaderPreference = FlowArticleListDateStickyHeaderPreference.default,
val flowArticleListTonalElevation: FlowArticleListTonalElevationPreference = FlowArticleListTonalElevationPreference.default,
+ val initialPage: InitialPagePreference = InitialPagePreference.default,
+ val initialFilter: InitialFilterPreference = InitialFilterPreference.default,
+
val languages: LanguagesPreference = LanguagesPreference.default,
)
-fun Preferences.toSettings(): Settings {
- return Settings(
- themeIndex = ThemeIndexPreference.fromPreferences(this),
- customPrimaryColor = CustomPrimaryColorPreference.fromPreferences(this),
- darkTheme = DarkThemePreference.fromPreferences(this),
- amoledDarkTheme = AmoledDarkThemePreference.fromPreferences(this),
-
- feedsFilterBarStyle = FeedsFilterBarStylePreference.fromPreferences(this),
- feedsFilterBarFilled = FeedsFilterBarFilledPreference.fromPreferences(this),
- feedsFilterBarPadding = FeedsFilterBarPaddingPreference.fromPreferences(this),
- feedsFilterBarTonalElevation = FeedsFilterBarTonalElevationPreference.fromPreferences(this),
- feedsTopBarTonalElevation = FeedsTopBarTonalElevationPreference.fromPreferences(this),
- feedsGroupListExpand = FeedsGroupListExpandPreference.fromPreferences(this),
- feedsGroupListTonalElevation = FeedsGroupListTonalElevationPreference.fromPreferences(this),
-
- flowFilterBarStyle = FlowFilterBarStylePreference.fromPreferences(this),
- flowFilterBarFilled = FlowFilterBarFilledPreference.fromPreferences(this),
- flowFilterBarPadding = FlowFilterBarPaddingPreference.fromPreferences(this),
- flowFilterBarTonalElevation = FlowFilterBarTonalElevationPreference.fromPreferences(this),
- flowTopBarTonalElevation = FlowTopBarTonalElevationPreference.fromPreferences(this),
- flowArticleListFeedIcon = FlowArticleListFeedIconPreference.fromPreferences(this),
- flowArticleListFeedName = FlowArticleListFeedNamePreference.fromPreferences(this),
- flowArticleListImage = FlowArticleListImagePreference.fromPreferences(this),
- flowArticleListDesc = FlowArticleListDescPreference.fromPreferences(this),
- flowArticleListTime = FlowArticleListTimePreference.fromPreferences(this),
- flowArticleListDateStickyHeader = FlowArticleListDateStickyHeaderPreference.fromPreferences(
- this
- ),
- flowArticleListTonalElevation = FlowArticleListTonalElevationPreference.fromPreferences(this),
-
- languages = LanguagesPreference.fromPreferences(this),
- )
-}
-
@Composable
fun SettingsProvider(
content: @Composable () -> Unit,
@@ -88,6 +64,13 @@ fun SettingsProvider(
}.collectAsStateValue(initial = Settings())
CompositionLocalProvider(
+ LocalNewVersionNumber provides settings.newVersionNumber,
+ LocalSkipVersionNumber provides settings.skipVersionNumber,
+ LocalNewVersionPublishDate provides settings.newVersionPublishDate,
+ LocalNewVersionLog provides settings.newVersionLog,
+ LocalNewVersionSize provides settings.newVersionSize,
+ LocalNewVersionDownloadUrl provides settings.newVersionDownloadUrl,
+
LocalThemeIndex provides settings.themeIndex,
LocalCustomPrimaryColor provides settings.customPrimaryColor,
LocalDarkTheme provides settings.darkTheme,
@@ -114,12 +97,22 @@ fun SettingsProvider(
LocalFlowFilterBarPadding provides settings.flowFilterBarPadding,
LocalFlowFilterBarTonalElevation provides settings.flowFilterBarTonalElevation,
+ LocalInitialPage provides settings.initialPage,
+ LocalInitialFilter provides settings.initialFilter,
+
LocalLanguages provides settings.languages,
) {
content()
}
}
+val LocalNewVersionNumber = compositionLocalOf { NewVersionNumberPreference.default }
+val LocalSkipVersionNumber = compositionLocalOf { SkipVersionNumberPreference.default }
+val LocalNewVersionPublishDate = compositionLocalOf { NewVersionPublishDatePreference.default }
+val LocalNewVersionLog = compositionLocalOf { NewVersionLogPreference.default }
+val LocalNewVersionSize = compositionLocalOf { NewVersionSizePreference.default }
+val LocalNewVersionDownloadUrl = compositionLocalOf { NewVersionDownloadUrlPreference.default }
+
val LocalThemeIndex =
compositionLocalOf { ThemeIndexPreference.default }
val LocalCustomPrimaryColor =
@@ -169,5 +162,9 @@ val LocalFlowArticleListDateStickyHeader =
val LocalFlowArticleListTonalElevation =
compositionLocalOf { FlowArticleListTonalElevationPreference.default }
+val LocalInitialPage = compositionLocalOf { InitialPagePreference.default }
+val LocalInitialFilter =
+ compositionLocalOf { InitialFilterPreference.default }
+
val LocalLanguages =
compositionLocalOf { LanguagesPreference.default }
diff --git a/app/src/main/java/me/ash/reader/data/preference/SkipVersionNumberPreference.kt b/app/src/main/java/me/ash/reader/data/preference/SkipVersionNumberPreference.kt
new file mode 100644
index 0000000..d862c42
--- /dev/null
+++ b/app/src/main/java/me/ash/reader/data/preference/SkipVersionNumberPreference.kt
@@ -0,0 +1,25 @@
+package me.ash.reader.data.preference
+
+import android.content.Context
+import androidx.datastore.preferences.core.Preferences
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import me.ash.reader.data.model.Version
+import me.ash.reader.data.model.toVersion
+import me.ash.reader.ui.ext.DataStoreKeys
+import me.ash.reader.ui.ext.dataStore
+import me.ash.reader.ui.ext.put
+
+object SkipVersionNumberPreference {
+ val default = Version()
+
+ fun put(context: Context, scope: CoroutineScope, value: String) {
+ scope.launch(Dispatchers.IO) {
+ context.dataStore.put(DataStoreKeys.SkipVersionNumber, value)
+ }
+ }
+
+ fun fromPreferences(preferences: Preferences) =
+ preferences[DataStoreKeys.SkipVersionNumber.key].toVersion()
+}
\ No newline at end of file
diff --git a/app/src/main/java/me/ash/reader/data/repository/AbstractRssRepository.kt b/app/src/main/java/me/ash/reader/data/repository/AbstractRssRepository.kt
index 71eb82d..bfa666d 100644
--- a/app/src/main/java/me/ash/reader/data/repository/AbstractRssRepository.kt
+++ b/app/src/main/java/me/ash/reader/data/repository/AbstractRssRepository.kt
@@ -2,14 +2,15 @@ package me.ash.reader.data.repository
import android.content.Context
import android.util.Log
-import androidx.hilt.work.HiltWorker
import androidx.paging.PagingSource
-import androidx.work.*
-import dagger.assisted.Assisted
-import dagger.assisted.AssistedInject
+import androidx.work.CoroutineWorker
+import androidx.work.ExistingPeriodicWorkPolicy
+import androidx.work.ListenableWorker
+import androidx.work.WorkManager
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.mapLatest
import me.ash.reader.data.dao.AccountDao
import me.ash.reader.data.dao.ArticleDao
import me.ash.reader.data.dao.FeedDao
@@ -17,7 +18,6 @@ import me.ash.reader.data.dao.GroupDao
import me.ash.reader.data.entity.*
import me.ash.reader.ui.ext.currentAccountId
import java.util.*
-import java.util.concurrent.TimeUnit
abstract class AbstractRssRepository constructor(
private val context: Context,
@@ -99,7 +99,7 @@ abstract class AbstractRssRepository constructor(
fun pullImportant(
isStarred: Boolean = false,
isUnread: Boolean = false,
- ): Flow> {
+ ): Flow