diff --git a/app/build.gradle b/app/build.gradle index c37e69c..330d85c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -44,6 +44,7 @@ dependencies { implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0' implementation 'androidx.navigation:navigation-fragment-ktx:2.1.0' implementation 'androidx.navigation:navigation-ui-ktx:2.1.0' + implementation "androidx.work:work-runtime-ktx:2.2.0" implementation "androidx.room:room-runtime:2.2.0-rc01" kapt "androidx.room:room-compiler:2.2.0-rc01" implementation "androidx.room:room-ktx:2.2.0-rc01" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 100aeb2..174589e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -20,6 +20,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/java/net/underdesk/circolapp/BootCompleteReceiver.kt b/app/src/main/java/net/underdesk/circolapp/BootCompleteReceiver.kt new file mode 100644 index 0000000..de68cf2 --- /dev/null +++ b/app/src/main/java/net/underdesk/circolapp/BootCompleteReceiver.kt @@ -0,0 +1,32 @@ +/* + * Circolapp + * Copyright (C) 2019 Matteo Schiff + * + * 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. + * + * This program 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 this program. If not, see . + */ + +package net.underdesk.circolapp + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import net.underdesk.circolapp.works.PollWork + + +class BootCompleteReceiver : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + if (intent.action == null || intent.action != "android.intent.action.BOOT_COMPLETED") return + PollWork.enqueue(context) + } +} \ No newline at end of file diff --git a/app/src/main/java/net/underdesk/circolapp/MainActivity.kt b/app/src/main/java/net/underdesk/circolapp/MainActivity.kt index e0a5be6..ca7b476 100644 --- a/app/src/main/java/net/underdesk/circolapp/MainActivity.kt +++ b/app/src/main/java/net/underdesk/circolapp/MainActivity.kt @@ -25,6 +25,7 @@ import androidx.navigation.ui.AppBarConfiguration import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupWithNavController import com.google.android.material.bottomnavigation.BottomNavigationView +import net.underdesk.circolapp.works.PollWork class MainActivity : AppCompatActivity() { @@ -45,5 +46,7 @@ class MainActivity : AppCompatActivity() { ) setupActionBarWithNavController(navController, appBarConfiguration) navView.setupWithNavController(navController) + + PollWork.enqueue(this) } } diff --git a/app/src/main/java/net/underdesk/circolapp/works/PollWork.kt b/app/src/main/java/net/underdesk/circolapp/works/PollWork.kt new file mode 100644 index 0000000..ad6983c --- /dev/null +++ b/app/src/main/java/net/underdesk/circolapp/works/PollWork.kt @@ -0,0 +1,128 @@ +/* + * Circolapp + * Copyright (C) 2019 Matteo Schiff + * + * 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. + * + * This program 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 this program. If not, see . + */ + +package net.underdesk.circolapp.works + +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.PendingIntent +import android.content.Context +import android.content.Intent +import android.os.Build +import androidx.core.app.NotificationCompat +import androidx.core.app.NotificationManagerCompat +import androidx.work.* +import net.underdesk.circolapp.MainActivity +import net.underdesk.circolapp.R +import net.underdesk.circolapp.data.AppDatabase +import net.underdesk.circolapp.data.Circular +import net.underdesk.circolapp.server.DataFetcher +import java.util.concurrent.TimeUnit + + +class PollWork(appContext: Context, workerParams: WorkerParameters) : + Worker(appContext, workerParams) { + + companion object { + const val CHANNEL_ID = "net.underdesk.circolapp.NEW_CIRCULAR" + + private const val pollWorkName = "net.underdesk.circolapp.POLL_WORK" + private const val repeatIntervalMin: Long = 30 + private const val flexIntervalMin: Long = 10 + + private fun getPollWorkRequest(): PeriodicWorkRequest { + val constraints = Constraints.Builder() + .setRequiredNetworkType(NetworkType.CONNECTED) + .build() + + return PeriodicWorkRequestBuilder( + repeatIntervalMin, + TimeUnit.MINUTES, + flexIntervalMin, + TimeUnit.MINUTES + ).setConstraints(constraints).build() + } + + fun enqueue(context: Context) { + WorkManager.getInstance(context) + .enqueueUniquePeriodicWork( + pollWorkName, + ExistingPeriodicWorkPolicy.KEEP, + getPollWorkRequest() + ) + } + } + + override fun doWork(): Result { + val fetcher = DataFetcher() + + val oldCirculars = AppDatabase.getInstance(applicationContext).circularDao().getCirculars() + val newCirculars = fetcher.getCircularsFromServer() + + if (newCirculars.size != oldCirculars.size) { + for (i in oldCirculars.lastIndex..newCirculars.lastIndex) { + createNotificationChannel() + createNotification(newCirculars[i]) + } + + AppDatabase.getInstance(applicationContext).circularDao().deleteAll() + AppDatabase.getInstance(applicationContext).circularDao().insertAll(newCirculars) + } + return Result.success() + } + + private fun createNotification(circular: Circular) { + val intent = Intent(applicationContext, MainActivity::class.java).apply { + flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK + } + val pendingIntent: PendingIntent = + PendingIntent.getActivity(applicationContext, 0, intent, 0) + + val builder = NotificationCompat.Builder(applicationContext, CHANNEL_ID) + .setSmallIcon(R.drawable.ic_notifications_black_24dp) + .setContentTitle(applicationContext.getString(R.string.notification_title, circular.id)) + .setContentText(circular.name) + .setPriority(NotificationCompat.PRIORITY_DEFAULT) + .setContentIntent(pendingIntent) + .setGroup(CHANNEL_ID) + .setStyle( + NotificationCompat.BigTextStyle() + .bigText(circular.name) + ) + + with(NotificationManagerCompat.from(applicationContext)) { + notify(circular.id.toInt(), builder.build()) + } + } + + private fun createNotificationChannel() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val name = applicationContext.getString(R.string.channel_name) + val descriptionText = applicationContext.getString(R.string.channel_description) + val importance = NotificationManager.IMPORTANCE_DEFAULT + val channel = NotificationChannel(CHANNEL_ID, name, importance).apply { + description = descriptionText + } + + val notificationManager: NotificationManager = + applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + notificationManager.createNotificationChannel(channel) + } + } + +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2198455..baba40b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3,4 +3,9 @@ Circular letters Favourites Reminders + + Published circular letter number %1$d + + Circular letters + Notify when your school issue a new circular letter