Compare commits

..
Author SHA1 Message Date
mwarning a8305b8fc9 statistics: complete removal 2026-02-12 23:13:58 +01:00
mwarning 43f0519487 LunaEvent: rework sleep event
Remove adjustment buttons and
simplify design.
2026-02-12 23:01:01 +01:00
mwarning 1bcfc18a71 MainActivity: rename datepicker 2026-02-12 23:01:01 +01:00
mwarning e345e98668 layout: replace menu icon with utf8 character
The three dot menu icosn looks odd when stretched
due to the dynamic menu feature. Thus replace it
with the hamburger menu character that looks better
when scaled.
2026-02-12 23:01:01 +01:00
mwarning 09f5a4e27b MainActivity: sort events before saving
Also replace notifyItemInserted since it does not
call the adapter to redraw the row striping when
a new event is added.
2026-02-12 23:01:01 +01:00
mwarning b3b432525e StatisticsActivity: rework all statistics
Improve the overall code.
2026-02-12 23:00:58 +01:00
mwarning d832aa4330 NumericUtils: remove possible trailing whitespace 2026-02-09 08:23:38 +01:00
mwarning 672ae37049 MainActivity: do not switch logbook on reload 2026-02-09 08:23:38 +01:00
mwarning 672e58c028 LunaEvent: reorganize event text getters
Use method names that better reflect
the use of the returned text.
2026-02-09 08:23:38 +01:00
mwarning d2729af30f MainAcitivty: add dynamic header setting
The setting allows to build the menu and
popup list to be populated by the frequency
of events that has been created.
This also makes the 'no breastfeeding'
setting irrelevant.
2026-02-09 08:23:21 +01:00
mwarning 85567cce77 LunaEvent: use enum class for event types
This helps to have compile errors when some
case it not handled while adding a new type.
The enum class can also be interated over
to create a complete drop down list.
2026-01-23 06:46:11 +01:00
mwarning 80a51ea8ef MainActivity: increase bottle volume to 340ml
This is the maximum amount found in sold bottles.
2026-01-23 06:46:11 +01:00
mwarning 28679a4a66 gradle: use uniform implementation directive for sardine-android 2026-01-23 06:46:11 +01:00
mwarning f73d3562a9 gradle: avoid inclusion of apk signing blobs
See https://android.izzysoft.de/articles/named/iod-scan-apkchecks?lang=en#blobs
2026-01-23 06:46:11 +01:00
mwarning 8a2932b1e7 gradle: set compileSDK/targetSdk to 36 2026-01-23 06:46:11 +01:00
mwarning 2af8989777 StatisticsActivity: add statistics for bottle and sleep events 2026-01-23 06:46:11 +01:00
12 changed files with 146 additions and 342 deletions
@@ -86,6 +86,8 @@ class MainActivity : AppCompatActivity() {
recyclerView = findViewById(R.id.list_events)
recyclerView.setLayoutManager(LinearLayoutManager(applicationContext))
populateHeaderMenu()
// Set listeners
findViewById<View>(R.id.logbooks_add_button).setOnClickListener {
showAddLogbookDialog(true)
@@ -136,6 +138,8 @@ class MainActivity : AppCompatActivity() {
allEvents = logbook?.logs ?: arrayListOf()
setListAdapter(allEvents)
populateHeaderMenu()
}
private fun populateHeaderMenu() {
@@ -144,12 +148,10 @@ class MainActivity : AppCompatActivity() {
val eventTypeStats = mutableMapOf<LunaEvent.Type, Int>()
if (dynamicMenu) {
// populate frequency map from all events of the last two weeks
val lastWeekTime = (System.currentTimeMillis() / 1000) - (14 * 24 * 60 * 60)
allEvents.forEach {
if (it.time > lastWeekTime) {
eventTypeStats[it.type] = 1 + (eventTypeStats[it.type] ?: 0)
}
val sampleSize = 100
// populate frequency map from first 100 events
allEvents.take(sampleSize.coerceAtMost(allEvents.size)).forEach {
eventTypeStats[it.type] = 1 + (eventTypeStats[it.type] ?: 0)
}
}
@@ -158,55 +160,60 @@ class MainActivity : AppCompatActivity() {
compareBy({ -1 * (eventTypeStats[it] ?: 0) }, { it.ordinal })
).filter { it != LunaEvent.Type.UNKNOWN }
fun setupMenu(maxButtonCount: Int, sortedEventTypes: List<LunaEvent.Type>): Int {
val row1 = findViewById<View>(R.id.linear_layout_row1)
val row1Button1 = findViewById<TextView>(R.id.button1_row1)
val row1Button2 = findViewById<TextView>(R.id.button2_row1)
val row2 = findViewById<View>(R.id.linear_layout_row2)
val row2Button1 = findViewById<TextView>(R.id.button1_row2)
val row2Button2 = findViewById<TextView>(R.id.button2_row2)
val row2Button3 = findViewById<TextView>(R.id.button3_row2)
val row3 = findViewById<View>(R.id.linear_layout_row3)
val row3Button1 = findViewById<TextView>(R.id.button1_row3)
val row3Button2 = findViewById<TextView>(R.id.button2_row3)
// hide all rows/buttons (except row 3)
for (view in listOf(row1, row1Button1, row1Button2,
row2, row2Button1, row2Button2, row2Button3,
row3, row3Button1, row3Button2)) {
view.visibility = View.GONE
}
row3.visibility = View.VISIBLE
var showCounter = 0
fun show(vararg tvs: TextView) {
for (tv in tvs) {
val type = sortedEventTypes[showCounter]
tv.text = LunaEvent.getHeaderEmoji(applicationContext, type)
tv.setOnClickListener { showCreateDialog(type) }
tv.visibility = View.VISIBLE
// show parent row
(tv.parent as View).visibility = View.VISIBLE
showCounter += 1
}
}
when (maxButtonCount) {
0 -> { } // ignore - show empty row3
1 -> show(row3Button1)
2 -> show(row3Button1, row3Button2)
3 -> show(row1Button1, row3Button1)
4, 5, 6 -> show(row1Button1, row1Button2, row3Button1, row3Button2)
else -> show(row1Button1, row1Button2, row2Button1, row2Button2, row2Button3, row3Button1, row3Button2)
}
return showCounter
}
val usedEventCount = eventTypeStats.count { it.value > 0 }
val maxButtonCount = if (dynamicMenu) { usedEventCount } else { 7 }
val row1 = findViewById<View>(R.id.linear_layout_row1)
val row1Button1 = findViewById<TextView>(R.id.button1_row1)
val row1Button2 = findViewById<TextView>(R.id.button2_row1)
val row2 = findViewById<View>(R.id.linear_layout_row2)
val row2Button1 = findViewById<TextView>(R.id.button1_row2)
val row2Button2 = findViewById<TextView>(R.id.button2_row2)
val row2Button3 = findViewById<TextView>(R.id.button3_row2)
val row3 = findViewById<View>(R.id.linear_layout_row3)
val row3Button1 = findViewById<TextView>(R.id.button1_row3)
val row3Button2 = findViewById<TextView>(R.id.button2_row3)
// hide all rows/buttons (except row 3)
for (view in listOf(row1, row1Button1, row1Button2,
row2, row2Button1, row2Button2, row2Button3,
row3, row3Button1, row3Button2)) {
view.visibility = View.GONE
}
row3.visibility = View.VISIBLE
var showCounter = 0
fun show(vararg tvs: TextView) {
for (tv in tvs) {
val type = eventTypesSorted[showCounter]
tv.text = LunaEvent.getHeaderEmoji(applicationContext, type)
tv.setOnClickListener { showCreateDialog(type) }
tv.visibility = View.VISIBLE
// show parent row
(tv.parent as View).visibility = View.VISIBLE
showCounter += 1
}
}
when (maxButtonCount) {
0 -> { } // ignore - show empty row3
1 -> show(row3Button1)
2 -> show(row3Button1, row3Button2)
3 -> show(row1Button1, row3Button1)
4, 5, 6 -> show(row1Button1, row1Button2, row3Button1, row3Button2)
else -> show(row1Button1, row1Button2, row2Button1, row2Button2, row2Button3, row3Button1, row3Button2)
}
val eventsShown = setupMenu(maxButtonCount, eventTypesSorted)
// store left over events for popup menu
currentPopupItems = eventTypesSorted.subList(showCounter, eventTypesSorted.size)
currentPopupItems = eventTypesSorted.subList(eventsShown, eventTypesSorted.size)
}
override fun onStart() {
@@ -268,9 +275,6 @@ class MainActivity : AppCompatActivity() {
numberPicker.wrapSelectorWheel = false
numberPicker.value = event.quantity / 10
val numberPickerUnit = dialogView.findViewById<TextView>(R.id.dialog_number_picker_unit)
numberPickerUnit.text = NumericUtils(this).measurement_unit_liquid_base
val dateTV = dialogView.findViewById<TextView>(R.id.dialog_date_picker)
val pickedTime = dateTimePicker(event.time, dateTV)
@@ -309,9 +313,6 @@ class MainActivity : AppCompatActivity() {
val weightET = dialogView.findViewById<EditText>(R.id.dialog_number_edittext)
weightET.setText(event.quantity.toString())
val unitTV = dialogView.findViewById<TextView>(R.id.dialog_number_unit)
unitTV.text = NumericUtils(this).measurement_unit_weight_base
val dateTV = dialogView.findViewById<TextView>(R.id.dialog_date_picker)
val pickedTime = dateTimePicker(event.time, dateTV)
@@ -340,53 +341,6 @@ class MainActivity : AppCompatActivity() {
alertDialog.show()
}
fun addHeightEvent(event: LunaEvent) {
setToPreviousQuantity(event)
askHeightValue(event, true) { saveEvent(event) }
}
fun askHeightValue(event: LunaEvent, showTime: Boolean, onPositive: () -> Unit) {
// Show number picker dialog
val d = AlertDialog.Builder(this)
val dialogView = layoutInflater.inflate(R.layout.dialog_edit_height, null)
d.setTitle(event.getDialogTitle(this))
d.setMessage(event.getDialogMessage(this))
d.setView(dialogView)
val heightET = dialogView.findViewById<EditText>(R.id.dialog_number_edittext)
heightET.setText(event.quantity.toString())
val unitTV = dialogView.findViewById<TextView>(R.id.dialog_number_unit)
unitTV.text = NumericUtils(this).measurement_unit_height_base
val dateTV = dialogView.findViewById<TextView>(R.id.dialog_date_picker)
val pickedTime = dateTimePicker(event.time, dateTV)
if (!showTime) {
dateTV.visibility = View.GONE
}
d.setPositiveButton(android.R.string.ok) { dialogInterface, i ->
val height = heightET.text.toString().toIntOrNull()
if (height != null) {
event.time = pickedTime.time.time / 1000
event.quantity = height
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()
}
val alertDialog = d.create()
alertDialog.show()
}
fun addTemperatureEvent(event: LunaEvent) {
setToPreviousQuantity(event)
askTemperatureValue(event, true) { saveEvent(event) }
@@ -467,110 +421,83 @@ class MainActivity : AppCompatActivity() {
return dateTime
}
fun addDurationEvent(event: LunaEvent) {
askDurationEvent(event, true) { saveEvent(event) }
fun addSleepEvent(event: LunaEvent) {
askSleepValue(event, true) { saveEvent(event) }
}
fun askDurationEvent(event: LunaEvent, showTime: Boolean, onPositive: () -> Unit) {
fun askSleepValue(event: LunaEvent, showTime: Boolean, onPositive: () -> Unit) {
val d = AlertDialog.Builder(this)
val dialogView = layoutInflater.inflate(R.layout.dialog_edit_duration, null)
d.setTitle(event.getDialogTitle(this))
d.setView(dialogView)
val durationTV = dialogView.findViewById<TextView>(R.id.dialog_date_duration)
val datePickerBeginTV = dialogView.findViewById<TextView>(R.id.dialog_date_picker_begin)
val datePickerEndTV = dialogView.findViewById<TextView>(R.id.dialog_date_picker_end)
val dateDelimiterTV = dialogView.findViewById<TextView>(R.id.dialog_date_range_delimiter)
val durationButtons = dialogView.findViewById<LinearLayout>(R.id.duration_buttons)
val durationNowButton = dialogView.findViewById<Button>(R.id.dialog_date_duration_now)
val durationClearButton = dialogView.findViewById<Button>(R.id.dialog_date_duration_clear)
val durationTextView = dialogView.findViewById<TextView>(R.id.dialog_date_duration)
val datePickerBegin = dialogView.findViewById<TextView>(R.id.dialog_date_picker_begin)
val datePickerEnd = dialogView.findViewById<TextView>(R.id.dialog_date_picker_end)
val currentDurationTextColor = durationTV.currentTextColor
val currentDurationTextColor = durationTextView.currentTextColor
val invalidDurationTextColor = ContextCompat.getColor(this, R.color.danger)
// in seconds
var durationStart = event.getStartTime()
var durationEnd = event.getEndTime()
fun isValidTime(timeUnix: Long): Boolean {
val now = System.currentTimeMillis() / 1000
return timeUnix in 1..now
}
var sleepStart = event.time
var sleepEnd = event.time + event.quantity
fun isValidTimeSpan(timeBeginUnix: Long, timeEndUnix: Long): Boolean {
return (timeBeginUnix <= timeEndUnix) && (timeEndUnix - timeBeginUnix) < (24 * 60 * 60)
val now = System.currentTimeMillis() / 1000
return (timeBeginUnix > 0)
&& (timeEndUnix > 0)
&& (timeBeginUnix <= timeEndUnix)
&& (timeBeginUnix <= now)
&& (timeEndUnix <= now)
&& (timeEndUnix - timeBeginUnix) < (24 * 60 * 60)
}
fun updateFields() {
datePickerBeginTV.text = DateUtils.formatDateTime(durationStart)
datePickerEndTV.text = DateUtils.formatDateTime(durationEnd)
// prevent printing of seconds
fun adjustToMinute(unixTime: Long): Long {
return unixTime - (unixTime % 60)
}
dateTimePicker(durationStart, datePickerBeginTV) { pickedTime: Long ->
durationStart = pickedTime
if (datePickerEndTV.visibility == View.GONE) {
durationEnd = pickedTime
}
updateFields()
}
dateTimePicker(durationEnd, datePickerEndTV) { pickedTime: Long ->
durationEnd = pickedTime
updateFields()
}
durationTV.setTextColor(currentDurationTextColor)
val duration = durationEnd - durationStart
fun updateDuration() {
durationTextView.setTextColor(currentDurationTextColor)
val duration = sleepEnd - sleepStart
if (duration == 0L) {
// event is ongoing
durationTV.text = "💤"
dateDelimiterTV.visibility = View.GONE
datePickerEndTV.visibility = View.GONE
// baby is sleeping
durationTextView.text = "💤"
} else {
durationTV.text = DateUtils.formatTimeDuration(applicationContext, duration)
if (!isValidTimeSpan(durationStart, durationEnd)) {
durationTV.setTextColor(invalidDurationTextColor)
durationTextView.text = DateUtils.formatTimeDuration(applicationContext, duration)
if (!isValidTimeSpan(sleepStart, sleepEnd)) {
durationTextView.setTextColor(invalidDurationTextColor)
}
dateDelimiterTV.visibility = View.VISIBLE
datePickerEndTV.visibility = View.VISIBLE
}
val colorBegin = if (isValidTime(durationStart)) { currentDurationTextColor } else { invalidDurationTextColor }
datePickerBeginTV.setTextColor(colorBegin)
val colorEnd = if (isValidTime(durationEnd)) { currentDurationTextColor } else { invalidDurationTextColor }
datePickerEndTV.setTextColor(colorEnd)
}
val pickedDateTimeBegin = dateTimePicker(event.time, datePickerBegin) { time: Long ->
sleepStart = adjustToMinute(time)
updateDuration()
}
val pickedDateTimeEnd = dateTimePicker(event.time + event.quantity, datePickerEnd) { time: Long ->
sleepEnd = adjustToMinute(time)
updateDuration()
}
sleepStart = adjustToMinute(pickedDateTimeBegin.time.time / 1000)
sleepEnd = adjustToMinute(pickedDateTimeEnd.time.time / 1000)
updateDuration()
if (showTime) {
dateDelimiterTV.visibility = View.GONE
datePickerEndTV.visibility = View.GONE
durationTV.visibility = View.GONE
durationButtons.visibility = View.GONE
datePickerEnd.visibility = View.GONE
durationTextView.visibility = View.GONE
//d.setMessage("")
} else {
dateDelimiterTV.visibility = View.VISIBLE
datePickerEndTV.visibility = View.VISIBLE
durationTV.visibility = View.VISIBLE
durationButtons.visibility = View.VISIBLE
durationTextView.visibility = View.VISIBLE
d.setMessage(event.getDialogMessage(this))
}
updateFields()
durationClearButton.setOnClickListener {
durationEnd = durationStart
updateFields()
}
durationNowButton.setOnClickListener {
durationEnd = System.currentTimeMillis() / 1000
updateFields()
}
d.setPositiveButton(android.R.string.ok) { dialogInterface, i ->
if (isValidTime(durationStart) && isValidTime(durationEnd) && isValidTimeSpan(durationStart, durationEnd)) {
event.time = durationStart
event.quantity = (durationEnd - durationStart).toInt()
if (isValidTimeSpan(sleepStart, sleepEnd)) {
event.time = sleepStart
event.quantity = (sleepEnd - sleepStart).toInt()
onPositive()
} else {
Toast.makeText(this, R.string.toast_date_error, Toast.LENGTH_SHORT).show()
@@ -691,6 +618,9 @@ class MainActivity : AppCompatActivity() {
var nextEvent = getNextSameEvent(current, templates)
notesET.setText(current.notes)
if (useQuantity) {
qtyET.setText(current.quantity.toString())
}
if (nextEvent == null && current != event) {
nextEvent = event
@@ -699,6 +629,9 @@ class MainActivity : AppCompatActivity() {
if (nextEvent != null) {
nextTextView.setOnClickListener {
notesET.setText(nextEvent.notes)
if (useQuantity) {
qtyET.setText(nextEvent.quantity.toString())
}
updateContent(nextEvent)
}
nextTextView.alpha = 1.0f
@@ -710,6 +643,9 @@ class MainActivity : AppCompatActivity() {
if (prevEvent != null) {
prevTextView.setOnClickListener {
notesET.setText(prevEvent.notes)
if (useQuantity) {
qtyET.setText(prevEvent.quantity.toString())
}
updateContent(prevEvent)
}
prevTextView.alpha = 1.0f
@@ -902,15 +838,12 @@ class MainActivity : AppCompatActivity() {
when (event.type) {
LunaEvent.Type.BABY_BOTTLE -> askBabyBottleContent(event, false, updateValues)
LunaEvent.Type.WEIGHT -> askWeightValue(event, false, updateValues)
LunaEvent.Type.HEIGHT -> askHeightValue(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.FOOD,
LunaEvent.Type.MEDICINE,
LunaEvent.Type.NOTE -> askNotes(event, false, updateValues)
LunaEvent.Type.SLEEP -> askDurationEvent(event, false, updateValues)
LunaEvent.Type.SLEEP -> askSleepValue(event, false, updateValues)
else -> {
Log.w(TAG, "Unexpected type: ${event.type}")
}
@@ -1123,8 +1056,6 @@ class MainActivity : AppCompatActivity() {
logbook = lb
showLogbook()
populateHeaderMenu()
if (DEBUG_CHECK_LOGBOOK_CONSISTENCY) {
for (e in logbook?.logs ?: listOf()) {
val em = e.getHeaderEmoji(this@MainActivity)
@@ -1243,8 +1174,6 @@ class MainActivity : AppCompatActivity() {
Toast.LENGTH_SHORT
).show()
savingEvent(false)
populateHeaderMenu()
})
}
@@ -1328,7 +1257,6 @@ class MainActivity : AppCompatActivity() {
when (type) {
LunaEvent.Type.BABY_BOTTLE -> addBabyBottleEvent(event)
LunaEvent.Type.WEIGHT -> addWeightEvent(event)
LunaEvent.Type.HEIGHT -> addHeightEvent(event)
LunaEvent.Type.BREASTFEEDING_LEFT_NIPPLE -> addPlainEvent(event)
LunaEvent.Type.BREASTFEEDING_BOTH_NIPPLE -> addPlainEvent(event)
LunaEvent.Type.BREASTFEEDING_RIGHT_NIPPLE -> addPlainEvent(event)
@@ -1342,7 +1270,7 @@ class MainActivity : AppCompatActivity() {
LunaEvent.Type.FOOD -> addNoteEvent(event)
LunaEvent.Type.PUKE -> addAmountEvent(event)
LunaEvent.Type.BATH -> addPlainEvent(event)
LunaEvent.Type.SLEEP -> addDurationEvent(event)
LunaEvent.Type.SLEEP -> addSleepEvent(event)
LunaEvent.Type.UNKNOWN -> {} // ignore
}
}
@@ -63,7 +63,7 @@ class LunaEventRecyclerAdapter: RecyclerView.Adapter<LunaEventRecyclerAdapter.Lu
// if the event is weight, show difference with the last one
if (item.type == LunaEvent.Type.WEIGHT) {
val lastWeight = getPreviousEvent(position, LunaEvent.Type.WEIGHT)
val lastWeight = getPreviousWeightEvent(position)
if (lastWeight != null) {
val differenceInWeight = item.quantity - lastWeight.quantity
val sign = if (differenceInWeight > 0) "+" else ""
@@ -74,19 +74,6 @@ class LunaEventRecyclerAdapter: RecyclerView.Adapter<LunaEventRecyclerAdapter.Lu
}
}
// if the event is height, show difference with the last one
if (item.type == LunaEvent.Type.HEIGHT) {
val lastHeight = getPreviousEvent(position, LunaEvent.Type.HEIGHT)
if (lastHeight != null) {
val differenceInHeight = item.quantity - lastHeight.quantity
val sign = if (differenceInHeight > 0) "+" else ""
quantityText += "\n($sign$differenceInHeight)"
if (differenceInHeight < 0) {
holder.quantity.setTextColor(ContextCompat.getColor(context, R.color.danger))
}
}
}
holder.quantity.text = quantityText
// Listeners
@@ -101,12 +88,12 @@ class LunaEventRecyclerAdapter: RecyclerView.Adapter<LunaEventRecyclerAdapter.Lu
return items.size
}
private fun getPreviousEvent(startFromPosition: Int, type: LunaEvent.Type): LunaEvent? {
private fun getPreviousWeightEvent(startFromPosition: Int): LunaEvent? {
if (startFromPosition == items.size - 1)
return null
for (pos in startFromPosition + 1 until items.size) {
val item = items.get(pos)
if (item.type != type)
if (item.type != LunaEvent.Type.WEIGHT)
continue
return item
}
@@ -22,7 +22,6 @@ class LunaEvent: Comparable<LunaEvent> {
DIAPERCHANGE_PEE,
SLEEP,
WEIGHT,
HEIGHT,
MEDICINE,
ENEMA,
NOTE,
@@ -146,7 +145,6 @@ class LunaEvent: Comparable<LunaEvent> {
when (type) {
Type.BABY_BOTTLE -> R.string.event_bottle_type
Type.WEIGHT -> R.string.event_weight_type
Type.HEIGHT -> R.string.event_height_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
@@ -176,8 +174,7 @@ class LunaEvent: Comparable<LunaEvent> {
Type.DIAPERCHANGE_PEE,
Type.PUKE -> R.string.log_amount_dialog_description
Type.WEIGHT -> R.string.log_weight_dialog_description
Type.HEIGHT -> R.string.log_height_dialog_description
Type.SLEEP -> R.string.log_duration_dialog_description
Type.SLEEP -> R.string.log_sleep_dialog_description
else -> R.string.log_unknown_dialog_description
}
)
@@ -188,7 +185,6 @@ class LunaEvent: Comparable<LunaEvent> {
when (type) {
Type.BABY_BOTTLE -> R.string.event_bottle_desc
Type.WEIGHT -> R.string.event_weight_desc
Type.HEIGHT -> R.string.event_height_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
@@ -214,7 +210,6 @@ class LunaEvent: Comparable<LunaEvent> {
when (type) {
Type.BABY_BOTTLE -> R.string.event_type_item_bottle
Type.WEIGHT -> R.string.event_type_item_weight
Type.HEIGHT -> R.string.event_type_item_height
Type.BREASTFEEDING_LEFT_NIPPLE -> R.string.event_type_item_breastfeeding_left
Type.BREASTFEEDING_BOTH_NIPPLE -> R.string.event_type_item_breastfeeding_both
Type.BREASTFEEDING_RIGHT_NIPPLE -> R.string.event_type_item_breastfeeding_right
+1 -6
View File
@@ -9,15 +9,10 @@ import java.util.Date
class DateUtils {
companion object {
/**
* Format time duration in seconds as e.g. "2 hours, 1 min", rounded to minutes.
* Format time duration in seconds as e.g. "2 hours, 1 min".
* Used for the duration to the next/previous event in the event details dialog.
*/
fun formatTimeDuration(context: Context, secondsDiff: Long): String {
val adjusted = (secondsDiff + 30) - (secondsDiff + 30) % 60
return formatTimeDurationExact(context, adjusted)
}
fun formatTimeDurationExact(context: Context, secondsDiff: Long): String {
var seconds = secondsDiff
val years = (seconds / (365 * 24 * 60 * 60F)).toLong()
+2 -8
View File
@@ -11,10 +11,10 @@ import utils.DateUtils.Companion.formatTimeDuration
import java.text.NumberFormat
class NumericUtils (val context: Context) {
val numberFormat: NumberFormat
val measurement_unit_liquid_base: String
val measurement_unit_weight_base: String
val measurement_unit_weight_tiny: String
val measurement_unit_height_base: String
val measurement_unit_temperature_base: String
private fun isMetricSystem(): Boolean {
@@ -35,6 +35,7 @@ class NumericUtils (val context: Context) {
}
init {
this.numberFormat = NumberFormat.getInstance()
this.measurement_unit_liquid_base = context.getString(
if (isMetricSystem())
R.string.measurement_unit_liquid_base_metric
@@ -53,12 +54,6 @@ class NumericUtils (val context: Context) {
else
R.string.measurement_unit_weight_tiny_imperial
)
this.measurement_unit_height_base = context.getString(
if (isMetricSystem())
R.string.measurement_unit_height_base_metric
else
R.string.measurement_unit_height_base_imperial
)
this.measurement_unit_temperature_base = context.getString(
if (isMetricSystem())
R.string.measurement_unit_temperature_base_metric
@@ -95,7 +90,6 @@ class NumericUtils (val context: Context) {
when (type) {
LunaEvent.Type.BABY_BOTTLE -> measurement_unit_liquid_base
LunaEvent.Type.WEIGHT -> measurement_unit_weight_base
LunaEvent.Type.HEIGHT -> measurement_unit_height_base
LunaEvent.Type.MEDICINE -> measurement_unit_weight_tiny
LunaEvent.Type.TEMPERATURE -> measurement_unit_temperature_base
else -> ""
@@ -259,7 +259,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginHorizontal="10dp"
android:gravity="center_horizontal"
android:text="@string/no_connection_explain"/>
@@ -18,7 +18,6 @@
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/dialog_number_picker_unit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
@@ -7,69 +7,26 @@
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/dialog_date_picker_begin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="10dp"/>
<TextView
android:id="@+id/dialog_date_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginTop="20dp"
android:textSize="20sp"
android:text="💤"/>
<LinearLayout
android:id="@+id/duration_buttons"
<TextView
android:id="@+id/dialog_date_picker_end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:gravity="center"
android:layout_marginTop="20dp"
android:layout_marginHorizontal="10dp"
android:orientation="horizontal">
<Button
android:id="@+id/dialog_date_duration_now"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/dialog_duration_button_now"/>
<Button
android:id="@+id/dialog_date_duration_clear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/dialog_duration_button_clear"/>
</LinearLayout>
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:gravity="center"
android:layout_marginTop="20dp"
android:layout_marginHorizontal="10dp"
android:orientation="horizontal">
<TextView
android:id="@+id/dialog_date_picker_begin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_weight="1"/>
<TextView
android:id="@+id/dialog_date_range_delimiter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_weight="1"
android:text=""/>
<TextView
android:id="@+id/dialog_date_picker_end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_weight="1"/>
</LinearLayout>
android:layout_gravity="center"
android:layout_marginTop="20dp"/>
</LinearLayout>
@@ -1,39 +0,0 @@
<?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:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:gravity="center"
android:orientation="horizontal">
<EditText
android:id="@+id/dialog_number_edittext"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:inputType="number"
android:hint="0"
android:background="@drawable/textview_background"/>
<TextView
android:id="@+id/dialog_number_unit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:text="cm"/>
</LinearLayout>
<TextView
android:id="@+id/dialog_date_picker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="20dp"/>
</LinearLayout>
@@ -21,7 +21,6 @@
android:background="@drawable/textview_background"/>
<TextView
android:id="@+id/dialog_number_unit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:gravity="center"
android:padding="5dip" />
+1 -19
View File
@@ -7,7 +7,6 @@
<string name="event_bottle_type" translatable="false">🍼</string>
<string name="event_food_type" translatable="false">🥣</string>
<string name="event_weight_type" translatable="false">⚖️</string>
<string name="event_height_type" translatable="false">📏</string>
<string name="event_breastfeeding_left_type" translatable="false">🤱⬅️</string>
<string name="event_breastfeeding_both_type" translatable="false">🤱↔️</string>
<string name="event_breastfeeding_right_type" translatable="false">🤱➡️</string>
@@ -27,7 +26,6 @@
<string name="event_type_item_bottle">🍼 Bottle</string>
<string name="event_type_item_food">🥣 Food</string>
<string name="event_type_item_weight">⚖️ Weight</string>
<string name="event_type_item_height">📏 Height</string>
<string name="event_type_item_breastfeeding_left">🤱⬅️ Nursing</string>
<string name="event_type_item_breastfeeding_both">🤱↔️ Nursing</string>
<string name="event_type_item_breastfeeding_right">🤱➡️ Nursing</string>
@@ -47,7 +45,6 @@
<string name="event_bottle_desc">Milk Bottle</string>
<string name="event_food_desc">Food</string>
<string name="event_weight_desc">Weight</string>
<string name="event_height_desc">Height</string>
<string name="event_breastfeeding_left_desc">Nursing (left)</string>
<string name="event_breastfeeding_both_desc">Nursing (both)</string>
<string name="event_breastfeeding_right_desc">Nursing (right)</string>
@@ -130,27 +127,17 @@
<string name="log_temperature_dialog_description">Select the temperature:</string>
<string name="log_unknown_dialog_description"></string>
<string name="log_weight_dialog_description">Insert the weight:</string>
<string name="log_height_dialog_description">Insert the height:</string>
<string name="log_duration_dialog_description">Set duration:</string>
<string name="log_sleep_dialog_description">Set sleep duration:</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_tiny_metric" translatable="false">mg</string>
<string name="measurement_unit_height_base_metric" translatable="false">cm</string>
<string name="measurement_unit_liquid_base_imperial" translatable="false">fl oz.</string>
<string name="measurement_unit_weight_base_imperial" translatable="false">oz</string>
<string name="measurement_unit_weight_tiny_imperial" translatable="false">gr</string>
<string name="measurement_unit_height_base_imperial" translatable="false">in</string>
<string name="measurement_unit_temperature_base_imperial" translatable="false">°F</string>
<string name="measurement_unit_temperature_base_metric" translatable="false">°C</string>
<string name="statistics_bottle_events">Bottle Events</string>
<string name="statistics_bottle_sum">Bottle Per Day</string>
<string name="statistics_medicine_events">Medicine Events</string>
<string name="statistics_sleep_sum">Sleep Per Day</string>
<string name="statistics_sleep_events">Sleep Events</string>
<string name="statistics_sleep_pattern">Sleep Pattern</string>
<string name="row_luna_event_description">Description</string>
<string name="row_luna_event_quantity">Qty</string>
<string name="row_luna_event_time">Time</string>
@@ -163,11 +150,6 @@
<string name="dialog_event_detail_notes">Notes</string>
<string name="dialog_event_detail_signature">by %s</string>
<string name="dialog_duration_button_clear">Clear</string>
<string name="dialog_duration_button_minus_5">-5 min</string>
<string name="dialog_duration_button_now">Now</string>
<string name="dialog_duration_button_plus_5">+5 min</string>
<string name="dialog_add_logbook_title">Add logbook</string>
<string name="dialog_add_logbook_logbookname">👶 Logbook name</string>
<string name="dialog_add_logbook_message">Write a name to identify this logbook. This name will appear on top of the screen and, if you use WebDAV, will be in the save file name as well.</string>