Skip to content
This repository has been archived by the owner on Nov 12, 2024. It is now read-only.

Queue notifications at startup #1949

Merged
merged 3 commits into from
Jul 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ kotlin {
dependencies {
implementation(libs.androidx.core)
implementation(libs.androidx.datastore)
implementation(projects.core.notificationsProtos)
implementation(projects.core.notifications.protos)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion domain/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ kotlin {
commonMain {
dependencies {
implementation(projects.core.base)
implementation(projects.core.notifications)
implementation(projects.core.notifications.core)
api(projects.common.ui.resources.strings)

api(projects.data.models)
Expand Down
4 changes: 2 additions & 2 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ include(
":core:permissions",
":core:powercontroller",
":core:preferences",
":core:notifications",
":core:notifications-protos",
":core:notifications:core",
":core:notifications:protos",
":common:ui:circuit",
":common:ui:resources:fonts",
":common:ui:resources:strings",
Expand Down
2 changes: 1 addition & 1 deletion shared/common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ kotlin {
api(projects.core.base)
api(projects.core.analytics)
api(projects.core.logging.implementation)
api(projects.core.notifications)
api(projects.core.notifications.core)
api(projects.core.performance)
api(projects.core.permissions)
api(projects.core.powercontroller)
Expand Down
2 changes: 1 addition & 1 deletion tasks/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ kotlin {
dependencies {
implementation(projects.core.base)
implementation(projects.core.logging.api)
implementation(projects.core.notifications)
implementation(projects.core.notifications.core)
implementation(projects.domain)
implementation(libs.kotlininject.runtime)
}
Expand Down
25 changes: 25 additions & 0 deletions tasks/src/androidMain/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2024, Christopher Banes and the Tivi project contributors -->
<!-- SPDX-License-Identifier: Apache-2.0 -->

<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<application>

<receiver
android:name="app.tivi.tasks.BootBroadcastReceiver"
android:directBootAware="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
</intent-filter>
</receiver>

</application>

</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package app.tivi.tasks

import androidx.work.Constraints
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.ExistingWorkPolicy
import androidx.work.NetworkType
import androidx.work.OneTimeWorkRequest
import androidx.work.PeriodicWorkRequestBuilder
Expand All @@ -14,9 +15,9 @@ import kotlin.time.toJavaDuration
import me.tatarka.inject.annotations.Inject

@Inject
class AndroidShowTasks(
class AndroidTasks(
workManager: Lazy<WorkManager>,
) : ShowTasks {
) : Tasks {
private val workManager by workManager

override fun registerPeriodicTasks() {
Expand All @@ -26,17 +27,15 @@ class AndroidShowTasks(
.build()

workManager.enqueueUniquePeriodicWork(
SyncLibraryShowsWorker.TAG,
SyncLibraryShowsWorker.NAME,
ExistingPeriodicWorkPolicy.UPDATE,
PeriodicWorkRequestBuilder<SyncLibraryShowsWorker>(
LIBRARY_NIGHTLY_SYNC_INTERVAL.toJavaDuration(),
)
PeriodicWorkRequestBuilder<SyncLibraryShowsWorker>(LIBRARY_SYNC_INTERVAL.toJavaDuration())
.setConstraints(nightlyConstraints)
.build(),
)

workManager.enqueueUniquePeriodicWork(
ScheduleEpisodeNotificationsWorker.TAG,
ScheduleEpisodeNotificationsWorker.NAME,
ExistingPeriodicWorkPolicy.UPDATE,
PeriodicWorkRequestBuilder<ScheduleEpisodeNotificationsWorker>(
SCHEDULE_EPISODE_NOTIFICATIONS_INTERVAL.toJavaDuration(),
Expand All @@ -45,13 +44,15 @@ class AndroidShowTasks(
}

override fun enqueueStartupTasks() {
workManager.enqueue(
workManager.enqueueUniqueWork(
"tasks_startup",
ExistingWorkPolicy.KEEP,
OneTimeWorkRequest.from(ScheduleEpisodeNotificationsWorker::class.java),
)
}

internal companion object {
val LIBRARY_NIGHTLY_SYNC_INTERVAL = 24.hours
val LIBRARY_SYNC_INTERVAL = 12.hours
val SCHEDULE_EPISODE_NOTIFICATIONS_INTERVAL = 6.hours
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright 2024, Christopher Banes and the Tivi project contributors
// SPDX-License-Identifier: Apache-2.0

package app.tivi.tasks

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent

class BootBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
// We don't need to do anything here, as the AppInitializers should do what we need
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,16 @@ class ScheduleEpisodeNotificationsWorker(
private val logger: Logger,
) : CoroutineWorker(context, params) {
companion object {
internal const val TAG = "set-episode-notifications"
internal const val NAME = "set-episode-notifications"
}

override suspend fun doWork(): Result {
logger.d { "$TAG worker running" }
logger.d { "$NAME worker running" }
val result = scheduleEpisodeNotifications.value.invoke(
ScheduleEpisodeNotifications.Params(
// We always schedule notifications for longer than the next task schedule, just in case
// the task doesn't run on time
AndroidShowTasks.SCHEDULE_EPISODE_NOTIFICATIONS_INTERVAL * 1.5,
AndroidTasks.SCHEDULE_EPISODE_NOTIFICATIONS_INTERVAL * 1.5,
),
)
return when {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ class SyncLibraryShowsWorker(
private val logger: Logger,
) : CoroutineWorker(context, params) {
companion object {
internal const val TAG = "night-sync-all-followed-shows"
internal const val NAME = "night-sync-all-followed-shows"
}

override suspend fun doWork(): Result {
logger.d { "$TAG worker running" }
logger.d { "$NAME worker running" }
val result = updateLibraryShows.value(UpdateLibraryShows.Params(true))
return when {
result.isSuccess -> Result.success()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import me.tatarka.inject.annotations.Provides
actual interface TasksPlatformComponent {
@ApplicationScope
@Provides
fun provideShowTasks(bind: AndroidShowTasks): ShowTasks = bind
fun provideShowTasks(bind: AndroidTasks): Tasks = bind

@ApplicationScope
@Provides
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

package app.tivi.tasks

interface ShowTasks {
interface Tasks {
fun registerPeriodicTasks() = Unit

fun enqueueStartupTasks() = Unit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ interface TasksComponent : TasksPlatformComponent {
@ApplicationScope
@Provides
@IntoSet
fun provideShowTasksInitializer(bind: ShowTasksInitializer): AppInitializer = bind
fun provideShowTasksInitializer(bind: TasksInitializer): AppInitializer = bind
}

expect interface TasksPlatformComponent
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import app.tivi.appinitializers.AppInitializer
import me.tatarka.inject.annotations.Inject

@Inject
class ShowTasksInitializer(
showTasks: Lazy<ShowTasks>,
class TasksInitializer(
tasks: Lazy<Tasks>,
) : AppInitializer {
private val showTasks by showTasks
private val tasks by tasks

override fun initialize() {
showTasks.registerPeriodicTasks()
showTasks.enqueueStartupTasks()
tasks.registerPeriodicTasks()
tasks.enqueueStartupTasks()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ package app.tivi.tasks

import app.tivi.domain.interactors.ScheduleEpisodeNotifications
import app.tivi.domain.interactors.UpdateLibraryShows
import app.tivi.inject.ApplicationCoroutineScope
import app.tivi.util.Logger
import kotlin.time.Duration.Companion.hours
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.plus
import kotlinx.coroutines.runBlocking
Expand All @@ -25,13 +24,13 @@ import platform.Foundation.NSCalendarMatchStrictly
import platform.Foundation.NSDate

@Inject
class IosShowTasks(
class IosTasks(
updateLibraryShows: Lazy<UpdateLibraryShows>,
scheduleEpisodeNotifications: Lazy<ScheduleEpisodeNotifications>,
private val logger: Logger,
) : ShowTasks {
private val scope: ApplicationCoroutineScope,
) : Tasks {
private val taskScheduler by lazy { BGTaskScheduler.sharedScheduler }
private val scope by lazy { MainScope() + CoroutineName("app.tivi.tasks.IosShowTasks") }

private val updateLibraryShows by updateLibraryShows
private val scheduleEpisodeNotifications by scheduleEpisodeNotifications
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ import me.tatarka.inject.annotations.Provides
actual interface TasksPlatformComponent {
@ApplicationScope
@Provides
fun provideShowTasks(bind: IosShowTasks): ShowTasks = bind
fun provideShowTasks(bind: IosTasks): Tasks = bind
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import me.tatarka.inject.annotations.Provides
actual interface TasksPlatformComponent {
@ApplicationScope
@Provides
fun provideShowTasks(): ShowTasks = EmptyShowTasks
fun provideShowTasks(): Tasks = EmptyShowTasks
}

object EmptyShowTasks : ShowTasks {
object EmptyShowTasks : Tasks {
override fun registerPeriodicTasks() = Unit
}
2 changes: 1 addition & 1 deletion ui/developer/notifications/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ kotlin {
commonMain {
dependencies {
implementation(projects.core.base)
api(projects.core.notifications)
api(projects.core.notifications.core)
api(projects.domain)

implementation(projects.common.ui.compose)
Expand Down
Loading