diff --git a/build.gradle b/build.gradle index f0f8e01f5..7732d0fd9 100644 --- a/build.gradle +++ b/build.gradle @@ -5,4 +5,11 @@ plugins { id "org.jetbrains.kotlin.android.extensions" version "$KOTLIN_VERSION" apply false id "org.jetbrains.kotlin.multiplatform" version "1.4.21" apply false id "org.jlleitschuh.gradle.ktlint" version "9.4.1" +} + +// Needed for ktlint. Taken from: https://github.com/JLLeitschuh/ktlint-gradle/issues/181#issuecomment-443146206 +allprojects { + repositories { + mavenCentral() + } } \ No newline at end of file diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/HabitsApplicationTestComponent.java b/uhabits-android/src/androidTest/java/org/isoron/uhabits/HabitsApplicationTestComponent.java index 933e45eff..8693399c7 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/HabitsApplicationTestComponent.java +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/HabitsApplicationTestComponent.java @@ -38,7 +38,7 @@ public interface HabitsApplicationTestComponent IntentScheduler getIntentScheduler(); } -@Module +@dagger.Module class SingleThreadModule { @Provides diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/intents/IntentSchedulerTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/intents/IntentSchedulerTest.kt index 1966e66b1..c0991ba17 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/intents/IntentSchedulerTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/intents/IntentSchedulerTest.kt @@ -100,12 +100,12 @@ class IntentSchedulerTest : BaseAndroidTest() { assertThat(scheduler.scheduleShowReminder(reminderTime, habit, 0), equalTo(OK)) setSystemTime("America/Chicago", 2020, JUNE, 2, 22, 44) - assertNull(ReminderReceiver.getLastReceivedIntent()) + assertNull(ReminderReceiver.lastReceivedIntent) setSystemTime("America/Chicago", 2020, JUNE, 2, 22, 46) - val intent = ReminderReceiver.getLastReceivedIntent() + val intent = ReminderReceiver.lastReceivedIntent assertNotNull(intent) - assertThat(parseId(intent.data!!), equalTo(habit.id)) + assertThat(parseId(intent?.data!!), equalTo(habit.id)) } @Test @@ -120,10 +120,10 @@ class IntentSchedulerTest : BaseAndroidTest() { assertThat(scheduler.scheduleWidgetUpdate(updateTime), equalTo(OK)) setSystemTime("America/Chicago", 2020, JUNE, 2, 22, 44) - assertNull(WidgetReceiver.getLastReceivedIntent()) + assertNull(WidgetReceiver.lastReceivedIntent) setSystemTime("America/Chicago", 2020, JUNE, 2, 22, 46) - val intent = WidgetReceiver.getLastReceivedIntent() + val intent = WidgetReceiver.lastReceivedIntent assertNotNull(intent) } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/notifications/SnoozeDelayPickerActivity.java b/uhabits-android/src/main/java/org/isoron/uhabits/notifications/SnoozeDelayPickerActivity.java deleted file mode 100644 index 4e5af8472..000000000 --- a/uhabits-android/src/main/java/org/isoron/uhabits/notifications/SnoozeDelayPickerActivity.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker 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. - * - * Loop Habit Tracker 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 org.isoron.uhabits.notifications; - - -import android.app.*; -import android.graphics.*; -import android.os.*; - -import androidx.annotation.Nullable; - -import android.text.format.*; -import android.view.*; -import android.widget.*; - -import androidx.fragment.app.FragmentActivity; - -import com.android.datetimepicker.time.TimePickerDialog; - -import org.isoron.uhabits.*; -import org.isoron.uhabits.core.models.*; -import org.isoron.uhabits.inject.*; -import org.isoron.uhabits.receivers.*; -import org.isoron.uhabits.utils.*; - -import java.util.*; - -import static android.content.ContentUris.parseId; - -public class SnoozeDelayPickerActivity extends FragmentActivity - implements AdapterView.OnItemClickListener -{ - private Habit habit; - - private ReminderController reminderController; - - @Nullable - private AlertDialog dialog; - - @Override - protected void onCreate(@Nullable Bundle bundle) - { - super.onCreate(bundle); - if (getIntent() == null) finish(); - if (getIntent().getData() == null) finish(); - - HabitsApplication app = (HabitsApplication) getApplicationContext(); - HabitsApplicationComponent appComponent = app.getComponent(); - reminderController = appComponent.getReminderController(); - habit = appComponent.getHabitList().getById(parseId(getIntent().getData())); - if (habit == null) finish(); - - int theme = R.style.Theme_AppCompat_Light_Dialog_Alert; - dialog = new AlertDialog.Builder(new ContextThemeWrapper(this, theme)) - .setTitle(R.string.select_snooze_delay) - .setItems(R.array.snooze_picker_names, null) - .create(); - - dialog.getListView().setOnItemClickListener(this); - dialog.setOnDismissListener(d -> finish()); - dialog.show(); - - SystemUtils.unlockScreen(this); - } - - private void showTimePicker() - { - final Calendar calendar = Calendar.getInstance(); - TimePickerDialog dialog = TimePickerDialog.newInstance( - (view, hour, minute) -> { - reminderController.onSnoozeTimePicked(habit, hour, minute); - finish(); - }, - calendar.get(Calendar.HOUR_OF_DAY), - calendar.get(Calendar.MINUTE), - DateFormat.is24HourFormat(this), - Color.BLUE); - dialog.show(getSupportFragmentManager(), "timePicker"); - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) - { - int[] snoozeValues = getResources().getIntArray(R.array.snooze_picker_values); - if (snoozeValues[position] >= 0) - { - reminderController.onSnoozeDelayPicked(habit, snoozeValues[position]); - finish(); - } - else showTimePicker(); - } - - @Override - public void finish() - { - super.finish(); - overridePendingTransition(0, 0); - } - - @Override - protected void onPause() - { - if (dialog != null) dialog.dismiss(); - super.onPause(); - } -} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/notifications/SnoozeDelayPickerActivity.kt b/uhabits-android/src/main/java/org/isoron/uhabits/notifications/SnoozeDelayPickerActivity.kt new file mode 100644 index 000000000..bc3afb97c --- /dev/null +++ b/uhabits-android/src/main/java/org/isoron/uhabits/notifications/SnoozeDelayPickerActivity.kt @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker 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. + * + * Loop Habit Tracker 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 org.isoron.uhabits.notifications + +import android.app.AlertDialog +import android.content.ContentUris +import android.graphics.Color +import android.os.Bundle +import android.text.format.DateFormat +import android.view.ContextThemeWrapper +import android.view.View +import android.widget.AdapterView +import android.widget.AdapterView.OnItemClickListener +import androidx.fragment.app.FragmentActivity +import com.android.datetimepicker.time.RadialPickerLayout +import com.android.datetimepicker.time.TimePickerDialog +import org.isoron.uhabits.HabitsApplication +import org.isoron.uhabits.R +import org.isoron.uhabits.core.models.Habit +import org.isoron.uhabits.receivers.ReminderController +import org.isoron.uhabits.utils.SystemUtils +import java.util.Calendar + +class SnoozeDelayPickerActivity : FragmentActivity(), OnItemClickListener { + private var habit: Habit? = null + private var reminderController: ReminderController? = null + private var dialog: AlertDialog? = null + override fun onCreate(bundle: Bundle?) { + super.onCreate(bundle) + if (intent == null) finish() + if (intent.data == null) finish() + val app = applicationContext as HabitsApplication + val appComponent = app.component + reminderController = appComponent.reminderController + habit = appComponent.habitList.getById(ContentUris.parseId(intent.data)) + if (habit == null) finish() + val theme = R.style.Theme_AppCompat_Light_Dialog_Alert + dialog = AlertDialog.Builder(ContextThemeWrapper(this, theme)) + .setTitle(R.string.select_snooze_delay) + .setItems(R.array.snooze_picker_names, null) + .create() + dialog!!.listView.onItemClickListener = this + dialog!!.setOnDismissListener { finish() } + dialog!!.show() + SystemUtils.unlockScreen(this) + } + + private fun showTimePicker() { + val calendar = Calendar.getInstance() + val dialog = TimePickerDialog.newInstance( + { view: RadialPickerLayout?, hour: Int, minute: Int -> + reminderController!!.onSnoozeTimePicked(habit, hour, minute) + finish() + }, + calendar[Calendar.HOUR_OF_DAY], + calendar[Calendar.MINUTE], + DateFormat.is24HourFormat(this), + Color.BLUE + ) + dialog.show(supportFragmentManager, "timePicker") + } + + override fun onItemClick(parent: AdapterView<*>?, view: View, position: Int, id: Long) { + val snoozeValues = resources.getIntArray(R.array.snooze_picker_values) + if (snoozeValues[position] >= 0) { + reminderController!!.onSnoozeDelayPicked(habit, snoozeValues[position]) + finish() + } else showTimePicker() + } + + override fun finish() { + super.finish() + overridePendingTransition(0, 0) + } + + override fun onPause() { + if (dialog != null) dialog!!.dismiss() + super.onPause() + } +} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReceiverScope.java b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReceiverScope.kt similarity index 88% rename from uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReceiverScope.java rename to uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReceiverScope.kt index 9932236fd..cf9301347 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReceiverScope.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReceiverScope.kt @@ -16,10 +16,9 @@ * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ +package org.isoron.uhabits.receivers -package org.isoron.uhabits.receivers; - -import javax.inject.*; +import javax.inject.Scope @Scope -public @interface ReceiverScope { } +annotation class ReceiverScope diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReminderController.java b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReminderController.java deleted file mode 100644 index 2251fd911..000000000 --- a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReminderController.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker 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. - * - * Loop Habit Tracker 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 org.isoron.uhabits.receivers; - -import android.content.*; -import android.net.*; - -import androidx.annotation.NonNull; - -import org.isoron.uhabits.core.*; -import org.isoron.uhabits.core.models.*; -import org.isoron.uhabits.core.preferences.*; -import org.isoron.uhabits.core.reminders.*; -import org.isoron.uhabits.core.ui.*; -import org.isoron.uhabits.core.utils.*; -import org.isoron.uhabits.notifications.*; - -import javax.inject.*; - -@AppScope -public class ReminderController -{ - @NonNull - private final ReminderScheduler reminderScheduler; - - @NonNull - private final NotificationTray notificationTray; - - @NonNull - private Preferences preferences; - - @Inject - public ReminderController(@NonNull ReminderScheduler reminderScheduler, - @NonNull NotificationTray notificationTray, - @NonNull Preferences preferences) - { - this.reminderScheduler = reminderScheduler; - this.notificationTray = notificationTray; - this.preferences = preferences; - } - - public void onBootCompleted() - { - reminderScheduler.scheduleAll(); - } - - public void onShowReminder(@NonNull Habit habit, - Timestamp timestamp, - long reminderTime) - { - notificationTray.show(habit, timestamp, reminderTime); - reminderScheduler.scheduleAll(); - } - - public void onSnoozePressed(@NonNull Habit habit, final Context context) - { - showSnoozeDelayPicker(habit, context); - } - - public void onSnoozeDelayPicked(Habit habit, int delayInMinutes) - { - reminderScheduler.snoozeReminder(habit, delayInMinutes); - notificationTray.cancel(habit); - } - - public void onSnoozeTimePicked(Habit habit, int hour, int minute) - { - long time = DateUtils.getUpcomingTimeInMillis(hour, minute); - reminderScheduler.scheduleAtTime(habit, time); - notificationTray.cancel(habit); - } - - public void onDismiss(@NonNull Habit habit) - { - notificationTray.cancel(habit); - } - - private void showSnoozeDelayPicker(@NonNull Habit habit, Context context) - { - context.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); - Intent intent = new Intent(context, SnoozeDelayPickerActivity.class); - intent.setData(Uri.parse(habit.getUriString())); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); - } -} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReminderController.kt b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReminderController.kt new file mode 100644 index 000000000..65956bb2d --- /dev/null +++ b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReminderController.kt @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker 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. + * + * Loop Habit Tracker 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 org.isoron.uhabits.receivers + +import android.content.Context +import android.content.Intent +import android.net.Uri +import org.isoron.uhabits.core.AppScope +import org.isoron.uhabits.core.models.Habit +import org.isoron.uhabits.core.models.Timestamp +import org.isoron.uhabits.core.preferences.Preferences +import org.isoron.uhabits.core.reminders.ReminderScheduler +import org.isoron.uhabits.core.ui.NotificationTray +import org.isoron.uhabits.core.utils.DateUtils.Companion.getUpcomingTimeInMillis +import org.isoron.uhabits.notifications.SnoozeDelayPickerActivity +import javax.inject.Inject + +@AppScope +class ReminderController @Inject constructor( + private val reminderScheduler: ReminderScheduler, + private val notificationTray: NotificationTray, + private val preferences: Preferences +) { + fun onBootCompleted() { + reminderScheduler.scheduleAll() + } + + fun onShowReminder( + habit: Habit, + timestamp: Timestamp?, + reminderTime: Long + ) { + notificationTray.show(habit, timestamp, reminderTime) + reminderScheduler.scheduleAll() + } + + fun onSnoozePressed(habit: Habit, context: Context) { + showSnoozeDelayPicker(habit, context) + } + + fun onSnoozeDelayPicked(habit: Habit?, delayInMinutes: Int) { + reminderScheduler.snoozeReminder(habit, delayInMinutes.toLong()) + notificationTray.cancel(habit!!) + } + + fun onSnoozeTimePicked(habit: Habit?, hour: Int, minute: Int) { + val time: Long = getUpcomingTimeInMillis(hour, minute) + reminderScheduler.scheduleAtTime(habit!!, time) + notificationTray.cancel(habit) + } + + fun onDismiss(habit: Habit) { + notificationTray.cancel(habit) + } + + private fun showSnoozeDelayPicker(habit: Habit, context: Context) { + context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) + val intent = Intent(context, SnoozeDelayPickerActivity::class.java) + intent.data = Uri.parse(habit.uriString) + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + context.startActivity(intent) + } +} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReminderReceiver.java b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReminderReceiver.java deleted file mode 100644 index aa55142ba..000000000 --- a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReminderReceiver.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker 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. - * - * Loop Habit Tracker 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 org.isoron.uhabits.receivers; - -import android.content.*; -import android.util.*; - -import androidx.annotation.Nullable; - -import org.isoron.uhabits.*; -import org.isoron.uhabits.core.models.*; -import org.isoron.uhabits.core.utils.*; -import org.isoron.uhabits.inject.*; - -import static android.content.ContentUris.*; - -/** - * The Android BroadcastReceiver for Loop Habit Tracker. - *

- * All broadcast messages are received and processed by this class. - */ -public class ReminderReceiver extends BroadcastReceiver -{ - public static final String ACTION_DISMISS_REMINDER = - "org.isoron.uhabits.ACTION_DISMISS_REMINDER"; - - public static final String ACTION_SHOW_REMINDER = - "org.isoron.uhabits.ACTION_SHOW_REMINDER"; - - public static final String ACTION_SNOOZE_REMINDER = - "org.isoron.uhabits.ACTION_SNOOZE_REMINDER"; - - private static final String TAG = "ReminderReceiver"; - - private static Intent lastReceivedIntent = null; - - @Override - public void onReceive(@Nullable final Context context, @Nullable Intent intent) - { - if (context == null || intent == null) return; - if (intent.getAction() == null) return; - lastReceivedIntent = intent; - - HabitsApplication app = (HabitsApplication) context.getApplicationContext(); - HabitsApplicationComponent appComponent = app.getComponent(); - HabitList habits = appComponent.getHabitList(); - ReminderController reminderController = appComponent.getReminderController(); - - Log.i(TAG, String.format("Received intent: %s", intent.toString())); - - Habit habit = null; - long today = DateUtils.getStartOfTodayWithOffset(); - - if (intent.getData() != null) - habit = habits.getById(parseId(intent.getData())); - final long timestamp = intent.getLongExtra("timestamp", today); - final long reminderTime = intent.getLongExtra("reminderTime", today); - - try - { - switch (intent.getAction()) - { - case ACTION_SHOW_REMINDER: - if (habit == null) return; - Log.d("ReminderReceiver", String.format( - "onShowReminder habit=%d timestamp=%d reminderTime=%d", - habit.getId(), - timestamp, - reminderTime)); - reminderController.onShowReminder(habit, - new Timestamp(timestamp), reminderTime); - break; - - case ACTION_DISMISS_REMINDER: - if (habit == null) return; - Log.d("ReminderReceiver", String.format("onDismiss habit=%d", habit.getId())); - reminderController.onDismiss(habit); - break; - - case ACTION_SNOOZE_REMINDER: - if (habit == null) return; - Log.d("ReminderReceiver", String.format("onSnoozePressed habit=%d", habit.getId())); - reminderController.onSnoozePressed(habit, context); - break; - - case Intent.ACTION_BOOT_COMPLETED: - Log.d("ReminderReceiver", "onBootCompleted"); - reminderController.onBootCompleted(); - break; - } - } - catch (RuntimeException e) - { - Log.e(TAG, "could not process intent", e); - } - } - - public static void clearLastReceivedIntent() - { - lastReceivedIntent = null; - } - - public static Intent getLastReceivedIntent() - { - return lastReceivedIntent; - } -} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReminderReceiver.kt b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReminderReceiver.kt new file mode 100644 index 000000000..026f99bec --- /dev/null +++ b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/ReminderReceiver.kt @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker 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. + * + * Loop Habit Tracker 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 org.isoron.uhabits.receivers + +import android.content.BroadcastReceiver +import android.content.ContentUris +import android.content.Context +import android.content.Intent +import android.util.Log +import org.isoron.uhabits.HabitsApplication +import org.isoron.uhabits.core.models.Habit +import org.isoron.uhabits.core.models.Timestamp +import org.isoron.uhabits.core.utils.DateUtils.Companion.getStartOfTodayWithOffset + +/** + * The Android BroadcastReceiver for Loop Habit Tracker. + * + * + * All broadcast messages are received and processed by this class. + */ +class ReminderReceiver : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + if (context == null || intent == null) return + if (intent.action == null) return + lastReceivedIntent = intent + val app = context.applicationContext as HabitsApplication + val appComponent = app.component + val habits = appComponent.habitList + val reminderController = appComponent.reminderController + Log.i(TAG, String.format("Received intent: %s", intent.toString())) + var habit: Habit? = null + val today: Long = getStartOfTodayWithOffset() + if (intent.data != null) habit = habits.getById(ContentUris.parseId(intent.data)) + val timestamp = intent.getLongExtra("timestamp", today) + val reminderTime = intent.getLongExtra("reminderTime", today) + try { + when (intent.action) { + ACTION_SHOW_REMINDER -> { + if (habit == null) return + Log.d( + "ReminderReceiver", + String.format( + "onShowReminder habit=%d timestamp=%d reminderTime=%d", + habit.id, + timestamp, + reminderTime + ) + ) + reminderController.onShowReminder( + habit, + Timestamp(timestamp), + reminderTime + ) + } + ACTION_DISMISS_REMINDER -> { + if (habit == null) return + Log.d("ReminderReceiver", String.format("onDismiss habit=%d", habit.id)) + reminderController.onDismiss(habit) + } + ACTION_SNOOZE_REMINDER -> { + if (habit == null) return + Log.d("ReminderReceiver", String.format("onSnoozePressed habit=%d", habit.id)) + reminderController.onSnoozePressed(habit, context) + } + Intent.ACTION_BOOT_COMPLETED -> { + Log.d("ReminderReceiver", "onBootCompleted") + reminderController.onBootCompleted() + } + } + } catch (e: RuntimeException) { + Log.e(TAG, "could not process intent", e) + } + } + + companion object { + const val ACTION_DISMISS_REMINDER = "org.isoron.uhabits.ACTION_DISMISS_REMINDER" + const val ACTION_SHOW_REMINDER = "org.isoron.uhabits.ACTION_SHOW_REMINDER" + const val ACTION_SNOOZE_REMINDER = "org.isoron.uhabits.ACTION_SNOOZE_REMINDER" + private const val TAG = "ReminderReceiver" + var lastReceivedIntent: Intent? = null + private set + + fun clearLastReceivedIntent() { + lastReceivedIntent = null + } + } +} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/WidgetReceiver.java b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/WidgetReceiver.java deleted file mode 100644 index cc51a8c0f..000000000 --- a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/WidgetReceiver.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker 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. - * - * Loop Habit Tracker 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 org.isoron.uhabits.receivers; - -import android.content.*; -import android.util.*; - -import org.isoron.uhabits.*; -import org.isoron.uhabits.core.preferences.*; -import org.isoron.uhabits.core.ui.widgets.*; -import org.isoron.uhabits.inject.*; -import org.isoron.uhabits.intents.*; -import org.isoron.uhabits.widgets.*; -import org.isoron.uhabits.widgets.activities.*; - -import dagger.*; - -/** - * The Android BroadcastReceiver for Loop Habit Tracker. - *

- * All broadcast messages are received and processed by this class. - */ -public class WidgetReceiver extends BroadcastReceiver -{ - public static final String ACTION_ADD_REPETITION = - "org.isoron.uhabits.ACTION_ADD_REPETITION"; - - public static final String ACTION_DISMISS_REMINDER = - "org.isoron.uhabits.ACTION_DISMISS_REMINDER"; - - public static final String ACTION_REMOVE_REPETITION = - "org.isoron.uhabits.ACTION_REMOVE_REPETITION"; - - public static final String ACTION_TOGGLE_REPETITION = - "org.isoron.uhabits.ACTION_TOGGLE_REPETITION"; - - public static final String ACTION_SET_NUMERICAL_VALUE = - "org.isoron.uhabits.ACTION_SET_NUMERICAL_VALUE"; - - public static final String ACTION_UPDATE_WIDGETS_VALUE = - "org.isoron.uhabits.ACTION_UPDATE_WIDGETS_VALUE"; - - private static final String TAG = "WidgetReceiver"; - - private static Intent lastReceivedIntent = null; - - @Override - public void onReceive(final Context context, Intent intent) - { - HabitsApplication app = - (HabitsApplication) context.getApplicationContext(); - - WidgetComponent component = DaggerWidgetReceiver_WidgetComponent - .builder() - .habitsApplicationComponent(app.getComponent()) - .build(); - - IntentParser parser = app.getComponent().getIntentParser(); - WidgetBehavior controller = component.getWidgetController(); - Preferences prefs = app.getComponent().getPreferences(); - WidgetUpdater widgetUpdater = app.getComponent().getWidgetUpdater(); - - Log.i(TAG, String.format("Received intent: %s", intent.toString())); - lastReceivedIntent = intent; - - try - { - IntentParser.CheckmarkIntentData data = null; - if (intent.getAction() != ACTION_UPDATE_WIDGETS_VALUE) - { - data = parser.parseCheckmarkIntent(intent); - } - - switch (intent.getAction()) - { - case ACTION_ADD_REPETITION: - Log.d(TAG, String.format( - "onAddRepetition habit=%d timestamp=%d", - data.getHabit().getId(), - data.getTimestamp().getUnixTime())); - controller.onAddRepetition(data.getHabit(), - data.getTimestamp()); - break; - - case ACTION_TOGGLE_REPETITION: - Log.d(TAG, String.format( - "onToggleRepetition habit=%d timestamp=%d", - data.getHabit().getId(), - data.getTimestamp().getUnixTime())); - controller.onToggleRepetition(data.getHabit(), - data.getTimestamp()); - break; - - case ACTION_REMOVE_REPETITION: - Log.d(TAG, String.format( - "onRemoveRepetition habit=%d timestamp=%d", - data.getHabit().getId(), - data.getTimestamp().getUnixTime())); - controller.onRemoveRepetition(data.getHabit(), - data.getTimestamp()); - break; - - case ACTION_SET_NUMERICAL_VALUE: - context.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); - Intent numberSelectorIntent = new Intent(context, NumericalCheckmarkWidgetActivity.class); - numberSelectorIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - numberSelectorIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); - numberSelectorIntent.setAction(NumericalCheckmarkWidgetActivity.ACTION_SHOW_NUMERICAL_VALUE_ACTIVITY); - parser.copyIntentData(intent,numberSelectorIntent); - context.startActivity(numberSelectorIntent); - break; - - case ACTION_UPDATE_WIDGETS_VALUE: - widgetUpdater.updateWidgets(); - widgetUpdater.scheduleStartDayWidgetUpdate(); - break; - } - } - catch (RuntimeException e) - { - Log.e("WidgetReceiver", "could not process intent", e); - } - } - - @ReceiverScope - @Component(dependencies = HabitsApplicationComponent.class) - interface WidgetComponent - { - WidgetBehavior getWidgetController(); - } - - public static Intent getLastReceivedIntent() - { - return lastReceivedIntent; - } - - public static void clearLastReceivedIntent() - { - lastReceivedIntent = null; - } -} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/WidgetReceiver.kt b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/WidgetReceiver.kt new file mode 100644 index 000000000..2f5702796 --- /dev/null +++ b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/WidgetReceiver.kt @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2016-2021 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker 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. + * + * Loop Habit Tracker 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 org.isoron.uhabits.receivers + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.util.Log +import dagger.Component +import org.isoron.uhabits.HabitsApplication +import org.isoron.uhabits.core.ui.widgets.WidgetBehavior +import org.isoron.uhabits.inject.HabitsApplicationComponent +import org.isoron.uhabits.intents.IntentParser.CheckmarkIntentData +import org.isoron.uhabits.widgets.activities.NumericalCheckmarkWidgetActivity + +/** + * The Android BroadcastReceiver for Loop Habit Tracker. + * + * + * All broadcast messages are received and processed by this class. + */ +class WidgetReceiver : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + val app = context.applicationContext as HabitsApplication + val component = DaggerWidgetReceiver_WidgetComponent + .builder() + .habitsApplicationComponent(app.component) + .build() + val parser = app.component.intentParser + val controller = component.widgetController + val prefs = app.component.preferences + val widgetUpdater = app.component.widgetUpdater + Log.i(TAG, String.format("Received intent: %s", intent.toString())) + lastReceivedIntent = intent + try { + var data: CheckmarkIntentData? = null + if (intent.action !== ACTION_UPDATE_WIDGETS_VALUE) { + data = parser.parseCheckmarkIntent(intent) + } + when (intent.action) { + ACTION_ADD_REPETITION -> { + Log.d( + TAG, + String.format( + "onAddRepetition habit=%d timestamp=%d", + data!!.habit.id, + data.timestamp.unixTime + ) + ) + controller.onAddRepetition( + data.habit, + data.timestamp + ) + } + ACTION_TOGGLE_REPETITION -> { + Log.d( + TAG, + String.format( + "onToggleRepetition habit=%d timestamp=%d", + data!!.habit.id, + data.timestamp.unixTime + ) + ) + controller.onToggleRepetition( + data.habit, + data.timestamp + ) + } + ACTION_REMOVE_REPETITION -> { + Log.d( + TAG, + String.format( + "onRemoveRepetition habit=%d timestamp=%d", + data!!.habit.id, + data.timestamp.unixTime + ) + ) + controller.onRemoveRepetition( + data.habit, + data.timestamp + ) + } + ACTION_SET_NUMERICAL_VALUE -> { + context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) + val numberSelectorIntent = Intent(context, NumericalCheckmarkWidgetActivity::class.java) + numberSelectorIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + numberSelectorIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) + numberSelectorIntent.action = NumericalCheckmarkWidgetActivity.ACTION_SHOW_NUMERICAL_VALUE_ACTIVITY + parser.copyIntentData(intent, numberSelectorIntent) + context.startActivity(numberSelectorIntent) + } + ACTION_UPDATE_WIDGETS_VALUE -> { + widgetUpdater.updateWidgets() + widgetUpdater.scheduleStartDayWidgetUpdate() + } + } + } catch (e: RuntimeException) { + Log.e("WidgetReceiver", "could not process intent", e) + } + } + + @ReceiverScope + @Component(dependencies = [HabitsApplicationComponent::class]) + internal interface WidgetComponent { + val widgetController: WidgetBehavior + } + + companion object { + const val ACTION_ADD_REPETITION = "org.isoron.uhabits.ACTION_ADD_REPETITION" + const val ACTION_DISMISS_REMINDER = "org.isoron.uhabits.ACTION_DISMISS_REMINDER" + const val ACTION_REMOVE_REPETITION = "org.isoron.uhabits.ACTION_REMOVE_REPETITION" + const val ACTION_TOGGLE_REPETITION = "org.isoron.uhabits.ACTION_TOGGLE_REPETITION" + const val ACTION_SET_NUMERICAL_VALUE = "org.isoron.uhabits.ACTION_SET_NUMERICAL_VALUE" + const val ACTION_UPDATE_WIDGETS_VALUE = "org.isoron.uhabits.ACTION_UPDATE_WIDGETS_VALUE" + private const val TAG = "WidgetReceiver" + var lastReceivedIntent: Intent? = null + private set + + fun clearLastReceivedIntent() { + lastReceivedIntent = null + } + } +}