Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,31 @@ package com.github.quarck.calnotify.ui
import android.app.AlertDialog
import android.content.Context
import android.content.Intent
import android.content.res.ColorStateList
import android.os.Bundle
import android.text.format.DateUtils
import android.view.View
import android.widget.DatePicker
import android.widget.LinearLayout
import android.widget.PopupMenu
import android.widget.TextView
import android.widget.TimePicker
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.github.quarck.calnotify.Consts
import com.github.quarck.calnotify.R
import com.github.quarck.calnotify.Settings
import com.github.quarck.calnotify.app.ApplicationController
import com.github.quarck.calnotify.calendar.CalendarIntents
import com.github.quarck.calnotify.calendar.CalendarProvider
import com.github.quarck.calnotify.calendar.CalendarProviderInterface
import com.github.quarck.calnotify.calendar.EventAlertRecord
import com.github.quarck.calnotify.calendar.EventDisplayStatus
import com.github.quarck.calnotify.calendar.EventOrigin
import com.github.quarck.calnotify.calendar.EventStatus
import com.github.quarck.calnotify.calendar.AttendanceStatus
import com.github.quarck.calnotify.calendar.CalendarProvider
import com.github.quarck.calnotify.utils.adjustCalendarColor
import com.github.quarck.calnotify.dismissedeventsstorage.DismissedEventsStorage
import com.github.quarck.calnotify.dismissedeventsstorage.EventDismissType
import com.github.quarck.calnotify.eventsstorage.EventsStorage
Expand All @@ -51,7 +58,11 @@ import com.github.quarck.calnotify.textutils.EventFormatterInterface
import com.github.quarck.calnotify.utils.CNPlusClockInterface
import com.github.quarck.calnotify.utils.CNPlusSystemClock
import com.github.quarck.calnotify.utils.background
import com.github.quarck.calnotify.utils.findOrThrow
import com.github.quarck.calnotify.utils.hourCompat
import com.github.quarck.calnotify.utils.minuteCompat
import com.github.quarck.calnotify.utils.setupStatusBarSpacer
import java.util.*

/**
* Activity for pre-actions on upcoming events.
Expand Down Expand Up @@ -140,6 +151,7 @@ class PreActionActivity : AppCompatActivity() {
private var eventIsMuted: Boolean = false

private lateinit var snoozePresets: LongArray
private val calendarProvider: CalendarProviderInterface = CalendarProvider

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Expand Down Expand Up @@ -213,33 +225,75 @@ class PreActionActivity : AppCompatActivity() {
showCustomSnoozeDialog()
}

// Mute toggle
updateMuteButton()
findViewById<TextView>(R.id.pre_action_mute_toggle).setOnClickListener {
toggleMute()
// Until specific time
findViewById<TextView>(R.id.pre_action_snooze_until).setOnClickListener {
showSnoozeUntilDatePicker()
}

// View in calendar
findViewById<TextView>(R.id.pre_action_view_calendar).setOnClickListener {
viewInCalendar()
}
// Edit FAB
setupEditFab()

// 3-dot menu
findViewById<View>(R.id.pre_action_menu).setOnClickListener { v ->
showMenu(v)
}
}

private fun setupEditFab() {
val fab = findOrThrow<FloatingActionButton>(R.id.pre_action_edit_button)
val calendar = calendarProvider.getCalendarById(this, calendarId)
?: calendarProvider.createCalendarNotFoundCal(this)

if (!calendar.isReadOnly) {
if (!eventIsRepeating && !settings.alwaysUseExternalEditor) {
fab.setOnClickListener {
val intent = Intent(this, EditEventActivity::class.java)
intent.putExtra(EditEventActivity.EVENT_ID, eventId)
startActivity(intent)
finish()
}
} else {
fab.setOnClickListener {
viewInCalendar()
finish()
}
}

val states = arrayOf(
intArrayOf(android.R.attr.state_enabled),
intArrayOf(android.R.attr.state_pressed)
)
val colors = intArrayOf(
eventColor.adjustCalendarColor(false),
eventColor.adjustCalendarColor(true)
)
fab.backgroundTintList = ColorStateList(states, colors)
} else {
fab.visibility = View.GONE
}
}

private fun showMenu(anchor: View) {
val popup = PopupMenu(this, anchor)
popup.menuInflater.inflate(R.menu.pre_action, popup.menu)

popup.menu.findItem(R.id.action_pre_mute)?.isVisible = !eventIsMuted
popup.menu.findItem(R.id.action_pre_unmute)?.isVisible = eventIsMuted

popup.setOnMenuItemClickListener { item ->
when (item.itemId) {
R.id.action_pre_dismiss -> {
executePreDismiss()
true
}
R.id.action_pre_mute, R.id.action_pre_unmute -> {
toggleMute()
true
}
R.id.action_open_in_calendar -> {
viewInCalendar()
true
}
else -> false
}
}
Expand Down Expand Up @@ -303,6 +357,65 @@ class PreActionActivity : AppCompatActivity() {
.show()
}

private fun showSnoozeUntilDatePicker() {
val dialogDate = layoutInflater.inflate(R.layout.dialog_date_picker, null) ?: return
val datePicker = dialogDate.findOrThrow<DatePicker>(R.id.datePickerCustomSnooze)

val firstDayOfWeek = settings.firstDayOfWeek
if (firstDayOfWeek != -1) {
datePicker.firstDayOfWeek = firstDayOfWeek
}

AlertDialog.Builder(this)
.setView(dialogDate)
.setPositiveButton(R.string.next) { _, _ ->
datePicker.clearFocus()
val date = Calendar.getInstance()
date.set(datePicker.year, datePicker.month, datePicker.dayOfMonth, 0, 0, 0)
showSnoozeUntilTimePicker(date.timeInMillis)
}
.setNegativeButton(R.string.cancel, null)
.create()
.show()
}

private fun showSnoozeUntilTimePicker(dateMillis: Long) {
val date = Calendar.getInstance()
date.timeInMillis = dateMillis

val dialogTime = layoutInflater.inflate(R.layout.dialog_time_picker, null) ?: return
val timePicker = dialogTime.findOrThrow<TimePicker>(R.id.timePickerCustomSnooze)
timePicker.setIs24HourView(android.text.format.DateFormat.is24HourFormat(this))

val title = dialogTime.findOrThrow<TextView>(R.id.textViewSnoozeUntilDate)
title.text = String.format(
resources.getString(R.string.choose_time),
DateUtils.formatDateTime(this, date.timeInMillis, DateUtils.FORMAT_SHOW_DATE)
)

AlertDialog.Builder(this)
.setView(dialogTime)
.setPositiveButton(R.string.snooze) { _, _ ->
timePicker.clearFocus()
date.set(Calendar.HOUR_OF_DAY, timePicker.hourCompat)
date.set(Calendar.MINUTE, timePicker.minuteCompat)

val snoozeUntil = date.timeInMillis + Consts.ALARM_THRESHOLD
if (snoozeUntil > getClock().currentTimeMillis()) {
executePreSnooze(snoozeUntil)
} else {
AlertDialog.Builder(this)
.setTitle(R.string.selected_time_is_in_the_past)
.setNegativeButton(R.string.cancel, null)
.create()
.show()
}
}
.setNegativeButton(R.string.cancel, null)
.create()
.show()
}

private fun executePreSnooze(snoozeUntil: Long) {
background {
var monitorSuccess = false
Expand Down Expand Up @@ -386,12 +499,6 @@ class PreActionActivity : AppCompatActivity() {
)
}

private fun updateMuteButton() {
// Null check in case activity is destroyed while background task runs
val muteView = findViewById<TextView>(R.id.pre_action_mute_toggle) ?: return
muteView.text = getString(if (eventIsMuted) R.string.pre_unmute else R.string.pre_mute)
}

private fun toggleMute() {
background {
val newMutedState = getMonitorStorage(this).use { storage ->
Expand All @@ -405,7 +512,6 @@ class PreActionActivity : AppCompatActivity() {

runOnUiThread {
if (newMutedState != null) {
updateMuteButton()
val msgRes = if (eventIsMuted) R.string.event_will_be_muted else R.string.event_unmuted
Toast.makeText(this, msgRes, Toast.LENGTH_SHORT).show()
} else {
Expand Down
53 changes: 15 additions & 38 deletions android/app/src/main/res/layout/activity_pre_action.xml
Original file line number Diff line number Diff line change
Expand Up @@ -208,53 +208,18 @@
android:textAppearance="?android:textAppearanceMedium"
android:textColor="@color/primary_text" />

</LinearLayout>

<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/divider" />

<!-- Actions Section -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@color/background"
android:paddingTop="@dimen/snooze_view_action_padding_top"
android:paddingBottom="@dimen/snooze_view_action_padding_bottom">

<TextView
android:id="@+id/pre_action_view_calendar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:drawableStart="@drawable/ic_event_available_black_24dp"
android:drawablePadding="@dimen/snooze_view_img_padding_end"
android:paddingBottom="@dimen/snooze_view_spacing"
android:paddingEnd="@dimen/snooze_view_padding_end"
android:paddingStart="@dimen/snooze_view_img_padding_start"
android:paddingTop="@dimen/snooze_view_spacing"
android:text="@string/view_in_calendar"
android:textAppearance="?android:textAppearanceMedium"
android:textColor="@color/primary_text" />

<TextView
android:id="@+id/pre_action_mute_toggle"
android:id="@+id/pre_action_snooze_until"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:drawableStart="@drawable/ic_volume_off_black_24dp"
android:drawablePadding="@dimen/snooze_view_img_padding_end"
android:paddingBottom="@dimen/snooze_view_spacing"
android:paddingEnd="@dimen/snooze_view_padding_end"
android:paddingStart="@dimen/snooze_view_img_padding_start"
android:paddingStart="@dimen/snooze_view_padding_start"
android:paddingTop="@dimen/snooze_view_spacing"
android:text="@string/pre_mute"
android:text="@string/until_specific_time"
android:textAppearance="?android:textAppearanceMedium"
android:textColor="@color/primary_text" />

Expand All @@ -264,4 +229,16 @@

</ScrollView>

<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/pre_action_edit_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/fab_layout_margin"
app:fabSize="mini"
app:layout_anchor="@id/pre_action_header"
app:layout_anchorGravity="bottom|start"
app:srcCompat="@drawable/ic_mode_edit_white_24dp"
android:elevation="@dimen/toolbar_elevation"
tools:targetApi="lollipop"/>

</androidx.coordinatorlayout.widget.CoordinatorLayout>
14 changes: 14 additions & 0 deletions android/app/src/main/res/menu/pre_action.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,18 @@
android:id="@+id/action_pre_dismiss"
android:title="@string/pre_dismiss" />

<item
android:id="@+id/action_pre_mute"
android:title="@string/pre_mute"
android:visible="false" />

<item
android:id="@+id/action_pre_unmute"
android:title="@string/pre_unmute"
android:visible="false" />

<item
android:id="@+id/action_open_in_calendar"
android:title="@string/open_in_calendar" />

</menu>
Original file line number Diff line number Diff line change
Expand Up @@ -103,22 +103,20 @@ class PreActionActivityTest {
}

@Test
fun `mute button shows correct text for non-muted event`() {
fun `snooze until button is present`() {
val activity = launchActivity()

val muteButton = activity.findViewById<TextView>(R.id.pre_action_mute_toggle)
assertEquals(activity.getString(R.string.pre_mute), muteButton.text)
val snoozeUntil = activity.findViewById<TextView>(R.id.pre_action_snooze_until)
assertNotNull(snoozeUntil)
assertEquals(activity.getString(R.string.until_specific_time), snoozeUntil.text)
}

@Test
fun `mute button shows unmute text for pre-muted event`() {
val mutedEvent = testEvent.copy(
flags = com.github.quarck.calnotify.calendar.EventAlertFlags.IS_MUTED
)
val activity = launchActivity(mutedEvent)
fun `edit FAB is visible for writable calendar`() {
val activity = launchActivity()

val muteButton = activity.findViewById<TextView>(R.id.pre_action_mute_toggle)
assertEquals(activity.getString(R.string.pre_unmute), muteButton.text)
val fab = activity.findViewById<View>(R.id.pre_action_edit_button)
assertNotNull(fab)
}

@Test
Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ Features and changes under consideration:
- [Milestone 3: Filter Pills](dev_todo/event_lookahead_milestone3_filter_pills.md) - Status, Time, Calendar filters 🚧
- [Upcoming Time Filter](dev_todo/upcoming_time_filter.md) - Time filter for Upcoming tab ([#216](https://github.com/williscool/CalendarNotification/issues/216))
- [Snoozed Until Filter Pill](dev_todo/snoozed_until_filter_pill.md) - Filter chip by snooze wake time ([#255](https://github.com/williscool/CalendarNotification/issues/255))
- [Pre-Action View Parity](dev_todo/pre_action_view_parity.md) - Align upcoming event view with main event view ([#249](https://github.com/williscool/CalendarNotification/issues/249))
- [Deprecated Features Removal](dev_todo/deprecated_features.md) - QuietHours, CalendarEditor
- [Android Modernization](dev_todo/android_modernization.md) - Coroutines, Hilt DI opportunities
- [Raise Min SDK](dev_todo/raise_min_sdk.md) - API 24 → 26+ considerations
Expand Down
Loading
Loading