feat: bedtime and wakeup reminders

This commit is contained in:
qureshikaif
2025-03-12 22:47:14 +05:00
committed by Miklos Vajna
parent 424ad44a28
commit d7e2f6ffe4
8 changed files with 164 additions and 2 deletions

10
.idea/deploymentTargetSelector.xml generated Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetSelector">
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
</selectionStates>
</component>
</project>

1
.idea/misc.xml generated
View File

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />

17
.idea/runConfigurations.xml generated Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
<option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
<option value="com.intellij.execution.junit.PatternConfigurationProducer" />
<option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
<option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
<option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
</set>
</option>
</component>
</project>

View File

@ -70,6 +70,8 @@
android:name="android.appwidget.provider"
android:resource="@xml/widget_info_toggle" />
</receiver>
<receiver android:name=".ReminderReceiver" />
</application>
</manifest>

View File

@ -7,7 +7,10 @@
package hu.vmiklos.plees_tracker
import android.Manifest
import android.app.AlarmManager
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.TimePickerDialog
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
@ -96,7 +99,7 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
var index = resources.getStringArray(R.array.duration_entry_values).indexOf(durationStr)
val durations = resources.getStringArray(R.array.duration_entries)
if (index == -1) {
index = durations.size - 1 // indexOf may return -1, which will out of bounds.
index = durations.size - 1 // indexOf may return -1, which will be out of bounds.
}
val durationHeaderStr = resources.getStringArray(R.array.duration_entries)[index]
findViewById<TextView>(R.id.dashboard_header)?.text =
@ -253,6 +256,15 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
// See if the activity is triggered from the widget. If so, toggle the start/stop state.
handleIntent(intent)
// Schedule bedtime and wakeup reminders if already set in preferences.
if (preferences.contains("bedtime_hour") && preferences.contains("wakeup_hour")) {
val bedHour = preferences.getInt("bedtime_hour", 22)
val bedMinute = preferences.getInt("bedtime_minute", 0)
val wakeHour = preferences.getInt("wakeup_hour", 7)
val wakeMinute = preferences.getInt("wakeup_minute", 0)
scheduleReminders(bedHour, bedMinute, wakeHour, wakeMinute)
}
updateView()
}
@ -440,6 +452,10 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
startActivity(Intent(this, GraphsActivity::class.java))
return true
}
R.id.set_bedtime -> {
showBedtimeDialog()
return true
}
else -> return super.onOptionsItemSelected(item)
}
}
@ -525,6 +541,69 @@ class MainActivity : AppCompatActivity(), View.OnClickListener {
startActivity(intent)
}
// --- New functions for bedtime/wakeup reminders ---
// Show a dialog to set bedtime and wakeup times (using two TimePickerDialogs sequentially)
private fun showBedtimeDialog() {
val preferences = PreferenceManager.getDefaultSharedPreferences(applicationContext)
// Get current values or use defaults (22:00 for bedtime, 07:00 for wakeup)
val currentBedHour = preferences.getInt("bedtime_hour", 22)
val currentBedMinute = preferences.getInt("bedtime_minute", 0)
val currentWakeHour = preferences.getInt("wakeup_hour", 7)
val currentWakeMinute = preferences.getInt("wakeup_minute", 0)
// First, pick bedtime
TimePickerDialog(this, { _, bedHour, bedMinute ->
// Save bedtime values
preferences.edit().putInt("bedtime_hour", bedHour).putInt("bedtime_minute", bedMinute).apply()
// Then, pick wakeup time
TimePickerDialog(this, { _, wakeHour, wakeMinute ->
// Save wakeup values
preferences.edit().putInt("wakeup_hour", wakeHour).putInt("wakeup_minute", wakeMinute).apply()
// Schedule the alarms with the selected times
scheduleReminders(bedHour, bedMinute, wakeHour, wakeMinute)
Toast.makeText(this, "Reminders set for bedtime and wakeup.", Toast.LENGTH_SHORT).show()
}, currentWakeHour, currentWakeMinute, true).show()
}, currentBedHour, currentBedMinute, true).show()
}
// Schedule two daily repeating alarms (one for bedtime and one for wakeup)
private fun scheduleReminders(bedHour: Int, bedMinute: Int, wakeHour: Int, wakeMinute: Int) {
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
// Schedule bedtime alarm
val bedTimeCalendar = Calendar.getInstance().apply {
set(Calendar.HOUR_OF_DAY, bedHour)
set(Calendar.MINUTE, bedMinute)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
if (timeInMillis <= System.currentTimeMillis()) {
add(Calendar.DAY_OF_MONTH, 1)
}
}
val bedIntent = Intent(this, ReminderReceiver::class.java).apply {
putExtra("reminder_type", "bedtime")
}
val bedPendingIntent = PendingIntent.getBroadcast(this, 100, bedIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, bedTimeCalendar.timeInMillis, AlarmManager.INTERVAL_DAY, bedPendingIntent)
// Schedule wakeup alarm
val wakeTimeCalendar = Calendar.getInstance().apply {
set(Calendar.HOUR_OF_DAY, wakeHour)
set(Calendar.MINUTE, wakeMinute)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
if (timeInMillis <= System.currentTimeMillis()) {
add(Calendar.DAY_OF_MONTH, 1)
}
}
val wakeIntent = Intent(this, ReminderReceiver::class.java).apply {
putExtra("reminder_type", "wakeup")
}
val wakePendingIntent = PendingIntent.getBroadcast(this, 101, wakeIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, wakeTimeCalendar.timeInMillis, AlarmManager.INTERVAL_DAY, wakePendingIntent)
}
companion object {
private const val TAG = "MainActivity"
}

View File

@ -0,0 +1,53 @@
/*
* Copyright 2023 Miklos Vajna
*
* SPDX-License-Identifier: MIT
*/
package hu.vmiklos.plees_tracker
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.app.NotificationChannel
import android.app.NotificationManager
import androidx.core.app.NotificationCompat
import android.os.Build
class ReminderReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val reminderType = intent.getStringExtra("reminder_type") ?: "unknown"
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// Create notification channel for API 26+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
"bedtime_reminder_channel",
"Bedtime Reminders",
NotificationManager.IMPORTANCE_HIGH
)
channel.description = "Channel for bedtime and wakeup reminders"
notificationManager.createNotificationChannel(channel)
}
val title = when (reminderType) {
"bedtime" -> "Bedtime Reminder"
"wakeup" -> "Wake Up Reminder"
else -> "Reminder"
}
val message = when (reminderType) {
"bedtime" -> "It's time to go to bed. Remember to start tracking your sleep!"
"wakeup" -> "Good morning! Don't forget to stop tracking if you haven't already."
else -> "Time for your reminder."
}
val notification = NotificationCompat.Builder(context, "bedtime_reminder_channel")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle(title)
.setContentText(message)
.setAutoCancel(true)
.build()
notificationManager.notify(reminderType.hashCode(), notification)
}
}

View File

@ -5,6 +5,7 @@
<item android:id="@+id/export_file_data" android:title="@string/export_file_item"/>
<item android:id="@+id/export_calendar_data" android:title="@string/export_calendar_item"/>
<item android:id="@+id/stats" android:title="@string/stats" />
<item android:id="@+id/set_bedtime" android:title="@string/bedtime_item" />
<item android:id="@+id/graphs" android:title="@string/graphs" />
<item android:id="@+id/settings" android:title="@string/settings" />
<item android:id="@+id/delete_all_sleep" android:title="@string/delete_all_sleep" />

View File

@ -24,6 +24,7 @@
<string name="deleted">Deleted</string>
<string name="undo">Undo</string>
<string name="about_item">About</string>
<string name="bedtime_item">Set Bedtime</string>
<string name="about_toolbar">About</string>
<string name="app_description">A simple sleep tracker for Android.</string>
<string name="sleep_id">Sleep #%s</string>