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) {} } }