mirror of
https://github.com/vmiklos/plees-tracker.git
synced 2025-05-17 19:16:07 +08:00
feat: bedtime and wakeup reminders
This commit is contained in:

committed by
Miklos Vajna

parent
424ad44a28
commit
d7e2f6ffe4
10
.idea/deploymentTargetSelector.xml
generated
Normal file
10
.idea/deploymentTargetSelector.xml
generated
Normal 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
1
.idea/misc.xml
generated
@ -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
17
.idea/runConfigurations.xml
generated
Normal 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>
|
@ -70,6 +70,8 @@
|
||||
android:name="android.appwidget.provider"
|
||||
android:resource="@xml/widget_info_toggle" />
|
||||
</receiver>
|
||||
<receiver android:name=".ReminderReceiver" />
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
@ -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"
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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" />
|
||||
|
@ -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>
|
||||
|
Reference in New Issue
Block a user