From c79649bb7739611d43904e8b3485dd625b562d01 Mon Sep 17 00:00:00 2001 From: Ashinch Date: Fri, 13 May 2022 23:21:21 +0800 Subject: [PATCH] Add articles image preview (#67) * Add articles image preview * Lowers the pagingItem state --- app/build.gradle | 11 + .../2.json | 321 ++++++++++++++++++ app/src/main/AndroidManifest.xml | 8 +- app/src/main/java/me/ash/reader/App.kt | 8 + .../java/me/ash/reader/data/dao/ArticleDao.kt | 18 +- .../java/me/ash/reader/data/entity/Article.kt | 2 + .../ash/reader/data/repository/RssHelper.kt | 12 +- .../ash/reader/data/source/ReaderDatabase.kt | 22 +- .../me/ash/reader/ui/component/AsyncImage.kt | 44 ++- .../me/ash/reader/ui/ext/LazyListStateExt.kt | 16 + .../me/ash/reader/ui/page/common/HomeEntry.kt | 6 - .../ash/reader/ui/page/home/HomeViewModel.kt | 3 - .../reader/ui/page/home/flow/ArticleItem.kt | 27 +- .../ash/reader/ui/page/home/flow/FlowPage.kt | 15 +- .../page/settings/color/flow/FlowPageStyle.kt | 10 +- .../main/res/xml/network_security_config.xml | 6 - 16 files changed, 464 insertions(+), 65 deletions(-) create mode 100644 app/schemas/me.ash.reader.data.source.ReaderDatabase/2.json delete mode 100644 app/src/main/res/xml/network_security_config.xml diff --git a/app/build.gradle b/app/build.gradle index d4d4bb5..a6ba043 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -28,6 +28,15 @@ android { vectorDrawables { useSupportLibrary true } + + javaCompileOptions { + annotationProcessorOptions { + arguments += [ + "room.schemaLocation": "$projectDir/schemas".toString(), + "room.incremental" : "true" + ] + } + } } flavorDimensions "channel" @@ -103,6 +112,8 @@ dependencies { implementation("io.coil-kt:coil-svg:$coil") implementation("io.coil-kt:coil-gif:$coil") + 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.retrofit2:retrofit:$retrofit2" diff --git a/app/schemas/me.ash.reader.data.source.ReaderDatabase/2.json b/app/schemas/me.ash.reader.data.source.ReaderDatabase/2.json new file mode 100644 index 0000000..5690ca5 --- /dev/null +++ b/app/schemas/me.ash.reader.data.source.ReaderDatabase/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 648c8bf..d275ec0 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,18 +5,18 @@ - - + + + android:theme="@style/Theme.Reader" + android:usesCleartextTraffic="true"> ): List @Update suspend fun update(vararg article: Article) - @Delete - suspend fun delete(vararg article: Article) - @RewriteQueriesToDropUnusedColumns @Transaction @Query( """ INSERT INTO article SELECT :id, :date, :title, :author, :rawDescription, - :shortDescription, :fullContent, :link, :feedId, + :shortDescription, :fullContent, :img, :link, :feedId, :accountId, :isUnread, :isStarred, :isReadLater WHERE NOT EXISTS(SELECT 1 FROM article WHERE link = :link AND accountId = :accountId) """ @@ -534,6 +528,7 @@ interface ArticleDao { rawDescription: String, shortDescription: String, fullContent: String? = null, + img: String? = null, link: String, feedId: String, accountId: Int, @@ -552,6 +547,7 @@ interface ArticleDao { article.rawDescription, article.shortDescription, article.fullContent, + article.img, article.link, article.feedId, article.accountId, diff --git a/app/src/main/java/me/ash/reader/data/entity/Article.kt b/app/src/main/java/me/ash/reader/data/entity/Article.kt index e80cff0..42845e0 100644 --- a/app/src/main/java/me/ash/reader/data/entity/Article.kt +++ b/app/src/main/java/me/ash/reader/data/entity/Article.kt @@ -32,6 +32,8 @@ data class Article( @ColumnInfo var fullContent: String? = null, @ColumnInfo + var img: String? = null, + @ColumnInfo val link: String, @ColumnInfo(index = true) val feedId: String, diff --git a/app/src/main/java/me/ash/reader/data/repository/RssHelper.kt b/app/src/main/java/me/ash/reader/data/repository/RssHelper.kt index 078bd05..149ec8c 100644 --- a/app/src/main/java/me/ash/reader/data/repository/RssHelper.kt +++ b/app/src/main/java/me/ash/reader/data/repository/RssHelper.kt @@ -116,13 +116,23 @@ class RssHelper @Inject constructor( .trim(), fullContent = content, link = it.link ?: "", - ) + ).apply { + img = findImg(rawDescription) + } ) } 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) suspend fun queryRssIcon( feedDao: FeedDao, diff --git a/app/src/main/java/me/ash/reader/data/source/ReaderDatabase.kt b/app/src/main/java/me/ash/reader/data/source/ReaderDatabase.kt index 76a4734..2fa0971 100644 --- a/app/src/main/java/me/ash/reader/data/source/ReaderDatabase.kt +++ b/app/src/main/java/me/ash/reader/data/source/ReaderDatabase.kt @@ -2,6 +2,8 @@ package me.ash.reader.data.source import android.content.Context 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.ArticleDao import me.ash.reader.data.dao.FeedDao @@ -14,8 +16,7 @@ import java.util.* @Database( entities = [Account::class, Feed::class, Article::class, Group::class], - version = 1, - exportSchema = false, + version = 2, ) @TypeConverters(ReaderDatabase.Converters::class) abstract class ReaderDatabase : RoomDatabase() { @@ -33,7 +34,7 @@ abstract class ReaderDatabase : RoomDatabase() { context.applicationContext, ReaderDatabase::class.java, "Reader" - ).build().also { + ).addMigrations(*allMigrations).build().also { instance = it } } @@ -52,4 +53,19 @@ abstract class ReaderDatabase : RoomDatabase() { 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() + ) + } } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/ui/component/AsyncImage.kt b/app/src/main/java/me/ash/reader/ui/component/AsyncImage.kt index 1e06009..fd9a2fc 100644 --- a/app/src/main/java/me/ash/reader/ui/component/AsyncImage.kt +++ b/app/src/main/java/me/ash/reader/ui/component/AsyncImage.kt @@ -3,6 +3,9 @@ package me.ash.reader.ui.component import androidx.annotation.DrawableRes import androidx.compose.material3.MaterialTheme 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.graphics.ColorFilter import androidx.compose.ui.graphics.DefaultAlpha @@ -31,6 +34,31 @@ fun AsyncImage( @DrawableRes error: Int? = R.drawable.ic_broken_image_black_24dp, ) { 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( modifier = modifier, @@ -45,20 +73,8 @@ fun AsyncImage( contentDescription = contentDescription, contentScale = contentScale, imageLoader = context.imageLoader, - placeholder = placeholder?.let { - forwardingPainter( - 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 - ) - }, + placeholder = placeholderPainter, + error = errorPainter, ) } diff --git a/app/src/main/java/me/ash/reader/ui/ext/LazyListStateExt.kt b/app/src/main/java/me/ash/reader/ui/ext/LazyListStateExt.kt index a991e8a..ca9eb77 100644 --- a/app/src/main/java/me/ash/reader/ui/ext/LazyListStateExt.kt +++ b/app/src/main/java/me/ash/reader/ui/ext/LazyListStateExt.kt @@ -1,6 +1,9 @@ package me.ash.reader.ui.ext 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 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) else (start - increase).coerceIn(end, start) } + +@Composable +fun LazyPagingItems.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() + } +} \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt b/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt index 88a2ccd..87b5015 100644 --- a/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt +++ b/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt @@ -9,7 +9,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.hilt.navigation.compose.hiltViewModel -import androidx.paging.compose.collectAsLazyPagingItems import com.google.accompanist.navigation.animation.AnimatedNavHost import com.google.accompanist.navigation.animation.rememberAnimatedNavController import com.google.accompanist.systemuicontroller.rememberSystemUiController @@ -38,11 +37,7 @@ fun HomeEntry( homeViewModel: HomeViewModel = hiltViewModel(), ) { val context = LocalContext.current - - val viewState = homeViewModel.viewState.collectAsStateValue() val filterState = homeViewModel.filterState.collectAsStateValue() - val pagingItems = viewState.pagingData.collectAsLazyPagingItems() - val navController = rememberAnimatedNavController() val intent by rememberSaveable { mutableStateOf(context.findActivity()?.intent) } @@ -116,7 +111,6 @@ fun HomeEntry( FlowPage( navController = navController, homeViewModel = homeViewModel, - pagingItems = pagingItems, ) } animatedComposable(route = "${RouteName.READING}/{articleId}") { diff --git a/app/src/main/java/me/ash/reader/ui/page/home/HomeViewModel.kt b/app/src/main/java/me/ash/reader/ui/page/home/HomeViewModel.kt index e787100..219ab62 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/HomeViewModel.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/HomeViewModel.kt @@ -3,7 +3,6 @@ package me.ash.reader.ui.page.home import androidx.lifecycle.ViewModel import androidx.paging.* import androidx.work.WorkManager -import com.google.accompanist.pager.ExperimentalPagerApi import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineScope 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 javax.inject.Inject -@OptIn(ExperimentalPagerApi::class) @HiltViewModel class HomeViewModel @Inject constructor( private val rssRepository: RssRepository, @@ -112,7 +110,6 @@ data class FilterState( val filter: Filter = Filter.All, ) -@OptIn(ExperimentalPagerApi::class) data class HomeViewState( val pagingData: Flow> = emptyFlow(), val searchContent: String = "", diff --git a/app/src/main/java/me/ash/reader/ui/page/home/flow/ArticleItem.kt b/app/src/main/java/me/ash/reader/ui/page/home/flow/ArticleItem.kt index 497e251..752b64f 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/flow/ArticleItem.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/flow/ArticleItem.kt @@ -15,13 +15,16 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.clip +import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +import coil.size.Scale import me.ash.reader.R import me.ash.reader.data.entity.ArticleWithFeed import me.ash.reader.data.preference.* +import me.ash.reader.ui.component.AsyncImage import me.ash.reader.ui.ext.formatAsString @Composable @@ -40,11 +43,12 @@ fun ArticleItem( Column( modifier = Modifier .padding(horizontal = 12.dp) - .clip(RoundedCornerShape(12.dp)) + .clip(RoundedCornerShape(20.dp)) .clickable { onClick(articleWithFeed) } .padding(horizontal = 12.dp, vertical = 12.dp) .alpha(if (articleWithFeed.article.isStarred || articleWithFeed.article.isUnread) 1f else 0.5f), ) { + // Upper Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, @@ -64,6 +68,7 @@ fun ArticleItem( ) } + // Right if (articleListDate.value) { Row( verticalAlignment = Alignment.CenterVertically, @@ -95,6 +100,8 @@ fun ArticleItem( } } } + + // Lower Row( modifier = Modifier.fillMaxWidth(), ) { @@ -108,10 +115,12 @@ fun ArticleItem( ) {} Spacer(modifier = Modifier.width(10.dp)) } + // Article Column( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier.weight(1f), ) { + // Title Text( text = articleWithFeed.article.title, @@ -120,6 +129,7 @@ fun ArticleItem( maxLines = if (articleListDesc.value) 2 else 4, overflow = TextOverflow.Ellipsis, ) + // Description if (articleListDesc.value && articleWithFeed.article.shortDescription.isNotBlank()) { 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, + ) + } } } } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt b/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt index c69b0dd..d6a1abd 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt @@ -2,7 +2,6 @@ package me.ash.reader.ui.page.home.flow import androidx.activity.compose.BackHandler import androidx.compose.animation.* -import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn @@ -22,7 +21,7 @@ import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavHostController import androidx.paging.LoadState -import androidx.paging.compose.LazyPagingItems +import androidx.paging.compose.collectAsLazyPagingItems import kotlinx.coroutines.delay import kotlinx.coroutines.launch import me.ash.reader.R @@ -43,7 +42,6 @@ import me.ash.reader.ui.theme.palette.onDark @OptIn( ExperimentalMaterial3Api::class, - ExperimentalFoundationApi::class, com.google.accompanist.pager.ExperimentalPagerApi::class, androidx.compose.ui.ExperimentalComposeUiApi::class, ) @@ -52,8 +50,9 @@ fun FlowPage( navController: NavHostController, flowViewModel: FlowViewModel = hiltViewModel(), homeViewModel: HomeViewModel, - pagingItems: LazyPagingItems, ) { + val homeViewView = homeViewModel.viewState.collectAsStateValue() + val pagingItems = homeViewView.pagingData.collectAsLazyPagingItems() val keyboardController = LocalSoftwareKeyboardController.current val topBarTonalElevation = LocalFlowTopBarTonalElevation.current val articleListTonalElevation = LocalFlowArticleListTonalElevation.current @@ -177,14 +176,6 @@ fun FlowPage( ) }, 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( onRefresh = { if (!isSyncing) { diff --git a/app/src/main/java/me/ash/reader/ui/page/settings/color/flow/FlowPageStyle.kt b/app/src/main/java/me/ash/reader/ui/page/settings/color/flow/FlowPageStyle.kt index 8c35bd2..a07e097 100644 --- a/app/src/main/java/me/ash/reader/ui/page/settings/color/flow/FlowPageStyle.kt +++ b/app/src/main/java/me/ash/reader/ui/page/settings/color/flow/FlowPageStyle.kt @@ -174,10 +174,13 @@ fun FlowPageStyle( } SettingItem( 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( title = stringResource(R.string.article_desc), @@ -403,6 +406,7 @@ fun FlowPagePreview( accountId = 0, date = Date(), 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( id = "", diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml deleted file mode 100644 index 2c950a5..0000000 --- a/app/src/main/res/xml/network_security_config.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file