Skip to content

Commit

Permalink
[feature|fix] Support for grouping RSS; fix #18, #19
Browse files Browse the repository at this point in the history
  • Loading branch information
SkyD666 committed Apr 24, 2024
1 parent bbb85e8 commit d6bafb6
Show file tree
Hide file tree
Showing 27 changed files with 1,269 additions and 373 deletions.
6 changes: 3 additions & 3 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ android {
applicationId = "com.skyd.anivu"
minSdk = 24
targetSdk = 34
versionCode = 13
versionName = "1.1-beta12"
versionCode = 14
versionName = "1.1-beta13"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

Expand Down Expand Up @@ -148,7 +148,7 @@ dependencies {
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.7.0")
implementation("androidx.compose.ui:ui:1.6.5")
implementation("androidx.compose.material:material:1.6.5")
implementation("androidx.compose.material3:material3:1.2.1")
implementation("androidx.compose.material3:material3:1.3.0-alpha05")
implementation("androidx.compose.material3:material3-window-size-class:1.2.1")
implementation("androidx.compose.material:material-icons-extended:1.6.5")
implementation("com.materialkolor:material-kolor:1.4.4")
Expand Down
5 changes: 5 additions & 0 deletions app/src/main/java/com/skyd/anivu/di/DatabaseModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.skyd.anivu.model.db.dao.ArticleDao
import com.skyd.anivu.model.db.dao.DownloadInfoDao
import com.skyd.anivu.model.db.dao.EnclosureDao
import com.skyd.anivu.model.db.dao.FeedDao
import com.skyd.anivu.model.db.dao.GroupDao
import com.skyd.anivu.model.db.dao.SearchDomainDao
import com.skyd.anivu.model.db.dao.SessionParamsDao
import com.skyd.anivu.model.db.dao.TorrentFileDao
Expand All @@ -26,6 +27,10 @@ object DatabaseModule {
fun provideAppDatabase(@ApplicationContext context: Context): AppDatabase =
AppDatabase.getInstance(context)

@Provides
@Singleton
fun provideGroupDao(database: AppDatabase): GroupDao = database.groupDao()

@Provides
@Singleton
fun provideFeedDao(database: AppDatabase): FeedDao = database.feedDao()
Expand Down
14 changes: 14 additions & 0 deletions app/src/main/java/com/skyd/anivu/ext/CollectionExt.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.skyd.anivu.ext

import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.saveable.Saver
import androidx.compose.runtime.snapshots.SnapshotStateMap
import androidx.compose.runtime.toMutableStateMap

fun <K, V> snapshotStateMapSaver() = Saver<SnapshotStateMap<K, V>, Any>(
save = { state -> state.toList() },
restore = { value ->
@Suppress("UNCHECKED_CAST")
(value as? List<Pair<K, V>>)?.toMutableStateMap() ?: mutableStateMapOf()
}
)
6 changes: 6 additions & 0 deletions app/src/main/java/com/skyd/anivu/model/bean/FeedBean.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,18 @@ data class FeedBean(
var link: String? = null,
@ColumnInfo(name = ICON_COLUMN)
var icon: String? = null,
@ColumnInfo(name = GROUP_ID_COLUMN)
var groupId: String? = null,
@ColumnInfo(name = NICKNAME_COLUMN)
var nickname: String? = null,
) : BaseBean, Parcelable {
companion object {
const val URL_COLUMN = "url"
const val TITLE_COLUMN = "title"
const val DESCRIPTION_COLUMN = "description"
const val LINK_COLUMN = "link"
const val ICON_COLUMN = "icon"
const val GROUP_ID_COLUMN = "groupId"
const val NICKNAME_COLUMN = "nickname"
}
}
36 changes: 36 additions & 0 deletions app/src/main/java/com/skyd/anivu/model/bean/GroupBean.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.skyd.anivu.model.bean

import android.os.Parcelable
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.skyd.anivu.R
import com.skyd.anivu.appContext
import com.skyd.anivu.base.BaseBean
import kotlinx.parcelize.Parcelize
import kotlinx.serialization.Serializable

const val GROUP_TABLE_NAME = "Group"

@Parcelize
@Serializable
@Entity(tableName = GROUP_TABLE_NAME)
data class GroupBean(
@PrimaryKey
@ColumnInfo(name = GROUP_ID_COLUMN)
val groupId: String,
@ColumnInfo(name = NAME_COLUMN)
val name: String,
) : BaseBean, Parcelable {
companion object {
const val DEFAULT_GROUP_ID = "default"

const val NAME_COLUMN = "name"
const val GROUP_ID_COLUMN = "groupId"

val defaultGroup = GroupBean(
groupId = DEFAULT_GROUP_ID,
name = appContext.getString(R.string.default_feed_group)
)
}
}
17 changes: 17 additions & 0 deletions app/src/main/java/com/skyd/anivu/model/bean/GroupWithFeedBean.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.skyd.anivu.model.bean

import androidx.room.Embedded
import androidx.room.Relation

/**
* A [group] contains many [feeds].
*/
data class GroupWithFeedBean(
@Embedded
var group: GroupBean,
@Relation(
parentColumn = GroupBean.GROUP_ID_COLUMN,
entityColumn = FeedBean.GROUP_ID_COLUMN,
)
var feeds: List<FeedBean>,
)
10 changes: 7 additions & 3 deletions app/src/main/java/com/skyd/anivu/model/db/AppDatabase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import androidx.room.TypeConverters
import com.skyd.anivu.model.bean.ArticleBean
import com.skyd.anivu.model.bean.EnclosureBean
import com.skyd.anivu.model.bean.FeedBean
import com.skyd.anivu.model.bean.GroupBean
import com.skyd.anivu.model.bean.download.DownloadInfoBean
import com.skyd.anivu.model.bean.download.DownloadLinkUuidMapBean
import com.skyd.anivu.model.bean.download.SessionParamsBean
Expand All @@ -16,10 +17,12 @@ import com.skyd.anivu.model.db.dao.ArticleDao
import com.skyd.anivu.model.db.dao.DownloadInfoDao
import com.skyd.anivu.model.db.dao.EnclosureDao
import com.skyd.anivu.model.db.dao.FeedDao
import com.skyd.anivu.model.db.dao.GroupDao
import com.skyd.anivu.model.db.dao.SessionParamsDao
import com.skyd.anivu.model.db.dao.TorrentFileDao
import com.skyd.anivu.model.db.migration.Migration1To2
import com.skyd.anivu.model.db.migration.Migration2To3
import com.skyd.anivu.model.db.migration.Migration3To4

const val APP_DATA_BASE_FILE_NAME = "app.db"

Expand All @@ -32,14 +35,15 @@ const val APP_DATA_BASE_FILE_NAME = "app.db"
DownloadLinkUuidMapBean::class,
SessionParamsBean::class,
TorrentFileBean::class,
GroupBean::class,
],
version = 3
version = 4
)
@TypeConverters(
value = []
)
abstract class AppDatabase : RoomDatabase() {

abstract fun groupDao(): GroupDao
abstract fun feedDao(): FeedDao
abstract fun articleDao(): ArticleDao
abstract fun enclosureDao(): EnclosureDao
Expand All @@ -51,7 +55,7 @@ abstract class AppDatabase : RoomDatabase() {
@Volatile
private var instance: AppDatabase? = null

private val migrations = arrayOf(Migration1To2(), Migration2To3())
private val migrations = arrayOf(Migration1To2(), Migration2To3(), Migration3To4())

fun getInstance(context: Context): AppDatabase {
return if (instance == null) {
Expand Down
42 changes: 41 additions & 1 deletion app/src/main/java/com/skyd/anivu/model/db/dao/FeedDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import com.skyd.anivu.appContext
import com.skyd.anivu.model.bean.FEED_TABLE_NAME
import com.skyd.anivu.model.bean.FeedBean
import com.skyd.anivu.model.bean.FeedWithArticleBean
import com.skyd.anivu.model.bean.GROUP_TABLE_NAME
import com.skyd.anivu.model.bean.GroupBean
import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn
import dagger.hilt.android.EntryPointAccessors
Expand Down Expand Up @@ -63,6 +65,34 @@ interface FeedDao {
@Query("DELETE FROM $FEED_TABLE_NAME WHERE ${FeedBean.URL_COLUMN} = :url")
suspend fun removeFeed(url: String): Int

@Transaction
@Query("DELETE FROM $FEED_TABLE_NAME WHERE ${FeedBean.GROUP_ID_COLUMN} = :groupId")
suspend fun removeFeedByGroupId(groupId: String): Int

@Transaction
@Query(
"""
UPDATE $FEED_TABLE_NAME
SET ${FeedBean.GROUP_ID_COLUMN} = :groupId
WHERE ${FeedBean.URL_COLUMN} = :feedUrl
"""
)
suspend fun updateFeedGroupId(feedUrl: String, groupId: String?): Int

@Transaction
@Query(
"""
UPDATE $FEED_TABLE_NAME
SET ${FeedBean.GROUP_ID_COLUMN} = :toGroupId
WHERE :fromGroupId IS NULL AND ${FeedBean.GROUP_ID_COLUMN} IS NULL OR
${FeedBean.GROUP_ID_COLUMN} = :fromGroupId OR
:fromGroupId IS NULL AND ${FeedBean.GROUP_ID_COLUMN} NOT IN (
SELECT DISTINCT ${GroupBean.GROUP_ID_COLUMN} FROM `$GROUP_TABLE_NAME`
)
"""
)
suspend fun moveFeedToGroup(fromGroupId: String?, toGroupId: String?): Int

@Transaction
@Query("SELECT * FROM $FEED_TABLE_NAME")
fun getFeedPagingSource(): PagingSource<Int, FeedBean>
Expand All @@ -71,13 +101,23 @@ interface FeedDao {
@Query("SELECT * FROM $FEED_TABLE_NAME WHERE ${FeedBean.URL_COLUMN} = :feedUrl")
suspend fun getFeed(feedUrl: String): FeedBean

@Transaction
@Query(
"""
SELECT * FROM $FEED_TABLE_NAME
WHERE ${FeedBean.GROUP_ID_COLUMN} IS NULL OR
${FeedBean.GROUP_ID_COLUMN} NOT IN (:groupIds)
"""
)
suspend fun getFeedsNotIn(groupIds: List<String>): List<FeedBean>

@Transaction
@RawQuery(observedEntities = [FeedBean::class])
fun getFeedPagingSource(sql: SupportSQLiteQuery): PagingSource<Int, FeedBean>

@Transaction
@RawQuery(observedEntities = [FeedBean::class])
fun getFeedListPagingSource(sql: SupportSQLiteQuery): List<FeedBean>
fun getFeedList(sql: SupportSQLiteQuery): List<FeedBean>

@Transaction
@Query("SELECT ${FeedBean.URL_COLUMN} FROM $FEED_TABLE_NAME")
Expand Down
61 changes: 61 additions & 0 deletions app/src/main/java/com/skyd/anivu/model/db/dao/GroupDao.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.skyd.anivu.model.db.dao

import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import com.skyd.anivu.appContext
import com.skyd.anivu.model.bean.GROUP_TABLE_NAME
import com.skyd.anivu.model.bean.GroupBean
import com.skyd.anivu.model.bean.GroupWithFeedBean
import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn
import dagger.hilt.android.EntryPointAccessors
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.flow.Flow

@Dao
interface GroupDao {
@EntryPoint
@InstallIn(SingletonComponent::class)
interface GroupDaoEntryPoint {
val feedDao: FeedDao
}

@Transaction
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun setGroup(groupBean: GroupBean)

@Transaction
@Delete
suspend fun removeGroup(groupBean: GroupBean): Int

@Transaction
@Query("DELETE FROM `$GROUP_TABLE_NAME` WHERE ${GroupBean.GROUP_ID_COLUMN} = :groupId")
suspend fun removeGroup(groupId: String): Int

@Transaction
suspend fun removeGroupWithFeed(groupId: String): Int {
removeGroup(groupId)
return EntryPointAccessors.fromApplication(appContext, GroupDaoEntryPoint::class.java).run {
feedDao.removeFeedByGroupId(groupId)
}
}

@Transaction
suspend fun moveGroupFeedsTo(fromGroupId: String?, toGroupId: String?): Int {
return EntryPointAccessors.fromApplication(appContext, GroupDaoEntryPoint::class.java).run {
feedDao.moveFeedToGroup(fromGroupId = fromGroupId, toGroupId = toGroupId)
}
}

@Transaction
@Query("SELECT * FROM `$GROUP_TABLE_NAME`")
fun getGroupWithFeeds(): Flow<List<GroupWithFeedBean>>

@Transaction
@Query("SELECT DISTINCT ${GroupBean.GROUP_ID_COLUMN} FROM `$GROUP_TABLE_NAME`")
fun getGroupIds(): Flow<List<String>>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.skyd.anivu.model.db.migration

import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import com.skyd.anivu.model.bean.FEED_TABLE_NAME
import com.skyd.anivu.model.bean.FeedBean
import com.skyd.anivu.model.bean.GROUP_TABLE_NAME
import com.skyd.anivu.model.bean.GroupBean

class Migration3To4 : Migration(3, 4) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
"""
CREATE TABLE `$GROUP_TABLE_NAME` (
${GroupBean.GROUP_ID_COLUMN} TEXT NOT NULL PRIMARY KEY,
${GroupBean.NAME_COLUMN} TEXT NOT NULL
)
"""
)
db.execSQL("ALTER TABLE $FEED_TABLE_NAME ADD ${FeedBean.GROUP_ID_COLUMN} TEXT")
db.execSQL("ALTER TABLE $FEED_TABLE_NAME ADD ${FeedBean.NICKNAME_COLUMN} TEXT")
}
}
Loading

0 comments on commit d6bafb6

Please sign in to comment.