forked from upstream-mirrors/quik
changes to save scheduled message attachment data in app local dir so external delete of attachment file doesn't result in it being unable to be found when sending message
This commit is contained in:
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Moez Bhatti <moez.bhatti@gmail.com>
|
||||
*
|
||||
* This file is part of QKSMS.
|
||||
*
|
||||
* QKSMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* QKSMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with QKSMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package dev.octoshrimpy.quik.extensions
|
||||
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import androidx.core.net.toFile
|
||||
|
||||
fun Uri.resourceExists(context: Context): Boolean {
|
||||
var retVal: Boolean? = null
|
||||
try {
|
||||
when (this.scheme) {
|
||||
ContentResolver.SCHEME_CONTENT -> {
|
||||
retVal = context.contentResolver.query(
|
||||
this, null, null, null, null
|
||||
)?.use { it.moveToFirst() }
|
||||
}
|
||||
ContentResolver.SCHEME_FILE -> retVal = this.toFile().exists()
|
||||
}
|
||||
} catch (e: Exception) { /* nothing */
|
||||
}
|
||||
|
||||
return retVal ?: false
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.moez.QKSMS.manager
|
||||
|
||||
import android.content.Context
|
||||
import androidx.work.Constraints
|
||||
import androidx.work.ExistingPeriodicWorkPolicy
|
||||
import androidx.work.PeriodicWorkRequest
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
import com.moez.QKSMS.manager.MediaRecorderManager.AUDIO_FILE_PREFIX
|
||||
import dev.octoshrimpy.quik.repository.ScheduledMessageRepositoryImpl
|
||||
import java.io.File
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class HousekeepingWorkManager(appContext: Context, workerParams: WorkerParameters)
|
||||
: Worker(appContext, workerParams) {
|
||||
|
||||
companion object {
|
||||
private val WORKER_TAG: String = HousekeepingWorkManager::class.java.simpleName
|
||||
|
||||
fun register(context: Context) {
|
||||
// don't check return value because, well, we can't do much about a failure
|
||||
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
|
||||
WORKER_TAG,
|
||||
ExistingPeriodicWorkPolicy.KEEP,
|
||||
PeriodicWorkRequest.Builder(
|
||||
HousekeepingWorkManager::class.java,
|
||||
24,
|
||||
TimeUnit.HOURS
|
||||
)
|
||||
.setConstraints(
|
||||
Constraints.Builder()
|
||||
// idle device constraint kinda guarantees quik won't be in use
|
||||
// as files are deleted (primarily for deleting audio recordings)
|
||||
.setRequiresDeviceIdle(true)
|
||||
// good citizens don't use up low batteries
|
||||
.setRequiresBatteryNotLow(true)
|
||||
.build()
|
||||
)
|
||||
.addTag(WORKER_TAG)
|
||||
.build()
|
||||
)
|
||||
}
|
||||
|
||||
fun cancel(context: Context) {
|
||||
WorkManager.getInstance(context).cancelUniqueWork(WORKER_TAG)
|
||||
}
|
||||
}
|
||||
|
||||
override fun doWork(): Result {
|
||||
removeOrphanedScheduledMessageAttachmentFiles()
|
||||
|
||||
removeOrphanedComposeAudioRecording()
|
||||
|
||||
return Result.success()
|
||||
}
|
||||
|
||||
private fun removeOrphanedScheduledMessageAttachmentFiles() {
|
||||
// get list of all scheduled message ids
|
||||
val scheduledMessageIds = ScheduledMessageRepositoryImpl().getAllScheduledMessageIdsSnapshot()
|
||||
|
||||
// remove orphaned scheduled message dirs in files dir
|
||||
File(applicationContext.filesDir,"")
|
||||
// get dirs that match prefix 'scheduled-'
|
||||
.listFiles { entry -> entry.isDirectory && entry.name.startsWith("scheduled-") }
|
||||
// filter out any dirs that have an associated scheduled message in db
|
||||
?.filterNot {
|
||||
scheduledMessageIds.contains(it.name.substringAfter('-').toLong())
|
||||
}
|
||||
// recursively delete orphan dir
|
||||
?.forEach { it.deleteRecursively() }
|
||||
}
|
||||
|
||||
private fun removeOrphanedComposeAudioRecording() {
|
||||
// find recording files in cache dir
|
||||
applicationContext.cacheDir.listFiles { entry ->
|
||||
entry.isFile &&
|
||||
entry.name.startsWith(AUDIO_FILE_PREFIX) &&
|
||||
entry.name.endsWith(MediaRecorderManager.AUDIO_FILE_SUFFIX)
|
||||
}
|
||||
// delete recording file
|
||||
?.forEach { it.delete() }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,9 +21,14 @@ class ScheduledMessageRepositoryImpl @Inject constructor() : ScheduledMessageRep
|
||||
sendAsGroup: Boolean,
|
||||
body: String,
|
||||
attachments: List<String>
|
||||
) {
|
||||
): ScheduledMessage {
|
||||
Realm.getDefaultInstance().use { realm ->
|
||||
val id = (realm.where(ScheduledMessage::class.java).max("id")?.toLong() ?: -1) + 1
|
||||
val id = (realm
|
||||
.where(ScheduledMessage::class.java)
|
||||
.max("id")
|
||||
?.toLong() ?: -1
|
||||
) + 1
|
||||
|
||||
val recipientsRealmList = RealmList(*recipients.toTypedArray())
|
||||
val attachmentsRealmList = RealmList(*attachments.toTypedArray())
|
||||
|
||||
@@ -31,6 +36,14 @@ class ScheduledMessageRepositoryImpl @Inject constructor() : ScheduledMessageRep
|
||||
attachmentsRealmList)
|
||||
|
||||
realm.executeTransaction { realm.insertOrUpdate(message) }
|
||||
|
||||
return message
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateScheduledMessage(scheduledMessage: ScheduledMessage) {
|
||||
Realm.getDefaultInstance().use { realm ->
|
||||
realm.executeTransaction { realm.insertOrUpdate(scheduledMessage) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +86,17 @@ class ScheduledMessageRepositoryImpl @Inject constructor() : ScheduledMessageRep
|
||||
ids.forEach { deleteScheduledMessage(it) }
|
||||
}
|
||||
|
||||
override fun getAllScheduledMessageIdsSnapshot(): List<Long> {
|
||||
Realm.getDefaultInstance().use { realm ->
|
||||
return realm
|
||||
.where(ScheduledMessage::class.java)
|
||||
.sort("date")
|
||||
.findAll()
|
||||
.createSnapshot()
|
||||
.map { it.id }
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure to clear disposables when the repository is no longer needed
|
||||
fun clearDisposables() {
|
||||
disposables.clear()
|
||||
|
||||
Reference in New Issue
Block a user