110 lines
5.0 KiB
Kotlin
110 lines
5.0 KiB
Kotlin
package space.bloggin.mercies
|
|
|
|
import android.Manifest
|
|
import android.app.AlarmManager
|
|
import android.app.NotificationChannel
|
|
import android.app.NotificationManager
|
|
import android.app.PendingIntent
|
|
import android.appwidget.AppWidgetManager
|
|
import android.appwidget.AppWidgetProvider
|
|
import android.content.BroadcastReceiver
|
|
import android.content.ComponentName
|
|
import android.content.Context
|
|
import android.content.Intent
|
|
import android.content.pm.PackageManager
|
|
import android.os.Build
|
|
import android.widget.RemoteViews
|
|
import androidx.core.app.NotificationCompat
|
|
import androidx.core.content.ContextCompat
|
|
import java.time.LocalDate
|
|
import java.util.Calendar
|
|
|
|
object Daily {
|
|
private const val CH = "mercies"
|
|
|
|
fun open(ctx: Context, tab: String, code: Int): PendingIntent {
|
|
val i = Intent(ctx, MainActivity::class.java).apply {
|
|
action = "space.bloggin.mercies.OPEN_$tab"; putExtra("tab", tab)
|
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
|
|
}
|
|
return PendingIntent.getActivity(ctx, code, i, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
|
|
}
|
|
|
|
private fun alarm(ctx: Context, which: String, on: Boolean, h: Int, m: Int, code: Int) {
|
|
val am = ctx.getSystemService(AlarmManager::class.java)
|
|
val pi = PendingIntent.getBroadcast(ctx, code, Intent(ctx, DailyReceiver::class.java).putExtra("which", which),
|
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
|
|
am.cancel(pi)
|
|
if (!on) return
|
|
val cal = Calendar.getInstance().apply {
|
|
set(Calendar.HOUR_OF_DAY, h); set(Calendar.MINUTE, m); set(Calendar.SECOND, 0)
|
|
if (timeInMillis <= System.currentTimeMillis()) add(Calendar.DAY_OF_YEAR, 1)
|
|
}
|
|
am.setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.timeInMillis, AlarmManager.INTERVAL_DAY, pi)
|
|
}
|
|
|
|
fun schedule(ctx: Context) {
|
|
val p = Prefs.get(ctx)
|
|
alarm(ctx, "eve", p.eve, p.eveH, p.eveM, 11)
|
|
alarm(ctx, "morn", true, if (p.morn) p.mornH else 0, if (p.morn) p.mornM else 3, 12) // also refreshes the widget each day
|
|
}
|
|
|
|
fun notify(ctx: Context, which: String) {
|
|
if (Build.VERSION.SDK_INT >= 33 && ContextCompat.checkSelfPermission(ctx, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) return
|
|
val nm = ctx.getSystemService(NotificationManager::class.java)
|
|
nm.createNotificationChannel(NotificationChannel(CH, "Gentle reminders", NotificationManager.IMPORTANCE_DEFAULT))
|
|
val n = if (which == "eve") {
|
|
val alreadyToday = Store.get(ctx).notesOn(LocalDate.now()).isNotEmpty()
|
|
if (alreadyToday) return
|
|
NotificationCompat.Builder(ctx, CH).setSmallIcon(R.drawable.ic_notify)
|
|
.setContentTitle("The jar is open")
|
|
.setContentText(Prompts.forDate(LocalDate.now()))
|
|
.setContentIntent(open(ctx, "jar", 21)).setAutoCancel(true).build()
|
|
} else {
|
|
val k = Store.get(ctx).kindToday()
|
|
NotificationCompat.Builder(ctx, CH).setSmallIcon(R.drawable.ic_notify)
|
|
.setContentTitle("Today's kindness")
|
|
.setContentText(Kindness.all[k.idx])
|
|
.setStyle(NotificationCompat.BigTextStyle().bigText(Kindness.all[k.idx]))
|
|
.setContentIntent(open(ctx, "kind", 22)).setAutoCancel(true).build()
|
|
}
|
|
nm.notify(if (which == "eve") 1 else 2, n)
|
|
}
|
|
}
|
|
|
|
class DailyReceiver : BroadcastReceiver() {
|
|
override fun onReceive(ctx: Context, intent: Intent) {
|
|
val which = intent.getStringExtra("which") ?: return
|
|
MercyWidget.refresh(ctx)
|
|
val p = Prefs.get(ctx)
|
|
if ((which == "eve" && p.eve) || (which == "morn" && p.morn)) Daily.notify(ctx, which)
|
|
}
|
|
}
|
|
|
|
class BootReceiver : BroadcastReceiver() {
|
|
override fun onReceive(ctx: Context, intent: Intent) { Daily.schedule(ctx); MercyWidget.refresh(ctx) }
|
|
}
|
|
|
|
class MercyWidget : AppWidgetProvider() {
|
|
override fun onUpdate(ctx: Context, mgr: AppWidgetManager, ids: IntArray) = update(ctx, mgr, ids)
|
|
|
|
companion object {
|
|
fun update(ctx: Context, mgr: AppWidgetManager, ids: IntArray) {
|
|
val store = Store.get(ctx)
|
|
val k = store.kindToday()
|
|
val count = store.noteCount()
|
|
for (id in ids) {
|
|
val rv = RemoteViews(ctx.packageName, R.layout.widget_mercy)
|
|
rv.setTextViewText(R.id.w_text, Kindness.all[k.idx])
|
|
rv.setTextViewText(R.id.w_foot, (if (k.status == 1) "Done ❀ " else "") + if (count == 1) "1 mercy in the jar" else "$count mercies in the jar")
|
|
rv.setOnClickPendingIntent(R.id.w_root, Daily.open(ctx, "kind", 23))
|
|
mgr.updateAppWidget(id, rv)
|
|
}
|
|
}
|
|
fun refresh(ctx: Context) = try {
|
|
val mgr = AppWidgetManager.getInstance(ctx)
|
|
update(ctx, mgr, mgr.getAppWidgetIds(ComponentName(ctx, MercyWidget::class.java)))
|
|
} catch (_: Exception) {}
|
|
}
|
|
}
|