Add articles image preview (#67)
* Add articles image preview * Lowers the pagingItem state
This commit is contained in:
parent
6583f3326c
commit
c79649bb77
|
@ -28,6 +28,15 @@ android {
|
||||||
vectorDrawables {
|
vectorDrawables {
|
||||||
useSupportLibrary true
|
useSupportLibrary true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
javaCompileOptions {
|
||||||
|
annotationProcessorOptions {
|
||||||
|
arguments += [
|
||||||
|
"room.schemaLocation": "$projectDir/schemas".toString(),
|
||||||
|
"room.incremental" : "true"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flavorDimensions "channel"
|
flavorDimensions "channel"
|
||||||
|
@ -103,6 +112,8 @@ dependencies {
|
||||||
implementation("io.coil-kt:coil-svg:$coil")
|
implementation("io.coil-kt:coil-svg:$coil")
|
||||||
implementation("io.coil-kt:coil-gif:$coil")
|
implementation("io.coil-kt:coil-gif:$coil")
|
||||||
|
|
||||||
|
implementation "org.conscrypt:conscrypt-android:2.5.2"
|
||||||
|
|
||||||
// https://square.github.io/okhttp/changelogs/changelog/
|
// https://square.github.io/okhttp/changelogs/changelog/
|
||||||
implementation "com.squareup.okhttp3:okhttp:5.0.0-alpha.6"
|
implementation "com.squareup.okhttp3:okhttp:5.0.0-alpha.6"
|
||||||
implementation "com.squareup.retrofit2:retrofit:$retrofit2"
|
implementation "com.squareup.retrofit2:retrofit:$retrofit2"
|
||||||
|
|
321
app/schemas/me.ash.reader.data.source.ReaderDatabase/2.json
Normal file
321
app/schemas/me.ash.reader.data.source.ReaderDatabase/2.json
Normal file
|
@ -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')"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,18 +5,18 @@
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
<!-- Disable automatic updates in F-Droid -->
|
<!-- Disable automatic updates in F-Droid -->
|
||||||
<!-- <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />-->
|
<!-- <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />-->
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".App"
|
android:name=".App"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/read_you"
|
android:label="@string/read_you"
|
||||||
android:networkSecurityConfig="@xml/network_security_config"
|
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.Reader">
|
android:theme="@style/Theme.Reader"
|
||||||
|
android:usesCleartextTraffic="true">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
|
|
|
@ -29,10 +29,18 @@ import me.ash.reader.data.source.AppNetworkDataSource
|
||||||
import me.ash.reader.data.source.OpmlLocalDataSource
|
import me.ash.reader.data.source.OpmlLocalDataSource
|
||||||
import me.ash.reader.data.source.ReaderDatabase
|
import me.ash.reader.data.source.ReaderDatabase
|
||||||
import me.ash.reader.ui.ext.*
|
import me.ash.reader.ui.ext.*
|
||||||
|
import org.conscrypt.Conscrypt
|
||||||
|
import java.security.Security
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltAndroidApp
|
@HiltAndroidApp
|
||||||
class App : Application(), Configuration.Provider, ImageLoader {
|
class App : Application(), Configuration.Provider, ImageLoader {
|
||||||
|
init {
|
||||||
|
// From: https://gitlab.com/spacecowboy/Feeder
|
||||||
|
// Install Conscrypt to handle TLSv1.3 pre Android10
|
||||||
|
Security.insertProviderAt(Conscrypt.newProvider(), 1)
|
||||||
|
}
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var readerDatabase: ReaderDatabase
|
lateinit var readerDatabase: ReaderDatabase
|
||||||
|
|
||||||
|
|
|
@ -374,7 +374,7 @@ interface ArticleDao {
|
||||||
@Query(
|
@Query(
|
||||||
"""
|
"""
|
||||||
SELECT a.id, a.date, a.title, a.author, a.rawDescription,
|
SELECT a.id, a.date, a.title, a.author, a.rawDescription,
|
||||||
a.shortDescription, a.fullContent, a.link, a.feedId,
|
a.shortDescription, a.fullContent, a.img, a.link, a.feedId,
|
||||||
a.accountId, a.isUnread, a.isStarred, a.isReadLater
|
a.accountId, a.isUnread, a.isStarred, a.isReadLater
|
||||||
FROM article AS a
|
FROM article AS a
|
||||||
LEFT JOIN feed AS b ON b.id = a.feedId
|
LEFT JOIN feed AS b ON b.id = a.feedId
|
||||||
|
@ -394,7 +394,7 @@ interface ArticleDao {
|
||||||
@Query(
|
@Query(
|
||||||
"""
|
"""
|
||||||
SELECT a.id, a.date, a.title, a.author, a.rawDescription,
|
SELECT a.id, a.date, a.title, a.author, a.rawDescription,
|
||||||
a.shortDescription, a.fullContent, a.link, a.feedId,
|
a.shortDescription, a.fullContent, a.img, a.link, a.feedId,
|
||||||
a.accountId, a.isUnread, a.isStarred, a.isReadLater
|
a.accountId, a.isUnread, a.isStarred, a.isReadLater
|
||||||
FROM article AS a
|
FROM article AS a
|
||||||
LEFT JOIN feed AS b ON b.id = a.feedId
|
LEFT JOIN feed AS b ON b.id = a.feedId
|
||||||
|
@ -416,7 +416,7 @@ interface ArticleDao {
|
||||||
@Query(
|
@Query(
|
||||||
"""
|
"""
|
||||||
SELECT a.id, a.date, a.title, a.author, a.rawDescription,
|
SELECT a.id, a.date, a.title, a.author, a.rawDescription,
|
||||||
a.shortDescription, a.fullContent, a.link, a.feedId,
|
a.shortDescription, a.fullContent, a.img, a.link, a.feedId,
|
||||||
a.accountId, a.isUnread, a.isStarred, a.isReadLater
|
a.accountId, a.isUnread, a.isStarred, a.isReadLater
|
||||||
FROM article AS a
|
FROM article AS a
|
||||||
LEFT JOIN feed AS b ON b.id = a.feedId
|
LEFT JOIN feed AS b ON b.id = a.feedId
|
||||||
|
@ -483,7 +483,7 @@ interface ArticleDao {
|
||||||
@Query(
|
@Query(
|
||||||
"""
|
"""
|
||||||
SELECT a.id, a.date, a.title, a.author, a.rawDescription,
|
SELECT a.id, a.date, a.title, a.author, a.rawDescription,
|
||||||
a.shortDescription, a.fullContent, a.link, a.feedId,
|
a.shortDescription, a.fullContent, a.img, a.link, a.feedId,
|
||||||
a.accountId, a.isUnread, a.isStarred, a.isReadLater
|
a.accountId, a.isUnread, a.isStarred, a.isReadLater
|
||||||
FROM article AS a LEFT JOIN feed AS b
|
FROM article AS a LEFT JOIN feed AS b
|
||||||
ON a.feedId = b.id
|
ON a.feedId = b.id
|
||||||
|
@ -503,25 +503,19 @@ interface ArticleDao {
|
||||||
)
|
)
|
||||||
suspend fun queryById(id: String): ArticleWithFeed?
|
suspend fun queryById(id: String): ArticleWithFeed?
|
||||||
|
|
||||||
@Insert
|
|
||||||
suspend fun insert(article: Article): Long
|
|
||||||
|
|
||||||
@Insert
|
@Insert
|
||||||
suspend fun insertList(articles: List<Article>): List<Long>
|
suspend fun insertList(articles: List<Article>): List<Long>
|
||||||
|
|
||||||
@Update
|
@Update
|
||||||
suspend fun update(vararg article: Article)
|
suspend fun update(vararg article: Article)
|
||||||
|
|
||||||
@Delete
|
|
||||||
suspend fun delete(vararg article: Article)
|
|
||||||
|
|
||||||
@RewriteQueriesToDropUnusedColumns
|
@RewriteQueriesToDropUnusedColumns
|
||||||
@Transaction
|
@Transaction
|
||||||
@Query(
|
@Query(
|
||||||
"""
|
"""
|
||||||
INSERT INTO article
|
INSERT INTO article
|
||||||
SELECT :id, :date, :title, :author, :rawDescription,
|
SELECT :id, :date, :title, :author, :rawDescription,
|
||||||
:shortDescription, :fullContent, :link, :feedId,
|
:shortDescription, :fullContent, :img, :link, :feedId,
|
||||||
:accountId, :isUnread, :isStarred, :isReadLater
|
:accountId, :isUnread, :isStarred, :isReadLater
|
||||||
WHERE NOT EXISTS(SELECT 1 FROM article WHERE link = :link AND accountId = :accountId)
|
WHERE NOT EXISTS(SELECT 1 FROM article WHERE link = :link AND accountId = :accountId)
|
||||||
"""
|
"""
|
||||||
|
@ -534,6 +528,7 @@ interface ArticleDao {
|
||||||
rawDescription: String,
|
rawDescription: String,
|
||||||
shortDescription: String,
|
shortDescription: String,
|
||||||
fullContent: String? = null,
|
fullContent: String? = null,
|
||||||
|
img: String? = null,
|
||||||
link: String,
|
link: String,
|
||||||
feedId: String,
|
feedId: String,
|
||||||
accountId: Int,
|
accountId: Int,
|
||||||
|
@ -552,6 +547,7 @@ interface ArticleDao {
|
||||||
article.rawDescription,
|
article.rawDescription,
|
||||||
article.shortDescription,
|
article.shortDescription,
|
||||||
article.fullContent,
|
article.fullContent,
|
||||||
|
article.img,
|
||||||
article.link,
|
article.link,
|
||||||
article.feedId,
|
article.feedId,
|
||||||
article.accountId,
|
article.accountId,
|
||||||
|
|
|
@ -32,6 +32,8 @@ data class Article(
|
||||||
@ColumnInfo
|
@ColumnInfo
|
||||||
var fullContent: String? = null,
|
var fullContent: String? = null,
|
||||||
@ColumnInfo
|
@ColumnInfo
|
||||||
|
var img: String? = null,
|
||||||
|
@ColumnInfo
|
||||||
val link: String,
|
val link: String,
|
||||||
@ColumnInfo(index = true)
|
@ColumnInfo(index = true)
|
||||||
val feedId: String,
|
val feedId: String,
|
||||||
|
|
|
@ -116,13 +116,23 @@ class RssHelper @Inject constructor(
|
||||||
.trim(),
|
.trim(),
|
||||||
fullContent = content,
|
fullContent = content,
|
||||||
link = it.link ?: "",
|
link = it.link ?: "",
|
||||||
)
|
).apply {
|
||||||
|
img = findImg(rawDescription)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
a
|
a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun findImg(rawDescription: String): String? {
|
||||||
|
// From: https://gitlab.com/spacecowboy/Feeder
|
||||||
|
// Using negative lookahead to skip data: urls, being inline base64
|
||||||
|
// And capturing original quote to use as ending quote
|
||||||
|
val regex = """img.*?src=(["'])((?!data).*?)\1""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||||
|
return regex.find(rawDescription)?.groupValues?.get(2)
|
||||||
|
}
|
||||||
|
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
suspend fun queryRssIcon(
|
suspend fun queryRssIcon(
|
||||||
feedDao: FeedDao,
|
feedDao: FeedDao,
|
||||||
|
|
|
@ -2,6 +2,8 @@ package me.ash.reader.data.source
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.room.*
|
import androidx.room.*
|
||||||
|
import androidx.room.migration.Migration
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
import me.ash.reader.data.dao.AccountDao
|
import me.ash.reader.data.dao.AccountDao
|
||||||
import me.ash.reader.data.dao.ArticleDao
|
import me.ash.reader.data.dao.ArticleDao
|
||||||
import me.ash.reader.data.dao.FeedDao
|
import me.ash.reader.data.dao.FeedDao
|
||||||
|
@ -14,8 +16,7 @@ import java.util.*
|
||||||
|
|
||||||
@Database(
|
@Database(
|
||||||
entities = [Account::class, Feed::class, Article::class, Group::class],
|
entities = [Account::class, Feed::class, Article::class, Group::class],
|
||||||
version = 1,
|
version = 2,
|
||||||
exportSchema = false,
|
|
||||||
)
|
)
|
||||||
@TypeConverters(ReaderDatabase.Converters::class)
|
@TypeConverters(ReaderDatabase.Converters::class)
|
||||||
abstract class ReaderDatabase : RoomDatabase() {
|
abstract class ReaderDatabase : RoomDatabase() {
|
||||||
|
@ -33,7 +34,7 @@ abstract class ReaderDatabase : RoomDatabase() {
|
||||||
context.applicationContext,
|
context.applicationContext,
|
||||||
ReaderDatabase::class.java,
|
ReaderDatabase::class.java,
|
||||||
"Reader"
|
"Reader"
|
||||||
).build().also {
|
).addMigrations(*allMigrations).build().also {
|
||||||
instance = it
|
instance = it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,4 +53,19 @@ abstract class ReaderDatabase : RoomDatabase() {
|
||||||
return date?.time
|
return date?.time
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val allMigrations = arrayOf(
|
||||||
|
MIGRATION_1_2,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Suppress("ClassName")
|
||||||
|
object MIGRATION_1_2 : Migration(1, 2) {
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
database.execSQL(
|
||||||
|
"""
|
||||||
|
ALTER TABLE article ADD COLUMN img TEXT DEFAULT NULL
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -3,6 +3,9 @@ package me.ash.reader.ui.component
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.graphics.DefaultAlpha
|
import androidx.compose.ui.graphics.DefaultAlpha
|
||||||
|
@ -31,6 +34,31 @@ fun AsyncImage(
|
||||||
@DrawableRes error: Int? = R.drawable.ic_broken_image_black_24dp,
|
@DrawableRes error: Int? = R.drawable.ic_broken_image_black_24dp,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
val color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
val placeholderPainterResource = placeholder?.run { painterResource(this) }
|
||||||
|
val errorPainterResource = error?.run { painterResource(this) }
|
||||||
|
val placeholderPainter by remember {
|
||||||
|
mutableStateOf(
|
||||||
|
placeholderPainterResource?.run {
|
||||||
|
forwardingPainter(
|
||||||
|
painter = this,
|
||||||
|
colorFilter = ColorFilter.tint(color),
|
||||||
|
alpha = 0.1f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val errorPainter by remember {
|
||||||
|
mutableStateOf(
|
||||||
|
errorPainterResource?.run {
|
||||||
|
forwardingPainter(
|
||||||
|
painter = this,
|
||||||
|
colorFilter = ColorFilter.tint(color),
|
||||||
|
alpha = 0.1f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
coil.compose.AsyncImage(
|
coil.compose.AsyncImage(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
|
@ -45,20 +73,8 @@ fun AsyncImage(
|
||||||
contentDescription = contentDescription,
|
contentDescription = contentDescription,
|
||||||
contentScale = contentScale,
|
contentScale = contentScale,
|
||||||
imageLoader = context.imageLoader,
|
imageLoader = context.imageLoader,
|
||||||
placeholder = placeholder?.let {
|
placeholder = placeholderPainter,
|
||||||
forwardingPainter(
|
error = errorPainter,
|
||||||
painter = painterResource(it),
|
|
||||||
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurfaceVariant),
|
|
||||||
alpha = 0.5f,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
error = error?.let {
|
|
||||||
forwardingPainter(
|
|
||||||
painter = painterResource(it),
|
|
||||||
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onError),
|
|
||||||
alpha = 0.5f
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package me.ash.reader.ui.ext
|
package me.ash.reader.ui.ext
|
||||||
|
|
||||||
import androidx.compose.foundation.lazy.LazyListState
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.paging.compose.LazyPagingItems
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
fun LazyListState.calculateTopBarAnimateValue(start: Float, end: Float): Float =
|
fun LazyListState.calculateTopBarAnimateValue(start: Float, end: Float): Float =
|
||||||
|
@ -12,3 +15,16 @@ fun LazyListState.calculateTopBarAnimateValue(start: Float, end: Float): Float =
|
||||||
if (start < end) (start + increase).coerceIn(start, end)
|
if (start < end) (start + increase).coerceIn(start, end)
|
||||||
else (start - increase).coerceIn(end, start)
|
else (start - increase).coerceIn(end, start)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun <T : Any> LazyPagingItems<T>.rememberLazyListState(): LazyListState {
|
||||||
|
// After recreation, LazyPagingItems first return 0 items, then the cached items.
|
||||||
|
// This behavior/issue is resetting the LazyListState scroll position.
|
||||||
|
// Below is a workaround. More info: https://issuetracker.google.com/issues/177245496.
|
||||||
|
return when (itemCount) {
|
||||||
|
// Return a different LazyListState instance.
|
||||||
|
0 -> remember(this) { LazyListState(0, 0) }
|
||||||
|
// Return rememberLazyListState (normal case).
|
||||||
|
else -> androidx.compose.foundation.lazy.rememberLazyListState()
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,6 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.paging.compose.collectAsLazyPagingItems
|
|
||||||
import com.google.accompanist.navigation.animation.AnimatedNavHost
|
import com.google.accompanist.navigation.animation.AnimatedNavHost
|
||||||
import com.google.accompanist.navigation.animation.rememberAnimatedNavController
|
import com.google.accompanist.navigation.animation.rememberAnimatedNavController
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
|
@ -38,11 +37,7 @@ fun HomeEntry(
|
||||||
homeViewModel: HomeViewModel = hiltViewModel(),
|
homeViewModel: HomeViewModel = hiltViewModel(),
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
val viewState = homeViewModel.viewState.collectAsStateValue()
|
|
||||||
val filterState = homeViewModel.filterState.collectAsStateValue()
|
val filterState = homeViewModel.filterState.collectAsStateValue()
|
||||||
val pagingItems = viewState.pagingData.collectAsLazyPagingItems()
|
|
||||||
|
|
||||||
val navController = rememberAnimatedNavController()
|
val navController = rememberAnimatedNavController()
|
||||||
|
|
||||||
val intent by rememberSaveable { mutableStateOf(context.findActivity()?.intent) }
|
val intent by rememberSaveable { mutableStateOf(context.findActivity()?.intent) }
|
||||||
|
@ -116,7 +111,6 @@ fun HomeEntry(
|
||||||
FlowPage(
|
FlowPage(
|
||||||
navController = navController,
|
navController = navController,
|
||||||
homeViewModel = homeViewModel,
|
homeViewModel = homeViewModel,
|
||||||
pagingItems = pagingItems,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
animatedComposable(route = "${RouteName.READING}/{articleId}") {
|
animatedComposable(route = "${RouteName.READING}/{articleId}") {
|
||||||
|
|
|
@ -3,7 +3,6 @@ package me.ash.reader.ui.page.home
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.paging.*
|
import androidx.paging.*
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import com.google.accompanist.pager.ExperimentalPagerApi
|
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
|
@ -17,7 +16,6 @@ import me.ash.reader.data.repository.SyncWorker
|
||||||
import me.ash.reader.ui.page.home.flow.FlowItemView
|
import me.ash.reader.ui.page.home.flow.FlowItemView
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@OptIn(ExperimentalPagerApi::class)
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class HomeViewModel @Inject constructor(
|
class HomeViewModel @Inject constructor(
|
||||||
private val rssRepository: RssRepository,
|
private val rssRepository: RssRepository,
|
||||||
|
@ -112,7 +110,6 @@ data class FilterState(
|
||||||
val filter: Filter = Filter.All,
|
val filter: Filter = Filter.All,
|
||||||
)
|
)
|
||||||
|
|
||||||
@OptIn(ExperimentalPagerApi::class)
|
|
||||||
data class HomeViewState(
|
data class HomeViewState(
|
||||||
val pagingData: Flow<PagingData<FlowItemView>> = emptyFlow(),
|
val pagingData: Flow<PagingData<FlowItemView>> = emptyFlow(),
|
||||||
val searchContent: String = "",
|
val searchContent: String = "",
|
||||||
|
|
|
@ -15,13 +15,16 @@ import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
import androidx.compose.ui.draw.alpha
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import coil.size.Scale
|
||||||
import me.ash.reader.R
|
import me.ash.reader.R
|
||||||
import me.ash.reader.data.entity.ArticleWithFeed
|
import me.ash.reader.data.entity.ArticleWithFeed
|
||||||
import me.ash.reader.data.preference.*
|
import me.ash.reader.data.preference.*
|
||||||
|
import me.ash.reader.ui.component.AsyncImage
|
||||||
import me.ash.reader.ui.ext.formatAsString
|
import me.ash.reader.ui.ext.formatAsString
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -40,11 +43,12 @@ fun ArticleItem(
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(horizontal = 12.dp)
|
.padding(horizontal = 12.dp)
|
||||||
.clip(RoundedCornerShape(12.dp))
|
.clip(RoundedCornerShape(20.dp))
|
||||||
.clickable { onClick(articleWithFeed) }
|
.clickable { onClick(articleWithFeed) }
|
||||||
.padding(horizontal = 12.dp, vertical = 12.dp)
|
.padding(horizontal = 12.dp, vertical = 12.dp)
|
||||||
.alpha(if (articleWithFeed.article.isStarred || articleWithFeed.article.isUnread) 1f else 0.5f),
|
.alpha(if (articleWithFeed.article.isStarred || articleWithFeed.article.isUnread) 1f else 0.5f),
|
||||||
) {
|
) {
|
||||||
|
// Upper
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
@ -64,6 +68,7 @@ fun ArticleItem(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Right
|
||||||
if (articleListDate.value) {
|
if (articleListDate.value) {
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
@ -95,6 +100,8 @@ fun ArticleItem(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lower
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
) {
|
) {
|
||||||
|
@ -108,10 +115,12 @@ fun ArticleItem(
|
||||||
) {}
|
) {}
|
||||||
Spacer(modifier = Modifier.width(10.dp))
|
Spacer(modifier = Modifier.width(10.dp))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Article
|
// Article
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.weight(1f),
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// Title
|
// Title
|
||||||
Text(
|
Text(
|
||||||
text = articleWithFeed.article.title,
|
text = articleWithFeed.article.title,
|
||||||
|
@ -120,6 +129,7 @@ fun ArticleItem(
|
||||||
maxLines = if (articleListDesc.value) 2 else 4,
|
maxLines = if (articleListDesc.value) 2 else 4,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Description
|
// Description
|
||||||
if (articleListDesc.value && articleWithFeed.article.shortDescription.isNotBlank()) {
|
if (articleListDesc.value && articleWithFeed.article.shortDescription.isNotBlank()) {
|
||||||
Text(
|
Text(
|
||||||
|
@ -131,6 +141,19 @@ fun ArticleItem(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Image
|
||||||
|
if (articleWithFeed.article.img != null && articleListImage.value) {
|
||||||
|
AsyncImage(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(start = 10.dp)
|
||||||
|
.size(80.dp)
|
||||||
|
.clip(RoundedCornerShape(20.dp)),
|
||||||
|
data = articleWithFeed.article.img,
|
||||||
|
scale = Scale.FILL,
|
||||||
|
contentScale = ContentScale.Crop,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,7 +2,6 @@ package me.ash.reader.ui.page.home.flow
|
||||||
|
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.animation.*
|
import androidx.compose.animation.*
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
@ -22,7 +21,7 @@ import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import androidx.paging.LoadState
|
import androidx.paging.LoadState
|
||||||
import androidx.paging.compose.LazyPagingItems
|
import androidx.paging.compose.collectAsLazyPagingItems
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import me.ash.reader.R
|
import me.ash.reader.R
|
||||||
|
@ -43,7 +42,6 @@ import me.ash.reader.ui.theme.palette.onDark
|
||||||
|
|
||||||
@OptIn(
|
@OptIn(
|
||||||
ExperimentalMaterial3Api::class,
|
ExperimentalMaterial3Api::class,
|
||||||
ExperimentalFoundationApi::class,
|
|
||||||
com.google.accompanist.pager.ExperimentalPagerApi::class,
|
com.google.accompanist.pager.ExperimentalPagerApi::class,
|
||||||
androidx.compose.ui.ExperimentalComposeUiApi::class,
|
androidx.compose.ui.ExperimentalComposeUiApi::class,
|
||||||
)
|
)
|
||||||
|
@ -52,8 +50,9 @@ fun FlowPage(
|
||||||
navController: NavHostController,
|
navController: NavHostController,
|
||||||
flowViewModel: FlowViewModel = hiltViewModel(),
|
flowViewModel: FlowViewModel = hiltViewModel(),
|
||||||
homeViewModel: HomeViewModel,
|
homeViewModel: HomeViewModel,
|
||||||
pagingItems: LazyPagingItems<FlowItemView>,
|
|
||||||
) {
|
) {
|
||||||
|
val homeViewView = homeViewModel.viewState.collectAsStateValue()
|
||||||
|
val pagingItems = homeViewView.pagingData.collectAsLazyPagingItems()
|
||||||
val keyboardController = LocalSoftwareKeyboardController.current
|
val keyboardController = LocalSoftwareKeyboardController.current
|
||||||
val topBarTonalElevation = LocalFlowTopBarTonalElevation.current
|
val topBarTonalElevation = LocalFlowTopBarTonalElevation.current
|
||||||
val articleListTonalElevation = LocalFlowArticleListTonalElevation.current
|
val articleListTonalElevation = LocalFlowArticleListTonalElevation.current
|
||||||
|
@ -177,14 +176,6 @@ fun FlowPage(
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
content = {
|
content = {
|
||||||
// if (pagingItems.loadState.source.refresh is LoadState.NotLoading && pagingItems.itemCount == 0) {
|
|
||||||
// LottieAnimation(
|
|
||||||
// modifier = Modifier
|
|
||||||
// .alpha(0.7f)
|
|
||||||
// .padding(80.dp),
|
|
||||||
// url = "https://assets7.lottiefiles.com/packages/lf20_l4ny0jjm.json",
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
SwipeRefresh(
|
SwipeRefresh(
|
||||||
onRefresh = {
|
onRefresh = {
|
||||||
if (!isSyncing) {
|
if (!isSyncing) {
|
||||||
|
|
|
@ -174,10 +174,13 @@ fun FlowPageStyle(
|
||||||
}
|
}
|
||||||
SettingItem(
|
SettingItem(
|
||||||
title = stringResource(R.string.article_images),
|
title = stringResource(R.string.article_images),
|
||||||
enable = false,
|
onClick = {
|
||||||
onClick = {},
|
(!articleListImage).put(context, scope)
|
||||||
|
},
|
||||||
) {
|
) {
|
||||||
Switch(activated = false, enable = false)
|
Switch(activated = articleListImage.value) {
|
||||||
|
(!articleListImage).put(context, scope)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
SettingItem(
|
SettingItem(
|
||||||
title = stringResource(R.string.article_desc),
|
title = stringResource(R.string.article_desc),
|
||||||
|
@ -403,6 +406,7 @@ fun FlowPagePreview(
|
||||||
accountId = 0,
|
accountId = 0,
|
||||||
date = Date(),
|
date = Date(),
|
||||||
isStarred = true,
|
isStarred = true,
|
||||||
|
img = "https://images.unsplash.com/photo-1544716278-ca5e3f4abd8c?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1yZWxhdGVkfDJ8fHxlbnwwfHx8fA%3D%3D&auto=format&fit=crop&w=800&q=60"
|
||||||
),
|
),
|
||||||
feed = Feed(
|
feed = Feed(
|
||||||
id = "",
|
id = "",
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<network-security-config xmlns:tools="http://schemas.android.com/tools">
|
|
||||||
<base-config
|
|
||||||
cleartextTrafficPermitted="true"
|
|
||||||
tools:ignore="InsecureBaseConfiguration" />
|
|
||||||
</network-security-config>
|
|
Loading…
Reference in New Issue
Block a user