Rework Feed table columns

This commit is contained in:
Shinokuni 2024-08-04 18:04:55 +02:00
parent 5247d878c4
commit 3af1220666
15 changed files with 109 additions and 70 deletions

View File

@ -130,8 +130,8 @@ class ItemScreen(
val itemWithFeed = state.itemWithFeed!! val itemWithFeed = state.itemWithFeed!!
val item = itemWithFeed.item val item = itemWithFeed.item
val accentColor = if (itemWithFeed.bgColor != 0) { val accentColor = if (itemWithFeed.color != 0) {
Color(itemWithFeed.bgColor) Color(itemWithFeed.color)
} else { } else {
primaryColor primaryColor
} }
@ -203,8 +203,8 @@ class ItemScreen(
if (item.imageLink != null) { if (item.imageLink != null) {
BackgroundTitle(itemWithFeed = itemWithFeed) BackgroundTitle(itemWithFeed = itemWithFeed)
} else { } else {
val tintColor = if (itemWithFeed.bgColor != 0) { val tintColor = if (itemWithFeed.color != 0) {
Color(itemWithFeed.bgColor) Color(itemWithFeed.color)
} else { } else {
MaterialTheme.colorScheme.onBackground MaterialTheme.colorScheme.onBackground
} }
@ -249,8 +249,8 @@ fun BackgroundTitle(
itemWithFeed: ItemWithFeed, itemWithFeed: ItemWithFeed,
) { ) {
val onScrimColor = Color.White.copy(alpha = 0.85f) val onScrimColor = Color.White.copy(alpha = 0.85f)
val accentColor = if (itemWithFeed.bgColor != 0) { val accentColor = if (itemWithFeed.color != 0) {
Color(itemWithFeed.bgColor) Color(itemWithFeed.color)
} else { } else {
onScrimColor onScrimColor
} }

View File

@ -124,7 +124,7 @@ class LocalRSSRepository(
try { try {
iconUrl = HtmlParser.getFaviconLink(siteUrl!!, get()).also { feedUrl -> iconUrl = HtmlParser.getFaviconLink(siteUrl!!, get()).also { feedUrl ->
feedUrl?.let { backgroundColor = FeedColors.getFeedColor(it) } feedUrl?.let { color = FeedColors.getFeedColor(it) }
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.d("LocalRSSRepository", "insertFeed: ${e.message}") Log.d("LocalRSSRepository", "insertFeed: ${e.message}")

View File

@ -119,7 +119,7 @@ class SyncAnalyzer(
text = text, text = text,
largeIcon = icon, largeIcon = icon,
item = item, item = item,
color = feed.backgroundColor, color = feed.color,
accountId = account.id accountId = account.id
) )
} }

View File

@ -67,7 +67,6 @@ private val itemWithFeed = ItemWithFeed(
), ),
feedName = "feed name", feedName = "feed name",
color = 0, color = 0,
bgColor = 0,
feedId = 0, feedId = 0,
feedIconUrl = "", feedIconUrl = "",
websiteUrl = "", websiteUrl = "",

View File

@ -62,7 +62,7 @@ fun RegularTimelineItem(
TimelineItemHeader( TimelineItemHeader(
feedName = itemWithFeed.feedName, feedName = itemWithFeed.feedName,
feedIconUrl = itemWithFeed.feedIconUrl, feedIconUrl = itemWithFeed.feedIconUrl,
feedColor = itemWithFeed.bgColor, feedColor = itemWithFeed.color,
folderName = itemWithFeed.folder?.name, folderName = itemWithFeed.folder?.name,
date = itemWithFeed.item.pubDate!!, date = itemWithFeed.item.pubDate!!,
duration = itemWithFeed.item.readTime, duration = itemWithFeed.item.readTime,
@ -80,7 +80,7 @@ fun RegularTimelineItem(
TimelineItemBadge( TimelineItemBadge(
date = itemWithFeed.item.pubDate!!, date = itemWithFeed.item.pubDate!!,
duration = itemWithFeed.item.readTime, duration = itemWithFeed.item.readTime,
color = itemWithFeed.bgColor color = itemWithFeed.color
) )
} }
} }
@ -111,7 +111,7 @@ fun CompactTimelineItem(
TimelineItemHeader( TimelineItemHeader(
feedName = itemWithFeed.feedName, feedName = itemWithFeed.feedName,
feedIconUrl = itemWithFeed.feedIconUrl, feedIconUrl = itemWithFeed.feedIconUrl,
feedColor = itemWithFeed.bgColor, feedColor = itemWithFeed.color,
folderName = itemWithFeed.folder?.name, folderName = itemWithFeed.folder?.name,
onFavorite = onFavorite, onFavorite = onFavorite,
onShare = onShare, onShare = onShare,
@ -162,7 +162,7 @@ fun LargeTimelineItem(
TimelineItemHeader( TimelineItemHeader(
feedName = itemWithFeed.feedName, feedName = itemWithFeed.feedName,
feedIconUrl = itemWithFeed.feedIconUrl, feedIconUrl = itemWithFeed.feedIconUrl,
feedColor = itemWithFeed.bgColor, feedColor = itemWithFeed.color,
folderName = itemWithFeed.folder?.name, folderName = itemWithFeed.folder?.name,
date = itemWithFeed.item.pubDate!!, date = itemWithFeed.item.pubDate!!,
duration = itemWithFeed.item.readTime, duration = itemWithFeed.item.readTime,
@ -176,7 +176,7 @@ fun LargeTimelineItem(
TimelineItemBadge( TimelineItemBadge(
date = itemWithFeed.item.pubDate!!, date = itemWithFeed.item.pubDate!!,
duration = itemWithFeed.item.readTime, duration = itemWithFeed.item.readTime,
color = itemWithFeed.bgColor color = itemWithFeed.color
) )
ShortSpacer() ShortSpacer()

View File

@ -3,6 +3,7 @@ package com.readrops.app.util
import android.content.Context import android.content.Context
import android.graphics.Color import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.widget.Toast import android.widget.Toast
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.SystemBarStyle import androidx.activity.SystemBarStyle
@ -54,9 +55,17 @@ class CrashActivity : ComponentActivity() {
val throwable = intent.getSerializableExtra(THROWABLE_KEY) as Throwable? val throwable = intent.getSerializableExtra(THROWABLE_KEY) as Throwable?
val stackTrace = try {
throwable?.stackTraceToString()
} catch (e: Exception) {
Log.e("CrashActivity", "Unable to get crash exception")
null
}
setContent { setContent {
ReadropsTheme { ReadropsTheme {
CrashScreen(throwable?.stackTraceToString().orEmpty()) CrashScreen(stackTrace.orEmpty())
} }
} }
} }

View File

@ -2,11 +2,11 @@
"formatVersion": 1, "formatVersion": 1,
"database": { "database": {
"version": 4, "version": 4,
"identityHash": "6a1403979efe044075bf2f30a47a9e08", "identityHash": "1cd84a05829477201803f5f27275fe29",
"entities": [ "entities": [
{ {
"tableName": "Feed", "tableName": "Feed",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT, `description` TEXT, `url` TEXT, `siteUrl` TEXT, `lastUpdated` TEXT, `text_color` INTEGER NOT NULL, `background_color` INTEGER NOT NULL, `icon_url` TEXT, `etag` TEXT, `last_modified` TEXT, `folder_id` INTEGER, `remoteId` TEXT, `account_id` INTEGER NOT NULL, `notification_enabled` INTEGER NOT NULL DEFAULT 1, FOREIGN KEY(`folder_id`) REFERENCES `Folder`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL , FOREIGN KEY(`account_id`) REFERENCES `Account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT, `description` TEXT, `url` TEXT, `siteUrl` TEXT, `last_updated` TEXT, `color` INTEGER NOT NULL, `icon_url` TEXT, `etag` TEXT, `last_modified` TEXT, `folder_id` INTEGER, `remote_id` TEXT, `account_id` INTEGER NOT NULL, `notification_enabled` INTEGER NOT NULL DEFAULT 1, FOREIGN KEY(`folder_id`) REFERENCES `Folder`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL , FOREIGN KEY(`account_id`) REFERENCES `Account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [ "fields": [
{ {
"fieldPath": "id", "fieldPath": "id",
@ -40,19 +40,13 @@
}, },
{ {
"fieldPath": "lastUpdated", "fieldPath": "lastUpdated",
"columnName": "lastUpdated", "columnName": "last_updated",
"affinity": "TEXT", "affinity": "TEXT",
"notNull": false "notNull": false
}, },
{ {
"fieldPath": "textColor", "fieldPath": "color",
"columnName": "text_color", "columnName": "color",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "backgroundColor",
"columnName": "background_color",
"affinity": "INTEGER", "affinity": "INTEGER",
"notNull": true "notNull": true
}, },
@ -82,7 +76,7 @@
}, },
{ {
"fieldPath": "remoteId", "fieldPath": "remoteId",
"columnName": "remoteId", "columnName": "remote_id",
"affinity": "TEXT", "affinity": "TEXT",
"notNull": false "notNull": false
}, },
@ -526,7 +520,7 @@
"views": [], "views": [],
"setupQueries": [ "setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", "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, '6a1403979efe044075bf2f30a47a9e08')" "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '1cd84a05829477201803f5f27275fe29')"
] ]
} }
} }

View File

@ -3,7 +3,7 @@ package com.readrops.db
import androidx.room.testing.MigrationTestHelper import androidx.room.testing.MigrationTestHelper
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry
import junit.framework.Assert.assertEquals import junit.framework.TestCase.assertEquals
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith

View File

@ -83,6 +83,17 @@ object MigrationFrom3To4 : Migration(3, 4) {
db.execSQL("DROP TABLE IF EXISTS `Item`") db.execSQL("DROP TABLE IF EXISTS `Item`")
db.execSQL("ALTER TABLE `_new_Item` RENAME TO `Item`") db.execSQL("ALTER TABLE `_new_Item` RENAME TO `Item`")
db.execSQL("CREATE INDEX IF NOT EXISTS `index_Item_feed_id` ON `Item` (`feed_id`)") db.execSQL("CREATE INDEX IF NOT EXISTS `index_Item_feed_id` ON `Item` (`feed_id`)")
// remove text_color
// rename background_color to color
// rename remoteId to remote_id
// rename lastUpdated to last_updated
db.execSQL("CREATE TABLE IF NOT EXISTS `_new_Feed` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT, `description` TEXT, `url` TEXT, `siteUrl` TEXT, `last_updated` TEXT, `color` INTEGER NOT NULL, `icon_url` TEXT, `etag` TEXT, `last_modified` TEXT, `folder_id` INTEGER, `remote_id` TEXT, `account_id` INTEGER NOT NULL, `notification_enabled` INTEGER NOT NULL DEFAULT 1, FOREIGN KEY(`folder_id`) REFERENCES `Folder`(`id`) ON UPDATE NO ACTION ON DELETE SET NULL , FOREIGN KEY(`account_id`) REFERENCES `Account`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )")
db.execSQL("INSERT INTO `_new_Feed` (`id`, `name`, `description`, `url`, `siteUrl`, `last_updated`, `color`, `icon_url`, `etag`, `last_modified`, `folder_id`, `remote_id`, `account_id`, `notification_enabled`) SELECT `id`, `name`, `description`, `url`, `siteUrl`, `lastUpdated`, `background_color`, `icon_url`, `etag`, `last_modified`, `folder_id`, `remoteId`, `account_id`, `notification_enabled` FROM `Feed`")
db.execSQL("DROP TABLE IF EXISTS `Feed`")
db.execSQL("ALTER TABLE `_new_Feed` RENAME TO `Feed`")
db.execSQL("CREATE INDEX IF NOT EXISTS `index_Feed_folder_id` ON `Feed` (`folder_id`)")
db.execSQL("CREATE INDEX IF NOT EXISTS `index_Feed_account_id` ON `Feed` (`account_id`)")
} }
} }

View File

@ -39,22 +39,22 @@ abstract class FeedDao : BaseDao<Feed> {
@Query("Select count(*) from Feed Where account_id = :accountId") @Query("Select count(*) from Feed Where account_id = :accountId")
abstract suspend fun selectFeedCount(accountId: Int): Int abstract suspend fun selectFeedCount(accountId: Int): Int
@Query("Select remoteId From Feed Where account_id = :accountId") @Query("Select remote_id From Feed Where account_id = :accountId")
abstract suspend fun selectFeedRemoteIds(accountId: Int): MutableList<String> abstract suspend fun selectFeedRemoteIds(accountId: Int): MutableList<String>
@Query("Select id From Folder Where remoteId = :remoteId And account_id = :accountId") @Query("Select id From Folder Where remoteId = :remoteId And account_id = :accountId")
abstract suspend fun selectRemoteFolderLocalId(remoteId: String, accountId: Int): Int abstract suspend fun selectRemoteFolderLocalId(remoteId: String, accountId: Int): Int
@Query("Select id From Feed Where remoteId = :remoteId And account_id = :accountId") @Query("Select id From Feed Where remote_id = :remoteId And account_id = :accountId")
abstract suspend fun selectRemoteFeedLocalId(remoteId: String, accountId: Int): Int abstract suspend fun selectRemoteFeedLocalId(remoteId: String, accountId: Int): Int
@Query("Update Feed set name = :name, folder_id = :folderId Where remoteId = :remoteFeedId And account_id = :accountId") @Query("Update Feed set name = :name, folder_id = :folderId Where remote_id = :remoteFeedId And account_id = :accountId")
abstract fun updateFeedNameAndFolder(remoteFeedId: String, accountId: Int, name: String, folderId: Int?) abstract fun updateFeedNameAndFolder(remoteFeedId: String, accountId: Int, name: String, folderId: Int?)
@Query("Delete from Feed Where remoteId in (:ids) And account_id = :accountId") @Query("Delete from Feed Where remote_id in (:ids) And account_id = :accountId")
abstract fun deleteByIds(ids: List<String>, accountId: Int) abstract fun deleteByIds(ids: List<String>, accountId: Int)
@Query("Update Feed set background_color = :color Where id = :feedId") @Query("Update Feed set color = :color Where id = :feedId")
abstract fun updateFeedColor(feedId: Int, color: Int) abstract fun updateFeedColor(feedId: Int, color: Int)
@Query("""Select Feed.*, Folder.name as folder_name From Feed Left Join Folder On Feed.folder_id = Folder.id @Query("""Select Feed.*, Folder.name as folder_name From Feed Left Join Folder On Feed.folder_id = Folder.id

View File

@ -8,25 +8,39 @@ import androidx.room.Ignore
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import com.readrops.db.entities.account.Account import com.readrops.db.entities.account.Account
@Entity(foreignKeys = [ForeignKey(entity = Folder::class, parentColumns = ["id"], childColumns = ["folder_id"], @Entity(
onDelete = ForeignKey.SET_NULL), ForeignKey(entity = Account::class, parentColumns = ["id"], foreignKeys = [
childColumns = ["account_id"], onDelete = ForeignKey.CASCADE)]) ForeignKey(
entity = Folder::class,
parentColumns = ["id"],
childColumns = ["folder_id"],
onDelete = ForeignKey.SET_NULL
), ForeignKey(
entity = Account::class,
parentColumns = ["id"],
childColumns = ["account_id"],
onDelete = ForeignKey.CASCADE
)
]
)
data class Feed( data class Feed(
@PrimaryKey(autoGenerate = true) var id: Int = 0, @PrimaryKey(autoGenerate = true) var id: Int = 0,
var name: String? = null, var name: String? = null,
var description: String? = null, var description: String? = null,
var url: String? = null, var url: String? = null,
var siteUrl: String? = null, var siteUrl: String? = null,
var lastUpdated: String? = null, @ColumnInfo("last_updated") var lastUpdated: String? = null,
@ColumnInfo(name = "text_color") @ColorInt var textColor: Int = 0, @ColorInt var color: Int = 0,
@ColumnInfo(name = "background_color") @ColorInt var backgroundColor: Int = 0,
@ColumnInfo(name = "icon_url") var iconUrl: String? = null, @ColumnInfo(name = "icon_url") var iconUrl: String? = null,
var etag: String? = null, var etag: String? = null,
@ColumnInfo(name = "last_modified") var lastModified: String? = null, @ColumnInfo(name = "last_modified") var lastModified: String? = null,
@ColumnInfo(name = "folder_id", index = true) var folderId: Int? = null, @ColumnInfo(name = "folder_id", index = true) var folderId: Int? = null,
var remoteId: String? = null, @ColumnInfo("remote_id") var remoteId: String? = null,
@ColumnInfo(name = "account_id", index = true) var accountId: Int = 0, @ColumnInfo(name = "account_id", index = true) var accountId: Int = 0,
@ColumnInfo(name = "notification_enabled", defaultValue = "1") var isNotificationEnabled: Boolean = true, @ColumnInfo(
name = "notification_enabled",
defaultValue = "1"
) var isNotificationEnabled: Boolean = true,
@Ignore var unreadCount: Int = 0, @Ignore var unreadCount: Int = 0,
@Ignore var remoteFolderId: String? = null, @Ignore var remoteFolderId: String? = null,
) )

View File

@ -10,9 +10,8 @@ data class ItemWithFeed(
@Embedded val item: Item, @Embedded val item: Item,
@ColumnInfo(name = "name") val feedName: String, @ColumnInfo(name = "name") val feedName: String,
@ColumnInfo(name = "feedId") val feedId: Int, @ColumnInfo(name = "feedId") val feedId: Int,
@ColumnInfo(name = "text_color") @ColorInt val color: Int, @ColumnInfo(name = "color") @ColorInt val color: Int,
@ColumnInfo(name = "background_color") @ColorInt val bgColor: Int,
@ColumnInfo(name = "icon_url") val feedIconUrl: String?, @ColumnInfo(name = "icon_url") val feedIconUrl: String?,
@ColumnInfo(name = "siteUrl") val websiteUrl: String?, @ColumnInfo(name = "siteUrl") val websiteUrl: String?,
@Embedded(prefix = "folder_") val folder: Folder?, @Embedded(prefix = "folder_") val folder: Folder?
) )

View File

@ -13,7 +13,7 @@ object FoldersAndFeedsQueryBuilder {
"Feed.url As feedUrl", "Feed.url As feedUrl",
"Feed.siteUrl As feedSiteUrl", "Feed.siteUrl As feedSiteUrl",
"Feed.description as feedDescription", "Feed.description as feedDescription",
"Feed.remoteId as feedRemoteId", "Feed.remote_id as feedRemoteId",
"Folder.id As folderId", "Folder.id As folderId",
"Folder.name As folderName", "Folder.name As folderName",
"Feed.account_id as accountId", "Feed.account_id as accountId",

View File

@ -6,10 +6,24 @@ import androidx.sqlite.db.SupportSQLiteQueryBuilder
object ItemSelectionQueryBuilder { object ItemSelectionQueryBuilder {
private val COLUMNS = arrayOf( private val COLUMNS = arrayOf(
"Item.id", "Item.remoteId", "title", "Item.description", "content", "Item.id",
"link", "pub_date", "image_link", "author", "Item.read", "text_color", "icon_url", "Item.remote_id",
"background_color", "read_time", "Feed.name", "Feed.id as feedId", "siteUrl", "title",
"Folder.id as folder_id", "Folder.name as folder_name" "Item.description",
"content",
"link",
"pub_date",
"image_link",
"author",
"Item.read",
"icon_url",
"color",
"read_time",
"Feed.name",
"Feed.id as feedId",
"siteUrl",
"Folder.id as folder_id",
"Folder.name as folder_name"
) )
private val SEPARATE_STATE_COLUMNS = private val SEPARATE_STATE_COLUMNS =
@ -19,7 +33,7 @@ object ItemSelectionQueryBuilder {
"Item Inner Join Feed On Item.feed_id = Feed.id Left Join Folder on Folder.id = Feed.folder_id" "Item Inner Join Feed On Item.feed_id = Feed.id Left Join Folder on Folder.id = Feed.folder_id"
private const val SEPARATE_STATE_JOIN = private const val SEPARATE_STATE_JOIN =
" Left Join ItemState On ItemState.remote_id = Item.remoteId" " Left Join ItemState On ItemState.remote_id = Item.remote_id"
/** /**
* @param separateState Indicates if item state must be retrieved from ItemState table * @param separateState Indicates if item state must be retrieved from ItemState table

View File

@ -17,8 +17,7 @@ object ItemsQueryBuilder {
"pub_date", "pub_date",
"link", "link",
"Feed.name", "Feed.name",
"text_color", "color",
"background_color",
"icon_url", "icon_url",
"read_time", "read_time",
"Feed.id as feedId", "Feed.id as feedId",