Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c7efb9c5 authored by Moez Bhatti's avatar Moez Bhatti
Browse files

Merge branch 'auto-delete'

Closes #119
parents df181caf e6f216fa
Loading
Loading
Loading
Loading
+5 −0
Original line number Original line Diff line number Diff line
@@ -18,6 +18,7 @@
 */
 */
package com.moez.QKSMS.common.util.extensions
package com.moez.QKSMS.common.util.extensions


import android.app.job.JobScheduler
import android.content.Context
import android.content.Context
import android.content.res.ColorStateList
import android.content.res.ColorStateList
import android.graphics.Color
import android.graphics.Color
@@ -25,6 +26,7 @@ import android.util.TypedValue
import android.widget.Toast
import android.widget.Toast
import androidx.annotation.StringRes
import androidx.annotation.StringRes
import androidx.core.content.ContextCompat
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import com.moez.QKSMS.util.tryOrNull
import com.moez.QKSMS.util.tryOrNull


fun Context.getColorCompat(colorRes: Int): Int {
fun Context.getColorCompat(colorRes: Int): Int {
@@ -84,3 +86,6 @@ fun Context.isInstalled(packageName: String): Boolean {


val Context.versionCode: Int
val Context.versionCode: Int
    get() = packageManager.getPackageInfo(packageName, 0).versionCode
    get() = packageManager.getPackageInfo(packageName, 0).versionCode

val Context.jobScheduler: JobScheduler
    get() = getSystemService()!!
+27 −1
Original line number Original line Diff line number Diff line
@@ -66,8 +66,11 @@ import java.io.File
import java.io.FileNotFoundException
import java.io.FileNotFoundException
import java.io.FileOutputStream
import java.io.FileOutputStream
import java.io.IOException
import java.io.IOException
import java.util.*
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import javax.inject.Inject
import javax.inject.Singleton
import javax.inject.Singleton
import kotlin.collections.ArrayList
import kotlin.math.sqrt
import kotlin.math.sqrt


@Singleton
@Singleton
@@ -724,4 +727,27 @@ class MessageRepositoryImpl @Inject constructor(
        }
        }
    }
    }


    override fun getOldMessageCounts(maxAgeDays: Int): Map<Long, Int> {
        return Realm.getDefaultInstance().use { realm ->
            realm.where(Message::class.java)
                    .lessThan("date", now() - TimeUnit.DAYS.toMillis(maxAgeDays.toLong()))
                    .findAll()
                    .groupingBy { message -> message.threadId }
                    .eachCount()
        }
    }

    override fun deleteOldMessages(maxAgeDays: Int) {
        return Realm.getDefaultInstance().use { realm ->
            val messages = realm.where(Message::class.java)
                    .lessThan("date", now() - TimeUnit.DAYS.toMillis(maxAgeDays.toLong()))
                    .findAll()

            val uris = messages.map { it.getUri() }

            realm.executeTransaction { messages.deleteAllFromRealm() }

            uris.forEach { uri -> context.contentResolver.delete(uri, null, null) }
        }
    }
}
}
+62 −0
Original line number Original line Diff line number Diff line
package com.moez.QKSMS.service

import android.annotation.SuppressLint
import android.app.job.JobInfo
import android.app.job.JobParameters
import android.app.job.JobService
import android.content.ComponentName
import android.content.Context
import androidx.core.content.getSystemService
import com.moez.QKSMS.common.util.extensions.jobScheduler
import com.moez.QKSMS.interactor.DeleteOldMessages
import dagger.android.AndroidInjection
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.plusAssign
import kotlinx.coroutines.Job
import timber.log.Timber
import java.util.concurrent.TimeUnit
import javax.inject.Inject

class AutoDeleteService : JobService() {

    companion object {
        private const val JobId = 8120235

        @SuppressLint("MissingPermission") // Added in [presentation]'s AndroidManifest.xml
        fun scheduleJob(context: Context) {
            Timber.i("Scheduling job")
            val serviceComponent = ComponentName(context, AutoDeleteService::class.java)
            val periodicJob = JobInfo.Builder(JobId, serviceComponent)
                    .setPeriodic(TimeUnit.DAYS.toMillis(1))
                    .setPersisted(true)
                    .build()

            context.jobScheduler.schedule(periodicJob)
        }

        fun cancelJob(context: Context) {
            Timber.i("Canceling job")
            context.jobScheduler.cancel(JobId)
        }
    }

    @Inject lateinit var deleteOldMessages: DeleteOldMessages

    private val disposables = CompositeDisposable()

    override fun onStartJob(params: JobParameters?): Boolean {
        Timber.i("onStartJob")
        AndroidInjection.inject(this)
        disposables += deleteOldMessages
        deleteOldMessages.execute(Unit) {
            jobFinished(params, false)
        }
        return true
    }

    override fun onStopJob(params: JobParameters?): Boolean {
        Timber.i("onStopJob")
        disposables.dispose()
        return true
    }
}
+44 −0
Original line number Original line Diff line number Diff line
/*
 * 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 com.moez.QKSMS.interactor

import com.moez.QKSMS.repository.ConversationRepository
import com.moez.QKSMS.repository.MessageRepository
import com.moez.QKSMS.util.Preferences
import io.reactivex.Flowable
import timber.log.Timber
import javax.inject.Inject

class DeleteOldMessages @Inject constructor(
    private val conversationRepo: ConversationRepository,
    private val messageRepo: MessageRepository,
    private val prefs: Preferences
) : Interactor<Unit>() {

    override fun buildObservable(params: Unit): Flowable<*> = Flowable.fromCallable {
        val maxAge = prefs.autoDelete.get().takeIf { it > 0 } ?: return@fromCallable
        val counts = messageRepo.getOldMessageCounts(maxAge)
        val threadIds = counts.keys.toLongArray()

        Timber.d("Deleting ${counts.values.sum()} old messages from ${threadIds.size} conversations")
        messageRepo.deleteOldMessages(maxAge)
        conversationRepo.updateConversations(*threadIds)
    }

}
+10 −0
Original line number Original line Diff line number Diff line
@@ -102,4 +102,14 @@ interface MessageRepository {


    fun deleteMessages(vararg messageIds: Long)
    fun deleteMessages(vararg messageIds: Long)


    /**
     * Returns the number of messages older than [maxAgeDays] per conversation
     */
    fun getOldMessageCounts(maxAgeDays: Int): Map<Long, Int>

    /**
     * Deletes all messages older than [maxAgeDays]
     */
    fun deleteOldMessages(maxAgeDays: Int)

}
}
Loading