Skip to content

Commit

Permalink
[feature] Support #84
Browse files Browse the repository at this point in the history
  • Loading branch information
SkyD666 committed Feb 12, 2025
1 parent bf65961 commit f205d1a
Show file tree
Hide file tree
Showing 23 changed files with 301 additions and 40 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ android {
applicationId = "com.skyd.anivu"
minSdk = 24
targetSdk = 35
versionCode = 25
versionName = "3.1-alpha01"
versionCode = 26
versionName = "3.1-alpha02"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/com/skyd/anivu/ext/PreferenceExt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import com.skyd.anivu.model.preference.appearance.feed.FeedDefaultGroupExpandPre
import com.skyd.anivu.model.preference.appearance.feed.FeedListTonalElevationPreference
import com.skyd.anivu.model.preference.appearance.feed.FeedNumberBadgePreference
import com.skyd.anivu.model.preference.appearance.feed.FeedTopBarTonalElevationPreference
import com.skyd.anivu.model.preference.appearance.feed.HideMutedFeedPreference
import com.skyd.anivu.model.preference.appearance.media.MediaFileFilterPreference
import com.skyd.anivu.model.preference.appearance.media.MediaShowGroupTabPreference
import com.skyd.anivu.model.preference.appearance.media.MediaShowThumbnailPreference
Expand Down Expand Up @@ -92,6 +93,7 @@ fun Preferences.toSettings(): Settings {
readContentTonalElevation = ReadContentTonalElevationPreference.fromPreferences(this),
readTopBarTonalElevation = ReadTopBarTonalElevationPreference.fromPreferences(this),
feedNumberBadge = FeedNumberBadgePreference.fromPreferences(this),
hideMutedFeed = HideMutedFeedPreference.fromPreferences(this),

// Update
ignoreUpdateVersion = IgnoreUpdateVersionPreference.fromPreferences(this),
Expand Down
9 changes: 9 additions & 0 deletions app/src/main/java/com/skyd/anivu/model/bean/feed/FeedBean.kt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ data class FeedBean(
val sortXmlArticlesOnUpdate: Boolean = false,
@ColumnInfo(name = REQUEST_HEADERS_COLUMN)
val requestHeaders: RequestHeaders? = null,
@ColumnInfo(name = MUTE_COLUMN)
val mute: Boolean = false,
@ColumnInfo(name = PREVIOUS_FEED_URL_COLUMN)
val previousFeedUrl: String? = null,
@ColumnInfo(name = NEXT_FEED_URL_COLUMN)
val nextFeedUrl: String? = null,
) : BaseBean, Parcelable {
companion object {
const val URL_COLUMN = "url"
Expand All @@ -51,6 +57,9 @@ data class FeedBean(
const val CUSTOM_ICON_COLUMN = "customIcon"
const val SORT_XML_ARTICLES_ON_UPDATE_COLUMN = "sortXmlArticlesOnUpdate"
const val REQUEST_HEADERS_COLUMN = "requestHeaders"
const val MUTE_COLUMN = "mute"
const val PREVIOUS_FEED_URL_COLUMN = "previousFeedUrl"
const val NEXT_FEED_URL_COLUMN = "nextFeedUrl"

fun FeedBean.isDefaultGroup(): Boolean =
this.groupId == null || this.groupId == GroupVo.DEFAULT_GROUP_ID
Expand Down
5 changes: 3 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 @@ -35,6 +35,7 @@ import com.skyd.anivu.model.db.migration.Migration12To13
import com.skyd.anivu.model.db.migration.Migration13To14
import com.skyd.anivu.model.db.migration.Migration14To15
import com.skyd.anivu.model.db.migration.Migration15To16
import com.skyd.anivu.model.db.migration.Migration16To17
import com.skyd.anivu.model.db.migration.Migration1To2
import com.skyd.anivu.model.db.migration.Migration2To3
import com.skyd.anivu.model.db.migration.Migration3To4
Expand Down Expand Up @@ -62,7 +63,7 @@ const val APP_DATA_BASE_FILE_NAME = "app.db"
RssMediaBean::class,
],
views = [FeedViewBean::class],
version = 16,
version = 17,
)
@TypeConverters(
value = [CategoriesConverter::class, RequestHeadersConverter::class]
Expand All @@ -87,7 +88,7 @@ abstract class AppDatabase : RoomDatabase() {
Migration1To2(), Migration2To3(), Migration3To4(), Migration4To5(),
Migration5To6(), Migration6To7(), Migration7To8(), Migration8To9(),
Migration9To10(), Migration10To11(), Migration11To12(), Migration12To13(),
Migration13To14(), Migration14To15(), Migration15To16(),
Migration13To14(), Migration14To15(), Migration15To16(), Migration16To17(),
)

fun getInstance(context: Context): AppDatabase {
Expand Down
23 changes: 23 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 @@ -160,6 +160,10 @@ interface FeedDao {
)
suspend fun getFeedsNotInGroup(groupIds: List<String>): List<FeedViewBean>

@Transaction
@Query("SELECT * FROM $FEED_VIEW_NAME WHERE ${FeedBean.GROUP_ID_COLUMN} IS NULL")
fun getFeedsInDefaultGroup(): Flow<List<FeedViewBean>>

@Transaction
@Query(
"""
Expand All @@ -182,11 +186,30 @@ interface FeedDao {
@Query("SELECT ${FeedBean.URL_COLUMN} FROM $FEED_TABLE_NAME")
fun getAllFeedUrl(): List<String>

@Transaction
@Query("SELECT ${FeedBean.URL_COLUMN} FROM $FEED_TABLE_NAME WHERE ${FeedBean.MUTE_COLUMN} = 0")
fun getAllUnmutedFeedUrl(): List<String>

@Transaction
@Query("SELECT COUNT(*) FROM $FEED_TABLE_NAME WHERE ${FeedBean.URL_COLUMN} LIKE :url")
fun containsByUrl(url: String): Int

@Transaction
@Query("SELECT COUNT(*) FROM $FEED_TABLE_NAME WHERE ${FeedBean.CUSTOM_ICON_COLUMN} LIKE :customIcon")
fun containsByCustomIcon(customIcon: String): Int

@Transaction
@Query(
"UPDATE $FEED_TABLE_NAME SET ${FeedBean.MUTE_COLUMN} = :mute " +
"WHERE ${FeedBean.URL_COLUMN} = :feedUrl"
)
suspend fun muteFeed(feedUrl: String, mute: Boolean): Int

@Transaction
@Query(
"UPDATE $FEED_TABLE_NAME SET ${FeedBean.MUTE_COLUMN} = :mute " +
"WHERE ${FeedBean.GROUP_ID_COLUMN} IS NULL AND :groupId IS NULL " +
"OR ${FeedBean.GROUP_ID_COLUMN} = :groupId"
)
suspend fun muteFeedsInGroup(groupId: String?, mute: Boolean): Int
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.skyd.anivu.model.db.migration

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

class Migration16To17 : Migration(16, 17) {
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE `$FEED_TABLE_NAME` ADD ${FeedBean.MUTE_COLUMN} INTEGER NOT NULL DEFAULT 0")
db.execSQL("ALTER TABLE `$FEED_TABLE_NAME` ADD ${FeedBean.PREVIOUS_FEED_URL_COLUMN} TEXT")
db.execSQL("ALTER TABLE `$FEED_TABLE_NAME` ADD ${FeedBean.NEXT_FEED_URL_COLUMN} TEXT")
}
}
4 changes: 4 additions & 0 deletions app/src/main/java/com/skyd/anivu/model/preference/Settings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import com.skyd.anivu.model.preference.appearance.feed.FeedDefaultGroupExpandPre
import com.skyd.anivu.model.preference.appearance.feed.FeedListTonalElevationPreference
import com.skyd.anivu.model.preference.appearance.feed.FeedNumberBadgePreference
import com.skyd.anivu.model.preference.appearance.feed.FeedTopBarTonalElevationPreference
import com.skyd.anivu.model.preference.appearance.feed.HideMutedFeedPreference
import com.skyd.anivu.model.preference.appearance.media.MediaFileFilterPreference
import com.skyd.anivu.model.preference.appearance.media.MediaShowGroupTabPreference
import com.skyd.anivu.model.preference.appearance.media.MediaShowThumbnailPreference
Expand Down Expand Up @@ -91,6 +92,7 @@ import com.skyd.anivu.ui.local.LocalFeedNumberBadge
import com.skyd.anivu.ui.local.LocalFeedTopBarTonalElevation
import com.skyd.anivu.ui.local.LocalHardwareDecode
import com.skyd.anivu.ui.local.LocalHideEmptyDefault
import com.skyd.anivu.ui.local.LocalHideMutedFeed
import com.skyd.anivu.ui.local.LocalIgnoreUpdateVersion
import com.skyd.anivu.ui.local.LocalMediaFileFilter
import com.skyd.anivu.ui.local.LocalMediaLibLocation
Expand Down Expand Up @@ -160,6 +162,7 @@ data class Settings(
val readContentTonalElevation: Float = ReadContentTonalElevationPreference.default,
val readTopBarTonalElevation: Float = ReadTopBarTonalElevationPreference.default,
val feedNumberBadge: Int = FeedNumberBadgePreference.default,
val hideMutedFeed: Boolean = HideMutedFeedPreference.default,
// Update
val ignoreUpdateVersion: Long = IgnoreUpdateVersionPreference.default,
// Behavior
Expand Down Expand Up @@ -240,6 +243,7 @@ fun SettingsProvider(
LocalReadContentTonalElevation provides settings.readContentTonalElevation,
LocalReadTopBarTonalElevation provides settings.readTopBarTonalElevation,
LocalFeedNumberBadge provides settings.feedNumberBadge,
LocalHideMutedFeed provides settings.hideMutedFeed,
// Update
LocalIgnoreUpdateVersion provides settings.ignoreUpdateVersion,
// Behavior
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.skyd.anivu.model.preference.appearance.feed

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 HideMutedFeedPreference : BasePreference<Boolean> {
private const val HIDE_MUTED_FEED = "hideMutedFeed"
override val default = true

val key = booleanPreferencesKey(HIDE_MUTED_FEED)

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
Expand Up @@ -16,10 +16,12 @@ import com.skyd.anivu.model.db.dao.ArticleDao
import com.skyd.anivu.model.db.dao.FeedDao
import com.skyd.anivu.model.db.dao.GroupDao
import com.skyd.anivu.model.preference.appearance.feed.FeedDefaultGroupExpandPreference
import com.skyd.anivu.model.preference.appearance.feed.HideMutedFeedPreference
import com.skyd.anivu.model.repository.RssHelper
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
Expand All @@ -37,16 +39,17 @@ class FeedRepository @Inject constructor(
) : BaseRepository() {
fun requestGroupAnyList(): Flow<List<Any>> = combine(
groupDao.getGroupWithFeeds(),
groupDao.getGroupIds(),
) { groupList, groupIds ->
groupList to feedDao.getFeedsNotInGroup(groupIds)
}.map { (groupList, defaultFeeds) ->
feedDao.getFeedsInDefaultGroup(),
appContext.dataStore.data.map {
it[HideMutedFeedPreference.key] ?: HideMutedFeedPreference.default
}.distinctUntilChanged()
) { groupList, defaultFeeds, hideMute ->
mutableListOf<Any>().apply {
add(GroupVo.DefaultGroup)
addAll(defaultFeeds)
addAll(defaultFeeds.run { if (hideMute) filter { !it.feed.mute } else this })
reorderGroupRepository.sortGroupWithFeed(groupList).forEach { group ->
add(group.group.toVo())
addAll(group.feeds)
addAll(group.feeds.run { if (hideMute) filter { !it.feed.mute } else this })
}
}
}.flowOn(Dispatchers.IO)
Expand Down Expand Up @@ -229,6 +232,15 @@ class FeedRepository @Inject constructor(
fun readAllInFeed(feedUrl: String): Flow<Int> = flow {
emit(articleDao.readAllInFeed(feedUrl))
}.flowOn(Dispatchers.IO)

fun muteFeed(feedUrl: String, mute: Boolean): Flow<Int> = flow {
emit(feedDao.muteFeed(feedUrl, mute))
}.flowOn(Dispatchers.IO)

fun muteFeedsInGroup(groupId: String?, mute: Boolean): Flow<Int> = flow {
val realGroupId = if (groupId == GroupVo.DefaultGroup.groupId) null else groupId
emit(feedDao.muteFeedsInGroup(realGroupId, mute))
}.flowOn(Dispatchers.IO)
}

fun tryDeleteFeedIconFile(path: String?) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class RssSyncWorker(context: Context, parameters: WorkerParameters) :
override suspend fun doWork(): Result {
var hasError = false
hiltEntryPoint.articleRepo
.refreshArticleList(hiltEntryPoint.feedDao.getAllFeedUrl())
.refreshArticleList(hiltEntryPoint.feedDao.getAllUnmutedFeedUrl())
.catch {
hasError = true
it.printStackTrace()
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/com/skyd/anivu/ui/local/LocalValue.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import com.skyd.anivu.model.preference.appearance.feed.FeedDefaultGroupExpandPre
import com.skyd.anivu.model.preference.appearance.feed.FeedListTonalElevationPreference
import com.skyd.anivu.model.preference.appearance.feed.FeedNumberBadgePreference
import com.skyd.anivu.model.preference.appearance.feed.FeedTopBarTonalElevationPreference
import com.skyd.anivu.model.preference.appearance.feed.HideMutedFeedPreference
import com.skyd.anivu.model.preference.appearance.media.MediaFileFilterPreference
import com.skyd.anivu.model.preference.appearance.media.MediaShowGroupTabPreference
import com.skyd.anivu.model.preference.appearance.media.MediaShowThumbnailPreference
Expand Down Expand Up @@ -108,6 +109,7 @@ val LocalReadContentTonalElevation =
val LocalReadTopBarTonalElevation =
compositionLocalOf { ReadTopBarTonalElevationPreference.default }
val LocalFeedNumberBadge = compositionLocalOf { FeedNumberBadgePreference.default }
val LocalHideMutedFeed = compositionLocalOf { HideMutedFeedPreference.default }

// Update
val LocalIgnoreUpdateVersion = compositionLocalOf { IgnoreUpdateVersionPreference.default }
Expand Down
36 changes: 31 additions & 5 deletions app/src/main/java/com/skyd/anivu/ui/screen/feed/EditFeedSheet.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.VolumeOff
import androidx.compose.material.icons.automirrored.outlined.VolumeUp
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material.icons.filled.ToggleOn
import androidx.compose.material.icons.outlined.Add
Expand Down Expand Up @@ -70,8 +72,8 @@ import com.skyd.anivu.ext.readable
import com.skyd.anivu.model.bean.feed.FeedViewBean
import com.skyd.anivu.model.bean.group.GroupVo
import com.skyd.anivu.ui.component.PodAuraIconButton
import com.skyd.anivu.ui.component.dialog.PodAuraDialog
import com.skyd.anivu.ui.component.dialog.DeleteWarningDialog
import com.skyd.anivu.ui.component.dialog.PodAuraDialog
import com.skyd.anivu.ui.component.dialog.TextFieldDialog
import com.skyd.anivu.ui.component.showToast
import com.skyd.anivu.ui.local.LocalNavController
Expand All @@ -87,6 +89,7 @@ fun EditFeedSheet(
groups: List<GroupVo>,
onReadAll: (String) -> Unit,
onRefresh: (String) -> Unit,
onMute: (String, Boolean) -> Unit,
onClear: (String) -> Unit,
onDelete: (String) -> Unit,
onUrlChange: (String) -> Unit,
Expand Down Expand Up @@ -131,8 +134,10 @@ fun EditFeedSheet(
// Options
OptionArea(
sortXmlArticlesOnUpdate = feed.sortXmlArticlesOnUpdate,
mute = feed.mute,
onReadAll = { onReadAll(feed.url) },
onRefresh = { onRefresh(feed.url) },
onMuteChanged = { onMute(feed.url, it) },
onClear = { onClear(feed.url) },
onDelete = {
onDelete(feed.url)
Expand Down Expand Up @@ -357,13 +362,15 @@ private fun LinkArea(link: String, onLinkClick: () -> Unit) {

@Composable
internal fun OptionArea(
deleteEnabled: Boolean = true,
deleteWarningText: String = stringResource(id = R.string.feed_screen_delete_feed_warning),
sortXmlArticlesOnUpdate: Boolean? = null,
mute: Boolean? = null,
onReadAll: () -> Unit,
onRefresh: () -> Unit,
onMuteChanged: ((Boolean) -> Unit)? = null,
onMuteAll: ((Boolean) -> Unit)? = null,
onClear: () -> Unit,
onDelete: () -> Unit,
onDelete: (() -> Unit)?,
onSortXmlArticlesOnUpdateChanged: ((Boolean) -> Unit)? = null,
onEditRequestHeaders: (() -> Unit)? = null,
) {
Expand Down Expand Up @@ -392,12 +399,31 @@ internal fun OptionArea(
text = stringResource(id = R.string.refresh),
onClick = onRefresh,
)
if (onMuteChanged != null && mute != null) {
SheetChip(
icon = if (mute) Icons.AutoMirrored.Outlined.VolumeUp else Icons.AutoMirrored.Outlined.VolumeOff,
text = stringResource(id = if (mute) R.string.feed_screen_unmute_feed else R.string.feed_screen_mute_feed),
onClick = { onMuteChanged(!mute) },
)
}
if (onMuteAll != null) {
SheetChip(
icon = Icons.AutoMirrored.Outlined.VolumeOff,
text = stringResource(id = R.string.feed_screen_mute_all_feeds),
onClick = { onMuteAll(true) },
)
SheetChip(
icon = Icons.AutoMirrored.Outlined.VolumeUp,
text = stringResource(id = R.string.feed_screen_unmute_all_feeds),
onClick = { onMuteAll(false) },
)
}
SheetChip(
icon = Icons.Outlined.ClearAll,
text = stringResource(id = R.string.clear),
onClick = { openClearWarningDialog = true },
)
if (deleteEnabled) {
if (onDelete != null) {
SheetChip(
icon = Icons.Outlined.Delete,
iconTint = MaterialTheme.colorScheme.onError,
Expand Down Expand Up @@ -442,7 +468,7 @@ internal fun OptionArea(
text = deleteWarningText,
onDismissRequest = { openDeleteWarningDialog = false },
onDismiss = { openDeleteWarningDialog = false },
onConfirm = onDelete,
onConfirm = { onDelete?.invoke() },
)
}

Expand Down
Loading

0 comments on commit f205d1a

Please sign in to comment.