diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index c2faf843e..7394f34da 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -116,6 +116,11 @@ dependencies {
compileOnly(libs.bundles.room)
testCompileOnly(libs.bundles.room)
+ // @HiltWorker annotation
+ implementation(libs.androidx.hilt.common)
+ implementation(libs.androidx.hilt.work)
+ ksp(libs.androidx.hilt.compiler)
+
implementation(projects.core.accounts)
implementation(projects.core.activity)
implementation(projects.core.common)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d2add7046..196362e85 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -212,17 +212,11 @@
android:resource="@xml/file_paths" />
-
+
-
-
+ tools:node="remove" />
diff --git a/app/src/main/java/app/pachli/PachliApplication.kt b/app/src/main/java/app/pachli/PachliApplication.kt
index 1d1c6e48c..884cbedf9 100644
--- a/app/src/main/java/app/pachli/PachliApplication.kt
+++ b/app/src/main/java/app/pachli/PachliApplication.kt
@@ -20,6 +20,7 @@ package app.pachli
import android.app.Application
import android.content.Context
import androidx.core.content.edit
+import androidx.hilt.work.HiltWorkerFactory
import androidx.work.Constraints
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.PeriodicWorkRequestBuilder
@@ -37,7 +38,6 @@ import app.pachli.util.LocaleManager
import app.pachli.util.setAppNightMode
import app.pachli.worker.PruneCacheWorker
import app.pachli.worker.PruneLogEntryEntityWorker
-import app.pachli.worker.WorkerFactory
import dagger.hilt.android.HiltAndroidApp
import de.c1710.filemojicompat_defaults.DefaultEmojiPackList
import de.c1710.filemojicompat_ui.helpers.EmojiPackHelper
@@ -51,7 +51,7 @@ import timber.log.Timber
@HiltAndroidApp
class PachliApplication : Application() {
@Inject
- lateinit var workerFactory: WorkerFactory
+ lateinit var workerFactory: HiltWorkerFactory
@Inject
lateinit var localeManager: LocaleManager
@@ -110,9 +110,7 @@ class PachliApplication : Application() {
WorkManager.initialize(
this,
- androidx.work.Configuration.Builder()
- .setWorkerFactory(workerFactory)
- .build(),
+ androidx.work.Configuration.Builder().setWorkerFactory(workerFactory).build(),
)
val workManager = WorkManager.getInstance(this)
diff --git a/app/src/main/java/app/pachli/di/WorkerModule.kt b/app/src/main/java/app/pachli/di/WorkerModule.kt
deleted file mode 100644
index 17542f08b..000000000
--- a/app/src/main/java/app/pachli/di/WorkerModule.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2023 Pachli Association
- *
- * This file is a part of Pachli.
- *
- * This program 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.
- *
- * Pachli 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 Pachli; if not,
- * see .
- */
-
-package app.pachli.di
-
-import androidx.work.ListenableWorker
-import app.pachli.worker.ChildWorkerFactory
-import app.pachli.worker.NotificationWorker
-import app.pachli.worker.PruneCacheWorker
-import dagger.Binds
-import dagger.MapKey
-import dagger.Module
-import dagger.hilt.InstallIn
-import dagger.hilt.components.SingletonComponent
-import dagger.multibindings.IntoMap
-import kotlin.reflect.KClass
-
-@Retention(AnnotationRetention.RUNTIME)
-@MapKey
-annotation class WorkerKey(val value: KClass)
-
-@InstallIn(SingletonComponent::class)
-@Module
-abstract class WorkerModule {
- @Binds
- @IntoMap
- @WorkerKey(NotificationWorker::class)
- internal abstract fun bindNotificationWorkerFactory(worker: NotificationWorker.Factory): ChildWorkerFactory
-
- @Binds
- @IntoMap
- @WorkerKey(PruneCacheWorker::class)
- internal abstract fun bindPruneCacheWorkerFactory(worker: PruneCacheWorker.Factory): ChildWorkerFactory
-}
diff --git a/app/src/main/java/app/pachli/worker/NotificationWorker.kt b/app/src/main/java/app/pachli/worker/NotificationWorker.kt
index a6ae37fce..0b49938ba 100644
--- a/app/src/main/java/app/pachli/worker/NotificationWorker.kt
+++ b/app/src/main/java/app/pachli/worker/NotificationWorker.kt
@@ -19,6 +19,7 @@ package app.pachli.worker
import android.app.Notification
import android.content.Context
+import androidx.hilt.work.HiltWorker
import androidx.work.CoroutineWorker
import androidx.work.ForegroundInfo
import androidx.work.WorkerParameters
@@ -26,13 +27,15 @@ import app.pachli.R
import app.pachli.components.notifications.NOTIFICATION_ID_FETCH_NOTIFICATION
import app.pachli.components.notifications.NotificationFetcher
import app.pachli.components.notifications.createWorkerNotification
-import javax.inject.Inject
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedInject
import timber.log.Timber
/** Fetch and show new notifications. */
-class NotificationWorker(
- appContext: Context,
- params: WorkerParameters,
+@HiltWorker
+class NotificationWorker @AssistedInject constructor(
+ @Assisted appContext: Context,
+ @Assisted params: WorkerParameters,
private val notificationsFetcher: NotificationFetcher,
) : CoroutineWorker(appContext, params) {
val notification: Notification = createWorkerNotification(applicationContext, R.string.notification_notification_worker)
@@ -44,12 +47,4 @@ class NotificationWorker(
}
override suspend fun getForegroundInfo() = ForegroundInfo(NOTIFICATION_ID_FETCH_NOTIFICATION, notification)
-
- class Factory @Inject constructor(
- private val notificationsFetcher: NotificationFetcher,
- ) : ChildWorkerFactory {
- override fun createWorker(appContext: Context, params: WorkerParameters): CoroutineWorker {
- return NotificationWorker(appContext, params, notificationsFetcher)
- }
- }
}
diff --git a/app/src/main/java/app/pachli/worker/PruneCacheWorker.kt b/app/src/main/java/app/pachli/worker/PruneCacheWorker.kt
index c4da51d28..521f440c3 100644
--- a/app/src/main/java/app/pachli/worker/PruneCacheWorker.kt
+++ b/app/src/main/java/app/pachli/worker/PruneCacheWorker.kt
@@ -19,22 +19,24 @@ package app.pachli.worker
import android.app.Notification
import android.content.Context
+import androidx.hilt.work.HiltWorker
import androidx.work.CoroutineWorker
import androidx.work.ForegroundInfo
-import androidx.work.ListenableWorker
import androidx.work.WorkerParameters
import app.pachli.R
import app.pachli.components.notifications.NOTIFICATION_ID_PRUNE_CACHE
import app.pachli.components.notifications.createWorkerNotification
import app.pachli.core.accounts.AccountManager
import app.pachli.core.database.dao.TimelineDao
-import javax.inject.Inject
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedInject
import timber.log.Timber
/** Prune the database cache of old statuses. */
-class PruneCacheWorker(
- appContext: Context,
- workerParams: WorkerParameters,
+@HiltWorker
+class PruneCacheWorker @AssistedInject constructor(
+ @Assisted appContext: Context,
+ @Assisted workerParams: WorkerParameters,
private val timelineDao: TimelineDao,
private val accountManager: AccountManager,
) : CoroutineWorker(appContext, workerParams) {
@@ -54,13 +56,4 @@ class PruneCacheWorker(
private const val MAX_STATUSES_IN_CACHE = 1000
const val PERIODIC_WORK_TAG = "PruneCacheWorker_periodic"
}
-
- class Factory @Inject constructor(
- private val timelineDao: TimelineDao,
- private val accountManager: AccountManager,
- ) : ChildWorkerFactory {
- override fun createWorker(appContext: Context, params: WorkerParameters): ListenableWorker {
- return PruneCacheWorker(appContext, params, timelineDao, accountManager)
- }
- }
}
diff --git a/app/src/main/java/app/pachli/worker/PruneLogEntryEntityWorker.kt b/app/src/main/java/app/pachli/worker/PruneLogEntryEntityWorker.kt
index cdecd8522..a857a0364 100644
--- a/app/src/main/java/app/pachli/worker/PruneLogEntryEntityWorker.kt
+++ b/app/src/main/java/app/pachli/worker/PruneLogEntryEntityWorker.kt
@@ -19,31 +19,39 @@ package app.pachli.worker
import android.app.Notification
import android.content.Context
+import androidx.hilt.work.HiltWorker
import androidx.work.CoroutineWorker
import androidx.work.ForegroundInfo
-import androidx.work.ListenableWorker
import androidx.work.WorkerParameters
import app.pachli.R
import app.pachli.components.notifications.NOTIFICATION_ID_PRUNE_CACHE
import app.pachli.components.notifications.createWorkerNotification
import app.pachli.core.database.dao.LogEntryDao
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedInject
import java.time.Instant
-import javax.inject.Inject
import kotlin.time.Duration.Companion.hours
+import timber.log.Timber
/** Prune the database cache of old statuses. */
-class PruneLogEntryEntityWorker(
- appContext: Context,
- workerParams: WorkerParameters,
+@HiltWorker
+class PruneLogEntryEntityWorker @AssistedInject constructor(
+ @Assisted appContext: Context,
+ @Assisted workerParams: WorkerParameters,
private val logEntryDao: LogEntryDao,
) : CoroutineWorker(appContext, workerParams) {
val notification: Notification = createWorkerNotification(applicationContext, R.string.notification_prune_cache)
override suspend fun doWork(): Result {
- val now = Instant.now()
- val oldest = now.minusMillis(OLDEST_ENTRY.inWholeMilliseconds)
- logEntryDao.prune(oldest)
- return Result.success()
+ return try {
+ val now = Instant.now()
+ val oldest = now.minusMillis(OLDEST_ENTRY.inWholeMilliseconds)
+ logEntryDao.prune(oldest)
+ Result.success()
+ } catch (e: Exception) {
+ Timber.e(e, "error in PruneLogEntryEntityWorker.doWork")
+ Result.failure()
+ }
}
override suspend fun getForegroundInfo() = ForegroundInfo(NOTIFICATION_ID_PRUNE_CACHE, notification)
@@ -52,12 +60,4 @@ class PruneLogEntryEntityWorker(
private val OLDEST_ENTRY = 48.hours
const val PERIODIC_WORK_TAG = "PruneLogEntryEntityWorker_periodic"
}
-
- class Factory @Inject constructor(
- private val logEntryDao: LogEntryDao,
- ) : ChildWorkerFactory {
- override fun createWorker(appContext: Context, params: WorkerParameters): ListenableWorker {
- return PruneLogEntryEntityWorker(appContext, params, logEntryDao)
- }
- }
}
diff --git a/app/src/main/java/app/pachli/worker/WorkerFactory.kt b/app/src/main/java/app/pachli/worker/WorkerFactory.kt
deleted file mode 100644
index 5bc9856bf..000000000
--- a/app/src/main/java/app/pachli/worker/WorkerFactory.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2023 Pachli Association
- *
- * This file is a part of Pachli.
- *
- * This program 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.
- *
- * Pachli 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 Pachli; if not,
- * see .
- */
-
-package app.pachli.worker
-
-import android.content.Context
-import androidx.work.ListenableWorker
-import androidx.work.WorkerFactory
-import androidx.work.WorkerParameters
-import javax.inject.Inject
-import javax.inject.Provider
-import javax.inject.Singleton
-import timber.log.Timber
-
-/**
- * Workers implement this and are added to the map in [app.pachli.di.WorkerModule]
- * so they can be created by [WorkerFactory.createWorker].
- */
-interface ChildWorkerFactory {
- /** Create a new instance of the given worker. */
- fun createWorker(appContext: Context, params: WorkerParameters): ListenableWorker
-}
-
-/**
- * Creates workers, delegating to each worker's [ChildWorkerFactory.createWorker] to do the
- * creation.
- *
- * @see [app.pachli.worker.NotificationWorker]
- */
-@Singleton
-class WorkerFactory @Inject constructor(
- private val workerFactories: Map, @JvmSuppressWildcards Provider>,
-) : WorkerFactory() {
- override fun createWorker(
- appContext: Context,
- workerClassName: String,
- workerParameters: WorkerParameters,
- ): ListenableWorker? {
- val key = try {
- Class.forName(workerClassName)
- } catch (e: ClassNotFoundException) {
- // Class might be missing if it was renamed / moved to a different package, as
- // periodic work requests from before the rename might still exist. Catch and
- // return null, which should stop future requests.
- Timber.d(e, "Invalid class: %s", workerClassName)
- null
- }
- workerFactories[key]?.let {
- return it.get().createWorker(appContext, workerParameters)
- }
- return null
- }
-}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index f2b053dff..b5d5d61a3 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -10,6 +10,7 @@ androidx-constraintlayout = "2.1.4"
androidx-core = "1.12.0"
androidx-exifinterface = "1.3.7"
androidx-fragment = "1.6.2"
+androidx-hilt = "1.2.0"
androidx-junit = "1.1.5"
androidx-lifecycle = "2.7.0"
androidx-media3 = "1.2.1"
@@ -109,6 +110,9 @@ androidx-emoji2-views-core = { module = "androidx.emoji2:emoji2-views", version.
androidx-emoji2-view-helper = { module = "androidx.emoji2:emoji2-views-helper", version.ref = "emoji2" }
androidx-exifinterface = { module = "androidx.exifinterface:exifinterface", version.ref = "androidx-exifinterface" }
androidx-fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref = "androidx-fragment" }
+androidx-hilt-common = { module = "androidx.hilt:hilt-common", version.ref = "androidx-hilt" }
+androidx-hilt-compiler = { module = "androidx.hilt:hilt-compiler", version.ref = "androidx-hilt" }
+androidx-hilt-work = { module = "androidx.hilt:hilt-work", version.ref = "androidx-hilt" }
androidx-lifecycle-common-java8 = { module = "androidx.lifecycle:lifecycle-common-java8", version.ref = "androidx-lifecycle" }
androidx-lifecycle-livedata-ktx = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "androidx-lifecycle" }
androidx-lifecycle-reactivestreams-ktx = { module = "androidx.lifecycle:lifecycle-reactivestreams-ktx", version.ref = "androidx-lifecycle" }