diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/EventActivity.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/EventActivity.kt index 2002b9d32..c27b1b2a7 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/EventActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/EventActivity.kt @@ -1169,7 +1169,7 @@ class EventActivity : SimpleActivity() { private fun storeEvent(wasRepeatable: Boolean) { if (mEvent.id == null || mEvent.id == null) { - eventsHelper.insertEvent(mEvent, true, true) { + eventsHelper.insertEvent(mEvent, addToCalDAV = true, showToasts = true) { hideKeyboard() if (DateTime.now().isAfter(mEventStartDateTime.millis)) { @@ -1187,7 +1187,7 @@ class EventActivity : SimpleActivity() { } } else { hideKeyboard() - eventsHelper.updateEvent(mEvent, true, true) { + eventsHelper.updateEvent(mEvent, updateAtCalDAV = true, showToasts = true) { finish() } } @@ -1221,7 +1221,7 @@ class EventActivity : SimpleActivity() { id = null } - eventsHelper.insertEvent(mEvent, true, true) { + eventsHelper.insertEvent(mEvent, addToCalDAV = true, showToasts = true) { finish() } } @@ -1230,7 +1230,7 @@ class EventActivity : SimpleActivity() { 2 -> { ensureBackgroundThread { eventsHelper.addEventRepeatLimit(mEvent.id!!, mEventOccurrenceTS) - eventsHelper.updateEvent(mEvent, true, true) { + eventsHelper.updateEvent(mEvent, updateAtCalDAV = true, showToasts = true) { finish() } } diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/TaskActivity.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/TaskActivity.kt index f4568c696..83a0c4c2e 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/TaskActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/TaskActivity.kt @@ -8,13 +8,16 @@ import android.os.Bundle import android.view.Menu import android.view.MenuItem import android.view.WindowManager +import androidx.core.app.NotificationManagerCompat import androidx.core.content.ContextCompat import com.simplemobiletools.calendar.pro.R +import com.simplemobiletools.calendar.pro.dialogs.ReminderWarningDialog import com.simplemobiletools.calendar.pro.dialogs.SelectEventTypeDialog import com.simplemobiletools.calendar.pro.extensions.* import com.simplemobiletools.calendar.pro.helpers.* import com.simplemobiletools.calendar.pro.helpers.Formatter import com.simplemobiletools.calendar.pro.models.Event +import com.simplemobiletools.calendar.pro.models.Reminder import com.simplemobiletools.commons.dialogs.ConfirmationDialog import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.ensureBackgroundThread @@ -26,6 +29,14 @@ class TaskActivity : SimpleActivity() { private var mEventTypeId = REGULAR_EVENT_TYPE_ID private lateinit var mTaskDateTime: DateTime private lateinit var mTask: Event + private var mIsAllDayEvent = false + + private var mReminder1Minutes = REMINDER_OFF + private var mReminder2Minutes = REMINDER_OFF + private var mReminder3Minutes = REMINDER_OFF + private var mReminder1Type = REMINDER_NOTIFICATION + private var mReminder2Type = REMINDER_NOTIFICATION + private var mReminder3Type = REMINDER_NOTIFICATION override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -85,6 +96,10 @@ class TaskActivity : SimpleActivity() { putSerializable(TASK, mTask) putLong(START_TS, mTaskDateTime.seconds()) putLong(EVENT_TYPE_ID, mEventTypeId) + + putInt(REMINDER_1_MINUTES, mReminder1Minutes) + putInt(REMINDER_2_MINUTES, mReminder2Minutes) + putInt(REMINDER_3_MINUTES, mReminder3Minutes) } } @@ -100,6 +115,10 @@ class TaskActivity : SimpleActivity() { mTask = getSerializable(TASK) as Event mTaskDateTime = Formatter.getDateTimeFromTS(getLong(START_TS)) mEventTypeId = getLong(EVENT_TYPE_ID) + + mReminder1Minutes = getInt(REMINDER_1_MINUTES) + mReminder2Minutes = getInt(REMINDER_2_MINUTES) + mReminder3Minutes = getInt(REMINDER_3_MINUTES) } updateEventType() @@ -123,12 +142,18 @@ class TaskActivity : SimpleActivity() { } } else { mTask = Event(null) + config.apply { + mReminder1Minutes = if (usePreviousEventReminders && lastEventReminderMinutes1 >= -1) lastEventReminderMinutes1 else defaultReminder1 + mReminder2Minutes = if (usePreviousEventReminders && lastEventReminderMinutes2 >= -1) lastEventReminderMinutes2 else defaultReminder2 + mReminder3Minutes = if (usePreviousEventReminders && lastEventReminderMinutes3 >= -1) lastEventReminderMinutes3 else defaultReminder3 + } + if (savedInstanceState == null) { setupNewTask() } } - task_all_day.setOnCheckedChangeListener { compoundButton, isChecked -> toggleAllDay(isChecked) } + task_all_day.setOnCheckedChangeListener { _, isChecked -> toggleAllDay(isChecked) } task_all_day_holder.setOnClickListener { task_all_day.toggle() } @@ -137,10 +162,27 @@ class TaskActivity : SimpleActivity() { task_time.setOnClickListener { setupTime() } event_type_holder.setOnClickListener { showEventTypeDialog() } + event_reminder_1.setOnClickListener { + handleNotificationAvailability { + if (config.wasAlarmWarningShown) { + showReminder1Dialog() + } else { + ReminderWarningDialog(this) { + config.wasAlarmWarningShown = true + showReminder1Dialog() + } + } + } + } + + event_reminder_2.setOnClickListener { showReminder2Dialog() } + event_reminder_3.setOnClickListener { showReminder3Dialog() } + if (savedInstanceState == null) { updateEventType() updateDateText() updateTimeText() + updateReminderTexts() } } @@ -150,6 +192,13 @@ class TaskActivity : SimpleActivity() { updateActionBarTitle(getString(R.string.edit_task)) mEventTypeId = mTask.eventType + mReminder1Minutes = mTask.reminder1Minutes + mReminder2Minutes = mTask.reminder2Minutes + mReminder3Minutes = mTask.reminder3Minutes + mReminder1Type = mTask.reminder1Type + mReminder2Type = mTask.reminder2Type + mReminder3Type = mTask.reminder3Type + task_title.setText(mTask.title) task_description.setText(mTask.description) task_all_day.isChecked = mTask.getIsAllDay() @@ -177,6 +226,34 @@ class TaskActivity : SimpleActivity() { return } + + val reminders = getReminders() + if (!task_all_day.isChecked) { + if ((reminders.getOrNull(2)?.minutes ?: 0) < -1) { + reminders.removeAt(2) + } + + if ((reminders.getOrNull(1)?.minutes ?: 0) < -1) { + reminders.removeAt(1) + } + + if ((reminders.getOrNull(0)?.minutes ?: 0) < -1) { + reminders.removeAt(0) + } + } + + val reminder1 = reminders.getOrNull(0) ?: Reminder(REMINDER_OFF, REMINDER_NOTIFICATION) + val reminder2 = reminders.getOrNull(1) ?: Reminder(REMINDER_OFF, REMINDER_NOTIFICATION) + val reminder3 = reminders.getOrNull(2) ?: Reminder(REMINDER_OFF, REMINDER_NOTIFICATION) + + config.apply { + if (usePreviousEventReminders) { + lastEventReminderMinutes1 = reminder1.minutes + lastEventReminderMinutes2 = reminder2.minutes + lastEventReminderMinutes3 = reminder3.minutes + } + } + config.lastUsedLocalEventTypeId = mEventTypeId mTask.apply { startTS = mTaskDateTime.withSecondOfMinute(0).withMillisOfSecond(0).seconds() @@ -187,11 +264,25 @@ class TaskActivity : SimpleActivity() { lastUpdated = System.currentTimeMillis() eventType = mEventTypeId type = TYPE_TASK + + reminder1Minutes = mReminder1Minutes + reminder1Type = reminder1Minutes + reminder2Minutes = mReminder2Minutes + reminder2Type = reminder2Minutes + reminder3Minutes = mReminder3Minutes + reminder3Type = reminder3Minutes } ensureBackgroundThread { - EventsHelper(this).insertTask(mTask) { + EventsHelper(this).insertTask(mTask, true) { hideKeyboard() + + if (DateTime.now().isAfter(mTaskDateTime.millis)) { + if (mTask.repeatInterval == 0 && mTask.getReminders().any { it.type == REMINDER_NOTIFICATION }) { + notifyEvent(mTask) + } + } + finish() } } @@ -223,12 +314,12 @@ class TaskActivity : SimpleActivity() { private fun setupDate() { hideKeyboard() - val datepicker = DatePickerDialog( + val datePicker = DatePickerDialog( this, getDatePickerDialogTheme(), dateSetListener, mTaskDateTime.year, mTaskDateTime.monthOfYear - 1, mTaskDateTime.dayOfMonth ) - datepicker.datePicker.firstDayOfWeek = if (config.isSundayFirst) Calendar.SUNDAY else Calendar.MONDAY - datepicker.show() + datePicker.datePicker.firstDayOfWeek = if (config.isSundayFirst) Calendar.SUNDAY else Calendar.MONDAY + datePicker.show() } private fun setupTime() { @@ -238,11 +329,11 @@ class TaskActivity : SimpleActivity() { ).show() } - private val dateSetListener = DatePickerDialog.OnDateSetListener { view, year, monthOfYear, dayOfMonth -> + private val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, monthOfYear, dayOfMonth -> dateSet(year, monthOfYear, dayOfMonth) } - private val timeSetListener = TimePickerDialog.OnTimeSetListener { view, hourOfDay, minute -> + private val timeSetListener = TimePickerDialog.OnTimeSetListener { _, hourOfDay, minute -> timeSet(hourOfDay, minute) } @@ -300,9 +391,93 @@ class TaskActivity : SimpleActivity() { } } + private fun updateReminderTexts() { + updateReminder1Text() + updateReminder2Text() + updateReminder3Text() + } + + private fun updateReminder1Text() { + event_reminder_1.text = getFormattedMinutes(mReminder1Minutes) + } + + private fun updateReminder2Text() { + event_reminder_2.apply { + beGoneIf(event_reminder_2.isGone() && mReminder1Minutes == REMINDER_OFF) + if (mReminder2Minutes == REMINDER_OFF) { + text = resources.getString(R.string.add_another_reminder) + alpha = 0.4f + } else { + text = getFormattedMinutes(mReminder2Minutes) + alpha = 1f + } + } + } + + private fun updateReminder3Text() { + event_reminder_3.apply { + beGoneIf(event_reminder_3.isGone() && (mReminder2Minutes == REMINDER_OFF || mReminder1Minutes == REMINDER_OFF)) + if (mReminder3Minutes == REMINDER_OFF) { + text = resources.getString(R.string.add_another_reminder) + alpha = 0.4f + } else { + text = getFormattedMinutes(mReminder3Minutes) + alpha = 1f + } + } + } + + private fun handleNotificationAvailability(callback: () -> Unit) { + if (NotificationManagerCompat.from(this).areNotificationsEnabled()) { + callback() + } else { + ConfirmationDialog(this, messageId = R.string.notifications_disabled, positive = R.string.ok, negative = 0) { + callback() + } + } + } + + private fun showReminder1Dialog() { + showPickSecondsDialogHelper(mReminder1Minutes, showDuringDayOption = mIsAllDayEvent) { + mReminder1Minutes = if (it == -1 || it == 0) it else it / 60 + updateReminderTexts() + } + } + + private fun showReminder2Dialog() { + showPickSecondsDialogHelper(mReminder2Minutes, showDuringDayOption = mIsAllDayEvent) { + mReminder2Minutes = if (it == -1 || it == 0) it else it / 60 + updateReminderTexts() + } + } + + private fun showReminder3Dialog() { + showPickSecondsDialogHelper(mReminder3Minutes, showDuringDayOption = mIsAllDayEvent) { + mReminder3Minutes = if (it == -1 || it == 0) it else it / 60 + updateReminderTexts() + } + } + + private fun getReminders(): ArrayList { + var reminders = arrayListOf( + Reminder(mReminder1Minutes, mReminder1Type), + Reminder(mReminder2Minutes, mReminder2Type), + Reminder(mReminder3Minutes, mReminder3Type) + ) + reminders = reminders.filter { it.minutes != REMINDER_OFF }.sortedBy { it.minutes }.toMutableList() as ArrayList + return reminders + } + private fun showEventTypeDialog() { hideKeyboard() - SelectEventTypeDialog(this, mEventTypeId, false, true, false, true) { + SelectEventTypeDialog( + activity = this, + currEventType = mEventTypeId, + showCalDAVCalendars = false, + showNewEventTypeOption = true, + addLastUsedOneAsFirstOption = false, + showOnlyWritable = true + ) { mEventTypeId = it.id!! updateEventType() } @@ -322,7 +497,11 @@ class TaskActivity : SimpleActivity() { private fun updateColors() { updateTextColors(task_scrollview) - task_time_image.applyColorFilter(getProperTextColor()) - event_type_image.applyColorFilter(getProperTextColor()) + val textColor = getProperTextColor() + arrayOf( + task_time_image, event_reminder_image, event_type_image + ).forEach { + it.applyColorFilter(textColor) + } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/extensions/Context.kt index 035fd41ac..ed3373eaf 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/extensions/Context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/extensions/Context.kt @@ -95,7 +95,7 @@ fun Context.updateDateWidget() { } fun Context.scheduleAllEvents() { - val events = eventsDB.getEventsAtReboot(getNowSeconds()) + val events = eventsDB.getEventsOrTasksAtReboot(getNowSeconds()) events.forEach { scheduleNextEventReminder(it, false) } @@ -116,9 +116,9 @@ fun Context.scheduleNextEventReminder(event: Event, showToasts: Boolean) { val now = getNowSeconds() val reminderSeconds = validReminders.reversed().map { it.minutes * 60 } - eventsHelper.getEvents(now, now + YEAR, event.id!!, false) { - if (it.isNotEmpty()) { - for (curEvent in it) { + eventsHelper.getEvents(now, now + YEAR, event.id!!, false) { events -> + if (events.isNotEmpty()) { + for (curEvent in events) { for (curReminder in reminderSeconds) { if (curEvent.getEventStartTS() - curReminder > now) { scheduleEventIn((curEvent.getEventStartTS() - curReminder) * 1000L, curEvent, showToasts) @@ -196,9 +196,11 @@ fun Context.getRepetitionText(seconds: Int) = when (seconds) { } fun Context.notifyRunningEvents() { - eventsHelper.getRunningEvents().filter { it.getReminders().any { it.type == REMINDER_NOTIFICATION } }.forEach { - notifyEvent(it) - } + eventsHelper.getRunningEventsOrTasks() + .filter { it.getReminders().any { reminder -> reminder.type == REMINDER_NOTIFICATION } } + .forEach { + notifyEvent(it) + } } fun Context.notifyEvent(originalEvent: Event) { diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/EventsHelper.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/EventsHelper.kt index 8ec0b1fce..64e3eb982 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/EventsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/EventsHelper.kt @@ -123,9 +123,10 @@ class EventsHelper(val context: Context) { callback?.invoke(event.id!!) } - fun insertTask(task: Event, callback: () -> Unit) { - eventsDB.insertOrUpdate(task) + fun insertTask(task: Event, showToasts: Boolean, callback: () -> Unit) { + task.id = eventsDB.insertOrUpdate(task) context.updateWidgets() + context.scheduleNextEventReminder(task, showToasts) callback() } @@ -295,7 +296,7 @@ class EventsHelper(val context: Context) { events.addAll( if (eventId == -1L) { - eventsDB.getOneTimeEventsFromTo(toTS, fromTS).toMutableList() as ArrayList + eventsDB.getOneTimeEventsOrTasksFromTo(toTS, fromTS).toMutableList() as ArrayList } else { eventsDB.getOneTimeEventFromToWithId(eventId, toTS, fromTS).toMutableList() as ArrayList } @@ -481,9 +482,9 @@ class EventsHelper(val context: Context) { return events } - fun getRunningEvents(): List { + fun getRunningEventsOrTasks(): List { val ts = getNowSeconds() - val events = eventsDB.getOneTimeEventsFromTo(ts, ts).toMutableList() as ArrayList + val events = eventsDB.getOneTimeEventsOrTasksFromTo(ts, ts).toMutableList() as ArrayList events.addAll(getRepeatableEventsFor(ts, ts)) return events } diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/interfaces/EventsDao.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/interfaces/EventsDao.kt index 9cbdf73d6..9d04e9757 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/interfaces/EventsDao.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/interfaces/EventsDao.kt @@ -27,16 +27,16 @@ interface EventsDao { @Query("SELECT * FROM events WHERE import_id = :importId AND type = $TYPE_EVENT") fun getEventWithImportId(importId: String): Event? - @Query("SELECT * FROM events WHERE start_ts <= :toTS AND end_ts >= :fromTS AND repeat_interval = 0 AND type = $TYPE_EVENT") - fun getOneTimeEventsFromTo(toTS: Long, fromTS: Long): List + @Query("SELECT * FROM events WHERE start_ts <= :toTS AND end_ts >= :fromTS AND repeat_interval = 0 AND (type = $TYPE_EVENT OR type = $TYPE_TASK)") + fun getOneTimeEventsOrTasksFromTo(toTS: Long, fromTS: Long): List @Query("SELECT * FROM events WHERE start_ts <= :toTS AND start_ts >= :fromTS AND event_type IN (:eventTypeIds) AND type = $TYPE_TASK") fun getTasksFromTo(fromTS: Long, toTS: Long, eventTypeIds: List): List - @Query("SELECT * FROM events WHERE id = :id AND start_ts <= :toTS AND end_ts >= :fromTS AND repeat_interval = 0 AND type = $TYPE_EVENT") + @Query("SELECT * FROM events WHERE id = :id AND start_ts <= :toTS AND end_ts >= :fromTS AND repeat_interval = 0 AND (type = $TYPE_EVENT OR type = $TYPE_TASK)") fun getOneTimeEventFromToWithId(id: Long, toTS: Long, fromTS: Long): List - @Query("SELECT * FROM events WHERE start_ts <= :toTS AND end_ts >= :fromTS AND start_ts != 0 AND repeat_interval = 0 AND event_type IN (:eventTypeIds) AND type = $TYPE_EVENT") + @Query("SELECT * FROM events WHERE start_ts <= :toTS AND end_ts >= :fromTS AND start_ts != 0 AND repeat_interval = 0 AND event_type IN (:eventTypeIds) AND (type = $TYPE_EVENT OR type = $TYPE_TASK)") fun getOneTimeEventsFromToWithTypes(toTS: Long, fromTS: Long, eventTypeIds: List): List @Query("SELECT * FROM events WHERE end_ts > :toTS AND repeat_interval = 0 AND event_type IN (:eventTypeIds) AND type = $TYPE_EVENT") @@ -76,8 +76,8 @@ interface EventsDao { fun getEventsWithIds(ids: List): List //val selection = "$COL_REMINDER_MINUTES != -1 AND ($COL_START_TS > ? OR $COL_REPEAT_INTERVAL != 0) AND $COL_START_TS != 0" - @Query("SELECT * FROM events WHERE reminder_1_minutes != -1 AND (start_ts > :currentTS OR repeat_interval != 0) AND start_ts != 0 AND type = $TYPE_EVENT") - fun getEventsAtReboot(currentTS: Long): List + @Query("SELECT * FROM events WHERE reminder_1_minutes != -1 AND (start_ts > :currentTS OR repeat_interval != 0) AND start_ts != 0 AND (type = $TYPE_EVENT OR type = $TYPE_TASK)") + fun getEventsOrTasksAtReboot(currentTS: Long): List @Query("SELECT id FROM events") fun getEventIds(): List diff --git a/app/src/main/res/layout/activity_task.xml b/app/src/main/res/layout/activity_task.xml index 8b5d1e7b4..e4fa3d126 100644 --- a/app/src/main/res/layout/activity_task.xml +++ b/app/src/main/res/layout/activity_task.xml @@ -72,6 +72,7 @@ android:layout_marginStart="@dimen/small_margin" android:layout_toEndOf="@+id/task_time_image" android:background="?attr/selectableItemBackground" + android:paddingStart="@dimen/zero" android:paddingTop="@dimen/normal_margin" android:paddingEnd="@dimen/normal_margin" android:paddingBottom="@dimen/normal_margin"> @@ -113,10 +114,88 @@ tools:text="00:00" /> + + + + + + + + + + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index af5bcd045..5ee3991d2 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -38,4 +38,5 @@ 88dp 6dp 2dp + 0dp