Skip to content

Commit 2f8ec10

Browse files
committed
[feature|fix|optimize] Support auto delete old articles; fix a bug that may crash when parsing image Host using URI; optimize code
1 parent 1c3e5e5 commit 2f8ec10

31 files changed

+553
-95
lines changed

app/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ android {
1919
applicationId = "com.skyd.anivu"
2020
minSdk = 24
2121
targetSdk = 34
22-
versionCode = 9
23-
versionName = "1.0"
22+
versionCode = 10
23+
versionName = "1.1-alpha01"
2424

2525
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
2626

app/src/main/java/com/skyd/anivu/App.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.skyd.anivu
33
import android.app.Application
44
import android.content.Context
55
import com.google.android.material.color.DynamicColors
6+
import com.skyd.anivu.model.worker.deletearticle.listenerDeleteArticleFrequency
67
import com.skyd.anivu.model.worker.rsssync.listenerRssSyncFrequency
78
import com.skyd.anivu.util.CrashHandler
89
import dagger.hilt.android.HiltAndroidApp
@@ -20,6 +21,7 @@ class App : Application() {
2021
DynamicColors.applyToActivitiesIfAvailable(this)
2122

2223
listenerRssSyncFrequency(this)
24+
listenerDeleteArticleFrequency(this)
2325
}
2426
}
2527

app/src/main/java/com/skyd/anivu/base/BaseFragment.kt

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,19 @@ abstract class BaseFragment<T : ViewBinding> : Fragment() {
5555
if (action()) {
5656
onSuccess()
5757
} else {
58-
if (onError == null) {
59-
MaterialAlertDialogBuilder(requireContext())
60-
.setIcon(R.drawable.ic_warning_24)
61-
.setTitle(R.string.warning)
62-
.setMessage(messageRes)
63-
.setCancelable(false)
64-
.setPositiveButton(R.string.exit) { _, _ ->
65-
findNavController().popBackStackWithLifecycle()
66-
}
67-
.show()
68-
} else onError()
58+
if (onError == null) showExitDialog(message = getString(messageRes)) else onError()
6959
}
7060
}
61+
62+
protected fun showExitDialog(title: String = getString(R.string.warning), message: String) {
63+
MaterialAlertDialogBuilder(requireContext())
64+
.setIcon(R.drawable.ic_warning_24)
65+
.setTitle(title)
66+
.setMessage(message)
67+
.setCancelable(false)
68+
.setPositiveButton(R.string.exit) { _, _ ->
69+
findNavController().popBackStackWithLifecycle()
70+
}
71+
.show()
72+
}
7173
}
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
package com.skyd.anivu.base
22

3-
abstract class BaseRepository {
4-
}
3+
abstract class BaseRepository

app/src/main/java/com/skyd/anivu/ext/ActivityExt.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import android.provider.Settings
55
import androidx.navigation.NavController
66
import androidx.navigation.Navigation
77
import com.skyd.anivu.R
8-
import com.skyd.anivu.ui.activity.MainActivity
98

109
/**
1110
* 获取系统屏幕亮度

app/src/main/java/com/skyd/anivu/model/db/dao/ArticleDao.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ interface ArticleDao {
118118
WHERE ${ArticleBean.ARTICLE_ID_COLUMN} LIKE :articleId
119119
"""
120120
)
121-
fun getArticleWithEnclosures(articleId: String): Flow<ArticleWithEnclosureBean>
121+
fun getArticleWithEnclosures(articleId: String): Flow<ArticleWithEnclosureBean?>
122122

123123
@RewriteQueriesToDropUnusedColumns
124124
@Query(
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package com.skyd.anivu.model.preference.autodelete
2+
3+
import android.content.Context
4+
import androidx.datastore.preferences.core.Preferences
5+
import androidx.datastore.preferences.core.longPreferencesKey
6+
import com.skyd.anivu.R
7+
import com.skyd.anivu.base.BasePreference
8+
import com.skyd.anivu.ext.dataStore
9+
import com.skyd.anivu.ext.getOrDefault
10+
import com.skyd.anivu.ext.put
11+
import kotlinx.coroutines.CoroutineScope
12+
import kotlinx.coroutines.Dispatchers
13+
import kotlinx.coroutines.launch
14+
import kotlin.time.Duration.Companion.days
15+
import kotlin.time.Duration.Companion.milliseconds
16+
17+
object AutoDeleteArticleBeforePreference : BasePreference<Long> {
18+
private const val AUTO_DELETE_ARTICLE_BEFORE = "autoDeleteArticleBefore"
19+
20+
val EVERY_1_DAY = 1.days.inWholeMilliseconds
21+
val EVERY_2_DAY = 2.days.inWholeMilliseconds
22+
val EVERY_3_DAY = 3.days.inWholeMilliseconds
23+
val EVERY_5_DAY = 5.days.inWholeMilliseconds
24+
val EVERY_7_DAY = 7.days.inWholeMilliseconds
25+
val EVERY_10_DAY = 10.days.inWholeMilliseconds
26+
val EVERY_15_DAY = 15.days.inWholeMilliseconds
27+
val EVERY_20_DAY = 20.days.inWholeMilliseconds
28+
val EVERY_40_DAY = 40.days.inWholeMilliseconds
29+
val EVERY_60_DAY = 60.days.inWholeMilliseconds
30+
31+
val frequencies = listOf(
32+
EVERY_1_DAY,
33+
EVERY_2_DAY,
34+
EVERY_3_DAY,
35+
EVERY_5_DAY,
36+
EVERY_7_DAY,
37+
EVERY_10_DAY,
38+
EVERY_15_DAY,
39+
EVERY_20_DAY,
40+
EVERY_40_DAY,
41+
EVERY_60_DAY,
42+
)
43+
44+
override val default = EVERY_5_DAY
45+
46+
val key = longPreferencesKey(AUTO_DELETE_ARTICLE_BEFORE)
47+
48+
fun put(context: Context, scope: CoroutineScope, value: Long) {
49+
scope.launch(Dispatchers.IO) {
50+
context.dataStore.put(key, value)
51+
}
52+
}
53+
54+
override fun fromPreferences(preferences: Preferences): Long = preferences[key] ?: default
55+
56+
fun toDisplayName(
57+
context: Context,
58+
value: Long = context.dataStore.getOrDefault(this),
59+
): String = when (value) {
60+
EVERY_1_DAY, EVERY_2_DAY, EVERY_3_DAY,
61+
EVERY_5_DAY, EVERY_7_DAY, EVERY_10_DAY,
62+
EVERY_15_DAY, EVERY_20_DAY, EVERY_40_DAY,
63+
EVERY_60_DAY -> context.resources.getQuantityString(
64+
R.plurals.before_day,
65+
value.milliseconds.inWholeDays.toInt(),
66+
value.milliseconds.inWholeDays.toInt(),
67+
)
68+
69+
else -> context.getString(R.string.frequency_manual)
70+
}
71+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package com.skyd.anivu.model.preference.autodelete
2+
3+
import android.content.Context
4+
import androidx.datastore.preferences.core.Preferences
5+
import androidx.datastore.preferences.core.longPreferencesKey
6+
import com.skyd.anivu.R
7+
import com.skyd.anivu.base.BasePreference
8+
import com.skyd.anivu.ext.dataStore
9+
import com.skyd.anivu.ext.getOrDefault
10+
import com.skyd.anivu.ext.put
11+
import kotlinx.coroutines.CoroutineScope
12+
import kotlinx.coroutines.Dispatchers
13+
import kotlinx.coroutines.launch
14+
import kotlin.time.Duration.Companion.days
15+
import kotlin.time.Duration.Companion.milliseconds
16+
17+
object AutoDeleteArticleFrequencyPreference : BasePreference<Long> {
18+
private const val AUTO_DELETE_ARTICLE_FREQUENCY = "autoDeleteArticleFrequency"
19+
20+
val EVERY_1_DAY = 1.days.inWholeMilliseconds
21+
val EVERY_2_DAY = 2.days.inWholeMilliseconds
22+
val EVERY_3_DAY = 3.days.inWholeMilliseconds
23+
val EVERY_5_DAY = 5.days.inWholeMilliseconds
24+
val EVERY_7_DAY = 7.days.inWholeMilliseconds
25+
val EVERY_10_DAY = 10.days.inWholeMilliseconds
26+
27+
val frequencies = listOf(
28+
EVERY_1_DAY,
29+
EVERY_2_DAY,
30+
EVERY_3_DAY,
31+
EVERY_5_DAY,
32+
EVERY_7_DAY,
33+
EVERY_10_DAY,
34+
)
35+
36+
override val default = EVERY_5_DAY
37+
38+
val key = longPreferencesKey(AUTO_DELETE_ARTICLE_FREQUENCY)
39+
40+
fun put(context: Context, scope: CoroutineScope, value: Long) {
41+
scope.launch(Dispatchers.IO) {
42+
context.dataStore.put(key, value)
43+
}
44+
}
45+
46+
override fun fromPreferences(preferences: Preferences): Long = preferences[key] ?: default
47+
48+
fun toDisplayName(
49+
context: Context,
50+
value: Long = context.dataStore.getOrDefault(this),
51+
): String = when (value) {
52+
EVERY_1_DAY, EVERY_2_DAY, EVERY_3_DAY,
53+
EVERY_5_DAY, EVERY_7_DAY, EVERY_10_DAY -> context.resources.getQuantityString(
54+
R.plurals.frequency_day,
55+
value.milliseconds.inWholeDays.toInt(),
56+
value.milliseconds.inWholeDays.toInt(),
57+
)
58+
59+
else -> context.getString(R.string.frequency_manual)
60+
}
61+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.skyd.anivu.model.preference.autodelete
2+
3+
import android.content.Context
4+
import androidx.datastore.preferences.core.Preferences
5+
import androidx.datastore.preferences.core.booleanPreferencesKey
6+
import com.skyd.anivu.base.BasePreference
7+
import com.skyd.anivu.ext.dataStore
8+
import com.skyd.anivu.ext.put
9+
import kotlinx.coroutines.CoroutineScope
10+
import kotlinx.coroutines.Dispatchers
11+
import kotlinx.coroutines.launch
12+
13+
object UseAutoDeletePreference : BasePreference<Boolean> {
14+
private const val USE_AUTO_DELETE = "useAutoDelete"
15+
override val default = true
16+
17+
val key = booleanPreferencesKey(USE_AUTO_DELETE)
18+
19+
fun put(context: Context, scope: CoroutineScope, value: Boolean) {
20+
scope.launch(Dispatchers.IO) {
21+
context.dataStore.put(key, value)
22+
}
23+
}
24+
25+
override fun fromPreferences(preferences: Preferences): Boolean = preferences[key] ?: default
26+
}

app/src/main/java/com/skyd/anivu/model/preference/proxy/ProxyPortPreference.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package com.skyd.anivu.model.preference.proxy
33
import android.content.Context
44
import androidx.datastore.preferences.core.Preferences
55
import androidx.datastore.preferences.core.intPreferencesKey
6-
import androidx.datastore.preferences.core.stringPreferencesKey
76
import com.skyd.anivu.base.BasePreference
87
import com.skyd.anivu.ext.dataStore
98
import com.skyd.anivu.ext.put

app/src/main/java/com/skyd/anivu/model/preference/rss/RssSyncFrequencyPreference.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ object RssSyncFrequencyPreference : BasePreference<Long> {
5757
context: Context,
5858
value: Long = context.dataStore.getOrDefault(this),
5959
): String = when (value) {
60-
MANUAL -> context.getString(R.string.rss_sync_frequency_manual)
60+
MANUAL -> context.getString(R.string.frequency_manual)
6161
EVERY_15_MINUTE, EVERY_30_MINUTE -> context.resources.getQuantityString(
6262
R.plurals.rss_sync_frequency_minute,
6363
value.milliseconds.inWholeMinutes.toInt(),
@@ -73,11 +73,11 @@ object RssSyncFrequencyPreference : BasePreference<Long> {
7373
}
7474

7575
EVERY_1_DAY -> context.resources.getQuantityString(
76-
R.plurals.rss_sync_frequency_day,
76+
R.plurals.frequency_day,
7777
value.milliseconds.inWholeDays.toInt(),
7878
value.milliseconds.inWholeDays.toInt(),
7979
)
8080

81-
else -> context.getString(R.string.rss_sync_frequency_manual)
81+
else -> context.getString(R.string.frequency_manual)
8282
}
8383
}

app/src/main/java/com/skyd/anivu/model/repository/ReadRepository.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import javax.inject.Inject
1111
class ReadRepository @Inject constructor(
1212
private val articleDao: ArticleDao,
1313
) : BaseRepository() {
14-
fun requestArticleWithEnclosure(articleId: String): Flow<ArticleWithEnclosureBean> {
14+
fun requestArticleWithEnclosure(articleId: String): Flow<ArticleWithEnclosureBean?> {
1515
return articleDao.getArticleWithEnclosures(articleId = articleId)
1616
.flowOn(Dispatchers.IO)
1717
}

app/src/main/java/com/skyd/anivu/model/repository/SearchRepository.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ import kotlinx.coroutines.flow.Flow
3030
import kotlinx.coroutines.flow.flatMapConcat
3131
import kotlinx.coroutines.flow.flow
3232
import kotlinx.coroutines.flow.flowOn
33-
import kotlinx.coroutines.flow.take
3433
import kotlinx.coroutines.withContext
3534
import javax.inject.Inject
3635

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.skyd.anivu.model.worker.deletearticle
2+
3+
import android.content.Context
4+
import androidx.work.CoroutineWorker
5+
import androidx.work.WorkerParameters
6+
import com.skyd.anivu.ext.dataStore
7+
import com.skyd.anivu.ext.getOrDefault
8+
import com.skyd.anivu.model.db.dao.ArticleDao
9+
import com.skyd.anivu.model.preference.autodelete.AutoDeleteArticleBeforePreference
10+
import dagger.hilt.EntryPoint
11+
import dagger.hilt.InstallIn
12+
import dagger.hilt.android.EntryPointAccessors
13+
import dagger.hilt.components.SingletonComponent
14+
15+
class DeleteArticleWorker(context: Context, parameters: WorkerParameters) :
16+
CoroutineWorker(context, parameters) {
17+
18+
@EntryPoint
19+
@InstallIn(SingletonComponent::class)
20+
interface WorkerEntryPoint {
21+
val articleDao: ArticleDao
22+
}
23+
24+
private val hiltEntryPoint = EntryPointAccessors.fromApplication(
25+
context, WorkerEntryPoint::class.java
26+
)
27+
28+
override suspend fun doWork(): Result {
29+
runCatching {
30+
hiltEntryPoint.articleDao.deleteArticleBefore(
31+
System.currentTimeMillis() -
32+
applicationContext.dataStore.getOrDefault(AutoDeleteArticleBeforePreference)
33+
)
34+
}.onFailure { return Result.failure() }
35+
return Result.success()
36+
}
37+
38+
companion object {
39+
const val uniqueWorkName = "deleteArticleWorker"
40+
}
41+
}

0 commit comments

Comments
 (0)