1 Commits

Author SHA1 Message Date
88e9cb7deb LunaEvent: add sleep event 2025-11-14 22:41:57 +01:00
5 changed files with 69 additions and 85 deletions

View File

@@ -12,7 +12,6 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.AdapterView import android.widget.AdapterView
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
import android.widget.Button
import android.widget.EditText import android.widget.EditText
import android.widget.NumberPicker import android.widget.NumberPicker
import android.widget.PopupWindow import android.widget.PopupWindow
@@ -331,7 +330,7 @@ class MainActivity : AppCompatActivity() {
alertDialog.show() alertDialog.show()
} }
fun datePickerHelper(time: Long, dateTextView: TextView, onChange: (Long) -> Unit = {}): Calendar { fun datePickerHelper(time: Long, dateTextView: TextView, onChange: () -> Unit = {}): Calendar {
dateTextView.text = DateUtils.formatDateTime(time) dateTextView.text = DateUtils.formatDateTime(time)
val dateTime = Calendar.getInstance() val dateTime = Calendar.getInstance()
@@ -350,7 +349,7 @@ class MainActivity : AppCompatActivity() {
{ _, hour, minute -> { _, hour, minute ->
dateTime.set(year, month, day, hour, minute) dateTime.set(year, month, day, hour, minute)
dateTextView.text = DateUtils.formatDateTime(dateTime.time.time / 1000) dateTextView.text = DateUtils.formatDateTime(dateTime.time.time / 1000)
onChange.invoke(dateTime.time.time / 1000) onChange.invoke()
}, },
startHour, startHour,
startMinute, startMinute,
@@ -374,6 +373,7 @@ class MainActivity : AppCompatActivity() {
} }
fun addSleepEvent(event: LunaEvent) { fun addSleepEvent(event: LunaEvent) {
setToPreviousQuantity(event)
askSleepValue(event) { saveEvent(event) } askSleepValue(event) { saveEvent(event) }
} }
@@ -384,74 +384,57 @@ class MainActivity : AppCompatActivity() {
d.setMessage(event.getDialogMessage(this)) d.setMessage(event.getDialogMessage(this))
d.setView(dialogView) d.setView(dialogView)
val fromTextView = dialogView.findViewById<TextView>(R.id.dialog_date_from)
val toTextView = dialogView.findViewById<TextView>(R.id.dialog_date_to)
val durationTextView = dialogView.findViewById<TextView>(R.id.dialog_date_duration) val durationTextView = dialogView.findViewById<TextView>(R.id.dialog_date_duration)
val durationPlus10Button = dialogView.findViewById<Button>(R.id.dialog_date_duration_plus10)
val durationMinus10Button = dialogView.findViewById<Button>(R.id.dialog_date_duration_minus10)
val durationNowButton = dialogView.findViewById<Button>(R.id.dialog_date_duration_now)
val datePicker = dialogView.findViewById<TextView>(R.id.dialog_date_picker)
val currentDurationTextColor = durationTextView.currentTextColor val currentDurationTextColor = durationTextView.currentTextColor
val invalidDurationTextColor = ContextCompat.getColor(this, R.color.danger) var pickedFromTime = Calendar.getInstance()
var pickedToTime = Calendar.getInstance()
var duration = event.quantity fun isValidTime(fromSeconds: Long, toSeconds: Long): Boolean {
if (fromSeconds < toSeconds) {
fun isValidTime(timeSeconds: Long, durationSeconds: Int): Boolean { val durationSeconds = toSeconds - fromSeconds
val now = Calendar.getInstance().time.time / 1000 // sleep between 0 seconds and 12 hours
return (timeSeconds + durationSeconds) <= now && durationSeconds < (12 * 60 * 60) return durationSeconds > 59 && durationSeconds < (12 * 60 * 60)
} else {
return false
}
} }
val onDateChange = { time: Long -> val onDateChange = {
val fromSeconds = pickedFromTime.time.time / 1000
val toSeconds = pickedToTime.time.time / 1000
val invalidDateText = getString(R.string.toast_date_error)
durationTextView.text = DateUtils.formatTimeDuration(applicationContext, toSeconds - fromSeconds, invalidDateText)
if (isValidTime(fromSeconds, toSeconds)) {
// valid duration: set default color
durationTextView.setTextColor(currentDurationTextColor) durationTextView.setTextColor(currentDurationTextColor)
if (duration == 0) {
// baby is sleeping
durationTextView.text = "💤"
} else { } else {
durationTextView.text = DateUtils.formatTimeDuration(applicationContext, duration.toLong()) // invalid duration: set danger color
if (!isValidTime(time, duration)) { durationTextView.setTextColor(ContextCompat.getColor(this, R.color.danger))
durationTextView.setTextColor(invalidDurationTextColor)
}
} }
} }
val pickedDateTime = datePickerHelper(event.time, datePicker, onDateChange) pickedFromTime = datePickerHelper(event.time, fromTextView, onDateChange)
pickedToTime = datePickerHelper(event.time + event.quantity, toTextView, onDateChange)
onDateChange(pickedDateTime.time.time / 1000) onDateChange()
durationPlus10Button.setOnClickListener {
duration += 10 * 60
onDateChange(pickedDateTime.time.time / 1000)
}
durationMinus10Button.setOnClickListener {
if (duration > 10 * 60) {
duration -= 10 * 60
} else {
duration = 0
}
onDateChange(pickedDateTime.time.time / 1000)
}
durationNowButton.setOnClickListener {
val now = Calendar.getInstance().time.time / 1000
val start = pickedDateTime.time.time / 1000
if (now > start) {
duration = (now - start).toInt()
onDateChange(pickedDateTime.time.time / 1000)
}
}
d.setPositiveButton(android.R.string.ok) { dialogInterface, i -> d.setPositiveButton(android.R.string.ok) { dialogInterface, i ->
val time = pickedDateTime.time.time / 1000 val fromSeconds = pickedFromTime.time.time / 1000
val toSeconds = pickedToTime.time.time / 1000
if (isValidTime(time, duration)) { if (isValidTime(fromSeconds, toSeconds)) {
event.time = time event.time = fromSeconds
event.quantity = duration event.quantity = (toSeconds - fromSeconds).toInt()
onPositive() onPositive()
dialogInterface.dismiss()
} else { } else {
Toast.makeText(this, R.string.toast_date_error, Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.toast_date_error, Toast.LENGTH_SHORT).show()
} }
dialogInterface.dismiss()
} }
d.setNegativeButton(android.R.string.cancel) { dialogInterface, i -> d.setNegativeButton(android.R.string.cancel) { dialogInterface, i ->

View File

@@ -13,6 +13,10 @@ class DateUtils {
* Used for the duration to the next/previous event in the event details dialog. * Used for the duration to the next/previous event in the event details dialog.
*/ */
fun formatTimeDuration(context: Context, secondsDiff: Long): String { fun formatTimeDuration(context: Context, secondsDiff: Long): String {
return formatTimeDuration(context, secondsDiff, context.getString(R.string.now))
}
fun formatTimeDuration(context: Context, secondsDiff: Long, fallbackText: String): String {
var seconds = secondsDiff var seconds = secondsDiff
val years = (seconds / (365 * 24 * 60 * 60F)).toLong() val years = (seconds / (365 * 24 * 60 * 60F)).toLong()
@@ -62,8 +66,10 @@ class DateUtils {
return format(days, hours, R.string.day_ago, R.string.days_ago, R.string.hour_ago, R.string.hours_ago) return format(days, hours, R.string.day_ago, R.string.days_ago, R.string.hour_ago, R.string.hours_ago)
} else if (hours > 0) { } else if (hours > 0) {
return format(hours, minutes, R.string.hour_ago, R.string.hours_ago, R.string.minute_ago, R.string.minutes_ago) return format(hours, minutes, R.string.hour_ago, R.string.hours_ago, R.string.minute_ago, R.string.minutes_ago)
} else { } else if (minutes > 0) {
return format(minutes, seconds, R.string.minute_ago, R.string.minute_ago, R.string.second_ago, R.string.seconds_ago) return format(minutes, seconds, R.string.minute_ago, R.string.minute_ago, R.string.second_ago, R.string.seconds_ago)
} else {
return fallbackText
} }
} }

View File

@@ -92,11 +92,6 @@ class NumericUtils (val context: Context) {
else -> "" else -> ""
} }
) )
} else {
formatted.append(when (event.type) {
LunaEvent.TYPE_SLEEP -> "💤" // baby is sleeping
else -> ""
})
} }
return formatted.toString() return formatted.toString()
} }

View File

@@ -7,12 +7,25 @@
android:gravity="center" android:gravity="center"
android:orientation="vertical"> android:orientation="vertical">
<TextView <LinearLayout
android:id="@+id/dialog_date_duration" android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textSize="20sp" android:gravity="center"
android:text="sleeping emoji"/> android:layout_marginTop="20dp"
android:orientation="horizontal">
<TextView
android:layout_width="40sp"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:text="From"/>
<TextView
android:id="@+id/dialog_date_from"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -21,37 +34,24 @@
android:layout_marginTop="20dp" android:layout_marginTop="20dp"
android:orientation="horizontal"> android:orientation="horizontal">
<Button <TextView
android:id="@+id/dialog_date_duration_minus10" android:layout_width="40sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="10dp" android:layout_marginEnd="10dp"
android:layout_weight="1" android:text="To"/>
android:text="-10"/>
<Button <TextView
android:id="@+id/dialog_date_duration_now" android:id="@+id/dialog_date_to"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"/>
android:layout_marginHorizontal="0dp"
android:layout_weight="1"
android:text="now"/>
<Button
android:id="@+id/dialog_date_duration_plus10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="10dp"
android:layout_weight="1"
android:text="+10"/>
</LinearLayout> </LinearLayout>
<TextView <TextView
android:id="@+id/dialog_date_picker" android:id="@+id/dialog_date_duration"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_marginTop="20dp"
android:layout_marginTop="20dp"/> android:text="0"/>
</LinearLayout> </LinearLayout>

View File

@@ -116,7 +116,7 @@
<string name="log_temperature_dialog_description">Select the temperature:</string> <string name="log_temperature_dialog_description">Select the temperature:</string>
<string name="log_unknown_dialog_description"></string> <string name="log_unknown_dialog_description"></string>
<string name="log_weight_dialog_description">Insert the weight:</string> <string name="log_weight_dialog_description">Insert the weight:</string>
<string name="log_sleep_dialog_description">Set sleep duration:</string> <string name="log_sleep_dialog_description">Select sleep range:</string>
<string name="measurement_unit_liquid_base_metric" translatable="false">ml</string> <string name="measurement_unit_liquid_base_metric" translatable="false">ml</string>
<string name="measurement_unit_weight_base_metric" translatable="false">g</string> <string name="measurement_unit_weight_base_metric" translatable="false">g</string>