Skip to content

Commit

Permalink
[feature] Support search feeds or articles
Browse files Browse the repository at this point in the history
  • Loading branch information
SkyD666 committed Feb 16, 2024
1 parent 8e07b80 commit 260765a
Show file tree
Hide file tree
Showing 41 changed files with 981 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.skyd.anivu.model.preference
package com.skyd.anivu.base

import androidx.datastore.preferences.core.Preferences

Expand Down
23 changes: 23 additions & 0 deletions app/src/main/java/com/skyd/anivu/config/SearchConfig.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.skyd.anivu.config

import com.skyd.anivu.model.bean.ARTICLE_TABLE_NAME
import com.skyd.anivu.model.bean.ArticleBean
import com.skyd.anivu.model.bean.FEED_TABLE_NAME
import com.skyd.anivu.model.bean.FeedBean

val allSearchDomain: HashMap<String, List<String>> = hashMapOf(
FEED_TABLE_NAME to listOf(
FeedBean.URL_COLUMN,
FeedBean.TITLE_COLUMN,
FeedBean.DESCRIPTION_COLUMN,
FeedBean.LINK_COLUMN,
FeedBean.ICON_COLUMN,
),
ARTICLE_TABLE_NAME to listOf(
ArticleBean.TITLE_COLUMN,
ArticleBean.AUTHOR_COLUMN,
ArticleBean.DESCRIPTION_COLUMN,
ArticleBean.CONTENT_COLUMN,
ArticleBean.LINK_COLUMN,
),
)
14 changes: 14 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 @@ -2,10 +2,12 @@ package com.skyd.anivu.di

import android.content.Context
import com.skyd.anivu.model.db.AppDatabase
import com.skyd.anivu.model.db.SearchDomainDatabase
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.SearchDomainDao
import com.skyd.anivu.model.db.dao.SessionParamsDao
import dagger.Module
import dagger.Provides
Expand Down Expand Up @@ -43,4 +45,16 @@ object DatabaseModule {
@Singleton
fun provideSessionParamsDao(database: AppDatabase): SessionParamsDao =
database.sessionParamsDao()


@Provides
@Singleton
fun provideSearchDomainDatabase(@ApplicationContext context: Context): SearchDomainDatabase =
SearchDomainDatabase.getInstance(context)

@Provides
@Singleton
fun provideSearchDomain(database: SearchDomainDatabase): SearchDomainDao =
database.searchDomainDao()

}
9 changes: 9 additions & 0 deletions app/src/main/java/com/skyd/anivu/ext/BundleExt.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.skyd.anivu.ext

import android.os.Bundle

inline fun <reified T : Enum<T>> Bundle.getEnum(key: String, default: T) =
getInt(key, -1).let { if (it >= 0) enumValues<T>()[it] else default }

fun <T : Enum<T>> Bundle.putEnum(key: String, value: T?) =
putInt(key, value?.ordinal ?: -1)
57 changes: 57 additions & 0 deletions app/src/main/java/com/skyd/anivu/ext/DataStoreExt.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.skyd.anivu.ext

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.emptyPreferences
import androidx.datastore.preferences.preferencesDataStore
import com.skyd.anivu.base.BasePreference
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import java.io.IOException

val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "App")

suspend fun <T> DataStore<Preferences>.put(key: Preferences.Key<T>, value: T) {
this.edit {
withContext(Dispatchers.IO) {
it[key] = value
}
}
}

@Suppress("UNCHECKED_CAST")
fun <T> DataStore<Preferences>.getOrNull(key: Preferences.Key<T>): T? {
return runBlocking {
this@getOrNull.data.catch { exception ->
if (exception is IOException) {
exception.printStackTrace()
emit(emptyPreferences())
} else {
throw exception
}
}.map {
it[key]
}.first() as T
}
}

fun <T> DataStore<Preferences>.getOrDefault(pref: BasePreference<T>): T {
return runBlocking {
this@getOrDefault.data.catch { exception ->
if (exception is IOException) {
exception.printStackTrace()
emit(emptyPreferences())
} else {
throw exception
}
}.map {
pref.fromPreferences(it)
}.first()
}
}
29 changes: 29 additions & 0 deletions app/src/main/java/com/skyd/anivu/model/bean/SearchDomainBean.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.skyd.anivu.model.bean

import androidx.room.ColumnInfo
import androidx.room.Entity
import com.skyd.anivu.base.BaseBean
import kotlinx.serialization.Serializable

const val SEARCH_DOMAIN_TABLE_NAME = "SearchDomain"

@Serializable
@Entity(
tableName = SEARCH_DOMAIN_TABLE_NAME,
primaryKeys = [SearchDomainBean.TABLE_NAME_COLUMN, SearchDomainBean.COLUMN_NAME_COLUMN]
)
data class SearchDomainBean(
@ColumnInfo(name = TABLE_NAME_COLUMN)
var tableName: String,
@ColumnInfo(name = COLUMN_NAME_COLUMN)
var columnName: String,
@ColumnInfo(name = SEARCH_COLUMN)
var search: Boolean,
) : BaseBean {
companion object {
const val TABLE_NAME_COLUMN = "tableName"
const val COLUMN_NAME_COLUMN = "columnName"
const val SEARCH_COLUMN = "search"
}
}

4 changes: 2 additions & 2 deletions app/src/main/java/com/skyd/anivu/model/db/AppDatabase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import androidx.room.migration.Migration
import com.skyd.anivu.model.bean.ArticleBean
import com.skyd.anivu.model.bean.DownloadInfoBean
import com.skyd.anivu.model.bean.EnclosureBean
import com.skyd.anivu.model.bean.FeedBean
import com.skyd.anivu.model.bean.SessionParamsBean
import com.skyd.anivu.model.bean.DownloadInfoBean
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.SessionParamsDao
import com.skyd.anivu.model.db.dao.DownloadInfoDao

const val APP_DATA_BASE_FILE_NAME = "app.db"

Expand Down
53 changes: 53 additions & 0 deletions app/src/main/java/com/skyd/anivu/model/db/SearchDomainDatabase.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.skyd.anivu.model.db

import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import androidx.room.migration.Migration
import com.skyd.anivu.model.bean.SearchDomainBean
import com.skyd.anivu.model.db.dao.SearchDomainDao

const val SEARCH_DOMAIN_DATA_BASE_FILE_NAME = "searchDomain.db"

@Database(
entities = [
SearchDomainBean::class,
],
version = 1
)
@TypeConverters(
value = []
)
abstract class SearchDomainDatabase : RoomDatabase() {

abstract fun searchDomainDao(): SearchDomainDao

companion object {
@Volatile
private var instance: SearchDomainDatabase? = null

private val migrations = arrayOf<Migration>()

fun getInstance(context: Context): SearchDomainDatabase {
return if (instance == null) {
synchronized(this) {
if (instance == null) {
Room.databaseBuilder(
context.applicationContext,
SearchDomainDatabase::class.java,
SEARCH_DOMAIN_DATA_BASE_FILE_NAME
)
.addMigrations(*migrations)
.build()
} else {
instance as SearchDomainDatabase
}
}
} else {
instance as SearchDomainDatabase
}
}
}
}
9 changes: 7 additions & 2 deletions app/src/main/java/com/skyd/anivu/model/db/dao/ArticleDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.RawQuery
import androidx.room.RewriteQueriesToDropUnusedColumns
import androidx.room.Transaction
import androidx.sqlite.db.SupportSQLiteQuery
import com.skyd.anivu.appContext
import com.skyd.anivu.model.bean.ARTICLE_TABLE_NAME
import com.skyd.anivu.model.bean.ArticleBean
import com.skyd.anivu.model.bean.ArticleWithEnclosureBean
import com.skyd.anivu.model.bean.FEED_TABLE_NAME
import com.skyd.anivu.model.bean.FeedBean
import com.skyd.anivu.model.db.APP_DATA_BASE_FILE_NAME
import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn
import dagger.hilt.android.EntryPointAccessors
Expand Down Expand Up @@ -76,12 +77,16 @@ interface ArticleDao {
@Query(
"""
SELECT * FROM $ARTICLE_TABLE_NAME
WHERE ${ArticleBean.FEED_URL_COLUMN} LIKE :feedUrl
WHERE ${ArticleBean.FEED_URL_COLUMN} = :feedUrl
ORDER BY ${ArticleBean.DATE_COLUMN} DESC
"""
)
fun getArticleList(feedUrl: String): Flow<List<ArticleBean>>

@Transaction
@RawQuery(observedEntities = [ArticleBean::class])
fun getArticleList(sql: SupportSQLiteQuery): Flow<List<ArticleBean>>

@Transaction
@Query(
"""
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/java/com/skyd/anivu/model/db/dao/FeedDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.RawQuery
import androidx.room.Transaction
import androidx.sqlite.db.SupportSQLiteQuery
import com.skyd.anivu.appContext
import com.skyd.anivu.model.bean.FEED_TABLE_NAME
import com.skyd.anivu.model.bean.FeedBean
Expand Down Expand Up @@ -68,4 +70,8 @@ interface FeedDao {
@Transaction
@Query("SELECT * FROM $FEED_TABLE_NAME WHERE ${FeedBean.URL_COLUMN} = :feedUrl")
suspend fun getFeed(feedUrl: String): FeedBean

@Transaction
@RawQuery(observedEntities = [FeedBean::class])
fun getFeedList(sql: SupportSQLiteQuery): Flow<List<FeedBean>>
}
41 changes: 41 additions & 0 deletions app/src/main/java/com/skyd/anivu/model/db/dao/SearchDomainDao.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.skyd.anivu.model.db.dao

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import com.skyd.anivu.model.bean.SEARCH_DOMAIN_TABLE_NAME
import com.skyd.anivu.model.bean.SearchDomainBean
import com.skyd.anivu.model.bean.SearchDomainBean.Companion.COLUMN_NAME_COLUMN
import com.skyd.anivu.model.bean.SearchDomainBean.Companion.SEARCH_COLUMN
import com.skyd.anivu.model.bean.SearchDomainBean.Companion.TABLE_NAME_COLUMN

@Dao
interface SearchDomainDao {
@Transaction
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun setSearchDomain(searchDomainBean: SearchDomainBean)

@Transaction
@Query(
"""SELECT $SEARCH_COLUMN FROM $SEARCH_DOMAIN_TABLE_NAME
WHERE $TABLE_NAME_COLUMN LIKE :tableName AND $COLUMN_NAME_COLUMN LIKE :columnName"""
)
fun getSearchDomainOrNull(tableName: String, columnName: String): Boolean?

// 被选择的搜索域的个数
@Transaction
@Query("SELECT COUNT(*) FROM $SEARCH_DOMAIN_TABLE_NAME WHERE $SEARCH_COLUMN = 1")
fun selectedSearchDomainCount(): Int

@Transaction
fun getSearchDomain(tableName: String, columnName: String): Boolean {
val result = getSearchDomainOrNull(tableName, columnName)
return result == true || selectedSearchDomainCount() == 0
}

@Transaction
@Query(value = "SELECT * FROM $SEARCH_DOMAIN_TABLE_NAME")
fun getAllSearchDomain(): List<SearchDomainBean>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.skyd.anivu.model.preference.search

import android.content.Context
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import com.skyd.anivu.base.BasePreference
import com.skyd.anivu.ext.dataStore
import com.skyd.anivu.ext.put
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

object IntersectSearchBySpacePreference : BasePreference<Boolean> {
private const val INTERSECT_SEARCH_BY_SPACE = "intersectSearchBySpace"
override val default = true

val key = booleanPreferencesKey(INTERSECT_SEARCH_BY_SPACE)

fun put(context: Context, scope: CoroutineScope, value: Boolean) {
scope.launch(Dispatchers.IO) {
context.dataStore.put(key, value)
}
}

override fun fromPreferences(preferences: Preferences): Boolean = preferences[key] ?: default
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.skyd.anivu.model.preference.search

import android.content.Context
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import com.skyd.anivu.base.BasePreference
import com.skyd.anivu.ext.dataStore
import com.skyd.anivu.ext.put
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

object UseRegexSearchPreference : BasePreference<Boolean> {
private const val USE_REGEX_SEARCH = "useRegexSearch"
override val default = false

val key = booleanPreferencesKey(USE_REGEX_SEARCH)

fun put(context: Context, scope: CoroutineScope, value: Boolean) {
scope.launch(Dispatchers.IO) {
context.dataStore.put(key, value)
}
}

override fun fromPreferences(preferences: Preferences): Boolean = preferences[key] ?: default
}
Loading

0 comments on commit 260765a

Please sign in to comment.