package com.github.libretube.util import android.app.PendingIntent import android.content.Context import android.content.Intent import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import androidx.work.Constraints import androidx.work.ExistingPeriodicWorkPolicy import androidx.work.NetworkType import androidx.work.PeriodicWorkRequest import androidx.work.WorkManager import com.github.libretube.NOTIFICATION_WORK_NAME import com.github.libretube.PUSH_CHANNEL_ID import com.github.libretube.PUSH_NOTIFICATION_ID import com.github.libretube.R import com.github.libretube.activities.MainActivity import com.github.libretube.api.RetrofitInstance import com.github.libretube.api.SubscriptionHelper import com.github.libretube.preferences.PreferenceHelper import com.github.libretube.preferences.PreferenceKeys import kotlinx.coroutines.async import kotlinx.coroutines.runBlocking import java.util.concurrent.TimeUnit object NotificationHelper { /** * Enqueue the work manager task */ fun enqueueWork( context: Context, existingPeriodicWorkPolicy: ExistingPeriodicWorkPolicy ) { // get the notification preferences PreferenceHelper.setContext(context) val notificationsEnabled = PreferenceHelper.getBoolean( PreferenceKeys.NOTIFICATION_ENABLED, true ) val checkingFrequency = PreferenceHelper.getString( PreferenceKeys.CHECKING_FREQUENCY, "60" ).toLong() // schedule the work manager request if logged in and notifications enabled if (notificationsEnabled && PreferenceHelper.getToken() != "") { // required network type for the work val networkType = when ( PreferenceHelper.getString(PreferenceKeys.REQUIRED_NETWORK, "all") ) { "all" -> NetworkType.CONNECTED "wifi" -> NetworkType.UNMETERED "metered" -> NetworkType.METERED else -> NetworkType.CONNECTED } // requirements for the work // here: network needed to run the task val constraints = Constraints.Builder() .setRequiredNetworkType(networkType) .build() // create the worker val notificationWorker = PeriodicWorkRequest.Builder( NotificationWorker::class.java, checkingFrequency, TimeUnit.MINUTES ) .setConstraints(constraints) .build() // enqueue the task WorkManager.getInstance(context) .enqueueUniquePeriodicWork( NOTIFICATION_WORK_NAME, existingPeriodicWorkPolicy, notificationWorker ) } else { // cancel the work if notifications are disabled or the user is not logged in WorkManager.getInstance(context) .cancelUniqueWork(NOTIFICATION_WORK_NAME) } } /** * check whether new streams are available in subscriptions */ fun checkForNewStreams(context: Context): Boolean { var result = true val token = PreferenceHelper.getToken() runBlocking { val task = async { if (token != "") RetrofitInstance.authApi.getFeed(token) else RetrofitInstance.authApi.getUnauthenticatedFeed( SubscriptionHelper.getFormattedLocalSubscriptions() ) } // fetch the users feed val videoFeed = try { task.await() } catch (e: Exception) { result = false return@runBlocking } val lastSeenStreamId = PreferenceHelper.getLatestVideoId() val latestFeedStreamId = videoFeed[0].url.toID() // first time notifications enabled if (lastSeenStreamId == "") PreferenceHelper.setLatestVideoId(lastSeenStreamId) else if (lastSeenStreamId != latestFeedStreamId) { // get the index of the last user-seen video var newStreamIndex = -1 videoFeed.forEachIndexed { index, stream -> if (stream.url?.toID() == lastSeenStreamId) { newStreamIndex = index } } if (newStreamIndex == -1) return@runBlocking val (title, description) = when (newStreamIndex) { // only one new stream available 1 -> { Pair(videoFeed[0].title, videoFeed[0].uploaderName) } else -> { Pair( // return the amount of new streams as title context.getString( R.string.new_streams_count, newStreamIndex.toString() ), // return the first few uploader as description context.getString( R.string.new_streams_by, videoFeed[0].uploaderName + ", " + videoFeed[1].uploaderName + ", " + videoFeed[2].uploaderName ) ) } } // save the id of the last recent video for the next time it's running PreferenceHelper.setLatestVideoId(videoFeed[0].url.toID()) createNotification(context, title!!, description!!) } } // return whether the work succeeded return result } /** * Notification that is created when new streams are found */ fun createNotification(context: Context, title: String, description: String) { val intent = Intent(context, MainActivity::class.java).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK } val pendingIntent: PendingIntent = PendingIntent.getActivity( context, 0, intent, PendingIntent.FLAG_IMMUTABLE ) val builder = NotificationCompat.Builder(context, PUSH_CHANNEL_ID) .setContentTitle(title) .setSmallIcon(R.drawable.ic_bell) .setContentText(description) .setPriority(NotificationCompat.PRIORITY_DEFAULT) // Set the intent that will fire when the user taps the notification .setContentIntent(pendingIntent) .setAutoCancel(true) with(NotificationManagerCompat.from(context)) { // notificationId is a unique int for each notification that you must define notify(PUSH_NOTIFICATION_ID, builder.build()) } } }