Implement auto-delete of notifications, closes #71
This commit is contained in:
parent
42188d5152
commit
d44358f75c
31 changed files with 227 additions and 50 deletions
app
build.gradle
src
main
java/io/heckel/ntfy
app
db
msg
ApiService.ktBroadcastService.ktDownloadManager.ktDownloadWorker.ktNotificationDispatcher.ktNotificationService.kt
service
ui
AddFragment.ktDetailActivity.ktDetailAdapter.ktDetailSettingsActivity.ktMainActivity.ktSettingsActivity.kt
up
util
work
res
play/java/io/heckel/ntfy/firebase
fastlane/metadata/android/en-US/changelog
|
@ -12,8 +12,8 @@ android {
|
|||
minSdkVersion 21
|
||||
targetSdkVersion 31
|
||||
|
||||
versionCode 21
|
||||
versionName "1.8.1"
|
||||
versionCode 22
|
||||
versionName "1.9.0"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import android.app.Application
|
|||
import android.content.Context
|
||||
import io.heckel.ntfy.db.Database
|
||||
import io.heckel.ntfy.db.Repository
|
||||
import io.heckel.ntfy.log.Log
|
||||
import io.heckel.ntfy.util.Log
|
||||
|
||||
class Application : Application() {
|
||||
private val database by lazy {
|
||||
|
|
|
@ -297,9 +297,15 @@ interface NotificationDao {
|
|||
@Query("UPDATE notification SET deleted = 1 WHERE subscriptionId = :subscriptionId")
|
||||
fun markAllAsDeleted(subscriptionId: Long)
|
||||
|
||||
@Query("UPDATE notification SET deleted = 1 WHERE timestamp < :olderThanTimestamp")
|
||||
fun markAsDeletedIfOlderThan(olderThanTimestamp: Long)
|
||||
|
||||
@Query("UPDATE notification SET deleted = 0 WHERE id = :notificationId")
|
||||
fun undelete(notificationId: String)
|
||||
|
||||
@Query("DELETE FROM notification WHERE timestamp < :olderThanTimestamp")
|
||||
fun removeIfOlderThan(olderThanTimestamp: Long)
|
||||
|
||||
@Query("DELETE FROM notification WHERE subscriptionId = :subscriptionId")
|
||||
fun removeAll(subscriptionId: Long)
|
||||
}
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
package io.heckel.ntfy.db
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Build
|
||||
import androidx.annotation.WorkerThread
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.lifecycle.*
|
||||
import io.heckel.ntfy.log.Log
|
||||
import io.heckel.ntfy.util.Log
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
|
||||
|
@ -116,20 +115,26 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
|
|||
notificationDao.update(notification)
|
||||
}
|
||||
|
||||
fun markAsDeleted(notificationId: String) {
|
||||
notificationDao.markAsDeleted(notificationId)
|
||||
}
|
||||
|
||||
fun undeleteNotification(notificationId: String) {
|
||||
notificationDao.undelete(notificationId)
|
||||
}
|
||||
|
||||
fun markAsDeleted(notificationId: String) {
|
||||
notificationDao.markAsDeleted(notificationId)
|
||||
}
|
||||
|
||||
fun markAllAsDeleted(subscriptionId: Long) {
|
||||
notificationDao.markAllAsDeleted(subscriptionId)
|
||||
}
|
||||
|
||||
@Suppress("RedundantSuspendModifier")
|
||||
@WorkerThread
|
||||
fun markAsDeletedIfOlderThan(olderThanTimestamp: Long) {
|
||||
notificationDao.markAsDeletedIfOlderThan(olderThanTimestamp)
|
||||
}
|
||||
|
||||
fun removeNotificationsIfOlderThan(olderThanTimestamp: Long) {
|
||||
notificationDao.removeIfOlderThan(olderThanTimestamp)
|
||||
}
|
||||
|
||||
fun removeAllNotifications(subscriptionId: Long) {
|
||||
notificationDao.removeAll(subscriptionId)
|
||||
}
|
||||
|
@ -164,6 +169,16 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
|
|||
.apply()
|
||||
}
|
||||
|
||||
fun getDeleteWorkerVersion(): Int {
|
||||
return sharedPrefs.getInt(SHARED_PREFS_DELETE_WORKER_VERSION, 0)
|
||||
}
|
||||
|
||||
fun setDeleteWorkerVersion(version: Int) {
|
||||
sharedPrefs.edit()
|
||||
.putInt(SHARED_PREFS_DELETE_WORKER_VERSION, version)
|
||||
.apply()
|
||||
}
|
||||
|
||||
fun getAutoRestartWorkerVersion(): Int {
|
||||
return sharedPrefs.getInt(SHARED_PREFS_AUTO_RESTART_WORKER_VERSION, 0)
|
||||
}
|
||||
|
@ -205,6 +220,16 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
|
|||
.apply()
|
||||
}
|
||||
|
||||
fun getAutoDeleteSeconds(): Long {
|
||||
return sharedPrefs.getLong(SHARED_PREFS_AUTO_DELETE_SECONDS, AUTO_DELETE_DEFAULT_SECONDS)
|
||||
}
|
||||
|
||||
fun setAutoDeleteSeconds(seconds: Long) {
|
||||
sharedPrefs.edit()
|
||||
.putLong(SHARED_PREFS_AUTO_DELETE_SECONDS, seconds)
|
||||
.apply()
|
||||
}
|
||||
|
||||
fun setDarkMode(mode: Int) {
|
||||
if (mode == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) {
|
||||
sharedPrefs.edit()
|
||||
|
@ -384,11 +409,12 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
|
|||
companion object {
|
||||
const val SHARED_PREFS_ID = "MainPreferences"
|
||||
const val SHARED_PREFS_POLL_WORKER_VERSION = "PollWorkerVersion"
|
||||
const val SHARED_PREFS_DELETE_WORKER_VERSION = "DeleteWorkerVersion"
|
||||
const val SHARED_PREFS_AUTO_RESTART_WORKER_VERSION = "AutoRestartWorkerVersion"
|
||||
const val SHARED_PREFS_MUTED_UNTIL_TIMESTAMP = "MutedUntil"
|
||||
const val SHARED_PREFS_MIN_PRIORITY = "MinPriority"
|
||||
const val SHARED_PREFS_AUTO_DOWNLOAD_MAX_SIZE = "AutoDownload"
|
||||
const val SHARED_PREFS_WAKELOCK_ENABLED = "WakelockEnabled"
|
||||
const val SHARED_PREFS_AUTO_DELETE_SECONDS = "AutoDelete"
|
||||
const val SHARED_PREFS_CONNECTION_PROTOCOL = "ConnectionProtocol"
|
||||
const val SHARED_PREFS_DARK_MODE = "DarkMode"
|
||||
const val SHARED_PREFS_BROADCAST_ENABLED = "BroadcastEnabled"
|
||||
|
@ -401,9 +427,19 @@ class Repository(private val sharedPrefs: SharedPreferences, private val databas
|
|||
const val MUTED_UNTIL_FOREVER = 1L
|
||||
const val MUTED_UNTIL_TOMORROW = 2L
|
||||
|
||||
const val AUTO_DOWNLOAD_NEVER = 0L
|
||||
private const val ONE_MB = 1024 * 1024L
|
||||
const val AUTO_DOWNLOAD_NEVER = 0L // Values must match values.xml
|
||||
const val AUTO_DOWNLOAD_ALWAYS = 1L
|
||||
const val AUTO_DOWNLOAD_DEFAULT = 1024 * 1024L // Must match a value in values.xml
|
||||
const val AUTO_DOWNLOAD_DEFAULT = ONE_MB
|
||||
|
||||
private const val ONE_DAY_SECONDS = 24 * 60 * 60L
|
||||
const val AUTO_DELETE_NEVER = 0L // Values must match values.xml
|
||||
const val AUTO_DELETE_ONE_DAY_SECONDS = ONE_DAY_SECONDS
|
||||
const val AUTO_DELETE_THREE_DAYS_SECONDS = 3 * ONE_DAY_SECONDS
|
||||
const val AUTO_DELETE_ONE_WEEK_SECONDS = 7 * ONE_DAY_SECONDS
|
||||
const val AUTO_DELETE_ONE_MONTH_SECONDS = 30 * ONE_DAY_SECONDS
|
||||
const val AUTO_DELETE_THREE_MONTHS_SECONDS = 90 * ONE_DAY_SECONDS
|
||||
const val AUTO_DELETE_DEFAULT_SECONDS = AUTO_DELETE_ONE_MONTH_SECONDS
|
||||
|
||||
const val CONNECTION_PROTOCOL_JSONHTTP = "jsonhttp"
|
||||
const val CONNECTION_PROTOCOL_WS = "ws"
|
||||
|
|
|
@ -4,7 +4,7 @@ import android.os.Build
|
|||
import io.heckel.ntfy.BuildConfig
|
||||
import io.heckel.ntfy.db.Notification
|
||||
import io.heckel.ntfy.db.User
|
||||
import io.heckel.ntfy.log.Log
|
||||
import io.heckel.ntfy.util.Log
|
||||
import io.heckel.ntfy.util.topicUrl
|
||||
import io.heckel.ntfy.util.topicUrlAuth
|
||||
import io.heckel.ntfy.util.topicUrlJson
|
||||
|
|
|
@ -6,7 +6,7 @@ import io.heckel.ntfy.R
|
|||
import io.heckel.ntfy.db.Notification
|
||||
import io.heckel.ntfy.db.Repository
|
||||
import io.heckel.ntfy.db.Subscription
|
||||
import io.heckel.ntfy.log.Log
|
||||
import io.heckel.ntfy.util.Log
|
||||
import io.heckel.ntfy.util.joinTagsMap
|
||||
import io.heckel.ntfy.util.splitTags
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
|
@ -5,7 +5,7 @@ import androidx.work.ExistingWorkPolicy
|
|||
import androidx.work.OneTimeWorkRequest
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.workDataOf
|
||||
import io.heckel.ntfy.log.Log
|
||||
import io.heckel.ntfy.util.Log
|
||||
|
||||
/**
|
||||
* Download attachment in the background via WorkManager
|
||||
|
|
|
@ -17,7 +17,7 @@ import io.heckel.ntfy.BuildConfig
|
|||
import io.heckel.ntfy.R
|
||||
import io.heckel.ntfy.app.Application
|
||||
import io.heckel.ntfy.db.*
|
||||
import io.heckel.ntfy.log.Log
|
||||
import io.heckel.ntfy.util.Log
|
||||
import io.heckel.ntfy.util.queryFilename
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
|
|
|
@ -4,7 +4,7 @@ import android.content.Context
|
|||
import io.heckel.ntfy.db.Notification
|
||||
import io.heckel.ntfy.db.Repository
|
||||
import io.heckel.ntfy.db.Subscription
|
||||
import io.heckel.ntfy.log.Log
|
||||
import io.heckel.ntfy.util.Log
|
||||
import io.heckel.ntfy.up.Distributor
|
||||
import io.heckel.ntfy.util.safeLet
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import androidx.core.content.ContextCompat
|
|||
import io.heckel.ntfy.R
|
||||
import io.heckel.ntfy.db.*
|
||||
import io.heckel.ntfy.db.Notification
|
||||
import io.heckel.ntfy.log.Log
|
||||
import io.heckel.ntfy.util.Log
|
||||
import io.heckel.ntfy.ui.Colors
|
||||
import io.heckel.ntfy.ui.DetailActivity
|
||||
import io.heckel.ntfy.ui.MainActivity
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package io.heckel.ntfy.service
|
||||
|
||||
import io.heckel.ntfy.db.*
|
||||
import io.heckel.ntfy.log.Log
|
||||
import io.heckel.ntfy.util.Log
|
||||
import io.heckel.ntfy.msg.ApiService
|
||||
import io.heckel.ntfy.util.topicUrl
|
||||
import kotlinx.coroutines.*
|
||||
|
|
|
@ -16,7 +16,7 @@ import io.heckel.ntfy.app.Application
|
|||
import io.heckel.ntfy.db.ConnectionState
|
||||
import io.heckel.ntfy.db.Repository
|
||||
import io.heckel.ntfy.db.Subscription
|
||||
import io.heckel.ntfy.log.Log
|
||||
import io.heckel.ntfy.util.Log
|
||||
import io.heckel.ntfy.msg.ApiService
|
||||
import io.heckel.ntfy.msg.NotificationDispatcher
|
||||
import io.heckel.ntfy.ui.Colors
|
||||
|
|
|
@ -5,7 +5,7 @@ import android.content.Intent
|
|||
import androidx.core.content.ContextCompat
|
||||
import androidx.work.*
|
||||
import io.heckel.ntfy.app.Application
|
||||
import io.heckel.ntfy.log.Log
|
||||
import io.heckel.ntfy.util.Log
|
||||
|
||||
/**
|
||||
* This class only manages the SubscriberService, i.e. it starts or stops it.
|
||||
|
|
|
@ -5,7 +5,7 @@ import android.os.Build
|
|||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import io.heckel.ntfy.db.*
|
||||
import io.heckel.ntfy.log.Log
|
||||
import io.heckel.ntfy.util.Log
|
||||
import io.heckel.ntfy.msg.ApiService.Companion.requestBuilder
|
||||
import io.heckel.ntfy.msg.NotificationParser
|
||||
import io.heckel.ntfy.util.topicShortUrl
|
||||
|
|
|
@ -20,7 +20,7 @@ import io.heckel.ntfy.BuildConfig
|
|||
import io.heckel.ntfy.R
|
||||
import io.heckel.ntfy.db.Repository
|
||||
import io.heckel.ntfy.db.User
|
||||
import io.heckel.ntfy.log.Log
|
||||
import io.heckel.ntfy.util.Log
|
||||
import io.heckel.ntfy.msg.ApiService
|
||||
import io.heckel.ntfy.util.topicUrl
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
|
@ -27,7 +27,7 @@ import io.heckel.ntfy.app.Application
|
|||
import io.heckel.ntfy.db.Notification
|
||||
import io.heckel.ntfy.db.Repository
|
||||
import io.heckel.ntfy.firebase.FirebaseMessenger
|
||||
import io.heckel.ntfy.log.Log
|
||||
import io.heckel.ntfy.util.Log
|
||||
import io.heckel.ntfy.msg.ApiService
|
||||
import io.heckel.ntfy.msg.NotificationService
|
||||
import io.heckel.ntfy.service.SubscriberServiceManager
|
||||
|
|
|
@ -20,7 +20,7 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import com.stfalcon.imageviewer.StfalconImageViewer
|
||||
import io.heckel.ntfy.R
|
||||
import io.heckel.ntfy.db.*
|
||||
import io.heckel.ntfy.log.Log
|
||||
import io.heckel.ntfy.util.Log
|
||||
import io.heckel.ntfy.msg.DownloadManager
|
||||
import io.heckel.ntfy.util.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
|
@ -7,7 +7,7 @@ import androidx.preference.PreferenceFragmentCompat
|
|||
import io.heckel.ntfy.R
|
||||
import io.heckel.ntfy.db.Repository
|
||||
import io.heckel.ntfy.db.Subscription
|
||||
import io.heckel.ntfy.log.Log
|
||||
import io.heckel.ntfy.util.Log
|
||||
import io.heckel.ntfy.service.SubscriberServiceManager
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
|
@ -30,12 +30,13 @@ import io.heckel.ntfy.app.Application
|
|||
import io.heckel.ntfy.db.Repository
|
||||
import io.heckel.ntfy.db.Subscription
|
||||
import io.heckel.ntfy.firebase.FirebaseMessenger
|
||||
import io.heckel.ntfy.log.Log
|
||||
import io.heckel.ntfy.util.Log
|
||||
import io.heckel.ntfy.msg.ApiService
|
||||
import io.heckel.ntfy.msg.NotificationDispatcher
|
||||
import io.heckel.ntfy.service.SubscriberService
|
||||
import io.heckel.ntfy.service.SubscriberServiceManager
|
||||
import io.heckel.ntfy.util.*
|
||||
import io.heckel.ntfy.work.DeleteWorker
|
||||
import io.heckel.ntfy.work.PollWorker
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
|
@ -158,8 +159,9 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
|||
AppCompatDelegate.setDefaultNightMode(repository.getDarkMode())
|
||||
|
||||
// Background things
|
||||
startPeriodicPollWorker()
|
||||
startPeriodicServiceRestartWorker()
|
||||
schedulePeriodicPollWorker()
|
||||
schedulePeriodicServiceRestartWorker()
|
||||
schedulePeriodicDeleteWorker()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
@ -178,7 +180,7 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
|||
Log.d(TAG, "Battery: ignoring optimizations = $ignoringOptimizations (we want this to be true); instant subscriptions = $hasInstantSubscriptions; remind time reached = $batteryRemindTimeReached; banner = $showBanner")
|
||||
}
|
||||
|
||||
private fun startPeriodicPollWorker() {
|
||||
private fun schedulePeriodicPollWorker() {
|
||||
val workerVersion = repository.getPollWorkerVersion()
|
||||
val workPolicy = if (workerVersion == PollWorker.VERSION) {
|
||||
Log.d(TAG, "Poll worker version matches: choosing KEEP as existing work policy")
|
||||
|
@ -200,7 +202,26 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
|||
workManager!!.enqueueUniquePeriodicWork(PollWorker.WORK_NAME_PERIODIC_ALL, workPolicy, work)
|
||||
}
|
||||
|
||||
private fun startPeriodicServiceRestartWorker() {
|
||||
|
||||
private fun schedulePeriodicDeleteWorker() {
|
||||
val workerVersion = repository.getDeleteWorkerVersion()
|
||||
val workPolicy = if (workerVersion == DeleteWorker.VERSION) {
|
||||
Log.d(TAG, "Delete worker version matches: choosing KEEP as existing work policy")
|
||||
ExistingPeriodicWorkPolicy.KEEP
|
||||
} else {
|
||||
Log.d(TAG, "Delete worker version DOES NOT MATCH: choosing REPLACE as existing work policy")
|
||||
repository.setDeleteWorkerVersion(DeleteWorker.VERSION)
|
||||
ExistingPeriodicWorkPolicy.REPLACE
|
||||
}
|
||||
val work = PeriodicWorkRequestBuilder<DeleteWorker>(DELETE_WORKER_INTERVAL_MINUTES, TimeUnit.MINUTES)
|
||||
.addTag(DeleteWorker.TAG)
|
||||
.addTag(DeleteWorker.WORK_NAME_PERIODIC_ALL)
|
||||
.build()
|
||||
Log.d(TAG, "Delete worker: Scheduling period work every $DELETE_WORKER_INTERVAL_MINUTES minutes")
|
||||
workManager!!.enqueueUniquePeriodicWork(DeleteWorker.WORK_NAME_PERIODIC_ALL, workPolicy, work)
|
||||
}
|
||||
|
||||
private fun schedulePeriodicServiceRestartWorker() {
|
||||
val workerVersion = repository.getAutoRestartWorkerVersion()
|
||||
val workPolicy = if (workerVersion == SubscriberService.SERVICE_START_WORKER_VERSION) {
|
||||
Log.d(TAG, "ServiceStartWorker version matches: choosing KEEP as existing work policy")
|
||||
|
@ -598,6 +619,7 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
|||
// Thanks to varunon9 (https://gist.github.com/varunon9/f2beec0a743c96708eb0ef971a9ff9cd) for this!
|
||||
|
||||
const val POLL_WORKER_INTERVAL_MINUTES = 2 * 60L
|
||||
const val DELETE_WORKER_INTERVAL_MINUTES = 8 * 60L
|
||||
const val SERVICE_START_WORKER_INTERVAL_MINUTES = 3 * 60L
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import android.app.AlertDialog
|
|||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
|
@ -25,7 +24,7 @@ import io.heckel.ntfy.BuildConfig
|
|||
import io.heckel.ntfy.R
|
||||
import io.heckel.ntfy.db.Repository
|
||||
import io.heckel.ntfy.db.User
|
||||
import io.heckel.ntfy.log.Log
|
||||
import io.heckel.ntfy.util.Log
|
||||
import io.heckel.ntfy.service.SubscriberServiceManager
|
||||
import io.heckel.ntfy.util.formatBytes
|
||||
import io.heckel.ntfy.util.formatDateShort
|
||||
|
@ -234,6 +233,32 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
|
|||
}
|
||||
}
|
||||
|
||||
// Auto delete
|
||||
val autoDeletePrefId = context?.getString(R.string.settings_notifications_auto_delete_key) ?: return
|
||||
val autoDelete: ListPreference? = findPreference(autoDeletePrefId)
|
||||
autoDelete?.value = repository.getAutoDeleteSeconds().toString()
|
||||
autoDelete?.preferenceDataStore = object : PreferenceDataStore() {
|
||||
override fun putString(key: String?, value: String?) {
|
||||
val seconds = value?.toLongOrNull() ?:return
|
||||
repository.setAutoDeleteSeconds(seconds)
|
||||
}
|
||||
override fun getString(key: String?, defValue: String?): String {
|
||||
return repository.getAutoDeleteSeconds().toString()
|
||||
}
|
||||
}
|
||||
autoDelete?.summaryProvider = Preference.SummaryProvider<ListPreference> { pref ->
|
||||
val seconds = pref.value.toLongOrNull() ?: repository.getAutoDeleteSeconds()
|
||||
when (seconds) {
|
||||
Repository.AUTO_DELETE_NEVER -> getString(R.string.settings_notifications_auto_delete_summary_never)
|
||||
Repository.AUTO_DELETE_ONE_DAY_SECONDS -> getString(R.string.settings_notifications_auto_delete_summary_one_day)
|
||||
Repository.AUTO_DELETE_THREE_DAYS_SECONDS -> getString(R.string.settings_notifications_auto_delete_summary_three_days)
|
||||
Repository.AUTO_DELETE_ONE_WEEK_SECONDS -> getString(R.string.settings_notifications_auto_delete_summary_one_week)
|
||||
Repository.AUTO_DELETE_ONE_MONTH_SECONDS -> getString(R.string.settings_notifications_auto_delete_summary_one_month)
|
||||
Repository.AUTO_DELETE_THREE_MONTHS_SECONDS -> getString(R.string.settings_notifications_auto_delete_summary_three_months)
|
||||
else -> getString(R.string.settings_notifications_auto_delete_summary_one_month) // Must match default const
|
||||
}
|
||||
}
|
||||
|
||||
// Dark mode
|
||||
val darkModePrefId = context?.getString(R.string.settings_appearance_dark_mode_key) ?: return
|
||||
val darkMode: ListPreference? = findPreference(darkModePrefId)
|
||||
|
|
|
@ -5,7 +5,7 @@ import android.content.Intent
|
|||
import io.heckel.ntfy.R
|
||||
import io.heckel.ntfy.app.Application
|
||||
import io.heckel.ntfy.db.Subscription
|
||||
import io.heckel.ntfy.log.Log
|
||||
import io.heckel.ntfy.util.Log
|
||||
import io.heckel.ntfy.service.SubscriberServiceManager
|
||||
import io.heckel.ntfy.util.randomString
|
||||
import io.heckel.ntfy.util.topicUrlUp
|
||||
|
|
|
@ -2,7 +2,7 @@ package io.heckel.ntfy.up
|
|||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import io.heckel.ntfy.log.Log
|
||||
import io.heckel.ntfy.util.Log
|
||||
|
||||
/**
|
||||
* This is the UnifiedPush distributor, an amalgamation of messages to be sent as part of the spec.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package io.heckel.ntfy.log
|
||||
package io.heckel.ntfy.util
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
52
app/src/main/java/io/heckel/ntfy/work/DeleteWorker.kt
Normal file
52
app/src/main/java/io/heckel/ntfy/work/DeleteWorker.kt
Normal file
|
@ -0,0 +1,52 @@
|
|||
package io.heckel.ntfy.work
|
||||
|
||||
import android.content.Context
|
||||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.WorkerParameters
|
||||
import io.heckel.ntfy.BuildConfig
|
||||
import io.heckel.ntfy.db.Repository
|
||||
import io.heckel.ntfy.util.Log
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class DeleteWorker(ctx: Context, params: WorkerParameters) : CoroutineWorker(ctx, params) {
|
||||
// IMPORTANT:
|
||||
// Every time the worker is changed, the periodic work has to be REPLACEd.
|
||||
// This is facilitated in the MainActivity using the VERSION below.
|
||||
|
||||
init {
|
||||
Log.init(ctx) // Init in all entrypoints
|
||||
}
|
||||
|
||||
override suspend fun doWork(): Result {
|
||||
return withContext(Dispatchers.IO) {
|
||||
Log.d(TAG, "Deleting expired notifications")
|
||||
val repository = Repository.getInstance(applicationContext)
|
||||
val deleteAfterSeconds = repository.getAutoDeleteSeconds()
|
||||
if (deleteAfterSeconds == Repository.AUTO_DELETE_NEVER) {
|
||||
Log.d(TAG, "Not deleting any notifications; global setting set to NEVER")
|
||||
return@withContext Result.success()
|
||||
}
|
||||
|
||||
// Mark as deleted
|
||||
val markDeletedOlderThanTimestamp = (System.currentTimeMillis()/1000) - deleteAfterSeconds
|
||||
Log.d(TAG, "Marking notifications older than $markDeletedOlderThanTimestamp as deleted")
|
||||
repository.markAsDeletedIfOlderThan(markDeletedOlderThanTimestamp)
|
||||
|
||||
// Hard delete
|
||||
val deleteOlderThanTimestamp = (System.currentTimeMillis()/1000) - HARD_DELETE_AFTER_SECONDS
|
||||
Log.d(TAG, "Hard deleting notifications older than $markDeletedOlderThanTimestamp")
|
||||
repository.removeNotificationsIfOlderThan(deleteOlderThanTimestamp)
|
||||
return@withContext Result.success()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val VERSION = BuildConfig.VERSION_CODE
|
||||
const val TAG = "NtfyDeleteWorker"
|
||||
const val WORK_NAME_PERIODIC_ALL = "NtfyDeleteWorkerPeriodic" // Do not change
|
||||
|
||||
private const val ONE_DAY_SECONDS = 24 * 60 * 60L
|
||||
const val HARD_DELETE_AFTER_SECONDS = 4 * 30 * ONE_DAY_SECONDS // 4 months
|
||||
}
|
||||
}
|
|
@ -4,17 +4,16 @@ import android.content.Context
|
|||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.WorkerParameters
|
||||
import io.heckel.ntfy.BuildConfig
|
||||
import io.heckel.ntfy.db.Database
|
||||
import io.heckel.ntfy.db.Repository
|
||||
import io.heckel.ntfy.log.Log
|
||||
import io.heckel.ntfy.msg.ApiService
|
||||
import io.heckel.ntfy.msg.NotificationDispatcher
|
||||
import io.heckel.ntfy.util.Log
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlin.random.Random
|
||||
|
||||
class PollWorker(ctx: Context, params: WorkerParameters) : CoroutineWorker(ctx, params) {
|
||||
// IMPORTANT WARNING:
|
||||
// IMPORTANT:
|
||||
// Every time the worker is changed, the periodic work has to be REPLACEd.
|
||||
// This is facilitated in the MainActivity using the VERSION below.
|
||||
|
||||
|
@ -25,9 +24,7 @@ class PollWorker(ctx: Context, params: WorkerParameters) : CoroutineWorker(ctx,
|
|||
override suspend fun doWork(): Result {
|
||||
return withContext(Dispatchers.IO) {
|
||||
Log.d(TAG, "Polling for new notifications")
|
||||
val database = Database.getInstance(applicationContext)
|
||||
val sharedPrefs = applicationContext.getSharedPreferences(Repository.SHARED_PREFS_ID, Context.MODE_PRIVATE)
|
||||
val repository = Repository.getInstance(sharedPrefs, database)
|
||||
val repository = Repository.getInstance(applicationContext)
|
||||
val dispatcher = NotificationDispatcher(applicationContext, repository)
|
||||
val api = ApiService()
|
||||
|
||||
|
|
|
@ -227,10 +227,10 @@
|
|||
<string name="settings_notifications_min_priority_high">High priority and higher</string>
|
||||
<string name="settings_notifications_min_priority_max">Only max priority</string>
|
||||
<string name="settings_notifications_auto_download_key">AutoDownload</string>
|
||||
<string name="settings_notifications_auto_download_title">Auto download attachments</string>
|
||||
<string name="settings_notifications_auto_download_summary_always">Attachments are always downloaded automatically</string>
|
||||
<string name="settings_notifications_auto_download_summary_never">Attachments are never downloaded automatically</string>
|
||||
<string name="settings_notifications_auto_download_summary_smaller_than_x">Attachments up to %1$s are downloaded automatically</string>
|
||||
<string name="settings_notifications_auto_download_title">Download attachments</string>
|
||||
<string name="settings_notifications_auto_download_summary_always">Automatically download all attachments</string>
|
||||
<string name="settings_notifications_auto_download_summary_never">Never download attachments automatically</string>
|
||||
<string name="settings_notifications_auto_download_summary_smaller_than_x">Auto-download attachments up to %1$s</string>
|
||||
<string name="settings_notifications_auto_download_never">Never download automatically</string>
|
||||
<string name="settings_notifications_auto_download_always">Always download automatically</string>
|
||||
<string name="settings_notifications_auto_download_100k">If smaller than 100 KB</string>
|
||||
|
@ -239,6 +239,20 @@
|
|||
<string name="settings_notifications_auto_download_5m">If smaller than 5 MB</string>
|
||||
<string name="settings_notifications_auto_download_10m">If smaller than 10 MB</string>
|
||||
<string name="settings_notifications_auto_download_50m">If smaller than 50 MB</string>
|
||||
<string name="settings_notifications_auto_delete_key">AutoDelete</string>
|
||||
<string name="settings_notifications_auto_delete_title">Delete notifications</string>
|
||||
<string name="settings_notifications_auto_delete_summary_never">Never automatically delete notifications</string>
|
||||
<string name="settings_notifications_auto_delete_summary_one_day">Auto-delete notifications after one day</string>
|
||||
<string name="settings_notifications_auto_delete_summary_three_days">Auto-delete notifications after 3 days</string>
|
||||
<string name="settings_notifications_auto_delete_summary_one_week">Auto-delete notifications after one week</string>
|
||||
<string name="settings_notifications_auto_delete_summary_one_month">Auto-delete notifications after one month</string>
|
||||
<string name="settings_notifications_auto_delete_summary_three_months">Auto-delete notifications after 3 months</string>
|
||||
<string name="settings_notifications_auto_delete_never">Never</string>
|
||||
<string name="settings_notifications_auto_delete_one_day">After one day</string>
|
||||
<string name="settings_notifications_auto_delete_three_days">After 3 days</string>
|
||||
<string name="settings_notifications_auto_delete_one_week">After one week</string>
|
||||
<string name="settings_notifications_auto_delete_one_month">After one month</string>
|
||||
<string name="settings_notifications_auto_delete_three_months">After 3 months</string>
|
||||
<string name="settings_appearance_header">Appearance</string>
|
||||
<string name="settings_appearance_dark_mode_key">DarkMode</string>
|
||||
<string name="settings_appearance_dark_mode_title">Dark mode</string>
|
||||
|
|
|
@ -53,6 +53,22 @@
|
|||
<item>10485760</item>
|
||||
<item>52428800</item>
|
||||
</string-array>
|
||||
<string-array name="settings_notifications_auto_delete_entries">
|
||||
<item>@string/settings_notifications_auto_delete_never</item>
|
||||
<item>@string/settings_notifications_auto_delete_one_day</item>
|
||||
<item>@string/settings_notifications_auto_delete_three_days</item>
|
||||
<item>@string/settings_notifications_auto_delete_one_week</item>
|
||||
<item>@string/settings_notifications_auto_delete_one_month</item>
|
||||
<item>@string/settings_notifications_auto_delete_three_months</item>
|
||||
</string-array>
|
||||
<string-array name="settings_notifications_auto_delete_values">
|
||||
<item>0</item>
|
||||
<item>86400</item>
|
||||
<item>259200</item>
|
||||
<item>604800</item>
|
||||
<item>2592000</item>
|
||||
<item>7776000</item>
|
||||
</string-array>
|
||||
<string-array name="settings_advanced_connection_protocol_entries">
|
||||
<item>@string/settings_advanced_connection_protocol_entry_jsonhttp</item>
|
||||
<item>@string/settings_advanced_connection_protocol_entry_ws</item>
|
||||
|
|
|
@ -21,6 +21,12 @@
|
|||
app:entries="@array/settings_notifications_auto_download_entries"
|
||||
app:entryValues="@array/settings_notifications_auto_download_values"
|
||||
app:defaultValue="1"/>
|
||||
<ListPreference
|
||||
app:key="@string/settings_notifications_auto_delete_key"
|
||||
app:title="@string/settings_notifications_auto_delete_title"
|
||||
app:entries="@array/settings_notifications_auto_delete_entries"
|
||||
app:entryValues="@array/settings_notifications_auto_delete_values"
|
||||
app:defaultValue="2592000"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory
|
||||
app:title="@string/settings_appearance_header"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package io.heckel.ntfy.firebase
|
||||
|
||||
import com.google.firebase.messaging.FirebaseMessaging
|
||||
import io.heckel.ntfy.log.Log
|
||||
import io.heckel.ntfy.util.Log
|
||||
|
||||
class FirebaseMessenger {
|
||||
fun subscribe(topic: String) {
|
||||
|
|
|
@ -9,7 +9,7 @@ import io.heckel.ntfy.R
|
|||
import io.heckel.ntfy.app.Application
|
||||
import io.heckel.ntfy.db.Attachment
|
||||
import io.heckel.ntfy.db.Notification
|
||||
import io.heckel.ntfy.log.Log
|
||||
import io.heckel.ntfy.util.Log
|
||||
import io.heckel.ntfy.msg.ApiService
|
||||
import io.heckel.ntfy.msg.MESSAGE_ENCODING_BASE64
|
||||
import io.heckel.ntfy.msg.NotificationDispatcher
|
||||
|
|
3
fastlane/metadata/android/en-US/changelog/22.txt
Normal file
3
fastlane/metadata/android/en-US/changelog/22.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
Features:
|
||||
* Dark theme: Improvements around style and contrast (#119, thanks @kzshantonu for reporting)
|
||||
* Automatically delete notifications (#71, thanks @arjan-s for reporting)
|
Loading…
Add table
Reference in a new issue