From 001fa68de5a50e2127a7a0dceff08ac4aeb0c8b9 Mon Sep 17 00:00:00 2001 From: Moritz Warning Date: Tue, 4 Nov 2025 15:10:45 +0100 Subject: [PATCH 1/7] events: allow editing of all used values 1. Allow to change the date/time and other relevant values of an event on creation and after it was created. 2. Harmonize layout file names and variable names. --- .../lunatracker/MainActivity.kt | 518 +++++++++++++----- .../lunatracker/entities/LunaEvent.kt | 9 + .../repository/LocalSettingsRepository.kt | 8 - app/src/main/java/utils/NumericUtils.kt | 14 +- .../main/res/layout/dialog_edit_bottle.xml | 35 ++ ...dialog_notes.xml => dialog_edit_notes.xml} | 7 + ...icker_dialog.xml => dialog_edit_plain.xml} | 14 +- .../{puke_dialog.xml => dialog_edit_puke.xml} | 6 + ...dialog.xml => dialog_edit_temperature.xml} | 7 + .../main/res/layout/dialog_edit_weight.xml | 38 ++ ...nt_detail.xml => dialog_event_details.xml} | 4 +- .../main/res/layout/number_edit_dialog.xml | 22 - app/src/main/res/values/strings.xml | 1 - 13 files changed, 482 insertions(+), 201 deletions(-) create mode 100644 app/src/main/res/layout/dialog_edit_bottle.xml rename app/src/main/res/layout/{dialog_notes.xml => dialog_edit_notes.xml} (79%) rename app/src/main/res/layout/{number_picker_dialog.xml => dialog_edit_plain.xml} (59%) rename app/src/main/res/layout/{puke_dialog.xml => dialog_edit_puke.xml} (73%) rename app/src/main/res/layout/{temperature_dialog.xml => dialog_edit_temperature.xml} (83%) create mode 100644 app/src/main/res/layout/dialog_edit_weight.xml rename app/src/main/res/layout/{dialog_event_detail.xml => dialog_event_details.xml} (95%) delete mode 100644 app/src/main/res/layout/number_edit_dialog.xml diff --git a/app/src/main/java/it/danieleverducci/lunatracker/MainActivity.kt b/app/src/main/java/it/danieleverducci/lunatracker/MainActivity.kt index d2900e9..3201035 100644 --- a/app/src/main/java/it/danieleverducci/lunatracker/MainActivity.kt +++ b/app/src/main/java/it/danieleverducci/lunatracker/MainActivity.kt @@ -62,7 +62,7 @@ class MainActivity : AppCompatActivity() { val updateListRunnable: Runnable = Runnable { if (logbook != null && !pauseLogbookUpdate) loadLogbook(logbook!!.name) - handler.postDelayed(updateListRunnable, 1000*60) + handler.postDelayed(updateListRunnable, 1000 * 60) } var logbookRepo: LogbookRepository? = null var showingOverflowPopupWindow = false @@ -81,34 +81,30 @@ class MainActivity : AppCompatActivity() { recyclerView.setLayoutManager(LinearLayoutManager(applicationContext)) // Set listeners - findViewById(R.id.logbooks_add_button).setOnClickListener { showAddLogbookDialog(true) } - findViewById(R.id.button_bottle).setOnClickListener { askBabyBottleContent() } - findViewById(R.id.button_food).setOnClickListener { askNotes(LunaEvent(LunaEvent.TYPE_FOOD)) } - findViewById(R.id.button_nipple_left).setOnClickListener { logEvent( - LunaEvent( - LunaEvent.TYPE_BREASTFEEDING_LEFT_NIPPLE - ) - ) } - findViewById(R.id.button_nipple_both).setOnClickListener { logEvent( - LunaEvent( - LunaEvent.TYPE_BREASTFEEDING_BOTH_NIPPLE - ) - ) } - findViewById(R.id.button_nipple_right).setOnClickListener { logEvent( - LunaEvent( - LunaEvent.TYPE_BREASTFEEDING_RIGHT_NIPPLE - ) - ) } - findViewById(R.id.button_change_poo).setOnClickListener { logEvent( - LunaEvent( - LunaEvent.TYPE_DIAPERCHANGE_POO - ) - ) } - findViewById(R.id.button_change_pee).setOnClickListener { logEvent( - LunaEvent( - LunaEvent.TYPE_DIAPERCHANGE_PEE - ) - ) } + findViewById(R.id.logbooks_add_button).setOnClickListener { + showAddLogbookDialog(true) + } + findViewById(R.id.button_bottle).setOnClickListener { + addBabyBottleEvent() + } + findViewById(R.id.button_food).setOnClickListener { + addNoteEvent(LunaEvent(LunaEvent.TYPE_FOOD)) + } + findViewById(R.id.button_nipple_left).setOnClickListener { + addPlainEvent(LunaEvent(LunaEvent.TYPE_BREASTFEEDING_LEFT_NIPPLE)) + } + findViewById(R.id.button_nipple_both).setOnClickListener { + addPlainEvent(LunaEvent(LunaEvent.TYPE_BREASTFEEDING_BOTH_NIPPLE)) + } + findViewById(R.id.button_nipple_right).setOnClickListener { + addPlainEvent(LunaEvent(LunaEvent.TYPE_BREASTFEEDING_RIGHT_NIPPLE)) + } + findViewById(R.id.button_change_poo).setOnClickListener { + addPlainEvent(LunaEvent(LunaEvent.TYPE_DIAPERCHANGE_POO)) + } + findViewById(R.id.button_change_pee).setOnClickListener { + addPlainEvent(LunaEvent(LunaEvent.TYPE_DIAPERCHANGE_PEE)) + } val moreButton = findViewById(R.id.button_more) moreButton.setOnClickListener { showOverflowPopupWindow(moreButton) @@ -130,9 +126,9 @@ class MainActivity : AppCompatActivity() { private fun setListAdapter(items: ArrayList) { val adapter = LunaEventRecyclerAdapter(this, items) - adapter.onItemClickListener = object: LunaEventRecyclerAdapter.OnItemClickListener { + adapter.onItemClickListener = object : LunaEventRecyclerAdapter.OnItemClickListener { override fun onItemClick(event: LunaEvent) { - showEventDetailDialog(event, items) + showEventDetailDialog(event) } } recyclerView.adapter = adapter @@ -195,118 +191,313 @@ class MainActivity : AppCompatActivity() { super.onStop() } - fun askBabyBottleContent() { - // Show number picker dialog - val localSettings = LocalSettingsRepository(this) + fun getAllEvents(): ArrayList { + return logbook?.logs ?: arrayListOf() + } + + fun addBabyBottleEvent() { + val event = LunaEvent(LunaEvent.TYPE_BABY_BOTTLE) + askBabyBottleContent(event, true) { + saveEvent(event) + } + } + + fun askBabyBottleContent(event: LunaEvent, showTime: Boolean, onPositive: () -> Unit) { val d = AlertDialog.Builder(this) - val dialogView = layoutInflater.inflate(R.layout.number_picker_dialog, null) + val dialogView = layoutInflater.inflate(R.layout.dialog_edit_bottle, null) d.setTitle(R.string.log_bottle_dialog_title) d.setMessage(R.string.log_bottle_dialog_description) d.setView(dialogView) + val numberPicker = dialogView.findViewById(R.id.dialog_number_picker) numberPicker.minValue = 1 // "10" numberPicker.maxValue = 25 // "250 numberPicker.displayedValues = ((10..250 step 10).map { it.toString() }.toTypedArray()) numberPicker.wrapSelectorWheel = false - numberPicker.value = localSettings.loadBabyBottleContent() - d.setPositiveButton(android.R.string.ok) { dialogInterface, i -> - logEvent(LunaEvent(LunaEvent.TYPE_BABY_BOTTLE, numberPicker.value * 10)) - localSettings.saveBabyBottleContent(numberPicker.value) + numberPicker.value = event.quantity / 10 + + val dateTV = dialogView.findViewById(R.id.dialog_date_picker) + val pickedTime = datePickerHelper(event.time, dateTV) + + if (!showTime) { + dateTV.visibility = View.GONE } - d.setNegativeButton(android.R.string.cancel) { dialogInterface, i -> dialogInterface.dismiss() } + + d.setPositiveButton(android.R.string.ok) { dialogInterface, i -> + event.time = pickedTime.time.time / 1000 + event.quantity = numberPicker.value * 10 + onPositive() + dialogInterface.dismiss() + } + + d.setNegativeButton(android.R.string.cancel) { dialogInterface, i -> + dialogInterface.dismiss() + } + val alertDialog = d.create() alertDialog.show() } - fun askWeightValue() { + fun addWeightEvent(event: LunaEvent) { + askWeightValue(event, true) { saveEvent(event) } + } + + fun askWeightValue(event: LunaEvent, showTime: Boolean, onPositive: () -> Unit) { // Show number picker dialog val d = AlertDialog.Builder(this) - val dialogView = layoutInflater.inflate(R.layout.number_edit_dialog, null) + val dialogView = layoutInflater.inflate(R.layout.dialog_edit_weight, null) d.setTitle(R.string.log_weight_dialog_title) d.setMessage(R.string.log_weight_dialog_description) d.setView(dialogView) + val weightET = dialogView.findViewById(R.id.dialog_number_edittext) + weightET.setText(event.quantity.toString()) + + val dateTV = dialogView.findViewById(R.id.dialog_date_picker) + val pickedTime = datePickerHelper(event.time, dateTV) + + if (!showTime) { + dateTV.visibility = View.GONE + } + d.setPositiveButton(android.R.string.ok) { dialogInterface, i -> val weight = weightET.text.toString().toIntOrNull() - if (weight != null) - logEvent(LunaEvent(LunaEvent.TYPE_WEIGHT, weight)) - else + if (weight != null) { + event.time = pickedTime.time.time / 1000 + event.quantity = weight + onPositive() + } else { Toast.makeText(this, R.string.toast_integer_error, Toast.LENGTH_SHORT).show() + } + + dialogInterface.dismiss() } - d.setNegativeButton(android.R.string.cancel) { dialogInterface, i -> dialogInterface.dismiss() } + + d.setNegativeButton(android.R.string.cancel) { dialogInterface, i -> + dialogInterface.dismiss() + } + val alertDialog = d.create() alertDialog.show() } - fun askTemperatureValue() { + fun addTemperatureEvent(event: LunaEvent) { + askTemperatureValue(event, true) { saveEvent(event) } + } + + fun askTemperatureValue(event: LunaEvent, showTime: Boolean, onPositive: () -> Unit) { // Show number picker dialog val d = AlertDialog.Builder(this) - val dialogView = layoutInflater.inflate(R.layout.temperature_dialog, null) + val dialogView = layoutInflater.inflate(R.layout.dialog_edit_temperature, null) d.setTitle(R.string.log_temperature_dialog_title) d.setMessage(R.string.log_temperature_dialog_description) d.setView(dialogView) + val tempSlider = dialogView.findViewById(R.id.dialog_temperature_value) val range = NumericUtils(this).getValidEventQuantityRange(LunaEvent.TYPE_TEMPERATURE)!! tempSlider.valueFrom = range.first.toFloat() tempSlider.valueTo = range.second.toFloat() - tempSlider.value = range.third.toFloat() - val tempTextView = dialogView.findViewById(R.id.dialog_temperature_display) - tempTextView.text = range.third.toString() - 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, temperature)) + tempSlider.value = if (event.quantity == 0) { + range.third.toFloat() // default + } else { + event.quantity.toFloat() / 10 } - d.setNegativeButton(android.R.string.cancel) { dialogInterface, i -> dialogInterface.dismiss() } + + val dateTV = dialogView.findViewById(R.id.dialog_date_picker) + val pickedTime = datePickerHelper(event.time, dateTV) + if (!showTime) { + dateTV.visibility = View.GONE + } + + val tempTextView = dialogView.findViewById(R.id.dialog_temperature_display) + tempTextView.text = tempSlider.value.toString() + tempSlider.addOnChangeListener({ s, v, b -> tempTextView.text = v.toString() }) + + d.setPositiveButton(android.R.string.ok) { dialogInterface, i -> + event.time = pickedTime.time.time / 1000 + event.quantity = (tempSlider.value * 10).toInt() // temperature in tenth of a grade + onPositive() + dialogInterface.dismiss() + } + + d.setNegativeButton(android.R.string.cancel) { dialogInterface, i -> + dialogInterface.dismiss() + } + val alertDialog = d.create() alertDialog.show() } - fun askPukeValue() { + fun datePickerHelper(time: Long, dateTextView: TextView): Calendar { + dateTextView.text = DateUtils.formatDateTime(time) + + val dateTime = Calendar.getInstance() + dateTime.time = Date(time * 1000) + dateTextView.setOnClickListener { + // Show datetime picker + val startYear = dateTime.get(Calendar.YEAR) + val startMonth = dateTime.get(Calendar.MONTH) + val startDay = dateTime.get(Calendar.DAY_OF_MONTH) + val startHour = dateTime.get(Calendar.HOUR_OF_DAY) + val startMinute = dateTime.get(Calendar.MINUTE) + + DatePickerDialog(this, { _, year, month, day -> + TimePickerDialog( + this, + { _, hour, minute -> + dateTime.set(year, month, day, hour, minute) + dateTextView.text = DateUtils.formatDateTime(dateTime.time.time / 1000) + }, + startHour, + startMinute, + android.text.format.DateFormat.is24HourFormat(this@MainActivity) + ).show() + }, startYear, startMonth, startDay).show() + } + + return dateTime + } + + fun saveEvent(event: LunaEvent) { + if (!getAllEvents().contains(event)) { + // new event + logEvent(event) + } + + logbook?.sort() + recyclerView.adapter?.notifyDataSetChanged() + saveLogbook() + } + + fun addPukeEvent(event: LunaEvent) { + askPukeValue(event, true) { saveEvent(event) } + } + + fun askPukeValue(event: LunaEvent, showTime: Boolean, onPositive: () -> Unit) { val d = AlertDialog.Builder(this) - val dialogView = layoutInflater.inflate(R.layout.puke_dialog, null) + val dialogView = layoutInflater.inflate(R.layout.dialog_edit_puke, null) d.setTitle(R.string.log_puke_dialog_title) d.setMessage(R.string.log_puke_dialog_description) d.setView(dialogView) val spinner = dialogView.findViewById(R.id.dialog_puke_value) - spinner.adapter = ArrayAdapter.createFromResource(this, R.array.AmountLabels, android.R.layout.simple_spinner_dropdown_item) - spinner.setSelection(1) + spinner.adapter = ArrayAdapter.createFromResource( + this, + R.array.AmountLabels, + android.R.layout.simple_spinner_dropdown_item + ) + spinner.setSelection(event.quantity - 1) + + val dateTV = dialogView.findViewById(R.id.dialog_date_picker) + val pickedTime = datePickerHelper(event.time, dateTV) + if (!showTime) { + dateTV.visibility = View.GONE + } d.setPositiveButton(android.R.string.ok) { dialogInterface, i -> - val pos = spinner.selectedItemPosition - logEvent(LunaEvent(LunaEvent.TYPE_PUKE, pos + 1)) + event.time = pickedTime.time.time / 1000 + event.quantity = spinner.selectedItemPosition + 1 + onPositive() + dialogInterface.dismiss() } - d.setNegativeButton(android.R.string.cancel) { dialogInterface, i -> dialogInterface.dismiss() } + + d.setNegativeButton(android.R.string.cancel) { dialogInterface, i -> + dialogInterface.dismiss() + } + val alertDialog = d.create() alertDialog.show() } - fun askNotes(lunaEvent: LunaEvent) { + fun addPlainEvent(event: LunaEvent) { + askDateValue(event, true) { saveEvent(event) } + } + + // Ask to edit events to be edited (only affects date) + fun askDateValue(event: LunaEvent, showTime: Boolean, onPositive: () -> Unit) { val d = AlertDialog.Builder(this) - val dialogView = layoutInflater.inflate(R.layout.dialog_notes, null) - d.setTitle(lunaEvent.getTypeDescription(this)) - d.setMessage(lunaEvent.getDialogMessage(this)) + val dialogView = layoutInflater.inflate(R.layout.dialog_edit_plain, null) + d.setTitle(event.getTypeDescription(this)) + d.setMessage(event.getDialogMessage(this)) + d.setView(dialogView) + + val dateTV = dialogView.findViewById(R.id.dialog_date_picker) + val pickedDateTime = datePickerHelper(event.time, dateTV) + if (!showTime) { + dateTV.visibility = View.GONE + } + + d.setPositiveButton(android.R.string.ok) { dialogInterface, i -> + event.time = pickedDateTime.time.time / 1000 + onPositive() + dialogInterface.dismiss() + } + + d.setNegativeButton(android.R.string.cancel) { dialogInterface, i -> + dialogInterface.dismiss() + } + + val alertDialog = d.create() + alertDialog.show() + } + + fun addNoteEvent(event: LunaEvent) { + askNotes(event, true) { saveEvent(event) } + } + + fun askNotes(event: LunaEvent, showTime: Boolean, onPositive: () -> Unit) { + val useQuantity = (event.type != LunaEvent.TYPE_NOTE && event.type != LunaEvent.TYPE_CUSTOM) + + val d = AlertDialog.Builder(this) + val dialogView = layoutInflater.inflate(R.layout.dialog_edit_notes, null) + d.setTitle(event.getTypeDescription(this)) + d.setMessage(event.getDialogMessage(this)) d.setView(dialogView) val notesET = dialogView.findViewById(R.id.notes_edittext) val qtyET = dialogView.findViewById(R.id.notes_qty_edittext) - if (lunaEvent.type == LunaEvent.TYPE_NOTE || lunaEvent.type == LunaEvent.TYPE_CUSTOM) - qtyET.visibility = View.GONE - d.setPositiveButton(android.R.string.ok) { dialogInterface, i -> - val qtyStr = qtyET.text.toString() - if (qtyStr.isNotEmpty()) { - val qty = qtyStr.toIntOrNull() - if (qty == null) { - Toast.makeText(this, R.string.toast_integer_error, Toast.LENGTH_SHORT).show() - return@setPositiveButton - } - lunaEvent.quantity = qty - } - val notes = notesET.text.toString() - lunaEvent.notes = notes - logEvent(lunaEvent) + + val dateTV = dialogView.findViewById(R.id.dialog_date_picker) + val pickedTime = datePickerHelper(event.time, dateTV) + + if (!showTime) { + dateTV.visibility = View.GONE } - d.setNegativeButton(android.R.string.cancel) { dialogInterface, i -> dialogInterface.dismiss() } + + notesET.setText(event.notes) + + if (useQuantity) { + qtyET.setText(event.quantity.toString()) + } else { + qtyET.visibility = View.GONE + } + + d.setPositiveButton(android.R.string.ok) { dialogInterface, i -> + val notes = notesET.text.toString() + + if (useQuantity) { + val quantity = qtyET.text.toString().toIntOrNull() + if (quantity != null) { + event.time = pickedTime.time.time / 1000 + event.notes = notes + event.quantity = quantity + onPositive() + } else { + Toast.makeText(this, R.string.toast_integer_error, Toast.LENGTH_SHORT).show() + } + + } else { + event.time = pickedTime.time.time / 1000 + event.notes = notes + onPositive() + } + + dialogInterface.dismiss() + } + + d.setNegativeButton(android.R.string.cancel) { dialogInterface, i -> + dialogInterface.dismiss() + } + val alertDialog = d.create() alertDialog.show() } @@ -359,55 +550,83 @@ class MainActivity : AppCompatActivity() { return nextEvent } - fun showEventDetailDialog(event: LunaEvent, items: ArrayList) { + fun showEventDetailDialog(originalEvent: LunaEvent) { + val event = LunaEvent(originalEvent) + // Do not update list while the detail is shown, to avoid changing the object below while it is changed by the user pauseLogbookUpdate = true + val d = AlertDialog.Builder(this) d.setTitle(R.string.dialog_event_detail_title) - val dialogView = layoutInflater.inflate(R.layout.dialog_event_detail, null) - dialogView.findViewById(R.id.dialog_event_detail_type_emoji).text = event.getTypeEmoji(this) - dialogView.findViewById(R.id.dialog_event_detail_type_description).text = event.getTypeDescription(this) - dialogView.findViewById(R.id.dialog_event_detail_type_quantity).text = - NumericUtils(this).formatEventQuantity(event) - dialogView.findViewById(R.id.dialog_event_detail_type_notes).text = event.notes - - val currentDateTime = Calendar.getInstance() - currentDateTime.time = Date(event.time * 1000) + val dialogView = layoutInflater.inflate(R.layout.dialog_event_details, null) + val emojiTextView = dialogView.findViewById(R.id.dialog_event_detail_type_emoji) + val descriptionTextView = dialogView.findViewById(R.id.dialog_event_detail_type_description) val dateTextView = dialogView.findViewById(R.id.dialog_event_detail_type_date) - dateTextView.text = String.format(getString(R.string.dialog_event_detail_datetime_icon), DateUtils.formatDateTime(event.time)) - dateTextView.setOnClickListener { - // Show datetime picker - val startYear = currentDateTime.get(Calendar.YEAR) - val startMonth = currentDateTime.get(Calendar.MONTH) - val startDay = currentDateTime.get(Calendar.DAY_OF_MONTH) - val startHour = currentDateTime.get(Calendar.HOUR_OF_DAY) - val startMinute = currentDateTime.get(Calendar.MINUTE) + val quantityTextView = dialogView.findViewById(R.id.dialog_event_detail_type_quantity) + val notesTextView = dialogView.findViewById(R.id.dialog_event_detail_type_notes) - DatePickerDialog(this, { _, year, month, day -> - TimePickerDialog(this, { _, hour, minute -> - val pickedDateTime = Calendar.getInstance() - pickedDateTime.set(year, month, day, hour, minute) - // Save event and move it to the right position in the logbook - event.time = pickedDateTime.time.time / 1000 // Seconds since epoch - dateTextView.text = String.format(getString(R.string.dialog_event_detail_datetime_icon), DateUtils.formatDateTime(event.time)) - logbook?.sort() - recyclerView.adapter?.notifyDataSetChanged() - saveLogbook() - }, startHour, startMinute, android.text.format.DateFormat.is24HourFormat(this@MainActivity)).show() - }, startYear, startMonth, startDay).show() + emojiTextView.text = event.getTypeEmoji(this) + descriptionTextView.text = event.getTypeDescription(this) + + val pickedTime = datePickerHelper(event.time, dateTextView) + val updateValues = { + quantityTextView.text = NumericUtils(this).formatEventQuantity(event) + notesTextView.text = event.notes + } + updateValues() + + quantityTextView.setOnClickListener { + when (event.type) { + LunaEvent.TYPE_BABY_BOTTLE -> askBabyBottleContent(event, false, updateValues) + LunaEvent.TYPE_WEIGHT -> askWeightValue(event, false, updateValues) + LunaEvent.TYPE_PUKE -> askPukeValue(event, false, updateValues) + LunaEvent.TYPE_TEMPERATURE -> askTemperatureValue(event, false, updateValues) + LunaEvent.TYPE_NOTE -> askNotes(event, false, updateValues) + } + } + + notesTextView.setOnClickListener { + when (event.type) { + LunaEvent.TYPE_FOOD, + LunaEvent.TYPE_MEDICINE, + LunaEvent.TYPE_NOTE -> askNotes(event, false, updateValues) + } } d.setView(dialogView) - d.setPositiveButton(R.string.dialog_event_detail_close_button) { dialogInterface, i -> dialogInterface.dismiss() } - d.setNeutralButton(R.string.dialog_event_detail_delete_button) { dialogInterface, i -> deleteEvent(event) } + + d.setNeutralButton(R.string.dialog_event_detail_delete_button) { dialogInterface, i -> + deleteEvent(originalEvent) + dialogInterface.dismiss() + } + + d.setPositiveButton(R.string.dialog_event_detail_close_button) { dialogInterface, i -> + event.time = pickedTime.time.time / 1000 + + if (event.time != originalEvent.time + || event.quantity != originalEvent.quantity + || event.notes != originalEvent.notes) { + originalEvent.time = event.time + originalEvent.quantity = event.quantity + originalEvent.notes = event.notes + saveEvent(originalEvent) + } + + dialogInterface.dismiss() + } + val alertDialog = d.create() alertDialog.show() - alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL).setTextColor(ContextCompat.getColor(this, R.color.danger)) - alertDialog.setOnDismissListener({ + + alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL).setTextColor( + ContextCompat.getColor(this, R.color.danger) + ) + + alertDialog.setOnDismissListener { // Resume logbook update pauseLogbookUpdate = false - }) + } // show optional signature if (event.signature.isNotEmpty()) { @@ -416,32 +635,33 @@ class MainActivity : AppCompatActivity() { signatureTextEdit.visibility = View.VISIBLE } - // create next/previous links to events of the same type + val allEvents = getAllEvents() + // create link to prevent event of the same type val previousTextView = dialogView.findViewById(R.id.dialog_event_previous) - val nextTextView = dialogView.findViewById(R.id.dialog_event_next) - val nextEvent = getNextSameEvent(event, items) - val previousEvent = getPreviousSameEvent(event, items) - + val previousEvent = getPreviousSameEvent(event, allEvents) if (previousEvent != null) { val emoji = previousEvent.getTypeEmoji(applicationContext) val time = DateUtils.formatTimeDuration(applicationContext, event.time - previousEvent.time) previousTextView.text = String.format("⬅️ %s %s", emoji, time) previousTextView.setOnClickListener { alertDialog.cancel() - showEventDetailDialog(previousEvent, items) + showEventDetailDialog(previousEvent) } } else { previousTextView.visibility = View.GONE } + // create link to next event of the same type + val nextTextView = dialogView.findViewById(R.id.dialog_event_next) + val nextEvent = getNextSameEvent(event, allEvents) if (nextEvent != null) { val emoji = nextEvent.getTypeEmoji(applicationContext) val time = DateUtils.formatTimeDuration(applicationContext, nextEvent.time - event.time) nextTextView.text = String.format("%s %s ➡️", time, emoji) nextTextView.setOnClickListener { alertDialog.cancel() - showEventDetailDialog(nextEvent, items) + showEventDetailDialog(nextEvent) } } else { nextTextView.visibility = View.GONE @@ -801,41 +1021,37 @@ class MainActivity : AppCompatActivity() { val inflater = LayoutInflater.from(anchor.context) contentView = inflater.inflate(R.layout.more_events_popup, null) contentView.findViewById(R.id.button_medicine).setOnClickListener { - askNotes(LunaEvent(LunaEvent.TYPE_MEDICINE)) + addNoteEvent(LunaEvent(LunaEvent.TYPE_MEDICINE)) dismiss() } - contentView.findViewById(R.id.button_enema).setOnClickListener({ - logEvent(LunaEvent(LunaEvent.TYPE_ENEMA)) + contentView.findViewById(R.id.button_enema).setOnClickListener { + addPlainEvent(LunaEvent(LunaEvent.TYPE_ENEMA)) dismiss() - }) - contentView.findViewById(R.id.button_note).setOnClickListener({ - askNotes(LunaEvent(LunaEvent.TYPE_NOTE)) + } + contentView.findViewById(R.id.button_note).setOnClickListener { + addNoteEvent(LunaEvent(LunaEvent.TYPE_NOTE)) dismiss() - }) - contentView.findViewById(R.id.button_temperature).setOnClickListener({ - askTemperatureValue() + } + contentView.findViewById(R.id.button_temperature).setOnClickListener { + addTemperatureEvent(LunaEvent(LunaEvent.TYPE_TEMPERATURE)) dismiss() - }) - contentView.findViewById(R.id.button_puke).setOnClickListener({ - askPukeValue() + } + contentView.findViewById(R.id.button_puke).setOnClickListener { + addPukeEvent(LunaEvent(LunaEvent.TYPE_PUKE, 1)) dismiss() - }) - contentView.findViewById(R.id.button_colic).setOnClickListener({ - logEvent( - LunaEvent(LunaEvent.TYPE_COLIC) - ) + } + contentView.findViewById(R.id.button_colic).setOnClickListener { + addPlainEvent(LunaEvent(LunaEvent.TYPE_COLIC)) dismiss() - }) - contentView.findViewById(R.id.button_scale).setOnClickListener({ - askWeightValue() + } + contentView.findViewById(R.id.button_scale).setOnClickListener { + addWeightEvent(LunaEvent(LunaEvent.TYPE_WEIGHT)) dismiss() - }) - contentView.findViewById(R.id.button_bath).setOnClickListener({ - logEvent( - LunaEvent(LunaEvent.TYPE_BATH) - ) + } + contentView.findViewById(R.id.button_bath).setOnClickListener { + addPlainEvent(LunaEvent(LunaEvent.TYPE_BATH)) dismiss() - }) + } }.also { popupWindow -> popupWindow.setOnDismissListener({ Handler(mainLooper).postDelayed({ diff --git a/app/src/main/java/it/danieleverducci/lunatracker/entities/LunaEvent.kt b/app/src/main/java/it/danieleverducci/lunatracker/entities/LunaEvent.kt index e46ab25..58160e3 100644 --- a/app/src/main/java/it/danieleverducci/lunatracker/entities/LunaEvent.kt +++ b/app/src/main/java/it/danieleverducci/lunatracker/entities/LunaEvent.kt @@ -69,6 +69,15 @@ class LunaEvent: Comparable { throw IllegalArgumentException("JSONObject is not a LunaEvent") } + constructor(event: LunaEvent) { + this.jo = JSONObject() + this.type = event.type + this.time = event.time + this.quantity = event.quantity + this.notes = event.notes + this.signature = event.signature + } + constructor(type: String) { this.jo = JSONObject() this.time = System.currentTimeMillis() / 1000 diff --git a/app/src/main/java/it/danieleverducci/lunatracker/repository/LocalSettingsRepository.kt b/app/src/main/java/it/danieleverducci/lunatracker/repository/LocalSettingsRepository.kt index 1462820..9431194 100644 --- a/app/src/main/java/it/danieleverducci/lunatracker/repository/LocalSettingsRepository.kt +++ b/app/src/main/java/it/danieleverducci/lunatracker/repository/LocalSettingsRepository.kt @@ -23,14 +23,6 @@ class LocalSettingsRepository(val context: Context) { sharedPreferences = context.getSharedPreferences(SHARED_PREFS_FILE_NAME, MODE_PRIVATE) } - fun saveBabyBottleContent(content: Int) { - sharedPreferences.edit { putInt(SHARED_PREFS_BB_CONTENT, content) } - } - - fun loadBabyBottleContent(): Int { - return sharedPreferences.getInt(SHARED_PREFS_BB_CONTENT, 1) - } - fun saveSignature(content: String) { sharedPreferences.edit { putString(SHARED_PREFS_SIGNATURE, content) } } diff --git a/app/src/main/java/utils/NumericUtils.kt b/app/src/main/java/utils/NumericUtils.kt index 23ac4f1..23cd5c6 100644 --- a/app/src/main/java/utils/NumericUtils.kt +++ b/app/src/main/java/utils/NumericUtils.kt @@ -60,21 +60,21 @@ class NumericUtils (val context: Context) { ) } - fun formatEventQuantity(item: LunaEvent): String { + fun formatEventQuantity(event: LunaEvent): String { val formatted = StringBuilder() - if (item.quantity > 0) { - formatted.append(when (item.type) { + if (event.quantity > 0) { + formatted.append(when (event.type) { LunaEvent.TYPE_TEMPERATURE -> - (item.quantity / 10.0f).toString() + (event.quantity / 10.0f).toString() LunaEvent.TYPE_PUKE -> - context.resources.getStringArray(R.array.AmountLabels)[item.quantity - 1] + context.resources.getStringArray(R.array.AmountLabels)[event.quantity - 1] else -> - item.quantity + event.quantity }) formatted.append(" ") formatted.append( - when (item.type) { + when (event.type) { LunaEvent.TYPE_BABY_BOTTLE -> measurement_unit_liquid_base LunaEvent.TYPE_WEIGHT -> measurement_unit_weight_base LunaEvent.TYPE_MEDICINE -> measurement_unit_weight_tiny diff --git a/app/src/main/res/layout/dialog_edit_bottle.xml b/app/src/main/res/layout/dialog_edit_bottle.xml new file mode 100644 index 0000000..9300467 --- /dev/null +++ b/app/src/main/res/layout/dialog_edit_bottle.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/dialog_notes.xml b/app/src/main/res/layout/dialog_edit_notes.xml similarity index 79% rename from app/src/main/res/layout/dialog_notes.xml rename to app/src/main/res/layout/dialog_edit_notes.xml index 6d30a5e..811eed6 100644 --- a/app/src/main/res/layout/dialog_notes.xml +++ b/app/src/main/res/layout/dialog_edit_notes.xml @@ -24,4 +24,11 @@ android:hint="@string/log_notes_dialog_note_hint" android:background="@drawable/textview_background"/> + + \ No newline at end of file diff --git a/app/src/main/res/layout/number_picker_dialog.xml b/app/src/main/res/layout/dialog_edit_plain.xml similarity index 59% rename from app/src/main/res/layout/number_picker_dialog.xml rename to app/src/main/res/layout/dialog_edit_plain.xml index ce2aa8b..62cc4eb 100644 --- a/app/src/main/res/layout/number_picker_dialog.xml +++ b/app/src/main/res/layout/dialog_edit_plain.xml @@ -4,16 +4,12 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" - android:gravity="center"> - - + android:gravity="center" + android:orientation="vertical"> + android:layout_height="wrap_content"/> + diff --git a/app/src/main/res/layout/puke_dialog.xml b/app/src/main/res/layout/dialog_edit_puke.xml similarity index 73% rename from app/src/main/res/layout/puke_dialog.xml rename to app/src/main/res/layout/dialog_edit_puke.xml index 6f924a0..2277369 100644 --- a/app/src/main/res/layout/puke_dialog.xml +++ b/app/src/main/res/layout/dialog_edit_puke.xml @@ -14,4 +14,10 @@ android:paddingHorizontal="16dp" android:paddingVertical="8dp"/> + + diff --git a/app/src/main/res/layout/temperature_dialog.xml b/app/src/main/res/layout/dialog_edit_temperature.xml similarity index 83% rename from app/src/main/res/layout/temperature_dialog.xml rename to app/src/main/res/layout/dialog_edit_temperature.xml index 292ed19..b4b3f65 100644 --- a/app/src/main/res/layout/temperature_dialog.xml +++ b/app/src/main/res/layout/dialog_edit_temperature.xml @@ -23,4 +23,11 @@ android:layout_height="wrap_content" android:textSize="30sp" android:textColor="@color/accent"/> + + + diff --git a/app/src/main/res/layout/dialog_edit_weight.xml b/app/src/main/res/layout/dialog_edit_weight.xml new file mode 100644 index 0000000..31dc8de --- /dev/null +++ b/app/src/main/res/layout/dialog_edit_weight.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/dialog_event_detail.xml b/app/src/main/res/layout/dialog_event_details.xml similarity index 95% rename from app/src/main/res/layout/dialog_event_detail.xml rename to app/src/main/res/layout/dialog_event_details.xml index 137baa9..3335b95 100644 --- a/app/src/main/res/layout/dialog_event_detail.xml +++ b/app/src/main/res/layout/dialog_event_details.xml @@ -36,9 +36,7 @@ android:drawablePadding="10dp" android:drawableTint="@color/accent" android:textSize="16sp" - android:textStyle="bold" - android:text="@string/dialog_event_detail_datetime_icon" - app:drawableEndCompat="@drawable/ic_edit" /> + android:textStyle="bold"/> - - - - - - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c612ca8..afd4eab 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -133,7 +133,6 @@ Time Event detail - 🕒 %s OK Delete Quantity -- 2.39.5 From 6f7faa97d386810c14f42fac1b7c30798a1aff8d Mon Sep 17 00:00:00 2001 From: Moritz Warning Date: Fri, 14 Nov 2025 09:26:16 +0100 Subject: [PATCH 2/7] MainActivity: preset quantity of bottle, weight and temperature Use the quantity of previous events to initialize new events. --- .../danieleverducci/lunatracker/MainActivity.kt | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/it/danieleverducci/lunatracker/MainActivity.kt b/app/src/main/java/it/danieleverducci/lunatracker/MainActivity.kt index 3201035..eb17ecf 100644 --- a/app/src/main/java/it/danieleverducci/lunatracker/MainActivity.kt +++ b/app/src/main/java/it/danieleverducci/lunatracker/MainActivity.kt @@ -85,7 +85,7 @@ class MainActivity : AppCompatActivity() { showAddLogbookDialog(true) } findViewById(R.id.button_bottle).setOnClickListener { - addBabyBottleEvent() + addBabyBottleEvent(LunaEvent(LunaEvent.TYPE_BABY_BOTTLE)) } findViewById(R.id.button_food).setOnClickListener { addNoteEvent(LunaEvent(LunaEvent.TYPE_FOOD)) @@ -195,8 +195,8 @@ class MainActivity : AppCompatActivity() { return logbook?.logs ?: arrayListOf() } - fun addBabyBottleEvent() { - val event = LunaEvent(LunaEvent.TYPE_BABY_BOTTLE) + fun addBabyBottleEvent(event: LunaEvent) { + setToPreviousQuantity(event) askBabyBottleContent(event, true) { saveEvent(event) } @@ -239,6 +239,7 @@ class MainActivity : AppCompatActivity() { } fun addWeightEvent(event: LunaEvent) { + setToPreviousQuantity(event) askWeightValue(event, true) { saveEvent(event) } } @@ -282,6 +283,7 @@ class MainActivity : AppCompatActivity() { } fun addTemperatureEvent(event: LunaEvent) { + setToPreviousQuantity(event) askTemperatureValue(event, true) { saveEvent(event) } } @@ -522,6 +524,13 @@ class MainActivity : AppCompatActivity() { alertDialog.show() } + fun setToPreviousQuantity(event: LunaEvent) { + val prev = getPreviousSameEvent(event, getAllEvents()) + if (prev != null) { + event.quantity = prev.quantity + } + } + fun getPreviousSameEvent(event: LunaEvent, items: ArrayList): LunaEvent? { var previousEvent: LunaEvent? = null for (item in items) { -- 2.39.5 From 1106c7d42a8f3d5ff361cde28f8a882e8d7614d1 Mon Sep 17 00:00:00 2001 From: Moritz Warning Date: Tue, 4 Nov 2025 15:08:10 +0100 Subject: [PATCH 3/7] notes: add icons to use previous/next event as template --- .../lunatracker/MainActivity.kt | 48 +++++++++++++++++++ app/src/main/res/layout/dialog_edit_notes.xml | 23 +++++++++ 2 files changed, 71 insertions(+) diff --git a/app/src/main/java/it/danieleverducci/lunatracker/MainActivity.kt b/app/src/main/java/it/danieleverducci/lunatracker/MainActivity.kt index eb17ecf..3a4fa6d 100644 --- a/app/src/main/java/it/danieleverducci/lunatracker/MainActivity.kt +++ b/app/src/main/java/it/danieleverducci/lunatracker/MainActivity.kt @@ -465,6 +465,52 @@ class MainActivity : AppCompatActivity() { dateTV.visibility = View.GONE } + val nextTextView = dialogView.findViewById(R.id.notes_template_next) + val prevTextView = dialogView.findViewById(R.id.notes_template_prev) + + fun updateContent(current: LunaEvent) { + val allEvents = getAllEvents() + val prevEvent = getPreviousSameEvent(current, allEvents) + var nextEvent = getNextSameEvent(current, allEvents) + + notesET.setText(current.notes) + if (useQuantity) { + qtyET.setText(current.quantity.toString()) + } + + if (nextEvent == null && current != event) { + nextEvent = event + } + + if (nextEvent != null) { + nextTextView.setOnClickListener { + notesET.setText(nextEvent.notes) + if (useQuantity) { + qtyET.setText(nextEvent.quantity.toString()) + } + updateContent(nextEvent) + } + nextTextView.alpha = 1.0f + } else { + nextTextView.setOnClickListener {} + nextTextView.alpha = 0.5f + } + + if (prevEvent != null) { + prevTextView.setOnClickListener { + notesET.setText(prevEvent.notes) + if (useQuantity) { + qtyET.setText(prevEvent.quantity.toString()) + } + updateContent(prevEvent) + } + prevTextView.alpha = 1.0f + } else { + prevTextView.setOnClickListener {} + prevTextView.alpha = 0.5f + } + } + notesET.setText(event.notes) if (useQuantity) { @@ -473,6 +519,8 @@ class MainActivity : AppCompatActivity() { qtyET.visibility = View.GONE } + updateContent(event) + d.setPositiveButton(android.R.string.ok) { dialogInterface, i -> val notes = notesET.text.toString() diff --git a/app/src/main/res/layout/dialog_edit_notes.xml b/app/src/main/res/layout/dialog_edit_notes.xml index 811eed6..241651f 100644 --- a/app/src/main/res/layout/dialog_edit_notes.xml +++ b/app/src/main/res/layout/dialog_edit_notes.xml @@ -24,6 +24,29 @@ android:hint="@string/log_notes_dialog_note_hint" android:background="@drawable/textview_background"/> + + + + + + + + Date: Fri, 14 Nov 2025 18:07:27 +0100 Subject: [PATCH 4/7] LunaEvent: remove quantity when the value is invalid --- .../java/it/danieleverducci/lunatracker/entities/LunaEvent.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/it/danieleverducci/lunatracker/entities/LunaEvent.kt b/app/src/main/java/it/danieleverducci/lunatracker/entities/LunaEvent.kt index 58160e3..b7cd0f0 100644 --- a/app/src/main/java/it/danieleverducci/lunatracker/entities/LunaEvent.kt +++ b/app/src/main/java/it/danieleverducci/lunatracker/entities/LunaEvent.kt @@ -49,6 +49,8 @@ class LunaEvent: Comparable { set(value) { if (value > 0) jo.put("quantity", value) + else + jo.remove("quantity") } var notes: String get(): String = jo.optString("notes") -- 2.39.5 From 9237d329e858e9175e6f48c374de3e7f9636ad24 Mon Sep 17 00:00:00 2001 From: Moritz Warning Date: Wed, 12 Nov 2025 22:43:09 +0100 Subject: [PATCH 5/7] strings: rename scale to weight in identifiers --- .../it/danieleverducci/lunatracker/entities/LunaEvent.kt | 4 ++-- app/src/main/res/layout/more_events_popup.xml | 2 +- app/src/main/res/values-de/strings.xml | 4 ++-- app/src/main/res/values-fr/strings.xml | 4 ++-- app/src/main/res/values-it/strings.xml | 4 ++-- app/src/main/res/values/strings.xml | 6 +++--- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/it/danieleverducci/lunatracker/entities/LunaEvent.kt b/app/src/main/java/it/danieleverducci/lunatracker/entities/LunaEvent.kt index b7cd0f0..587da29 100644 --- a/app/src/main/java/it/danieleverducci/lunatracker/entities/LunaEvent.kt +++ b/app/src/main/java/it/danieleverducci/lunatracker/entities/LunaEvent.kt @@ -97,7 +97,7 @@ class LunaEvent: Comparable { return context.getString( when (type) { TYPE_BABY_BOTTLE -> R.string.event_bottle_type - TYPE_WEIGHT -> R.string.event_scale_type + TYPE_WEIGHT -> R.string.event_weight_type TYPE_BREASTFEEDING_LEFT_NIPPLE -> R.string.event_breastfeeding_left_type TYPE_BREASTFEEDING_BOTH_NIPPLE -> R.string.event_breastfeeding_both_type TYPE_BREASTFEEDING_RIGHT_NIPPLE -> R.string.event_breastfeeding_right_type @@ -120,7 +120,7 @@ class LunaEvent: Comparable { return context.getString( when (type) { TYPE_BABY_BOTTLE -> R.string.event_bottle_desc - TYPE_WEIGHT -> R.string.event_scale_desc + TYPE_WEIGHT -> R.string.event_weight_desc TYPE_BREASTFEEDING_LEFT_NIPPLE -> R.string.event_breastfeeding_left_desc TYPE_BREASTFEEDING_BOTH_NIPPLE -> R.string.event_breastfeeding_both_desc TYPE_BREASTFEEDING_RIGHT_NIPPLE -> R.string.event_breastfeeding_right_desc diff --git a/app/src/main/res/layout/more_events_popup.xml b/app/src/main/res/layout/more_events_popup.xml index 34ee31b..b1dfbea 100644 --- a/app/src/main/res/layout/more_events_popup.xml +++ b/app/src/main/res/layout/more_events_popup.xml @@ -67,7 +67,7 @@ android:padding="10dp" android:background="@drawable/dropdown_list_item_background" style="@style/OverflowMenuText" - android:text="@string/overflow_event_scale"/> + android:text="@string/overflow_event_weight"/> Fläschchen Essen - Gewicht + Gewicht Stillen (links) Stillen Stillen (rechts) @@ -27,7 +27,7 @@ Blähungskolik - ⚖️ Gewicht + ⚖️ Gewicht 💊 Medikament 🪠 Einlauf 📝 Notiz diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 3d783db..0afd508 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -14,7 +14,7 @@ Biberon Nourriture - Poids + Poids Allaitement (sein gauche) Allaitement Allaitement (sein droit) @@ -27,7 +27,7 @@ Colique gazeuse - ⚖️ Poids + ⚖️ Poids 💊 Médicament 🪠 Lavement 📝 Note diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index e6adaa2..69dc200 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -12,7 +12,7 @@ Temperatura Inserisci la temperatura - ⚖️ Peso + ⚖️ Peso 💊 Medicina 🪠 Clistere 📝 Nota @@ -21,7 +21,7 @@ Biberon Cibo - Pesata + Pesata Allatt. al seno (sx) Allatt. al seno Allatt. al seno (dx) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index afd4eab..6242696 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -17,7 +17,7 @@ 🍼 🥣 - ⚖️ + ⚖️ 🤱 ← 🤱 ↔ 🤱 → @@ -34,7 +34,7 @@ Baby bottle Food - Weight + Weight Breastfeeding (left) Breastfeeding Breastfeeding (right) @@ -49,7 +49,7 @@ Bath - ⚖️ Weight + ⚖️ Weight 💊 Medicine 🪠 Enema 📝 Note -- 2.39.5 From f85094b0ff02609512bbaf46e68bf3b24ed4e085 Mon Sep 17 00:00:00 2001 From: Moritz Warning Date: Wed, 12 Nov 2025 22:47:09 +0100 Subject: [PATCH 6/7] MainActivity: allow amount for poo and pee events An unspecified amount has also been added to have the same semantics as before. During these actions, the strings for title and description of dialogs have been cleaned up. --- .../lunatracker/MainActivity.kt | 41 ++++++++++--------- .../lunatracker/entities/LunaEvent.kt | 16 ++++++-- app/src/main/java/utils/NumericUtils.kt | 12 +++++- ...g_edit_puke.xml => dialog_edit_amount.xml} | 2 +- app/src/main/res/values-de/strings.xml | 16 +++----- app/src/main/res/values-fr/strings.xml | 16 +++----- app/src/main/res/values-it/strings.xml | 16 +++----- app/src/main/res/values/arrays.xml | 1 + app/src/main/res/values/strings.xml | 22 ++++------ 9 files changed, 69 insertions(+), 73 deletions(-) rename app/src/main/res/layout/{dialog_edit_puke.xml => dialog_edit_amount.xml} (93%) diff --git a/app/src/main/java/it/danieleverducci/lunatracker/MainActivity.kt b/app/src/main/java/it/danieleverducci/lunatracker/MainActivity.kt index 3a4fa6d..2f4fea2 100644 --- a/app/src/main/java/it/danieleverducci/lunatracker/MainActivity.kt +++ b/app/src/main/java/it/danieleverducci/lunatracker/MainActivity.kt @@ -100,10 +100,10 @@ class MainActivity : AppCompatActivity() { addPlainEvent(LunaEvent(LunaEvent.TYPE_BREASTFEEDING_RIGHT_NIPPLE)) } findViewById(R.id.button_change_poo).setOnClickListener { - addPlainEvent(LunaEvent(LunaEvent.TYPE_DIAPERCHANGE_POO)) + addAmountEvent(LunaEvent(LunaEvent.TYPE_DIAPERCHANGE_POO)) } findViewById(R.id.button_change_pee).setOnClickListener { - addPlainEvent(LunaEvent(LunaEvent.TYPE_DIAPERCHANGE_PEE)) + addAmountEvent(LunaEvent(LunaEvent.TYPE_DIAPERCHANGE_PEE)) } val moreButton = findViewById(R.id.button_more) moreButton.setOnClickListener { @@ -205,8 +205,8 @@ class MainActivity : AppCompatActivity() { fun askBabyBottleContent(event: LunaEvent, showTime: Boolean, onPositive: () -> Unit) { val d = AlertDialog.Builder(this) val dialogView = layoutInflater.inflate(R.layout.dialog_edit_bottle, null) - d.setTitle(R.string.log_bottle_dialog_title) - d.setMessage(R.string.log_bottle_dialog_description) + d.setTitle(event.getTypeDescription(this)) + d.setMessage(event.getDialogMessage(this)) d.setView(dialogView) val numberPicker = dialogView.findViewById(R.id.dialog_number_picker) @@ -247,8 +247,8 @@ class MainActivity : AppCompatActivity() { // Show number picker dialog val d = AlertDialog.Builder(this) val dialogView = layoutInflater.inflate(R.layout.dialog_edit_weight, null) - d.setTitle(R.string.log_weight_dialog_title) - d.setMessage(R.string.log_weight_dialog_description) + d.setTitle(event.getTypeDescription(this)) + d.setMessage(event.getDialogMessage(this)) d.setView(dialogView) val weightET = dialogView.findViewById(R.id.dialog_number_edittext) @@ -291,8 +291,8 @@ class MainActivity : AppCompatActivity() { // Show number picker dialog val d = AlertDialog.Builder(this) val dialogView = layoutInflater.inflate(R.layout.dialog_edit_temperature, null) - d.setTitle(R.string.log_temperature_dialog_title) - d.setMessage(R.string.log_temperature_dialog_description) + d.setTitle(event.getTypeDescription(this)) + d.setMessage(event.getDialogMessage(this)) d.setView(dialogView) val tempSlider = dialogView.findViewById(R.id.dialog_temperature_value) @@ -371,24 +371,25 @@ class MainActivity : AppCompatActivity() { saveLogbook() } - fun addPukeEvent(event: LunaEvent) { - askPukeValue(event, true) { saveEvent(event) } + fun addAmountEvent(event: LunaEvent) { + askAmountValue(event, true) { saveEvent(event) } } - fun askPukeValue(event: LunaEvent, showTime: Boolean, onPositive: () -> Unit) { + fun askAmountValue(event: LunaEvent, showTime: Boolean, onPositive: () -> Unit) { val d = AlertDialog.Builder(this) - val dialogView = layoutInflater.inflate(R.layout.dialog_edit_puke, null) - d.setTitle(R.string.log_puke_dialog_title) - d.setMessage(R.string.log_puke_dialog_description) + val dialogView = layoutInflater.inflate(R.layout.dialog_edit_amount, null) + d.setTitle(event.getTypeDescription(this)) + d.setMessage(event.getDialogMessage(this)) d.setView(dialogView) - val spinner = dialogView.findViewById(R.id.dialog_puke_value) + val spinner = dialogView.findViewById(R.id.dialog_amount_value) spinner.adapter = ArrayAdapter.createFromResource( this, R.array.AmountLabels, android.R.layout.simple_spinner_dropdown_item ) - spinner.setSelection(event.quantity - 1) + // set pre-selected item and ensure the quantity to index is in bounds + spinner.setSelection(event.quantity.coerceIn(0, spinner.count - 1)) val dateTV = dialogView.findViewById(R.id.dialog_date_picker) val pickedTime = datePickerHelper(event.time, dateTV) @@ -398,7 +399,7 @@ class MainActivity : AppCompatActivity() { d.setPositiveButton(android.R.string.ok) { dialogInterface, i -> event.time = pickedTime.time.time / 1000 - event.quantity = spinner.selectedItemPosition + 1 + event.quantity = spinner.selectedItemPosition onPositive() dialogInterface.dismiss() } @@ -637,7 +638,9 @@ class MainActivity : AppCompatActivity() { when (event.type) { LunaEvent.TYPE_BABY_BOTTLE -> askBabyBottleContent(event, false, updateValues) LunaEvent.TYPE_WEIGHT -> askWeightValue(event, false, updateValues) - LunaEvent.TYPE_PUKE -> askPukeValue(event, false, updateValues) + LunaEvent.TYPE_DIAPERCHANGE_POO, + LunaEvent.TYPE_DIAPERCHANGE_PEE, + LunaEvent.TYPE_PUKE -> askAmountValue(event, false, updateValues) LunaEvent.TYPE_TEMPERATURE -> askTemperatureValue(event, false, updateValues) LunaEvent.TYPE_NOTE -> askNotes(event, false, updateValues) } @@ -1094,7 +1097,7 @@ class MainActivity : AppCompatActivity() { dismiss() } contentView.findViewById(R.id.button_puke).setOnClickListener { - addPukeEvent(LunaEvent(LunaEvent.TYPE_PUKE, 1)) + addAmountEvent(LunaEvent(LunaEvent.TYPE_PUKE)) dismiss() } contentView.findViewById(R.id.button_colic).setOnClickListener { diff --git a/app/src/main/java/it/danieleverducci/lunatracker/entities/LunaEvent.kt b/app/src/main/java/it/danieleverducci/lunatracker/entities/LunaEvent.kt index 587da29..1eade79 100644 --- a/app/src/main/java/it/danieleverducci/lunatracker/entities/LunaEvent.kt +++ b/app/src/main/java/it/danieleverducci/lunatracker/entities/LunaEvent.kt @@ -140,10 +140,18 @@ class LunaEvent: Comparable { } fun getDialogMessage(context: Context): String? { - return when(type) { - TYPE_MEDICINE -> context.getString(R.string.log_medicine_dialog_description) - else -> null - } + return context.getString( + when(type) { + TYPE_BABY_BOTTLE -> R.string.log_bottle_dialog_description + TYPE_MEDICINE -> R.string.log_medicine_dialog_description + TYPE_TEMPERATURE -> R.string.log_temperature_dialog_description + TYPE_DIAPERCHANGE_POO, + TYPE_DIAPERCHANGE_PEE, + TYPE_PUKE -> R.string.log_amount_dialog_description + TYPE_WEIGHT -> R.string.log_weight_dialog_description + else -> R.string.log_unknown_dialog_description + } + ) } fun toJson(): JSONObject { diff --git a/app/src/main/java/utils/NumericUtils.kt b/app/src/main/java/utils/NumericUtils.kt index 23cd5c6..8d12c35 100644 --- a/app/src/main/java/utils/NumericUtils.kt +++ b/app/src/main/java/utils/NumericUtils.kt @@ -4,6 +4,7 @@ import android.content.Context import android.icu.util.LocaleData import android.icu.util.ULocale import android.os.Build +import android.util.Log import it.danieleverducci.lunatracker.R import it.danieleverducci.lunatracker.entities.LunaEvent import java.text.NumberFormat @@ -66,8 +67,15 @@ class NumericUtils (val context: Context) { formatted.append(when (event.type) { LunaEvent.TYPE_TEMPERATURE -> (event.quantity / 10.0f).toString() - LunaEvent.TYPE_PUKE -> - context.resources.getStringArray(R.array.AmountLabels)[event.quantity - 1] + LunaEvent.TYPE_DIAPERCHANGE_POO, + LunaEvent.TYPE_DIAPERCHANGE_PEE, + LunaEvent.TYPE_PUKE -> { + val array = context.resources.getStringArray(R.array.AmountLabels) + return array.getOrElse(event.quantity) { + Log.e("NumericUtils", "Invalid index ${event.quantity}") + return "" + } + } else -> event.quantity }) diff --git a/app/src/main/res/layout/dialog_edit_puke.xml b/app/src/main/res/layout/dialog_edit_amount.xml similarity index 93% rename from app/src/main/res/layout/dialog_edit_puke.xml rename to app/src/main/res/layout/dialog_edit_amount.xml index 2277369..2a4b4b7 100644 --- a/app/src/main/res/layout/dialog_edit_puke.xml +++ b/app/src/main/res/layout/dialog_edit_amount.xml @@ -8,7 +8,7 @@ android:orientation="vertical"> 🌜 LunaTracker 🌛 Ereignisprotokoll - Fläschchen - Trinkmenge eingeben - - Gewicht - Gewicht eingeben - - Temperatur - Temperatur eingeben - Fläschchen Essen Gewicht @@ -77,10 +68,13 @@ Jetzt bereinigen Später erinnern - Notizen: + Trinkmenge eingeben Medikamentenname, Menge, Art, Notizen, …: - Menge (optional) + Notizen: Notiz eingeben + Menge (optional) + Temperatur eingeben + Gewicht eingeben Ereignisdetails OK diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 0afd508..9364887 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -3,15 +3,6 @@ 🌜 LunaTracker 🌛 Entrées enregistrées - Biberon - Renseignez la quantité contenue dans le biberon - - Poids - Renseignez le poids - - Température - Renseignez la Température - Biberon Nourriture Poids @@ -76,10 +67,13 @@ Supprimer les vieilles entrées maintenant Me rappeller plus tard - Notes: + Renseignez la quantité contenue dans le biberon nom du médicament, quantité, type, notes …: - Quantité (ou vide) + Notes: Notes ... + Quantité (ou vide) + Renseignez la Température + Renseignez le poids Détails de l\'entrée OK diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 69dc200..3e1fdd2 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -3,15 +3,6 @@ 🌜 LunaTracker 🌛 Diario di bordo - Biberon - Inserisci la quantità contenuta nel biberon - - Pesata - Inserisci il peso rilevato - - Temperatura - Inserisci la temperatura - ⚖️ Peso 💊 Medicina 🪠 Clistere @@ -76,10 +67,13 @@ Cancella i più vecchi Ricordamelo dopo - Note: + Inserisci la quantità contenuta nel biberon Nome della medicina, quantità, formato, note…: - Quantità, o vuoto + Note: Inserisci le note + Quantità, o vuoto + Inserisci la temperatura + Inserisci il peso rilevato Dettaglio evento OK diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 4f5ae1a..87a93d3 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -1,6 +1,7 @@ + @string/amount_unspecified @string/amount_little @string/amount_normal @string/amount_plenty diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6242696..487a06c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3,18 +3,6 @@ 🌜 LunaTracker 🌛 Logged events - Baby bottle - Insert the quantity contained in the baby bottle - - Weight - Insert the weight - - Temperature - Insert the temperature - - Puke - Select the amount - 🍼 🥣 ⚖️ @@ -75,6 +63,7 @@ year years + Little Normal Plenty @@ -114,10 +103,15 @@ Trim it now Remind me later - Notes: + Select the amount: + Insert the quantity contained in the baby bottle: Medicine name, quantity, type, notes…: - Quantity (or empty) + Notes: Write some notes + Quantity (or empty) + Select the temperature: + + Insert the weight: ml g -- 2.39.5 From fc3b67638d265489121258766218ee980bd5bc54 Mon Sep 17 00:00:00 2001 From: Moritz Warning Date: Fri, 14 Nov 2025 21:42:35 +0100 Subject: [PATCH 7/7] LunaEvent: add sleep event --- .../lunatracker/MainActivity.kt | 100 +++++++++++++++++- .../lunatracker/entities/LunaEvent.kt | 4 + app/src/main/java/utils/DateUtils.kt | 4 +- app/src/main/java/utils/NumericUtils.kt | 7 ++ .../main/res/layout/dialog_edit_duration.xml | 69 ++++++++++++ app/src/main/res/layout/more_events_popup.xml | 10 ++ app/src/main/res/values/strings.xml | 5 + 7 files changed, 195 insertions(+), 4 deletions(-) create mode 100644 app/src/main/res/layout/dialog_edit_duration.xml diff --git a/app/src/main/java/it/danieleverducci/lunatracker/MainActivity.kt b/app/src/main/java/it/danieleverducci/lunatracker/MainActivity.kt index 2f4fea2..947ab4f 100644 --- a/app/src/main/java/it/danieleverducci/lunatracker/MainActivity.kt +++ b/app/src/main/java/it/danieleverducci/lunatracker/MainActivity.kt @@ -12,6 +12,7 @@ import android.view.View import android.view.ViewGroup import android.widget.AdapterView import android.widget.ArrayAdapter +import android.widget.Button import android.widget.EditText import android.widget.NumberPicker import android.widget.PopupWindow @@ -330,7 +331,7 @@ class MainActivity : AppCompatActivity() { alertDialog.show() } - fun datePickerHelper(time: Long, dateTextView: TextView): Calendar { + fun datePickerHelper(time: Long, dateTextView: TextView, onChange: (Long) -> Unit = {}): Calendar { dateTextView.text = DateUtils.formatDateTime(time) val dateTime = Calendar.getInstance() @@ -349,6 +350,7 @@ class MainActivity : AppCompatActivity() { { _, hour, minute -> dateTime.set(year, month, day, hour, minute) dateTextView.text = DateUtils.formatDateTime(dateTime.time.time / 1000) + onChange.invoke(dateTime.time.time / 1000) }, startHour, startMinute, @@ -371,6 +373,97 @@ class MainActivity : AppCompatActivity() { saveLogbook() } + fun addSleepEvent(event: LunaEvent) { + askSleepValue(event) { saveEvent(event) } + } + + fun askSleepValue(event: LunaEvent, onPositive: () -> Unit) { + val d = AlertDialog.Builder(this) + val dialogView = layoutInflater.inflate(R.layout.dialog_edit_duration, null) + d.setTitle(event.getTypeDescription(this)) + d.setMessage(event.getDialogMessage(this)) + d.setView(dialogView) + + val durationTextView = dialogView.findViewById(R.id.dialog_date_duration) + val durationNowButton = dialogView.findViewById