7 Commits

Author SHA1 Message Date
7f67c758c9 activity_setting: fine tune layout style 2025-10-26 20:38:26 +01:00
dfa64d71a8 add signature setting
For multiple users it helps to
keep track about who did what.
2025-10-26 20:38:26 +01:00
b7180068f3 DateUtils: move event details formatting to DateUtils
Also do not display seconds, because it is not
meaningful and is not selected in date picker.
2025-10-26 20:38:22 +01:00
36b848b95e add bath event type 2025-10-26 13:54:16 +01:00
a1bde917f8 add no-breastfeeding help text 2025-10-26 13:54:16 +01:00
4f4ff5ed21 more_events_popup: move enema to bottom and adjust padding
Enemas are usually are rare thing. Let's
move it to the bottom. Also adjust padding
to have more space to display all items.
2025-10-26 13:54:16 +01:00
453d838470 add puke event 2025-10-26 13:54:04 +01:00
10 changed files with 98 additions and 56 deletions

View File

@@ -13,7 +13,6 @@ import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.NumberPicker
import android.widget.PopupWindow
import android.widget.Spinner
@@ -211,7 +210,7 @@ class MainActivity : AppCompatActivity() {
numberPicker.wrapSelectorWheel = false
numberPicker.value = localSettings.loadBabyBottleContent()
d.setPositiveButton(android.R.string.ok) { dialogInterface, i ->
logEvent(LunaEvent(LunaEvent.TYPE_BABY_BOTTLE, signature, numberPicker.value * 10))
logEvent(LunaEvent(LunaEvent.TYPE_BABY_BOTTLE, numberPicker.value * 10))
localSettings.saveBabyBottleContent(numberPicker.value)
}
d.setNegativeButton(android.R.string.cancel) { dialogInterface, i -> dialogInterface.dismiss() }
@@ -230,7 +229,7 @@ class MainActivity : AppCompatActivity() {
d.setPositiveButton(android.R.string.ok) { dialogInterface, i ->
val weight = weightET.text.toString().toIntOrNull()
if (weight != null)
logEvent(LunaEvent(LunaEvent.TYPE_WEIGHT, signature, weight))
logEvent(LunaEvent(LunaEvent.TYPE_WEIGHT, weight))
else
Toast.makeText(this, R.string.toast_integer_error, Toast.LENGTH_SHORT).show()
}
@@ -256,7 +255,27 @@ class MainActivity : AppCompatActivity() {
tempSlider.addOnChangeListener({s, v, b -> tempTextView.text = v.toString()})
d.setPositiveButton(android.R.string.ok) { dialogInterface, i ->
val temperature = (tempSlider.value * 10).toInt() // In tenth of a grade
logEvent(LunaEvent(LunaEvent.TYPE_TEMPERATURE, signature, temperature))
logEvent(LunaEvent(LunaEvent.TYPE_TEMPERATURE, temperature))
}
d.setNegativeButton(android.R.string.cancel) { dialogInterface, i -> dialogInterface.dismiss() }
val alertDialog = d.create()
alertDialog.show()
}
fun askPukeValue() {
val d = AlertDialog.Builder(this)
val dialogView = layoutInflater.inflate(R.layout.puke_dialog, null)
d.setTitle(R.string.log_puke_dialog_title)
d.setMessage(R.string.log_puke_dialog_description)
d.setView(dialogView)
val spinner = dialogView.findViewById<Spinner>(R.id.dialog_puke_value)
spinner.adapter = ArrayAdapter.createFromResource(this, R.array.AmountLabels, android.R.layout.simple_spinner_dropdown_item)
spinner.setSelection(1)
d.setPositiveButton(android.R.string.ok) { dialogInterface, i ->
val pos = spinner.selectedItemPosition
logEvent(LunaEvent(LunaEvent.TYPE_PUKE, pos))
}
d.setNegativeButton(android.R.string.cancel) { dialogInterface, i -> dialogInterface.dismiss() }
val alertDialog = d.create()
@@ -391,11 +410,10 @@ class MainActivity : AppCompatActivity() {
})
// show optional signature
dialogView.findViewById<TextView>(R.id.dialog_event_detail_type_signature).text = event.signature
dialogView.findViewById<LinearLayout>(R.id.dialog_event_signature_layout).visibility = if (event.signature.isNotEmpty()) {
View.VISIBLE
} else {
View.GONE
if (event.signature.isNotEmpty()) {
val signatureTextEdit = dialogView.findViewById<TextView>(R.id.dialog_event_detail_type_signature)
signatureTextEdit.text = String.format(getString(R.string.dialog_event_detail_signature), event.signature)
signatureTextEdit.visibility = View.VISIBLE
}
// create next/previous links to events of the same type
@@ -647,6 +665,8 @@ class MainActivity : AppCompatActivity() {
fun logEvent(event: LunaEvent) {
savingEvent(true)
event.signature = signature
setLoading(true)
logbook?.logs?.add(0, event)
recyclerView.adapter?.notifyItemInserted(0)
@@ -781,15 +801,15 @@ class MainActivity : AppCompatActivity() {
val inflater = LayoutInflater.from(anchor.context)
contentView = inflater.inflate(R.layout.more_events_popup, null)
contentView.findViewById<View>(R.id.button_medicine).setOnClickListener {
askNotes(LunaEvent(LunaEvent.TYPE_MEDICINE, signature))
askNotes(LunaEvent(LunaEvent.TYPE_MEDICINE))
dismiss()
}
contentView.findViewById<View>(R.id.button_enema).setOnClickListener({
logEvent(LunaEvent(LunaEvent.TYPE_ENEMA, signature))
logEvent(LunaEvent(LunaEvent.TYPE_ENEMA))
dismiss()
})
contentView.findViewById<View>(R.id.button_note).setOnClickListener({
askNotes(LunaEvent(LunaEvent.TYPE_NOTE, signature))
askNotes(LunaEvent(LunaEvent.TYPE_NOTE))
dismiss()
})
contentView.findViewById<View>(R.id.button_temperature).setOnClickListener({
@@ -797,14 +817,12 @@ class MainActivity : AppCompatActivity() {
dismiss()
})
contentView.findViewById<View>(R.id.button_puke).setOnClickListener({
logEvent(
LunaEvent(LunaEvent.TYPE_PUKE, signature)
)
askPukeValue()
dismiss()
})
contentView.findViewById<View>(R.id.button_colic).setOnClickListener({
logEvent(
LunaEvent(LunaEvent.TYPE_COLIC, signature)
LunaEvent(LunaEvent.TYPE_COLIC)
)
dismiss()
})
@@ -814,7 +832,7 @@ class MainActivity : AppCompatActivity() {
})
contentView.findViewById<View>(R.id.button_bath).setOnClickListener({
logEvent(
LunaEvent(LunaEvent.TYPE_BATH, signature)
LunaEvent(LunaEvent.TYPE_BATH)
)
dismiss()
})

View File

@@ -69,18 +69,16 @@ class LunaEvent: Comparable<LunaEvent> {
throw IllegalArgumentException("JSONObject is not a LunaEvent")
}
constructor(type: String, signature: String) {
constructor(type: String) {
this.jo = JSONObject()
this.time = System.currentTimeMillis() / 1000
this.signature = signature
this.type = type
}
constructor(type: String, signature: String, quantity: Int) {
constructor(type: String, quantity: Int) {
this.jo = JSONObject()
this.time = System.currentTimeMillis() / 1000
this.type = type
this.signature = signature
this.quantity = quantity
}

View File

@@ -1,11 +1,11 @@
package utils
import android.content.Context
import android.os.Build
import android.text.format.DateFormat
import it.danieleverducci.lunatracker.R
import java.util.Date
class DateUtils {
companion object {
/**
@@ -108,15 +108,19 @@ class DateUtils {
}
/**
* Format time as localized string without seconds. E.g. "28 Sept 03:36:00".
* The seconds are set to 0 since they are distracting and not relevant.
* Format time as localized string without seconds. E.g. "Sept 18, 2025, 03:36 PM".
* Used in the event detail dialog.
*/
fun formatDateTime(unixTime: Long): String {
val roundedUnixTime = unixTime - (unixTime % 60)
val date = Date(roundedUnixTime * 1000)
val dateFormat = java.text.DateFormat.getDateTimeInstance()
return dateFormat.format(date)
val date = Date(unixTime * 1000)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val dateFormat = android.icu.text.DateFormat.getDateTimeInstance(android.icu.text.DateFormat.DEFAULT, android.icu.text.DateFormat.SHORT)
return dateFormat.format(date)
} else {
// fallback
val dateFormat = java.text.DateFormat.getDateTimeInstance()
return dateFormat.format(date)
}
}
}
}

View File

@@ -66,6 +66,8 @@ class NumericUtils (val context: Context) {
formatted.append(when (item.type) {
LunaEvent.TYPE_TEMPERATURE ->
(item.quantity / 10.0f).toString()
LunaEvent.TYPE_PUKE ->
context.resources.getStringArray(R.array.AmountLabels)[item.quantity]
else ->
item.quantity
})

View File

@@ -130,7 +130,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:layout_marginTop="5dp"
android:inputType="textEmailAddress"
android:background="@drawable/textview_background"/>

View File

@@ -4,7 +4,9 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="20dp">
android:paddingTop="20dp"
android:paddingBottom="10dp"
android:paddingHorizontal="20dp">
<TextView
android:id="@+id/dialog_event_detail_type_emoji"
@@ -61,6 +63,14 @@
</ScrollView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:id="@+id/dialog_event_detail_type_signature"
android:layout_marginBottom="5dp"
android:visibility="gone"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -89,25 +99,4 @@
</LinearLayout>
<LinearLayout
android:id="@+id/dialog_event_signature_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:text="@string/dialog_event_detail_signature"/>
<TextView
android:id="@+id/dialog_event_detail_type_signature"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:text="" />
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical">
<Spinner
android:id="@+id/dialog_puke_value"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:paddingHorizontal="16dp"
android:paddingVertical="8dp"/>
</LinearLayout>

View File

@@ -50,9 +50,8 @@
<string name="no_connection_go_to_settings">Einstellungen</string>
<string name="no_connection_retry">Erneut versuchen</string>
<string name="no_breastfeeding">Kein Stillen</string>
<string name="settings_title">Einstellungen</string>
<string name="settings_no_breastfeeding">Kein Stillen</string>
<string name="settings_storage">Speicherort für Daten auswählen</string>
<string name="settings_storage_local">Auf dem Gerät</string>
<string name="settings_storage_local_desc">Datenschutzfreundlichste Lösung: Deine Daten verlassen dein Gerät nicht</string>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="AmountLabels">
<item>@string/amount_little</item>
<item>@string/amount_normal</item>
<item>@string/amount_plenty</item>
</string-array>
</resources>

View File

@@ -12,6 +12,9 @@
<string name="log_temperature_dialog_title">Temperature</string>
<string name="log_temperature_dialog_description">Insert the temperature</string>
<string name="log_puke_dialog_title">Puke</string>
<string name="log_puke_dialog_description">Select the amount</string>
<string name="event_bottle_type" translatable="false">🍼</string>
<string name="event_food_type" translatable="false">🥣</string>
<string name="event_scale_type" translatable="false">⚖️</string>
@@ -72,6 +75,10 @@
<string name="year_ago">year</string>
<string name="years_ago">years</string>
<string name="amount_little">Little</string>
<string name="amount_normal">Normal</string>
<string name="amount_plenty">Plenty</string>
<string name="no_connection">No connection</string>
<string name="no_connection_explain">Unable to reach WebDAV service</string>
<string name="no_connection_go_to_settings">Settings</string>
@@ -79,7 +86,7 @@
<string name="settings_title">Settings</string>
<string name="settings_signature">Signature</string>
<string name="settings_signature_desc">Attach a signature to each event your create and for others to see. Useful if multiple people add events.</string>
<string name="settings_signature_desc">Attach a signature to each event you create and for others to see. Useful if multiple people add events.</string>
<string name="settings_storage">Choose where to save data</string>
<string name="settings_storage_local">On device</string>
<string name="settings_storage_local_desc">Most privacy-friendly solution: data doesn\'t leave your device</string>
@@ -131,7 +138,7 @@
<string name="dialog_event_detail_delete_button">Delete</string>
<string name="dialog_event_detail_quantity">Quantity</string>
<string name="dialog_event_detail_notes">Notes</string>
<string name="dialog_event_detail_signature">Created By</string>
<string name="dialog_event_detail_signature">by %s</string>
<string name="dialog_add_logbook_title">Add logbook</string>
<string name="dialog_add_logbook_logbookname">👶 Logbook name</string>