8 Commits

Author SHA1 Message Date
4a443e19d3 activity_setting: fine tune layout style 2025-09-29 13:44:12 +02:00
cbc2c121f0 add signature setting
For multiple users it helps to
keep track about who did what.
2025-09-29 13:44:07 +02:00
b497d1db3f DateUtils: move event details formatting to DateUtils
Also display second as 0 since it is easier
to read and does not have meaning for the user.
2025-09-29 09:33:10 +02:00
e7070b23c6 add bath event type 2025-09-29 09:33:10 +02:00
19bf58f400 add no-breastfeeding help text 2025-09-29 09:33:10 +02:00
01f24694b5 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-09-29 09:33:10 +02:00
693405cadb simplify puke event 2025-09-29 09:33:07 +02:00
730ef95220 add complex puke event 2025-09-29 04:56:14 +02:00
29 changed files with 293 additions and 1434 deletions

View File

@@ -12,8 +12,8 @@ android {
applicationId = "it.danieleverducci.lunatracker" applicationId = "it.danieleverducci.lunatracker"
minSdk = 21 minSdk = 21
targetSdk = 34 targetSdk = 34
versionCode = 7 versionCode = 5
versionName = "0.9" versionName = "0.7"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }
@@ -60,5 +60,4 @@ dependencies {
androidTestImplementation(libs.androidx.ui.test.junit4) androidTestImplementation(libs.androidx.ui.test.junit4)
debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest) debugImplementation(libs.androidx.ui.test.manifest)
implementation(libs.mpandroidchart.vv310) }
}

View File

@@ -30,10 +30,6 @@
android:name=".SettingsActivity" android:name=".SettingsActivity"
android:label="@string/settings_title" android:label="@string/settings_title"
android:theme="@style/Theme.LunaTracker"/> android:theme="@style/Theme.LunaTracker"/>
<activity
android:name=".StatisticsActivity"
android:label="@string/statistics_title"
android:theme="@style/Theme.LunaTracker"/>
</application> </application>
</manifest> </manifest>

View File

@@ -6,15 +6,14 @@ import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.text.Editable
import android.util.Log import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.AdapterView import android.widget.AdapterView
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
import android.widget.Button
import android.widget.EditText import android.widget.EditText
import android.widget.LinearLayout
import android.widget.NumberPicker import android.widget.NumberPicker
import android.widget.PopupWindow import android.widget.PopupWindow
import android.widget.Spinner import android.widget.Spinner
@@ -51,8 +50,6 @@ class MainActivity : AppCompatActivity() {
const val TAG = "MainActivity" const val TAG = "MainActivity"
const val UPDATE_EVERY_SECS: Long = 30 const val UPDATE_EVERY_SECS: Long = 30
const val DEBUG_CHECK_LOGBOOK_CONSISTENCY = false const val DEBUG_CHECK_LOGBOOK_CONSISTENCY = false
// list of all events
var allEvents = arrayListOf<LunaEvent>()
} }
var logbook: Logbook? = null var logbook: Logbook? = null
@@ -66,7 +63,7 @@ class MainActivity : AppCompatActivity() {
val updateListRunnable: Runnable = Runnable { val updateListRunnable: Runnable = Runnable {
if (logbook != null && !pauseLogbookUpdate) if (logbook != null && !pauseLogbookUpdate)
loadLogbook(logbook!!.name) loadLogbook(logbook!!.name)
handler.postDelayed(updateListRunnable, 1000 * 60) handler.postDelayed(updateListRunnable, 1000*60)
} }
var logbookRepo: LogbookRepository? = null var logbookRepo: LogbookRepository? = null
var showingOverflowPopupWindow = false var showingOverflowPopupWindow = false
@@ -85,30 +82,34 @@ class MainActivity : AppCompatActivity() {
recyclerView.setLayoutManager(LinearLayoutManager(applicationContext)) recyclerView.setLayoutManager(LinearLayoutManager(applicationContext))
// Set listeners // Set listeners
findViewById<View>(R.id.logbooks_add_button).setOnClickListener { findViewById<View>(R.id.logbooks_add_button).setOnClickListener { showAddLogbookDialog(true) }
showAddLogbookDialog(true) findViewById<View>(R.id.button_bottle).setOnClickListener { askBabyBottleContent() }
} findViewById<View>(R.id.button_food).setOnClickListener { askNotes(LunaEvent(LunaEvent.TYPE_FOOD)) }
findViewById<View>(R.id.button_bottle).setOnClickListener { findViewById<View>(R.id.button_nipple_left).setOnClickListener { logEvent(
addBabyBottleEvent(LunaEvent(LunaEvent.TYPE_BABY_BOTTLE)) LunaEvent(
} LunaEvent.TYPE_BREASTFEEDING_LEFT_NIPPLE
findViewById<View>(R.id.button_food).setOnClickListener { )
addNoteEvent(LunaEvent(LunaEvent.TYPE_FOOD)) ) }
} findViewById<View>(R.id.button_nipple_both).setOnClickListener { logEvent(
findViewById<View>(R.id.button_nipple_left).setOnClickListener { LunaEvent(
addPlainEvent(LunaEvent(LunaEvent.TYPE_BREASTFEEDING_LEFT_NIPPLE)) LunaEvent.TYPE_BREASTFEEDING_BOTH_NIPPLE
} )
findViewById<View>(R.id.button_nipple_both).setOnClickListener { ) }
addPlainEvent(LunaEvent(LunaEvent.TYPE_BREASTFEEDING_BOTH_NIPPLE)) findViewById<View>(R.id.button_nipple_right).setOnClickListener { logEvent(
} LunaEvent(
findViewById<View>(R.id.button_nipple_right).setOnClickListener { LunaEvent.TYPE_BREASTFEEDING_RIGHT_NIPPLE
addPlainEvent(LunaEvent(LunaEvent.TYPE_BREASTFEEDING_RIGHT_NIPPLE)) )
} ) }
findViewById<View>(R.id.button_change_poo).setOnClickListener { findViewById<View>(R.id.button_change_poo).setOnClickListener { logEvent(
addAmountEvent(LunaEvent(LunaEvent.TYPE_DIAPERCHANGE_POO)) LunaEvent(
} LunaEvent.TYPE_DIAPERCHANGE_POO
findViewById<View>(R.id.button_change_pee).setOnClickListener { )
addAmountEvent(LunaEvent(LunaEvent.TYPE_DIAPERCHANGE_PEE)) ) }
} findViewById<View>(R.id.button_change_pee).setOnClickListener { logEvent(
LunaEvent(
LunaEvent.TYPE_DIAPERCHANGE_PEE
)
) }
val moreButton = findViewById<View>(R.id.button_more) val moreButton = findViewById<View>(R.id.button_more)
moreButton.setOnClickListener { moreButton.setOnClickListener {
showOverflowPopupWindow(moreButton) showOverflowPopupWindow(moreButton)
@@ -130,9 +131,9 @@ class MainActivity : AppCompatActivity() {
private fun setListAdapter(items: ArrayList<LunaEvent>) { private fun setListAdapter(items: ArrayList<LunaEvent>) {
val adapter = LunaEventRecyclerAdapter(this, items) val adapter = LunaEventRecyclerAdapter(this, items)
adapter.onItemClickListener = object : LunaEventRecyclerAdapter.OnItemClickListener { adapter.onItemClickListener = object: LunaEventRecyclerAdapter.OnItemClickListener {
override fun onItemClick(event: LunaEvent) { override fun onItemClick(event: LunaEvent) {
showEventDetailDialog(event) showEventDetailDialog(event, items)
} }
} }
recyclerView.adapter = adapter recyclerView.adapter = adapter
@@ -148,8 +149,7 @@ class MainActivity : AppCompatActivity() {
if (logbook == null) if (logbook == null)
Log.w(TAG, "showLogbook(): logbook is null!") Log.w(TAG, "showLogbook(): logbook is null!")
allEvents = logbook?.logs ?: arrayListOf() setListAdapter(logbook?.logs ?: arrayListOf())
setListAdapter(allEvents)
} }
override fun onStart() { override fun onStart() {
@@ -196,448 +196,98 @@ class MainActivity : AppCompatActivity() {
super.onStop() super.onStop()
} }
fun addBabyBottleEvent(event: LunaEvent) { fun askBabyBottleContent() {
setToPreviousQuantity(event) // Show number picker dialog
askBabyBottleContent(event, true) { val localSettings = LocalSettingsRepository(this)
saveEvent(event)
}
}
fun askBabyBottleContent(event: LunaEvent, showTime: Boolean, onPositive: () -> Unit) {
val d = AlertDialog.Builder(this) val d = AlertDialog.Builder(this)
val dialogView = layoutInflater.inflate(R.layout.dialog_edit_bottle, null) val dialogView = layoutInflater.inflate(R.layout.number_picker_dialog, null)
d.setTitle(event.getTypeDescription(this)) d.setTitle(R.string.log_bottle_dialog_title)
d.setMessage(event.getDialogMessage(this)) d.setMessage(R.string.log_bottle_dialog_description)
d.setView(dialogView) d.setView(dialogView)
val numberPicker = dialogView.findViewById<NumberPicker>(R.id.dialog_number_picker) val numberPicker = dialogView.findViewById<NumberPicker>(R.id.dialog_number_picker)
numberPicker.minValue = 1 // "10" numberPicker.minValue = 1 // "10"
numberPicker.maxValue = 25 // "250 numberPicker.maxValue = 25 // "250
numberPicker.displayedValues = ((10..250 step 10).map { it.toString() }.toTypedArray()) numberPicker.displayedValues = ((10..250 step 10).map { it.toString() }.toTypedArray())
numberPicker.wrapSelectorWheel = false numberPicker.wrapSelectorWheel = false
numberPicker.value = event.quantity / 10 numberPicker.value = localSettings.loadBabyBottleContent()
val dateTV = dialogView.findViewById<TextView>(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 -> d.setPositiveButton(android.R.string.ok) { dialogInterface, i ->
event.time = pickedTime.time.time / 1000 logEvent(LunaEvent(LunaEvent.TYPE_BABY_BOTTLE, numberPicker.value * 10))
event.quantity = numberPicker.value * 10 localSettings.saveBabyBottleContent(numberPicker.value)
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() val alertDialog = d.create()
alertDialog.show() alertDialog.show()
} }
fun addWeightEvent(event: LunaEvent) { fun askWeightValue() {
setToPreviousQuantity(event)
askWeightValue(event, true) { saveEvent(event) }
}
fun askWeightValue(event: LunaEvent, showTime: Boolean, onPositive: () -> Unit) {
// Show number picker dialog // Show number picker dialog
val d = AlertDialog.Builder(this) val d = AlertDialog.Builder(this)
val dialogView = layoutInflater.inflate(R.layout.dialog_edit_weight, null) val dialogView = layoutInflater.inflate(R.layout.number_edit_dialog, null)
d.setTitle(event.getTypeDescription(this)) d.setTitle(R.string.log_weight_dialog_title)
d.setMessage(event.getDialogMessage(this)) d.setMessage(R.string.log_weight_dialog_description)
d.setView(dialogView) d.setView(dialogView)
val weightET = dialogView.findViewById<EditText>(R.id.dialog_number_edittext) val weightET = dialogView.findViewById<EditText>(R.id.dialog_number_edittext)
weightET.setText(event.quantity.toString())
val dateTV = dialogView.findViewById<TextView>(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 -> d.setPositiveButton(android.R.string.ok) { dialogInterface, i ->
val weight = weightET.text.toString().toIntOrNull() val weight = weightET.text.toString().toIntOrNull()
if (weight != null) { if (weight != null)
event.time = pickedTime.time.time / 1000 logEvent(LunaEvent(LunaEvent.TYPE_WEIGHT, weight))
event.quantity = weight else
onPositive()
} else {
Toast.makeText(this, R.string.toast_integer_error, Toast.LENGTH_SHORT).show() 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() val alertDialog = d.create()
alertDialog.show() alertDialog.show()
} }
fun addTemperatureEvent(event: LunaEvent) { fun askTemperatureValue() {
setToPreviousQuantity(event)
askTemperatureValue(event, true) { saveEvent(event) }
}
fun askTemperatureValue(event: LunaEvent, showTime: Boolean, onPositive: () -> Unit) {
// Show number picker dialog // Show number picker dialog
val d = AlertDialog.Builder(this) val d = AlertDialog.Builder(this)
val dialogView = layoutInflater.inflate(R.layout.dialog_edit_temperature, null) val dialogView = layoutInflater.inflate(R.layout.temperature_dialog, null)
d.setTitle(event.getTypeDescription(this)) d.setTitle(R.string.log_temperature_dialog_title)
d.setMessage(event.getDialogMessage(this)) d.setMessage(R.string.log_temperature_dialog_description)
d.setView(dialogView) d.setView(dialogView)
val tempSlider = dialogView.findViewById<Slider>(R.id.dialog_temperature_value) val tempSlider = dialogView.findViewById<Slider>(R.id.dialog_temperature_value)
val range = NumericUtils(this).getValidEventQuantityRange(LunaEvent.TYPE_TEMPERATURE)!! val range = NumericUtils(this).getValidEventQuantityRange(LunaEvent.TYPE_TEMPERATURE)!!
tempSlider.valueFrom = range.first.toFloat() tempSlider.valueFrom = range.first.toFloat()
tempSlider.valueTo = range.second.toFloat() tempSlider.valueTo = range.second.toFloat()
tempSlider.value = if (event.quantity == 0) { tempSlider.value = range.third.toFloat()
range.third.toFloat() // default
} else {
event.quantity.toFloat() / 10
}
val dateTV = dialogView.findViewById<TextView>(R.id.dialog_date_picker)
val pickedTime = datePickerHelper(event.time, dateTV)
if (!showTime) {
dateTV.visibility = View.GONE
}
val tempTextView = dialogView.findViewById<TextView>(R.id.dialog_temperature_display) val tempTextView = dialogView.findViewById<TextView>(R.id.dialog_temperature_display)
tempTextView.text = tempSlider.value.toString() tempTextView.text = range.third.toString()
tempSlider.addOnChangeListener({ s, v, b -> tempTextView.text = v.toString() }) tempSlider.addOnChangeListener({s, v, b -> tempTextView.text = v.toString()})
d.setPositiveButton(android.R.string.ok) { dialogInterface, i -> d.setPositiveButton(android.R.string.ok) { dialogInterface, i ->
event.time = pickedTime.time.time / 1000 val temperature = (tempSlider.value * 10).toInt() // In tenth of a grade
event.quantity = (tempSlider.value * 10).toInt() // temperature in tenth of a grade logEvent(LunaEvent(LunaEvent.TYPE_TEMPERATURE, temperature))
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() val alertDialog = d.create()
alertDialog.show() alertDialog.show()
} }
fun datePickerHelper(time: Long, dateTextView: TextView, onChange: (Long) -> Unit = {}): Calendar { fun askNotes(lunaEvent: LunaEvent) {
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)
onChange.invoke(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 (!allEvents.contains(event)) {
// new event
logEvent(event)
}
logbook?.sort()
recyclerView.adapter?.notifyDataSetChanged()
saveLogbook()
}
fun addSleepEvent(event: LunaEvent) {
askSleepValue(event) { saveEvent(event) }
}
fun askSleepValue(event: LunaEvent, onPositive: () -> Unit) {
val d = AlertDialog.Builder(this) val d = AlertDialog.Builder(this)
val dialogView = layoutInflater.inflate(R.layout.dialog_edit_duration, null) val dialogView = layoutInflater.inflate(R.layout.dialog_notes, null)
d.setTitle(event.getTypeDescription(this)) d.setTitle(lunaEvent.getTypeDescription(this))
d.setMessage(event.getDialogMessage(this)) d.setMessage(lunaEvent.getDialogMessage(this))
d.setView(dialogView)
val durationTextView = dialogView.findViewById<TextView>(R.id.dialog_date_duration)
val durationNowButton = dialogView.findViewById<Button>(R.id.dialog_date_duration_now)
val datePicker = dialogView.findViewById<TextView>(R.id.dialog_date_picker)
val durationMinus5Button = dialogView.findViewById<Button>(R.id.dialog_date_duration_minus5)
val durationPlus5Button = dialogView.findViewById<Button>(R.id.dialog_date_duration_plus5)
val currentDurationTextColor = durationTextView.currentTextColor
val invalidDurationTextColor = ContextCompat.getColor(this, R.color.danger)
var duration = event.quantity
fun isValidTime(timeSeconds: Long, durationSeconds: Int): Boolean {
val now = Calendar.getInstance().time.time / 1000
return (timeSeconds + durationSeconds) <= now && durationSeconds < (12 * 60 * 60)
}
val onDateChange = { time: Long ->
durationTextView.setTextColor(currentDurationTextColor)
if (duration == 0) {
// baby is sleeping
durationTextView.text = "💤"
} else {
durationTextView.text = DateUtils.formatTimeDuration(applicationContext, duration.toLong())
if (!isValidTime(time, duration)) {
durationTextView.setTextColor(invalidDurationTextColor)
}
}
}
val pickedDateTime = datePickerHelper(event.time, datePicker, onDateChange)
onDateChange(pickedDateTime.time.time / 1000)
fun adjust(minutes: Int) {
duration += minutes * 60
if (duration < 0) {
duration = 0
}
onDateChange(pickedDateTime.time.time / 1000)
}
durationMinus5Button.setOnClickListener { adjust(-5) }
durationPlus5Button.setOnClickListener { adjust(5) }
durationNowButton.setOnClickListener {
val now = Calendar.getInstance().time.time / 1000
val start = pickedDateTime.time.time / 1000
if (now > start) {
duration = (now - start).toInt()
duration -= duration % 60 // prevent printing of seconds
onDateChange(pickedDateTime.time.time / 1000)
}
}
d.setPositiveButton(android.R.string.ok) { dialogInterface, i ->
val time = pickedDateTime.time.time / 1000
if (isValidTime(time, duration)) {
event.time = time
event.quantity = duration
onPositive()
} else {
Toast.makeText(this, R.string.toast_date_error, Toast.LENGTH_SHORT).show()
}
dialogInterface.dismiss()
}
d.setNegativeButton(android.R.string.cancel) { dialogInterface, i ->
dialogInterface.dismiss()
}
val alertDialog = d.create()
alertDialog.show()
}
fun addAmountEvent(event: LunaEvent) {
askAmountValue(event, true) { saveEvent(event) }
}
fun askAmountValue(event: LunaEvent, showTime: Boolean, onPositive: () -> Unit) {
val d = AlertDialog.Builder(this)
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<Spinner>(R.id.dialog_amount_value)
spinner.adapter = ArrayAdapter.createFromResource(
this,
R.array.AmountLabels,
android.R.layout.simple_spinner_dropdown_item
)
// 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<TextView>(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 ->
event.time = pickedTime.time.time / 1000
event.quantity = spinner.selectedItemPosition
onPositive()
dialogInterface.dismiss()
}
d.setNegativeButton(android.R.string.cancel) { dialogInterface, i ->
dialogInterface.dismiss()
}
val alertDialog = d.create()
alertDialog.show()
}
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_edit_plain, null)
d.setTitle(event.getTypeDescription(this))
d.setMessage(event.getDialogMessage(this))
d.setView(dialogView)
val dateTV = dialogView.findViewById<TextView>(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) d.setView(dialogView)
val notesET = dialogView.findViewById<EditText>(R.id.notes_edittext) val notesET = dialogView.findViewById<EditText>(R.id.notes_edittext)
val qtyET = dialogView.findViewById<EditText>(R.id.notes_qty_edittext) val qtyET = dialogView.findViewById<EditText>(R.id.notes_qty_edittext)
if (lunaEvent.type == LunaEvent.TYPE_NOTE || lunaEvent.type == LunaEvent.TYPE_CUSTOM)
val dateTV = dialogView.findViewById<TextView>(R.id.dialog_date_picker)
val pickedTime = datePickerHelper(event.time, dateTV)
if (!showTime) {
dateTV.visibility = View.GONE
}
val nextTextView = dialogView.findViewById<TextView>(R.id.notes_template_next)
val prevTextView = dialogView.findViewById<TextView>(R.id.notes_template_prev)
val templates = allEvents.filter { it.type == event.type }.distinctBy { it.notes }.sortedBy { it.time }
fun updateContent(current: LunaEvent) {
val prevEvent = getPreviousSameEvent(current, templates)
var nextEvent = getNextSameEvent(current, templates)
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) {
qtyET.setText(event.quantity.toString())
} else {
qtyET.visibility = View.GONE qtyET.visibility = View.GONE
}
updateContent(event)
d.setPositiveButton(android.R.string.ok) { dialogInterface, i -> d.setPositiveButton(android.R.string.ok) { dialogInterface, i ->
val notes = notesET.text.toString().trim() val qtyStr = qtyET.text.toString()
if (qtyStr.isNotEmpty()) {
if (useQuantity) { val qty = qtyStr.toIntOrNull()
val quantity = qtyET.text.toString().toIntOrNull() if (qty == null) {
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() Toast.makeText(this, R.string.toast_integer_error, Toast.LENGTH_SHORT).show()
return@setPositiveButton
} }
lunaEvent.quantity = qty
} else {
event.time = pickedTime.time.time / 1000
event.notes = notes
onPositive()
} }
val notes = notesET.text.toString()
dialogInterface.dismiss() lunaEvent.notes = notes
logEvent(lunaEvent)
} }
d.setNegativeButton(android.R.string.cancel) { dialogInterface, i -> dialogInterface.dismiss() }
d.setNegativeButton(android.R.string.cancel) { dialogInterface, i ->
dialogInterface.dismiss()
}
val alertDialog = d.create() val alertDialog = d.create()
alertDialog.show() alertDialog.show()
} }
@@ -662,14 +312,7 @@ class MainActivity : AppCompatActivity() {
alertDialog.show() alertDialog.show()
} }
fun setToPreviousQuantity(event: LunaEvent) { fun getPreviousSameEvent(event: LunaEvent, items: ArrayList<LunaEvent>): LunaEvent? {
val prev = getPreviousSameEvent(event, allEvents)
if (prev != null) {
event.quantity = prev.quantity
}
}
fun getPreviousSameEvent(event: LunaEvent, items: List<LunaEvent>): LunaEvent? {
var previousEvent: LunaEvent? = null var previousEvent: LunaEvent? = null
for (item in items) { for (item in items) {
if (item.type == event.type && item.time < event.time) { if (item.type == event.type && item.time < event.time) {
@@ -683,7 +326,7 @@ class MainActivity : AppCompatActivity() {
return previousEvent return previousEvent
} }
fun getNextSameEvent(event: LunaEvent, items: List<LunaEvent>): LunaEvent? { fun getNextSameEvent(event: LunaEvent, items: ArrayList<LunaEvent>): LunaEvent? {
var nextEvent: LunaEvent? = null var nextEvent: LunaEvent? = null
for (item in items) { for (item in items) {
if (item.type == event.type && item.time > event.time) { if (item.type == event.type && item.time > event.time) {
@@ -697,110 +340,56 @@ class MainActivity : AppCompatActivity() {
return nextEvent return nextEvent
} }
fun showEventDetailDialog(originalEvent: LunaEvent) { fun showEventDetailDialog(event: LunaEvent, items: ArrayList<LunaEvent>) {
val event = LunaEvent(originalEvent)
fun eventValuesChanged(): Boolean {
return (event.time != originalEvent.time
|| event.quantity != originalEvent.quantity
|| event.notes != originalEvent.notes)
}
// Do not update list while the detail is shown, to avoid changing the object below while it is changed by the user // Do not update list while the detail is shown, to avoid changing the object below while it is changed by the user
pauseLogbookUpdate = true pauseLogbookUpdate = true
val d = AlertDialog.Builder(this) val d = AlertDialog.Builder(this)
d.setTitle(R.string.dialog_event_detail_title) d.setTitle(R.string.dialog_event_detail_title)
val dialogView = layoutInflater.inflate(R.layout.dialog_event_detail, null)
dialogView.findViewById<TextView>(R.id.dialog_event_detail_type_emoji).text = event.getTypeEmoji(this)
dialogView.findViewById<TextView>(R.id.dialog_event_detail_type_description).text = event.getTypeDescription(this)
dialogView.findViewById<TextView>(R.id.dialog_event_detail_type_quantity).text =
NumericUtils(this).formatEventQuantity(event)
dialogView.findViewById<TextView>(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<TextView>(R.id.dialog_event_detail_type_emoji)
val descriptionTextView = dialogView.findViewById<TextView>(R.id.dialog_event_detail_type_description)
val dateTextView = dialogView.findViewById<TextView>(R.id.dialog_event_detail_type_date) val dateTextView = dialogView.findViewById<TextView>(R.id.dialog_event_detail_type_date)
val dateEndTextView = dialogView.findViewById<TextView>(R.id.dialog_event_detail_type_date_end) dateTextView.text = String.format(getString(R.string.dialog_event_detail_datetime_icon), DateUtils.formatDateTime(event.time))
val quantityTextView = dialogView.findViewById<TextView>(R.id.dialog_event_detail_type_quantity) dateTextView.setOnClickListener {
val notesTextView = dialogView.findViewById<TextView>(R.id.dialog_event_detail_type_notes) // 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)
emojiTextView.text = event.getTypeEmoji(this) DatePickerDialog(this, { _, year, month, day ->
descriptionTextView.text = event.getTypeDescription(this) 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()
}
d.setView(dialogView) 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 -> d.setNeutralButton(R.string.dialog_event_detail_delete_button) { dialogInterface, i -> deleteEvent(event) }
deleteEvent(originalEvent)
dialogInterface.dismiss()
}
d.setNegativeButton(R.string.dialog_event_detail_save_button) { dialogInterface, i ->
if (eventValuesChanged()) {
originalEvent.time = event.time
originalEvent.quantity = event.quantity
originalEvent.notes = event.notes
saveEvent(originalEvent)
}
dialogInterface.dismiss()
}
d.setPositiveButton(R.string.dialog_event_detail_close_button) { dialogInterface, i ->
dialogInterface.dismiss()
}
val alertDialog = d.create() val alertDialog = d.create()
alertDialog.show() alertDialog.show()
alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL).setTextColor(ContextCompat.getColor(this, R.color.danger))
alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL).setTextColor( alertDialog.setOnDismissListener({
ContextCompat.getColor(this, R.color.danger)
)
alertDialog.setOnDismissListener {
// Resume logbook update // Resume logbook update
pauseLogbookUpdate = false pauseLogbookUpdate = false
}
val updateValues = {
quantityTextView.text = NumericUtils(this).formatEventQuantity(event)
notesTextView.text = event.notes
if (event.type == LunaEvent.TYPE_SLEEP && event.quantity > 0) {
dateEndTextView.text = DateUtils.formatDateTime(event.time + event.quantity)
dateEndTextView.visibility = View.VISIBLE
} else {
dateEndTextView.visibility = View.GONE
}
alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).visibility = if (eventValuesChanged()) {
View.VISIBLE
} else {
View.GONE
}
}
updateValues()
datePickerHelper(event.time, dateTextView, { newTime: Long ->
event.time = newTime
updateValues()
}) })
quantityTextView.setOnClickListener {
when (event.type) {
LunaEvent.TYPE_BABY_BOTTLE -> askBabyBottleContent(event, false, updateValues)
LunaEvent.TYPE_WEIGHT -> askWeightValue(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)
LunaEvent.TYPE_SLEEP -> askSleepValue(event, updateValues)
}
}
notesTextView.setOnClickListener {
when (event.type) {
LunaEvent.TYPE_FOOD,
LunaEvent.TYPE_MEDICINE,
LunaEvent.TYPE_NOTE -> askNotes(event, false, updateValues)
}
}
// show optional signature // show optional signature
if (event.signature.isNotEmpty()) { if (event.signature.isNotEmpty()) {
val signatureTextEdit = dialogView.findViewById<TextView>(R.id.dialog_event_detail_type_signature) val signatureTextEdit = dialogView.findViewById<TextView>(R.id.dialog_event_detail_type_signature)
@@ -808,31 +397,32 @@ class MainActivity : AppCompatActivity() {
signatureTextEdit.visibility = View.VISIBLE signatureTextEdit.visibility = View.VISIBLE
} }
// create link to prevent event of the same type // create next/previous links to events of the same type
val previousTextView = dialogView.findViewById<TextView>(R.id.dialog_event_previous) val previousTextView = dialogView.findViewById<TextView>(R.id.dialog_event_previous)
val previousEvent = getPreviousSameEvent(event, allEvents) val nextTextView = dialogView.findViewById<TextView>(R.id.dialog_event_next)
val nextEvent = getNextSameEvent(event, items)
val previousEvent = getPreviousSameEvent(event, items)
if (previousEvent != null) { if (previousEvent != null) {
val emoji = previousEvent.getTypeEmoji(applicationContext) val emoji = previousEvent.getTypeEmoji(applicationContext)
val time = DateUtils.formatTimeDuration(applicationContext, event.time - previousEvent.time) val time = DateUtils.formatTimeDuration(applicationContext, event.time - previousEvent.time)
previousTextView.text = String.format("⬅️ %s %s", emoji, time) previousTextView.text = String.format("⬅️ %s %s", emoji, time)
previousTextView.setOnClickListener { previousTextView.setOnClickListener {
alertDialog.cancel() alertDialog.cancel()
showEventDetailDialog(previousEvent) showEventDetailDialog(previousEvent, items)
} }
} else { } else {
previousTextView.visibility = View.GONE previousTextView.visibility = View.GONE
} }
// create link to next event of the same type
val nextTextView = dialogView.findViewById<TextView>(R.id.dialog_event_next)
val nextEvent = getNextSameEvent(event, allEvents)
if (nextEvent != null) { if (nextEvent != null) {
val emoji = nextEvent.getTypeEmoji(applicationContext) val emoji = nextEvent.getTypeEmoji(applicationContext)
val time = DateUtils.formatTimeDuration(applicationContext, nextEvent.time - event.time) val time = DateUtils.formatTimeDuration(applicationContext, nextEvent.time - event.time)
nextTextView.text = String.format("%s %s ➡️", time, emoji) nextTextView.text = String.format("%s %s ➡️", time, emoji)
nextTextView.setOnClickListener { nextTextView.setOnClickListener {
alertDialog.cancel() alertDialog.cancel()
showEventDetailDialog(nextEvent) showEventDetailDialog(nextEvent, items)
} }
} else { } else {
nextTextView.visibility = View.GONE nextTextView.visibility = View.GONE
@@ -1192,51 +782,41 @@ class MainActivity : AppCompatActivity() {
val inflater = LayoutInflater.from(anchor.context) val inflater = LayoutInflater.from(anchor.context)
contentView = inflater.inflate(R.layout.more_events_popup, null) contentView = inflater.inflate(R.layout.more_events_popup, null)
contentView.findViewById<View>(R.id.button_medicine).setOnClickListener { contentView.findViewById<View>(R.id.button_medicine).setOnClickListener {
addNoteEvent(LunaEvent(LunaEvent.TYPE_MEDICINE)) askNotes(LunaEvent(LunaEvent.TYPE_MEDICINE))
dismiss() dismiss()
} }
contentView.findViewById<View>(R.id.button_enema).setOnClickListener { contentView.findViewById<View>(R.id.button_enema).setOnClickListener({
addPlainEvent(LunaEvent(LunaEvent.TYPE_ENEMA)) logEvent(LunaEvent(LunaEvent.TYPE_ENEMA))
dismiss() dismiss()
} })
contentView.findViewById<View>(R.id.button_note).setOnClickListener { contentView.findViewById<View>(R.id.button_note).setOnClickListener({
addNoteEvent(LunaEvent(LunaEvent.TYPE_NOTE)) askNotes(LunaEvent(LunaEvent.TYPE_NOTE))
dismiss() dismiss()
} })
contentView.findViewById<View>(R.id.button_temperature).setOnClickListener { contentView.findViewById<View>(R.id.button_temperature).setOnClickListener({
addTemperatureEvent(LunaEvent(LunaEvent.TYPE_TEMPERATURE)) askTemperatureValue()
dismiss() dismiss()
} })
contentView.findViewById<View>(R.id.button_puke).setOnClickListener { contentView.findViewById<View>(R.id.button_puke).setOnClickListener({
addAmountEvent(LunaEvent(LunaEvent.TYPE_PUKE)) logEvent(LunaEvent(LunaEvent.TYPE_PUKE))
dismiss() dismiss()
} })
contentView.findViewById<View>(R.id.button_sleep).setOnClickListener { contentView.findViewById<View>(R.id.button_colic).setOnClickListener({
addSleepEvent(LunaEvent(LunaEvent.TYPE_SLEEP)) logEvent(
LunaEvent(LunaEvent.TYPE_COLIC)
)
dismiss() dismiss()
} })
contentView.findViewById<View>(R.id.button_colic).setOnClickListener { contentView.findViewById<View>(R.id.button_scale).setOnClickListener({
addPlainEvent(LunaEvent(LunaEvent.TYPE_COLIC)) askWeightValue()
dismiss() dismiss()
} })
contentView.findViewById<View>(R.id.button_scale).setOnClickListener { contentView.findViewById<View>(R.id.button_bath).setOnClickListener({
addWeightEvent(LunaEvent(LunaEvent.TYPE_WEIGHT)) logEvent(
LunaEvent(LunaEvent.TYPE_BATH)
)
dismiss() dismiss()
} })
contentView.findViewById<View>(R.id.button_bath).setOnClickListener {
addPlainEvent(LunaEvent(LunaEvent.TYPE_BATH))
dismiss()
}
contentView.findViewById<View>(R.id.button_statistics).setOnClickListener {
if (logbook != null && !pauseLogbookUpdate) {
val i = Intent(applicationContext, StatisticsActivity::class.java)
i.putExtra("LOOGBOOK_NAME", logbook!!.name)
startActivity(i)
} else {
Toast.makeText(applicationContext, "No logbook selected!", Toast.LENGTH_SHORT).show()
}
dismiss()
}
}.also { popupWindow -> }.also { popupWindow ->
popupWindow.setOnDismissListener({ popupWindow.setOnDismissListener({
Handler(mainLooper).postDelayed({ Handler(mainLooper).postDelayed({

View File

@@ -1,375 +0,0 @@
package it.danieleverducci.lunatracker
import android.graphics.Color
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Spinner
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.github.mikephil.charting.charts.BarChart
import com.github.mikephil.charting.data.BarData
import com.github.mikephil.charting.data.BarDataSet
import com.github.mikephil.charting.data.BarEntry
import com.github.mikephil.charting.formatter.ValueFormatter
import com.github.mikephil.charting.interfaces.datasets.IBarDataSet
import it.danieleverducci.lunatracker.entities.LunaEvent
import utils.DateUtils.Companion.formatTimeDuration
import utils.NumericUtils
import java.util.Calendar
import java.util.Date
import kotlin.math.max
import kotlin.math.min
class StatisticsActivity : AppCompatActivity() {
lateinit var barChart: BarChart
lateinit var noDataTextView: TextView
lateinit var eventTypeSelection: Spinner
lateinit var dataTypeSelection: Spinner
lateinit var timeRangeSelection: Spinner
// default selection
var eventTypeSelectionValue = "BOTTLE"
var dataTypeSelectionValue = "AMOUNT"
var timeRangeSelectionValue = "DAY"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_statistics)
val logbookName = intent.getStringExtra("LOOGBOOK_NAME")
if (logbookName == null) {
finish()
return
}
noDataTextView = findViewById(R.id.no_data)
barChart = findViewById(R.id.bar_chart)
barChart.setBackgroundColor(Color.WHITE)
barChart.description.text = "$logbookName"
barChart.setDrawValueAboveBar(false)
barChart.axisLeft.setAxisMinimum(0F)
barChart.axisLeft.setDrawGridLines(false)
barChart.axisLeft.setDrawLabels(false)
barChart.axisRight.setDrawGridLines(false)
barChart.axisRight.setDrawLabels(false)
barChart.xAxis.setDrawGridLines(true)
barChart.xAxis.setDrawLabels(true)
barChart.xAxis.setDrawAxisLine(false)
eventTypeSelection = findViewById(R.id.type_selection)
dataTypeSelection = findViewById(R.id.data_selection)
timeRangeSelection = findViewById(R.id.time_selection)
setupSpinner(eventTypeSelectionValue,
R.id.type_selection,
R.array.StatisticsTypeLabels,
R.array.StatisticsTypeValues,
object : SpinnerItemSelected {
override fun call(newValue: String?) {
if (newValue != null) {
eventTypeSelectionValue = newValue
//Log.d("event", "new value: $newValue")
updateGraph()
}
}
}
)
setupSpinner(dataTypeSelectionValue,
R.id.data_selection,
R.array.StatisticsDataLabels,
R.array.StatisticsDataValues,
object : SpinnerItemSelected {
override fun call(newValue: String?) {
if (newValue != null) {
dataTypeSelectionValue = newValue
//Log.d("event", "new value: $newValue")
updateGraph()
}
}
}
)
setupSpinner(timeRangeSelectionValue,
R.id.time_selection,
R.array.StatisticsTimeLabels,
R.array.StatisticsTimeValues,
object : SpinnerItemSelected {
override fun call(newValue: String?) {
if (newValue != null) {
timeRangeSelectionValue = newValue
//Log.d("event", "new value: $newValue")
updateGraph()
}
}
}
)
updateGraph()
}
fun updateGraph() {
val eventType = when (eventTypeSelectionValue) {
"BOTTLE" -> LunaEvent.TYPE_BABY_BOTTLE
"SLEEP" -> LunaEvent.TYPE_SLEEP
else -> {
Log.e(TAG, "unhandled eventTypeSelectionValue: $eventTypeSelectionValue")
return
}
}
val allEvents = MainActivity.allEvents.filter { it.type == eventType }.sortedBy { it.time }
val values = ArrayList<BarEntry>()
val labels = ArrayList<String>()
val unixToSpan = when (timeRangeSelectionValue) {
"DAY" -> { unix: Long -> unixToDays(unix) }
"WEEK" -> { unix: Long -> unixToWeeks(unix) }
"MONTH" -> { unix: Long -> unixToMonths(unix) }
else -> {
Log.e(TAG, "Invalid timeRangeSelectionValue: $timeRangeSelectionValue")
return
}
}
val spanToUnix = when (timeRangeSelectionValue) {
"DAY" -> { span: Int -> daysToUnix(span) }
"WEEK" -> { span: Int -> weeksToUnix(span) }
"MONTH" -> { span: Int -> monthsToUnix(span) }
else -> {
Log.e(TAG, "Invalid timeRangeSelectionValue: $timeRangeSelectionValue")
return
}
}
fun spanToLabel(span: Int): String {
val dateTime = Calendar.getInstance()
dateTime.time = Date(1000 * spanToUnix(span))
val year = dateTime.get(Calendar.YEAR)
val month = dateTime.get(Calendar.MONTH) + 1 // month starts at 0
val week = dateTime.get(Calendar.WEEK_OF_YEAR)
val day = dateTime.get(Calendar.DAY_OF_MONTH)
return when (timeRangeSelectionValue) {
"DAY" -> "$day/$month/$year"
"WEEK" -> "$week/$year"
"MONTH" -> "$month/$year"
else -> {
Log.e(TAG, "Invalid timeRangeSelectionValue: $timeRangeSelectionValue")
"?"
}
}
}
if (allEvents.isNotEmpty()) {
barChart.visibility = View.VISIBLE
noDataTextView.visibility = View.GONE
// unix time span of all events
val startUnix = allEvents.minOf { it.getStartTime() }
val endUnix = allEvents.maxOf { it.getEndTime() }
// convert to days, weeks or months
val startSpan = unixToSpan(startUnix)
val endSpan = unixToSpan(endUnix)
//Log.d(TAG, "startUnix: $startUnix (${Date(1000 * startUnix)}), startSpan: $startSpan (${Date(1000 * spanToUnix(startSpan))}), endUnix: $endUnix (${Date(1000 * endUnix)}), endSpan: $endSpan (${Date(1000 * spanToUnix(endSpan))})")
for (span in startSpan..endSpan) {
values.add(BarEntry(values.size.toFloat(), 0F))
labels.add(spanToLabel(span))
}
for (event in allEvents) {
if (dataTypeSelectionValue == "AMOUNT") {
if (eventTypeSelectionValue == "SLEEP") {
// a sleep event can span to another day
// distribute sleep time over the days
val startUnix = event.getStartTime()
val endUnix = event.getEndTime()
val begIndex = unixToSpan(startUnix)
val endIndex = unixToSpan(endUnix)
var mid = startUnix
//Log.d(TAG, "startUnix: ${Date(startUnix * 1000)}, endUnix: ${Date(endUnix * 1000)}, begIndex: $begIndex, endIndex: $endIndex (index diff: ${endIndex - begIndex})")
for (i in begIndex..endIndex) {
val spanBegin = spanToUnix(i)
val spanEnd = spanToUnix(i + 1)
//Log.d(TAG, "mid: ${Date(mid * 1000)}, spanBegin: ${Date(spanBegin * 1000)}, spanEnd: ${Date(spanEnd * 1000)}, endUnix: ${Date(endUnix * 1000)}")
val beg = max(mid, spanBegin)
val end = min(endUnix, spanEnd)
val index = i - startSpan
val duration = end - beg
//Log.d(TAG, "[$index] beg: ${Date(beg * 1000)}, end: ${Date(end * 1000)}, ${formatTimeDuration(this, duration)}")
values[index].y += duration
mid = end
}
} else {
val index = unixToSpan(event.time) - startSpan
//Log.d(TAG, "[${index}] ${event.quantity}")
values[index].y += event.quantity
}
} else {
val index = unixToSpan(event.time) - startSpan
values[index].y += 1
}
}
} else {
barChart.visibility = View.GONE
noDataTextView.visibility = View.VISIBLE
}
barChart.xAxis.setLabelCount(min(values.size, 24))
val set1 = BarDataSet(values, "")
set1.setDrawValues(true)
set1.setDrawIcons(false)
val dataSets = ArrayList<IBarDataSet?>()
dataSets.add(set1)
val data = BarData(dataSets)
data.setValueFormatter(object : ValueFormatter() {
override fun getFormattedValue(value: Float): String {
//Log.d(TAG, "getFormattedValue ${dataTypeSelectionValue} ${eventTypeSelectionValue}")
return when (dataTypeSelectionValue) {
"EVENT" -> value.toInt().toString()
"AMOUNT" -> when (eventTypeSelectionValue) {
"BOTTLE" -> NumericUtils(applicationContext).formatEventQuantity(LunaEvent.TYPE_BABY_BOTTLE, value.toInt())
"SLEEP" -> NumericUtils(applicationContext).formatEventQuantity(LunaEvent.TYPE_SLEEP, value.toInt())
else -> {
Log.e(TAG, "unhandled eventTypeSelectionValue: $eventTypeSelectionValue")
value.toInt().toString()
}
} else -> {
Log.e(TAG, "unhandled dataTypeSelectionValue: $dataTypeSelectionValue")
value.toInt().toString()
}
}
}
})
barChart.xAxis.valueFormatter = object: ValueFormatter() {
override fun getFormattedValue(value: Float): String {
return labels.getOrElse(value.toInt(), {"?"})
}
}
data.setValueTextSize(12f)
barChart.setData(data)
barChart.invalidate()
}
private interface SpinnerItemSelected {
fun call(newValue: String?)
}
private fun setupSpinner(
currentValue: String,
spinnerId: Int,
arrayId: Int,
arrayValuesId: Int,
callback: SpinnerItemSelected
) {
val arrayValues = resources.getStringArray(arrayValuesId)
val spinner = findViewById<Spinner>(spinnerId)
val spinnerAdapter =
ArrayAdapter.createFromResource(this, arrayId, R.layout.statistics_spinner_item) //android.R.layout.simple_spinner_item) //android.R.layout.simple_list_item_single_choice) //R.layout.spinner_item_settings)
spinner.adapter = spinnerAdapter
spinner.setSelection(arrayValues.indexOf(currentValue))
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
var check = 0
override fun onItemSelected(parent: AdapterView<*>?, view: View?, pos: Int, id: Long) {
if (pos >= arrayValues.size) {
Toast.makeText(
this@StatisticsActivity,
"pos out of bounds: $arrayValues", Toast.LENGTH_SHORT
).show()
return
}
if (check++ > 0) {
callback.call(arrayValues[pos])
}
}
override fun onNothingSelected(parent: AdapterView<*>?) {
// ignore
}
}
}
companion object {
const val TAG = "StatisticsActivity"
fun unixToMonths(seconds: Long): Int {
val dateTime = Calendar.getInstance()
dateTime.time = Date(seconds * 1000)
val years = dateTime.get(Calendar.YEAR)
val months = dateTime.get(Calendar.MONTH)
return 12 * years + months
}
fun monthsToUnix(months: Int): Long {
val dateTime = Calendar.getInstance()
dateTime.time = Date(0)
dateTime.set(Calendar.YEAR, months / 12)
dateTime.set(Calendar.MONTH, months % 12)
//Calendar.MONTH_OF_YEAR?
dateTime.set(Calendar.HOUR, 0)
dateTime.set(Calendar.MINUTE, 0)
dateTime.set(Calendar.SECOND, 0)
return dateTime.time.time / 1000
}
fun unixToWeeks(seconds: Long): Int {
val dateTime = Calendar.getInstance()
dateTime.time = Date(seconds * 1000)
val years = dateTime.get(Calendar.YEAR)
val weeks = dateTime.get(Calendar.WEEK_OF_YEAR)
return 52 * years + weeks
}
fun weeksToUnix(weeks: Int): Long {
val dateTime = Calendar.getInstance()
dateTime.time = Date(0)
dateTime.set(Calendar.YEAR, weeks / 52)
dateTime.set(Calendar.WEEK_OF_YEAR, weeks % 52)
dateTime.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY)
dateTime.set(Calendar.HOUR, 0)
dateTime.set(Calendar.MINUTE, 0)
dateTime.set(Calendar.SECOND, 0)
return dateTime.time.time / 1000
}
fun unixToDays(seconds: Long): Int {
val dateTime = Calendar.getInstance()
dateTime.time = Date(seconds * 1000)
val years = dateTime.get(Calendar.YEAR)
val days = dateTime.get(Calendar.DAY_OF_YEAR)
return 365 * years + days
}
// convert from days to Date
fun daysToUnix(days: Int): Long {
val dateTime = Calendar.getInstance()
dateTime.time = Date(0)
dateTime.set(Calendar.YEAR, days / 365)
dateTime.set(Calendar.DAY_OF_YEAR, days % 365)
dateTime.set(Calendar.HOUR, 0)
dateTime.set(Calendar.MINUTE, 0)
dateTime.set(Calendar.SECOND, 0)
return dateTime.time.time / 1000
}
}
}

View File

@@ -59,7 +59,7 @@ class LunaEventRecyclerAdapter: RecyclerView.Adapter<LunaEventRecyclerAdapter.Lu
LunaEvent.TYPE_CUSTOM -> item.notes LunaEvent.TYPE_CUSTOM -> item.notes
else -> item.getTypeDescription(context) else -> item.getTypeDescription(context)
} }
holder.time.text = DateUtils.formatTimeAgo(context, item.getEndTime()) holder.time.text = DateUtils.formatTimeAgo(context, item.time)
var quantityText = numericUtils.formatEventQuantity(item) var quantityText = numericUtils.formatEventQuantity(item)
// if the event is weight, show difference with the last one // if the event is weight, show difference with the last one

View File

@@ -30,7 +30,6 @@ class LunaEvent: Comparable<LunaEvent> {
const val TYPE_FOOD = "FOOD" const val TYPE_FOOD = "FOOD"
const val TYPE_PUKE = "PUKE" const val TYPE_PUKE = "PUKE"
const val TYPE_BATH = "BATH" const val TYPE_BATH = "BATH"
const val TYPE_SLEEP = "SLEEP"
} }
private val jo: JSONObject private val jo: JSONObject
@@ -50,8 +49,6 @@ class LunaEvent: Comparable<LunaEvent> {
set(value) { set(value) {
if (value > 0) if (value > 0)
jo.put("quantity", value) jo.put("quantity", value)
else
jo.remove("quantity")
} }
var notes: String var notes: String
get(): String = jo.optString("notes") get(): String = jo.optString("notes")
@@ -72,15 +69,6 @@ class LunaEvent: Comparable<LunaEvent> {
throw IllegalArgumentException("JSONObject is not a LunaEvent") 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) { constructor(type: String) {
this.jo = JSONObject() this.jo = JSONObject()
this.time = System.currentTimeMillis() / 1000 this.time = System.currentTimeMillis() / 1000
@@ -94,23 +82,11 @@ class LunaEvent: Comparable<LunaEvent> {
this.quantity = quantity this.quantity = quantity
} }
fun getStartTime(): Long {
return time
}
fun getEndTime(): Long {
return if (type == TYPE_SLEEP) {
time + quantity
} else {
time
}
}
fun getTypeEmoji(context: Context): String { fun getTypeEmoji(context: Context): String {
return context.getString( return context.getString(
when (type) { when (type) {
TYPE_BABY_BOTTLE -> R.string.event_bottle_type TYPE_BABY_BOTTLE -> R.string.event_bottle_type
TYPE_WEIGHT -> R.string.event_weight_type TYPE_WEIGHT -> R.string.event_scale_type
TYPE_BREASTFEEDING_LEFT_NIPPLE -> R.string.event_breastfeeding_left_type TYPE_BREASTFEEDING_LEFT_NIPPLE -> R.string.event_breastfeeding_left_type
TYPE_BREASTFEEDING_BOTH_NIPPLE -> R.string.event_breastfeeding_both_type TYPE_BREASTFEEDING_BOTH_NIPPLE -> R.string.event_breastfeeding_both_type
TYPE_BREASTFEEDING_RIGHT_NIPPLE -> R.string.event_breastfeeding_right_type TYPE_BREASTFEEDING_RIGHT_NIPPLE -> R.string.event_breastfeeding_right_type
@@ -124,7 +100,6 @@ class LunaEvent: Comparable<LunaEvent> {
TYPE_FOOD -> R.string.event_food_type TYPE_FOOD -> R.string.event_food_type
TYPE_PUKE -> R.string.event_puke_type TYPE_PUKE -> R.string.event_puke_type
TYPE_BATH -> R.string.event_bath_type TYPE_BATH -> R.string.event_bath_type
TYPE_SLEEP -> R.string.event_sleep_type
else -> R.string.event_unknown_type else -> R.string.event_unknown_type
} }
) )
@@ -134,7 +109,7 @@ class LunaEvent: Comparable<LunaEvent> {
return context.getString( return context.getString(
when (type) { when (type) {
TYPE_BABY_BOTTLE -> R.string.event_bottle_desc TYPE_BABY_BOTTLE -> R.string.event_bottle_desc
TYPE_WEIGHT -> R.string.event_weight_desc TYPE_WEIGHT -> R.string.event_scale_desc
TYPE_BREASTFEEDING_LEFT_NIPPLE -> R.string.event_breastfeeding_left_desc TYPE_BREASTFEEDING_LEFT_NIPPLE -> R.string.event_breastfeeding_left_desc
TYPE_BREASTFEEDING_BOTH_NIPPLE -> R.string.event_breastfeeding_both_desc TYPE_BREASTFEEDING_BOTH_NIPPLE -> R.string.event_breastfeeding_both_desc
TYPE_BREASTFEEDING_RIGHT_NIPPLE -> R.string.event_breastfeeding_right_desc TYPE_BREASTFEEDING_RIGHT_NIPPLE -> R.string.event_breastfeeding_right_desc
@@ -148,26 +123,16 @@ class LunaEvent: Comparable<LunaEvent> {
TYPE_FOOD -> R.string.event_food_desc TYPE_FOOD -> R.string.event_food_desc
TYPE_PUKE -> R.string.event_puke_desc TYPE_PUKE -> R.string.event_puke_desc
TYPE_BATH -> R.string.event_bath_desc TYPE_BATH -> R.string.event_bath_desc
TYPE_SLEEP -> R.string.event_sleep_desc
else -> R.string.event_unknown_desc else -> R.string.event_unknown_desc
} }
) )
} }
fun getDialogMessage(context: Context): String? { fun getDialogMessage(context: Context): String? {
return context.getString( return when(type) {
when(type) { TYPE_MEDICINE -> context.getString(R.string.log_medicine_dialog_description)
TYPE_BABY_BOTTLE -> R.string.log_bottle_dialog_description else -> null
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
TYPE_SLEEP -> R.string.log_sleep_dialog_description
else -> R.string.log_unknown_dialog_description
}
)
} }
fun toJson(): JSONObject { fun toJson(): JSONObject {

View File

@@ -23,6 +23,14 @@ class LocalSettingsRepository(val context: Context) {
sharedPreferences = context.getSharedPreferences(SHARED_PREFS_FILE_NAME, MODE_PRIVATE) 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) { fun saveSignature(content: String) {
sharedPreferences.edit { putString(SHARED_PREFS_SIGNATURE, content) } sharedPreferences.edit { putString(SHARED_PREFS_SIGNATURE, content) }
} }

View File

@@ -1,7 +1,6 @@
package utils package utils
import android.content.Context import android.content.Context
import android.os.Build
import android.text.format.DateFormat import android.text.format.DateFormat
import it.danieleverducci.lunatracker.R import it.danieleverducci.lunatracker.R
import java.util.Date import java.util.Date
@@ -62,8 +61,10 @@ class DateUtils {
return format(days, hours, R.string.day_ago, R.string.days_ago, R.string.hour_ago, R.string.hours_ago) return format(days, hours, R.string.day_ago, R.string.days_ago, R.string.hour_ago, R.string.hours_ago)
} else if (hours > 0) { } else if (hours > 0) {
return format(hours, minutes, R.string.hour_ago, R.string.hours_ago, R.string.minute_ago, R.string.minutes_ago) return format(hours, minutes, R.string.hour_ago, R.string.hours_ago, R.string.minute_ago, R.string.minutes_ago)
} else { } else if (minutes > 0) {
return format(minutes, seconds, R.string.minute_ago, R.string.minute_ago, R.string.second_ago, R.string.seconds_ago) return format(minutes, seconds, R.string.minute_ago, R.string.minute_ago, R.string.second_ago, R.string.seconds_ago)
} else {
return context.getString(R.string.now)
} }
} }
@@ -106,19 +107,15 @@ class DateUtils {
} }
/** /**
* Format time as localized string without seconds. E.g. "Sept 18, 2025, 03:36 PM". * Format time as localized string. E.g. "28 Sept 03:36:00".
* The seconds are set to 0 since they are distracting and not relevant.
* Used in the event detail dialog. * Used in the event detail dialog.
*/ */
fun formatDateTime(unixTime: Long): String { fun formatDateTime(unixTime: Long): String {
val date = Date(unixTime * 1000) val roundedUnixTime = unixTime - (unixTime % 60)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { val date = Date(roundedUnixTime * 1000)
val dateFormat = android.icu.text.DateFormat.getDateTimeInstance(android.icu.text.DateFormat.DEFAULT, android.icu.text.DateFormat.SHORT) val dateFormat = java.text.DateFormat.getDateTimeInstance()
return dateFormat.format(date) return dateFormat.format(date)
} else {
// fallback
val dateFormat = java.text.DateFormat.getDateTimeInstance()
return dateFormat.format(date)
}
} }
} }
} }

View File

@@ -4,10 +4,8 @@ import android.content.Context
import android.icu.util.LocaleData import android.icu.util.LocaleData
import android.icu.util.ULocale import android.icu.util.ULocale
import android.os.Build import android.os.Build
import android.util.Log
import it.danieleverducci.lunatracker.R import it.danieleverducci.lunatracker.R
import it.danieleverducci.lunatracker.entities.LunaEvent import it.danieleverducci.lunatracker.entities.LunaEvent
import utils.DateUtils.Companion.formatTimeDuration
import java.text.NumberFormat import java.text.NumberFormat
class NumericUtils (val context: Context) { class NumericUtils (val context: Context) {
@@ -62,32 +60,19 @@ class NumericUtils (val context: Context) {
) )
} }
fun formatEventQuantity(event: LunaEvent): String { fun formatEventQuantity(item: LunaEvent): String {
return formatEventQuantity(event.type, event.quantity)
}
fun formatEventQuantity(type: String, quantity: Int): String {
val formatted = StringBuilder() val formatted = StringBuilder()
if (quantity > 0) { if (item.quantity > 0) {
formatted.append(when (type) { formatted.append(when (item.type) {
LunaEvent.TYPE_TEMPERATURE -> LunaEvent.TYPE_TEMPERATURE ->
(quantity / 10.0f).toString() (item.quantity / 10.0f).toString()
LunaEvent.TYPE_DIAPERCHANGE_POO, else ->
LunaEvent.TYPE_DIAPERCHANGE_PEE, item.quantity
LunaEvent.TYPE_PUKE -> {
val array = context.resources.getStringArray(R.array.AmountLabels)
return array.getOrElse(quantity) {
Log.e("NumericUtils", "Invalid index $quantity")
return ""
}
}
LunaEvent.TYPE_SLEEP -> formatTimeDuration(context, quantity.toLong())
else -> quantity
}) })
formatted.append(" ") formatted.append(" ")
formatted.append( formatted.append(
when (type) { when (item.type) {
LunaEvent.TYPE_BABY_BOTTLE -> measurement_unit_liquid_base LunaEvent.TYPE_BABY_BOTTLE -> measurement_unit_liquid_base
LunaEvent.TYPE_WEIGHT -> measurement_unit_weight_base LunaEvent.TYPE_WEIGHT -> measurement_unit_weight_base
LunaEvent.TYPE_MEDICINE -> measurement_unit_weight_tiny LunaEvent.TYPE_MEDICINE -> measurement_unit_weight_tiny
@@ -95,11 +80,6 @@ class NumericUtils (val context: Context) {
else -> "" else -> ""
} }
) )
} else {
formatted.append(when (type) {
LunaEvent.TYPE_SLEEP -> "💤" // baby is sleeping
else -> ""
})
} }
return formatted.toString() return formatted.toString()
} }

View File

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

View File

@@ -1,55 +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"
android:padding="10dp">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1">
<com.github.mikephil.charting.charts.HorizontalBarChart
android:id="@+id/bar_chart"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="@+id/no_data"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:gravity="center"
android:text="No Data"/>
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<Spinner
android:id="@+id/type_selection"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
<Spinner
android:id="@+id/data_selection"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<Spinner
android:id="@+id/time_selection"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"/>
</LinearLayout>
</LinearLayout>

View File

@@ -1,35 +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="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="horizontal">
<NumberPicker
android:id="@+id/dialog_number_picker"
android:layout_width="150dp"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:text="ml"/>
</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>

View File

@@ -1,55 +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:layout_gravity="center"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/dialog_date_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:text="💤"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_marginTop="20dp"
android:layout_marginHorizontal="10dp"
android:orientation="horizontal">
<Button
android:id="@+id/dialog_date_duration_minus5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="-5"/>
<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/now"/>
<Button
android:id="@+id/dialog_date_duration_plus5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="+5"/>
</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>

View File

@@ -1,57 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="20dp">
<EditText
android:id="@+id/notes_qty_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:lines="1"
android:inputType="number"
android:hint="@string/log_notes_dialog_qty_hint"
android:background="@drawable/textview_background"/>
<EditText
android:id="@+id/notes_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="top"
android:lines="10"
android:hint="@string/log_notes_dialog_note_hint"
android:background="@drawable/textview_background"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:gravity="end"
android:orientation="horizontal">
<TextView
android:id="@+id/notes_template_prev"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18dp"
android:text="⬅️"/>
<TextView
android:id="@+id/notes_template_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18dp"
android:text="➡️"/>
</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="15dp"/>
</LinearLayout>

View File

@@ -1,38 +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:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:text="g"/>
</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>

View File

@@ -1,11 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:paddingTop="20dp" android:padding="20dp">
android:paddingBottom="10dp"
android:paddingHorizontal="20dp">
<TextView <TextView
android:id="@+id/dialog_event_detail_type_emoji" android:id="@+id/dialog_event_detail_type_emoji"
@@ -35,7 +34,9 @@
android:drawablePadding="10dp" android:drawablePadding="10dp"
android:drawableTint="@color/accent" android:drawableTint="@color/accent"
android:textSize="16sp" android:textSize="16sp"
android:textStyle="bold"/> android:textStyle="bold"
android:text="@string/dialog_event_detail_datetime_icon"
app:drawableEndCompat="@drawable/ic_edit" />
<TextView <TextView
android:id="@+id/dialog_event_detail_type_quantity" android:id="@+id/dialog_event_detail_type_quantity"
@@ -45,18 +46,6 @@
android:textSize="28sp" android:textSize="28sp"
android:text="@string/dialog_event_detail_quantity"/> android:text="@string/dialog_event_detail_quantity"/>
<TextView
android:id="@+id/dialog_event_detail_type_date_end"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_gravity="center_horizontal"
android:gravity="center_vertical"
android:drawablePadding="10dp"
android:drawableTint="@color/accent"
android:visibility="gone"
android:textSize="16sp"
android:textStyle="bold"/>
<ScrollView <ScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="200dp" android:layout_height="200dp"

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="20dp">
<EditText
android:id="@+id/notes_qty_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:lines="1"
android:inputType="number"
android:hint="@string/log_notes_dialog_qty_hint"
android:background="@drawable/textview_background"/>
<EditText
android:id="@+id/notes_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="top"
android:lines="10"
android:hint="@string/log_notes_dialog_note_hint"
android:background="@drawable/textview_background"/>
</LinearLayout>

View File

@@ -10,21 +10,10 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:orientation="vertical">
<TextView
android:id="@+id/button_statistics"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:padding="10dp"
android:background="@drawable/dropdown_list_item_background"
style="@style/OverflowMenuText"
android:text="📊 Statistics"/>
<TextView <TextView
android:id="@+id/button_medicine" android:id="@+id/button_medicine"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:padding="10dp" android:padding="10dp"
android:background="@drawable/dropdown_list_item_background" android:background="@drawable/dropdown_list_item_background"
style="@style/OverflowMenuText" style="@style/OverflowMenuText"
@@ -60,16 +49,6 @@
style="@style/OverflowMenuText" style="@style/OverflowMenuText"
android:text="@string/overflow_event_puke"/> android:text="@string/overflow_event_puke"/>
<TextView
android:id="@+id/button_sleep"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:padding="10dp"
android:background="@drawable/dropdown_list_item_background"
style="@style/OverflowMenuText"
android:text="@string/overflow_event_sleep"/>
<TextView <TextView
android:id="@+id/button_colic" android:id="@+id/button_colic"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -88,7 +67,7 @@
android:padding="10dp" android:padding="10dp"
android:background="@drawable/dropdown_list_item_background" android:background="@drawable/dropdown_list_item_background"
style="@style/OverflowMenuText" style="@style/OverflowMenuText"
android:text="@string/overflow_event_weight"/> android:text="@string/overflow_event_scale"/>
<TextView <TextView
android:id="@+id/button_bath" android:id="@+id/button_bath"

View File

@@ -4,19 +4,19 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_gravity="center" android:layout_gravity="center"
android:gravity="center" android:gravity="center">
android:orientation="vertical">
<Spinner <EditText
android:id="@+id/dialog_amount_value" android:id="@+id/dialog_number_edittext"
android:layout_width="250dp" android:layout_width="150dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingHorizontal="16dp"/> android:inputType="number"
android:hint="0"
android:background="@drawable/textview_background"/>
<TextView <TextView
android:id="@+id/dialog_date_picker"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="20dp"/> android:layout_marginStart="10dp"
android:text="g"/>
</LinearLayout> </LinearLayout>

View File

@@ -4,12 +4,16 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_gravity="center" android:layout_gravity="center"
android:gravity="center" android:gravity="center">
android:orientation="vertical">
<TextView <NumberPicker
android:id="@+id/dialog_date_picker" android:id="@+id/dialog_number_picker"
android:layout_width="wrap_content" android:layout_width="150dp"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:text="ml"/>
</LinearLayout> </LinearLayout>

View File

@@ -1,8 +0,0 @@
<?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" />

View File

@@ -23,11 +23,4 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textSize="30sp" android:textSize="30sp"
android:textColor="@color/accent"/> android:textColor="@color/accent"/>
<TextView
android:id="@+id/dialog_date_picker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"/>
</LinearLayout> </LinearLayout>

View File

@@ -3,9 +3,18 @@
<string name="title">🌜 LunaTracker 🌛</string> <string name="title">🌜 LunaTracker 🌛</string>
<string name="logbook">Ereignisprotokoll</string> <string name="logbook">Ereignisprotokoll</string>
<string name="log_bottle_dialog_title">Fläschchen</string>
<string name="log_bottle_dialog_description">Trinkmenge eingeben</string>
<string name="log_weight_dialog_title">Gewicht</string>
<string name="log_weight_dialog_description">Gewicht eingeben</string>
<string name="log_temperature_dialog_title">Temperatur</string>
<string name="log_temperature_dialog_description">Temperatur eingeben</string>
<string name="event_bottle_desc">Fläschchen</string> <string name="event_bottle_desc">Fläschchen</string>
<string name="event_food_desc">Essen</string> <string name="event_food_desc">Essen</string>
<string name="event_weight_desc">Gewicht</string> <string name="event_scale_desc">Gewicht</string>
<string name="event_breastfeeding_left_desc">Stillen (links)</string> <string name="event_breastfeeding_left_desc">Stillen (links)</string>
<string name="event_breastfeeding_both_desc">Stillen</string> <string name="event_breastfeeding_both_desc">Stillen</string>
<string name="event_breastfeeding_right_desc">Stillen (rechts)</string> <string name="event_breastfeeding_right_desc">Stillen (rechts)</string>
@@ -18,7 +27,7 @@
<string name="event_colic_desc">Blähungskolik</string> <string name="event_colic_desc">Blähungskolik</string>
<string name="event_unknown_desc"></string> <string name="event_unknown_desc"></string>
<string name="overflow_event_weight">⚖️ Gewicht</string> <string name="overflow_event_scale">⚖️ Gewicht</string>
<string name="overflow_event_medicine">💊 Medikament</string> <string name="overflow_event_medicine">💊 Medikament</string>
<string name="overflow_event_enema">🪠 Einlauf</string> <string name="overflow_event_enema">🪠 Einlauf</string>
<string name="overflow_event_note">📝 Notiz</string> <string name="overflow_event_note">📝 Notiz</string>
@@ -41,8 +50,9 @@
<string name="no_connection_go_to_settings">Einstellungen</string> <string name="no_connection_go_to_settings">Einstellungen</string>
<string name="no_connection_retry">Erneut versuchen</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_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">Speicherort für Daten auswählen</string>
<string name="settings_storage_local">Auf dem Gerät</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> <string name="settings_storage_local_desc">Datenschutzfreundlichste Lösung: Deine Daten verlassen dein Gerät nicht</string>
@@ -68,13 +78,10 @@
<string name="trim_logbook_dialog_button_ok">Jetzt bereinigen</string> <string name="trim_logbook_dialog_button_ok">Jetzt bereinigen</string>
<string name="trim_logbook_dialog_button_cancel">Später erinnern</string> <string name="trim_logbook_dialog_button_cancel">Später erinnern</string>
<string name="log_bottle_dialog_description">Trinkmenge eingeben</string>
<string name="log_medicine_dialog_description">Medikamentenname, Menge, Art, Notizen, …:</string>
<string name="log_notes_dialog_description">Notizen:</string> <string name="log_notes_dialog_description">Notizen:</string>
<string name="log_notes_dialog_note_hint">Notiz eingeben</string> <string name="log_medicine_dialog_description">Medikamentenname, Menge, Art, Notizen, …:</string>
<string name="log_notes_dialog_qty_hint">Menge (optional)</string> <string name="log_notes_dialog_qty_hint">Menge (optional)</string>
<string name="log_temperature_dialog_description">Temperatur eingeben</string> <string name="log_notes_dialog_note_hint">Notiz eingeben</string>
<string name="log_weight_dialog_description">Gewicht eingeben</string>
<string name="dialog_event_detail_title">Ereignisdetails</string> <string name="dialog_event_detail_title">Ereignisdetails</string>
<string name="dialog_event_detail_close_button">OK</string> <string name="dialog_event_detail_close_button">OK</string>

View File

@@ -3,9 +3,18 @@
<string name="title">🌜 LunaTracker 🌛</string> <string name="title">🌜 LunaTracker 🌛</string>
<string name="logbook">Entrées enregistrées</string> <string name="logbook">Entrées enregistrées</string>
<string name="log_bottle_dialog_title">Biberon</string>
<string name="log_bottle_dialog_description">Renseignez la quantité contenue dans le biberon</string>
<string name="log_weight_dialog_title">Poids</string>
<string name="log_weight_dialog_description">Renseignez le poids</string>
<string name="log_temperature_dialog_title">Température</string>
<string name="log_temperature_dialog_description">Renseignez la Température</string>
<string name="event_bottle_desc">Biberon</string> <string name="event_bottle_desc">Biberon</string>
<string name="event_food_desc">Nourriture</string> <string name="event_food_desc">Nourriture</string>
<string name="event_weight_desc">Poids</string> <string name="event_scale_desc">Poids</string>
<string name="event_breastfeeding_left_desc">Allaitement (sein gauche)</string> <string name="event_breastfeeding_left_desc">Allaitement (sein gauche)</string>
<string name="event_breastfeeding_both_desc">Allaitement</string> <string name="event_breastfeeding_both_desc">Allaitement</string>
<string name="event_breastfeeding_right_desc">Allaitement (sein droit)</string> <string name="event_breastfeeding_right_desc">Allaitement (sein droit)</string>
@@ -18,7 +27,7 @@
<string name="event_colic_desc">Colique gazeuse</string> <string name="event_colic_desc">Colique gazeuse</string>
<string name="event_unknown_desc"></string> <string name="event_unknown_desc"></string>
<string name="overflow_event_weight">⚖️ Poids</string> <string name="overflow_event_scale">⚖️ Poids</string>
<string name="overflow_event_medicine">💊 Médicament</string> <string name="overflow_event_medicine">💊 Médicament</string>
<string name="overflow_event_enema">🪠 Lavement</string> <string name="overflow_event_enema">🪠 Lavement</string>
<string name="overflow_event_note">📝 Note</string> <string name="overflow_event_note">📝 Note</string>
@@ -67,13 +76,10 @@
<string name="trim_logbook_dialog_button_ok">Supprimer les vieilles entrées maintenant</string> <string name="trim_logbook_dialog_button_ok">Supprimer les vieilles entrées maintenant</string>
<string name="trim_logbook_dialog_button_cancel">Me rappeller plus tard</string> <string name="trim_logbook_dialog_button_cancel">Me rappeller plus tard</string>
<string name="log_bottle_dialog_description">Renseignez la quantité contenue dans le biberon</string>
<string name="log_medicine_dialog_description">nom du médicament, quantité, type, notes …:</string>
<string name="log_notes_dialog_description">Notes:</string> <string name="log_notes_dialog_description">Notes:</string>
<string name="log_notes_dialog_note_hint">Notes ...</string> <string name="log_medicine_dialog_description">nom du médicament, quantité, type, notes …:</string>
<string name="log_notes_dialog_qty_hint">Quantité (ou vide)</string> <string name="log_notes_dialog_qty_hint">Quantité (ou vide)</string>
<string name="log_temperature_dialog_description">Renseignez la Température</string> <string name="log_notes_dialog_note_hint">Notes ...</string>
<string name="log_weight_dialog_description">Renseignez le poids</string>
<string name="dialog_event_detail_title">Détails de l\'entrée</string> <string name="dialog_event_detail_title">Détails de l\'entrée</string>
<string name="dialog_event_detail_close_button">OK</string> <string name="dialog_event_detail_close_button">OK</string>

View File

@@ -3,7 +3,16 @@
<string name="title">🌜 LunaTracker 🌛</string> <string name="title">🌜 LunaTracker 🌛</string>
<string name="logbook">Diario di bordo</string> <string name="logbook">Diario di bordo</string>
<string name="overflow_event_weight">⚖️ Peso</string> <string name="log_bottle_dialog_title">Biberon</string>
<string name="log_bottle_dialog_description">Inserisci la quantità contenuta nel biberon</string>
<string name="log_weight_dialog_title">Pesata</string>
<string name="log_weight_dialog_description">Inserisci il peso rilevato</string>
<string name="log_temperature_dialog_title">Temperatura</string>
<string name="log_temperature_dialog_description">Inserisci la temperatura</string>
<string name="overflow_event_scale">⚖️ Peso</string>
<string name="overflow_event_medicine">💊 Medicina</string> <string name="overflow_event_medicine">💊 Medicina</string>
<string name="overflow_event_enema">🪠 Clistere</string> <string name="overflow_event_enema">🪠 Clistere</string>
<string name="overflow_event_note">📝 Nota</string> <string name="overflow_event_note">📝 Nota</string>
@@ -12,7 +21,7 @@
<string name="event_bottle_desc">Biberon</string> <string name="event_bottle_desc">Biberon</string>
<string name="event_food_desc">Cibo</string> <string name="event_food_desc">Cibo</string>
<string name="event_weight_desc">Pesata</string> <string name="event_scale_desc">Pesata</string>
<string name="event_breastfeeding_left_desc">Allatt. al seno (sx)</string> <string name="event_breastfeeding_left_desc">Allatt. al seno (sx)</string>
<string name="event_breastfeeding_both_desc">Allatt. al seno</string> <string name="event_breastfeeding_both_desc">Allatt. al seno</string>
<string name="event_breastfeeding_right_desc">Allatt. al seno (dx)</string> <string name="event_breastfeeding_right_desc">Allatt. al seno (dx)</string>
@@ -67,13 +76,10 @@
<string name="trim_logbook_dialog_button_ok">Cancella i più vecchi</string> <string name="trim_logbook_dialog_button_ok">Cancella i più vecchi</string>
<string name="trim_logbook_dialog_button_cancel">Ricordamelo dopo</string> <string name="trim_logbook_dialog_button_cancel">Ricordamelo dopo</string>
<string name="log_bottle_dialog_description">Inserisci la quantità contenuta nel biberon</string>
<string name="log_medicine_dialog_description">Nome della medicina, quantità, formato, note…:</string>
<string name="log_notes_dialog_description">Note:</string> <string name="log_notes_dialog_description">Note:</string>
<string name="log_notes_dialog_note_hint">Inserisci le note</string> <string name="log_medicine_dialog_description">Nome della medicina, quantità, formato, note…:</string>
<string name="log_notes_dialog_qty_hint">Quantità, o vuoto</string> <string name="log_notes_dialog_qty_hint">Quantità, o vuoto</string>
<string name="log_temperature_dialog_description">Inserisci la temperatura</string> <string name="log_notes_dialog_note_hint">Inserisci le note</string>
<string name="log_weight_dialog_description">Inserisci il peso rilevato</string>
<string name="dialog_event_detail_title">Dettaglio evento</string> <string name="dialog_event_detail_title">Dettaglio evento</string>
<string name="dialog_event_detail_close_button">OK</string> <string name="dialog_event_detail_close_button">OK</string>

View File

@@ -1,42 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="AmountLabels">
<item>@string/amount_unspecified</item>
<item>@string/amount_little</item>
<item>@string/amount_normal</item>
<item>@string/amount_plenty</item>
</string-array>
<string-array name="StatisticsTypeLabels">
<item>Bottle</item>
<item>Sleep</item>
</string-array>
<string-array name="StatisticsTypeValues">
<item>BOTTLE</item>
<item>SLEEP</item>
</string-array>
<string-array name="StatisticsDataLabels">
<item>Event</item>
<item>Amount</item>
</string-array>
<string-array name="StatisticsDataValues">
<item>EVENT</item>
<item>AMOUNT</item>
</string-array>
<string-array name="StatisticsTimeLabels">
<item>Day</item>
<item>Week</item>
<item>Month</item>
</string-array>
<string-array name="StatisticsTimeValues">
<item>DAY</item>
<item>WEEK</item>
<item>MONTH</item>
</string-array>
</resources>

View File

@@ -3,9 +3,18 @@
<string name="title">🌜 LunaTracker 🌛</string> <string name="title">🌜 LunaTracker 🌛</string>
<string name="logbook">Logged events</string> <string name="logbook">Logged events</string>
<string name="log_bottle_dialog_title">Baby bottle</string>
<string name="log_bottle_dialog_description">Insert the quantity contained in the baby bottle</string>
<string name="log_weight_dialog_title">Weight</string>
<string name="log_weight_dialog_description">Insert the weight</string>
<string name="log_temperature_dialog_title">Temperature</string>
<string name="log_temperature_dialog_description">Insert the temperature</string>
<string name="event_bottle_type" translatable="false">🍼</string> <string name="event_bottle_type" translatable="false">🍼</string>
<string name="event_food_type" translatable="false">🥣</string> <string name="event_food_type" translatable="false">🥣</string>
<string name="event_weight_type" translatable="false">⚖️</string> <string name="event_scale_type" translatable="false">⚖️</string>
<string name="event_breastfeeding_left_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_both_type" translatable="false">🤱 ↔</string>
<string name="event_breastfeeding_right_type" translatable="false">🤱 →</string> <string name="event_breastfeeding_right_type" translatable="false">🤱 →</string>
@@ -18,12 +27,11 @@
<string name="event_colic_type" translatable="false">💨</string> <string name="event_colic_type" translatable="false">💨</string>
<string name="event_puke_type" translatable="false">🤮</string> <string name="event_puke_type" translatable="false">🤮</string>
<string name="event_bath_type" translatable="false">🛁</string> <string name="event_bath_type" translatable="false">🛁</string>
<string name="event_sleep_type" translatable="false">💤</string>
<string name="event_unknown_type" translatable="false">\?</string> <string name="event_unknown_type" translatable="false">\?</string>
<string name="event_bottle_desc">Baby bottle</string> <string name="event_bottle_desc">Baby bottle</string>
<string name="event_food_desc">Food</string> <string name="event_food_desc">Food</string>
<string name="event_weight_desc">Weight</string> <string name="event_scale_desc">Weight</string>
<string name="event_breastfeeding_left_desc">Breastfeeding (left)</string> <string name="event_breastfeeding_left_desc">Breastfeeding (left)</string>
<string name="event_breastfeeding_both_desc">Breastfeeding</string> <string name="event_breastfeeding_both_desc">Breastfeeding</string>
<string name="event_breastfeeding_right_desc">Breastfeeding (right)</string> <string name="event_breastfeeding_right_desc">Breastfeeding (right)</string>
@@ -36,24 +44,21 @@
<string name="event_colic_desc">Gaseous colic</string> <string name="event_colic_desc">Gaseous colic</string>
<string name="event_puke_desc">Puke</string> <string name="event_puke_desc">Puke</string>
<string name="event_bath_desc">Bath</string> <string name="event_bath_desc">Bath</string>
<string name="event_sleep_desc">Sleep</string>
<string name="event_unknown_desc"></string> <string name="event_unknown_desc"></string>
<string name="overflow_event_weight">⚖️ Weight</string> <string name="overflow_event_scale">⚖️ Weight</string>
<string name="overflow_event_medicine">💊 Medicine</string> <string name="overflow_event_medicine">💊 Medicine</string>
<string name="overflow_event_enema">🪠 Enema</string> <string name="overflow_event_enema">🪠 Enema</string>
<string name="overflow_event_note">📝 Note</string> <string name="overflow_event_note">📝 Note</string>
<string name="overflow_event_temperature">🌡️ Temperature</string> <string name="overflow_event_temperature">🌡️ Temperature</string>
<string name="overflow_event_colic">💨 Gaseous colic</string> <string name="overflow_event_colic">💨 Gaseous colic</string>
<string name="overflow_event_puke">🤮 Puke</string> <string name="overflow_event_puke">🤮 Puke</string>
<string name="overflow_event_sleep">💤 Sleep</string>
<string name="overflow_event_bath">🛁 Bath</string> <string name="overflow_event_bath">🛁 Bath</string>
<string name="toast_event_added">Event logged</string> <string name="toast_event_added">Event logged</string>
<string name="toast_logbook_saved">Logbook saved</string> <string name="toast_logbook_saved">Logbook saved</string>
<string name="toast_event_add_error">Unable to log the event</string> <string name="toast_event_add_error">Unable to log the event</string>
<string name="toast_integer_error">Invalid value. Insert an integer.</string> <string name="toast_integer_error">Invalid value. Insert an integer.</string>
<string name="toast_date_error">Invalid date.</string>
<string name="now">now</string> <string name="now">now</string>
<string name="second_ago">sec</string> <string name="second_ago">sec</string>
@@ -67,18 +72,11 @@
<string name="year_ago">year</string> <string name="year_ago">year</string>
<string name="years_ago">years</string> <string name="years_ago">years</string>
<string name="amount_unspecified"></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">No connection</string>
<string name="no_connection_explain">Unable to reach WebDAV service</string> <string name="no_connection_explain">Unable to reach WebDAV service</string>
<string name="no_connection_go_to_settings">Settings</string> <string name="no_connection_go_to_settings">Settings</string>
<string name="no_connection_retry">Retry</string> <string name="no_connection_retry">Retry</string>
<string name="statistics_title">Statistics</string>
<string name="settings_title">Settings</string> <string name="settings_title">Settings</string>
<string name="settings_signature">Signature</string> <string name="settings_signature">Signature</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_signature_desc">Attach a signature to each event you create and for others to see. Useful if multiple people add events.</string>
@@ -109,16 +107,10 @@
<string name="trim_logbook_dialog_button_ok">Trim it now</string> <string name="trim_logbook_dialog_button_ok">Trim it now</string>
<string name="trim_logbook_dialog_button_cancel">Remind me later</string> <string name="trim_logbook_dialog_button_cancel">Remind me later</string>
<string name="log_amount_dialog_description">Select the amount:</string>
<string name="log_bottle_dialog_description">Insert the quantity contained in the baby bottle:</string>
<string name="log_medicine_dialog_description">Medicine name, quantity, type, notes…:</string>
<string name="log_notes_dialog_description">Notes:</string> <string name="log_notes_dialog_description">Notes:</string>
<string name="log_notes_dialog_note_hint">Write some notes</string> <string name="log_medicine_dialog_description">Medicine name, quantity, type, notes…:</string>
<string name="log_notes_dialog_qty_hint">Quantity (or empty)</string> <string name="log_notes_dialog_qty_hint">Quantity (or empty)</string>
<string name="log_temperature_dialog_description">Select the temperature:</string> <string name="log_notes_dialog_note_hint">Write some notes</string>
<string name="log_unknown_dialog_description"></string>
<string name="log_weight_dialog_description">Insert the weight:</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_liquid_base_metric" translatable="false">ml</string>
<string name="measurement_unit_weight_base_metric" translatable="false">g</string> <string name="measurement_unit_weight_base_metric" translatable="false">g</string>
@@ -134,8 +126,8 @@
<string name="row_luna_event_time">Time</string> <string name="row_luna_event_time">Time</string>
<string name="dialog_event_detail_title">Event detail</string> <string name="dialog_event_detail_title">Event detail</string>
<string name="dialog_event_detail_close_button">Close</string> <string name="dialog_event_detail_datetime_icon" translatable="false">🕒 %s</string>
<string name="dialog_event_detail_save_button">Save</string> <string name="dialog_event_detail_close_button">OK</string>
<string name="dialog_event_detail_delete_button">Delete</string> <string name="dialog_event_detail_delete_button">Delete</string>
<string name="dialog_event_detail_quantity">Quantity</string> <string name="dialog_event_detail_quantity">Quantity</string>
<string name="dialog_event_detail_notes">Notes</string> <string name="dialog_event_detail_notes">Notes</string>

View File

@@ -1,5 +1,5 @@
[versions] [versions]
agp = "8.12.0" agp = "8.13.0"
kotlin = "2.0.0" kotlin = "2.0.0"
coreKtx = "1.10.1" coreKtx = "1.10.1"
junit = "4.13.2" junit = "4.13.2"
@@ -9,8 +9,6 @@ lifecycleRuntimeKtx = "2.6.1"
activityCompose = "1.8.0" activityCompose = "1.8.0"
composeBom = "2024.04.01" composeBom = "2024.04.01"
appcompat = "1.7.0" appcompat = "1.7.0"
mpandroidchart = "v4.2.2"
mpandroidchartVersion = "v3.1.0"
recyclerview = "1.3.2" recyclerview = "1.3.2"
material = "1.12.0" material = "1.12.0"
@@ -32,8 +30,6 @@ androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit
androidx-material3 = { group = "androidx.compose.material3", name = "material3" } androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" } material = { group = "com.google.android.material", name = "material", version.ref = "material" }
mpandroidchart = { module = "com.github.PhilJay:MPAndroidChart", version.ref = "mpandroidchart" }
mpandroidchart-vv310 = { module = "com.github.PhilJay:MPAndroidChart", version.ref = "mpandroidchartVersion" }
[plugins] [plugins]
android-application = { id = "com.android.application", version.ref = "agp" } android-application = { id = "com.android.application", version.ref = "agp" }

View File

@@ -16,7 +16,7 @@ dependencyResolutionManagement {
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
maven(url = uri("https://jitpack.io")) maven(url = "https://jitpack.io")
} }
} }