diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsActivity.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsActivity.kt index 64c7a02c9..19d8cf7ea 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsActivity.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsActivity.kt @@ -85,7 +85,6 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener { Thread.setDefaultUncaughtExceptionHandler(BaseExceptionHandler(this)) component.listHabitsBehavior.onStartup() setContentView(rootView) - parseIntents() } override fun onPause() { @@ -110,6 +109,7 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener { if (prefs.theme == THEME_DARK && prefs.isPureBlackEnabled != pureBlack) { restartWithFade(ListHabitsActivity::class.java) } + parseIntents() super.onResume() } @@ -129,6 +129,7 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener { } private fun parseIntents() { + if (intent == null) return if (intent.action == ACTION_EDIT) { val habitId = intent.extras?.getLong("habit") val timestamp = intent.extras?.getLong("timestamp") @@ -137,6 +138,12 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener { component.listHabitsBehavior.onEdit(habit, Timestamp(timestamp)) } } + intent = null + } + + override fun onNewIntent(intent: Intent?) { + super.onNewIntent(intent) + setIntent(intent) } companion object { diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt b/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt index 3a1ee29c5..c8cc79065 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt @@ -21,13 +21,16 @@ package org.isoron.uhabits.intents import android.app.PendingIntent import android.app.PendingIntent.FLAG_IMMUTABLE +import android.app.PendingIntent.FLAG_MUTABLE import android.app.PendingIntent.FLAG_UPDATE_CURRENT import android.app.PendingIntent.getActivity import android.app.PendingIntent.getBroadcast import android.content.Context import android.content.Intent import android.net.Uri +import android.os.Build import org.isoron.uhabits.activities.habits.list.ListHabitsActivity +import org.isoron.uhabits.activities.habits.show.ShowHabitActivity import org.isoron.uhabits.core.AppScope import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.Timestamp @@ -89,6 +92,20 @@ class PendingIntentFactory ) .getPendingIntent(0, FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT)!! + fun showHabitTemplate(): PendingIntent { + return getActivity( + context, + 0, + Intent(context, ShowHabitActivity::class.java), + getIntentTemplateFlags() + ) + } + + fun showHabitFillIn(habit: Habit) = + Intent().apply { + data = Uri.parse(habit.uriString) + } + fun showReminder( habit: Habit, reminderTime: Long?, @@ -151,4 +168,43 @@ class PendingIntentFactory FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT ) } + + fun showNumberPickerTemplate(): PendingIntent { + return getActivity( + context, + 1, + Intent(context, ListHabitsActivity::class.java).apply { + action = ListHabitsActivity.ACTION_EDIT + }, + getIntentTemplateFlags() + ) + } + + fun showNumberPickerFillIn(habit: Habit, timestamp: Timestamp) = Intent().apply { + putExtra("habit", habit.id) + putExtra("timestamp", timestamp.unixTime) + } + + private fun getIntentTemplateFlags(): Int { + var flags = 0 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + flags = flags or FLAG_MUTABLE + } + return flags + } + + fun toggleCheckmarkTemplate(): PendingIntent = + getBroadcast( + context, + 2, + Intent(context, WidgetReceiver::class.java).apply { + action = WidgetReceiver.ACTION_TOGGLE_REPETITION + }, + getIntentTemplateFlags() + ) + + fun toggleCheckmarkFillIn(habit: Habit, timestamp: Timestamp) = Intent().apply { + data = Uri.parse(habit.uriString) + putExtra("timestamp", timestamp.unixTime) + } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidget.kt index fa6452a0e..ab2bace27 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidget.kt @@ -73,6 +73,10 @@ class StackWidget( StackWidgetType.getStackWidgetAdapterViewId(widgetType), StackWidgetType.getStackWidgetEmptyViewId(widgetType) ) + remoteViews.setPendingIntentTemplate( + StackWidgetType.getStackWidgetAdapterViewId(widgetType), + StackWidgetType.getPendingIntentTemplate(pendingIntentFactory, widgetType, habits) + ) return remoteViews } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetService.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetService.kt index dc86b9b66..c8eabcc1c 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetService.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetService.kt @@ -29,11 +29,14 @@ import android.widget.RemoteViewsService import android.widget.RemoteViewsService.RemoteViewsFactory import org.isoron.platform.utils.StringUtils.Companion.splitLongs import org.isoron.uhabits.HabitsApplication +import org.isoron.uhabits.R import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.HabitNotFoundException import org.isoron.uhabits.core.preferences.Preferences +import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday +import org.isoron.uhabits.intents.IntentFactory +import org.isoron.uhabits.intents.PendingIntentFactory import org.isoron.uhabits.utils.InterfaceUtils.dpToPixels -import java.util.ArrayList class StackWidgetService : RemoteViewsService() { override fun onGetViewFactory(intent: Intent): RemoteViewsFactory { @@ -138,14 +141,18 @@ internal class StackRemoteViewsFactory(private val context: Context, intent: Int val options = AppWidgetManager.getInstance(context).getAppWidgetOptions(widgetId) val newRemoteViews = ArrayList() if (Looper.myLooper() == null) Looper.prepare() - for (id in habitIds) { - val h = habitList.getById(id) ?: throw HabitNotFoundException() + val habits = habitIds.map { habitList.getById(it) ?: throw HabitNotFoundException() } + for (h in habits) { val widget = constructWidget(h, prefs) widget.setDimensions(getDimensionsFromOptions(context, options)) val landscapeViews = widget.landscapeRemoteViews val portraitViews = widget.portraitRemoteViews + val factory = PendingIntentFactory(context, IntentFactory()) + val intent = StackWidgetType.getIntentFillIn(factory, widgetType, h, habits, getToday()) + landscapeViews.setOnClickFillInIntent(R.id.button, intent) + portraitViews.setOnClickFillInIntent(R.id.button, intent) newRemoteViews.add(RemoteViews(landscapeViews, portraitViews)) - Log.i("StackRemoteViewsFactory", "onDataSetChanged constructed widget $id") + Log.i("StackRemoteViewsFactory", "onDataSetChanged constructed widget ${h.id}") } remoteViews = newRemoteViews Log.i("StackRemoteViewsFactory", "onDataSetChanged ended") diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetType.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetType.kt index 68e8018aa..1e3a5d217 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetType.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetType.kt @@ -18,7 +18,12 @@ */ package org.isoron.uhabits.widgets +import android.app.PendingIntent +import android.content.Intent import org.isoron.uhabits.R +import org.isoron.uhabits.core.models.Habit +import org.isoron.uhabits.core.models.Timestamp +import org.isoron.uhabits.intents.PendingIntentFactory import java.lang.IllegalStateException enum class StackWidgetType(val value: Int) { @@ -73,5 +78,39 @@ enum class StackWidgetType(val value: Int) { else -> throw IllegalStateException() } } + + fun getPendingIntentTemplate( + factory: PendingIntentFactory, + widgetType: StackWidgetType, + habits: List + ): PendingIntent { + val containsNumerical = habits.any { it.isNumerical } + return when (widgetType) { + CHECKMARK -> if (containsNumerical) { + factory.showNumberPickerTemplate() + } else { + factory.toggleCheckmarkTemplate() + } + FREQUENCY, SCORE, HISTORY, STREAKS, TARGET -> factory.showHabitTemplate() + } + } + + fun getIntentFillIn( + factory: PendingIntentFactory, + widgetType: StackWidgetType, + habit: Habit, + allHabitsInStackWidget: List, + timestamp: Timestamp + ): Intent { + val containsNumerical = allHabitsInStackWidget.any { it.isNumerical } + return when (widgetType) { + CHECKMARK -> if (containsNumerical) { + factory.showNumberPickerFillIn(habit, timestamp) + } else { + factory.toggleCheckmarkFillIn(habit, timestamp) + } + FREQUENCY, SCORE, HISTORY, STREAKS, TARGET -> factory.showHabitFillIn(habit) + } + } } }