forked from penguin86/luna-tracker
Compare commits
1 Commits
20d7612b46
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 8c906369df |
19
README.md
19
README.md
@@ -13,7 +13,24 @@ Dedicated to my daughter Luna.
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Thanks for the valuable contributions to:
|
## Contributions
|
||||||
|
|
||||||
|
### Why isn't this hosted on GitHub?
|
||||||
|
|
||||||
|
I'm using a private git server just because I'm worried for the vast majority of open source code being hosted in a server property of Microsoft and being used to train theirs AI.
|
||||||
|
I didn't find a better option, BTW the Gitea project is working on implementing federation, so soon it will be possible to contribute using any other gitea server, selfhosted or not.
|
||||||
|
|
||||||
|
### How to contribute
|
||||||
|
|
||||||
|
The project is open to contribution, but with some limits:
|
||||||
|
|
||||||
|
- I'm sorry I can't accept AI-generated contributions. Reviewing a contribution requires time and effort from my side, while generating code with AI requires very little time and produces non reliable code that must be reviewed in detail. This is effectively shifting the work on my side, and in a forced way. If you feel you need a feature but you're not able to implement it by yourself, I prefer you to create an issue in the repository so I can implement it when I can, in a more mantainable way.
|
||||||
|
- I prefer to make project-wide changes (i.e. updating Android target, app name and icon, release number...) by myself.
|
||||||
|
|
||||||
|
To contribute, you'll have to create an account on this git instance. Unfortunately, I had to disable registration to avoid huge waves of fake accounts created by bots.
|
||||||
|
You can request an account writing to daniele.verducci@ichibi.eu
|
||||||
|
|
||||||
|
### Thanks for the valuable contributions to:
|
||||||
|
|
||||||
- Chepycou (French translation)
|
- Chepycou (French translation)
|
||||||
- Daniel Neubauer (German translation)
|
- Daniel Neubauer (German translation)
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ plugins {
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "it.danieleverducci.lunatracker"
|
namespace = "it.danieleverducci.lunatracker"
|
||||||
compileSdk = 36
|
compileSdk = 34
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "it.danieleverducci.lunatracker"
|
applicationId = "it.danieleverducci.lunatracker"
|
||||||
minSdk = 21
|
minSdk = 21
|
||||||
targetSdk = 36
|
targetSdk = 34
|
||||||
versionCode = 7
|
versionCode = 7
|
||||||
versionName = "0.9"
|
versionName = "0.9"
|
||||||
|
|
||||||
@@ -31,12 +31,6 @@ android {
|
|||||||
sourceCompatibility = JavaVersion.VERSION_11
|
sourceCompatibility = JavaVersion.VERSION_11
|
||||||
targetCompatibility = JavaVersion.VERSION_11
|
targetCompatibility = JavaVersion.VERSION_11
|
||||||
}
|
}
|
||||||
dependenciesInfo {
|
|
||||||
// Disables dependency metadata when building APKs.
|
|
||||||
includeInApk = false
|
|
||||||
// Disables dependency metadata when building Android App Bundles.
|
|
||||||
includeInBundle = false
|
|
||||||
}
|
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = "11"
|
jvmTarget = "11"
|
||||||
}
|
}
|
||||||
@@ -46,6 +40,7 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
implementation(libs.androidx.core.ktx)
|
implementation(libs.androidx.core.ktx)
|
||||||
implementation(libs.androidx.lifecycle.runtime.ktx)
|
implementation(libs.androidx.lifecycle.runtime.ktx)
|
||||||
implementation(libs.androidx.activity.compose)
|
implementation(libs.androidx.activity.compose)
|
||||||
@@ -56,7 +51,7 @@ dependencies {
|
|||||||
implementation(libs.androidx.material3)
|
implementation(libs.androidx.material3)
|
||||||
implementation(libs.androidx.appcompat)
|
implementation(libs.androidx.appcompat)
|
||||||
implementation(libs.androidx.recyclerview)
|
implementation(libs.androidx.recyclerview)
|
||||||
implementation(libs.sardine.android)
|
implementation("com.github.thegrizzlylabs:sardine-android:v0.9")
|
||||||
implementation(libs.material)
|
implementation(libs.material)
|
||||||
testImplementation(libs.junit)
|
testImplementation(libs.junit)
|
||||||
androidTestImplementation(libs.androidx.junit)
|
androidTestImplementation(libs.androidx.junit)
|
||||||
@@ -65,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)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -6,14 +6,12 @@ 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.NumberPicker
|
import android.widget.NumberPicker
|
||||||
import android.widget.PopupWindow
|
import android.widget.PopupWindow
|
||||||
@@ -51,8 +49,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 +62,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 +81,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 +130,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 +148,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 +195,118 @@ 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 askPukeValue() {
|
||||||
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.puke_dialog, null)
|
||||||
d.setTitle(event.getTypeDescription(this))
|
d.setTitle(R.string.log_puke_dialog_title)
|
||||||
d.setMessage(event.getDialogMessage(this))
|
d.setMessage(R.string.log_puke_dialog_description)
|
||||||
d.setView(dialogView)
|
d.setView(dialogView)
|
||||||
|
|
||||||
val durationTextView = dialogView.findViewById<TextView>(R.id.dialog_date_duration)
|
val spinner = dialogView.findViewById<Spinner>(R.id.dialog_puke_value)
|
||||||
val durationNowButton = dialogView.findViewById<Button>(R.id.dialog_date_duration_now)
|
spinner.adapter = ArrayAdapter.createFromResource(this, R.array.AmountLabels, android.R.layout.simple_spinner_dropdown_item)
|
||||||
val datePicker = dialogView.findViewById<TextView>(R.id.dialog_date_picker)
|
spinner.setSelection(1)
|
||||||
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 ->
|
d.setPositiveButton(android.R.string.ok) { dialogInterface, i ->
|
||||||
val time = pickedDateTime.time.time / 1000
|
val pos = spinner.selectedItemPosition
|
||||||
|
logEvent(LunaEvent(LunaEvent.TYPE_PUKE, pos + 1))
|
||||||
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() }
|
||||||
d.setNegativeButton(android.R.string.cancel) { dialogInterface, i ->
|
|
||||||
dialogInterface.dismiss()
|
|
||||||
}
|
|
||||||
|
|
||||||
val alertDialog = d.create()
|
val alertDialog = d.create()
|
||||||
alertDialog.show()
|
alertDialog.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addAmountEvent(event: LunaEvent) {
|
fun askNotes(lunaEvent: LunaEvent) {
|
||||||
askAmountValue(event, true) { saveEvent(event) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun askAmountValue(event: LunaEvent, showTime: Boolean, onPositive: () -> Unit) {
|
|
||||||
val d = AlertDialog.Builder(this)
|
val d = AlertDialog.Builder(this)
|
||||||
val dialogView = layoutInflater.inflate(R.layout.dialog_edit_amount, 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 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 +331,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 +345,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 +359,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 +416,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 +801,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))
|
askPukeValue()
|
||||||
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({
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,8 +62,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,21 @@ 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,
|
LunaEvent.TYPE_PUKE ->
|
||||||
LunaEvent.TYPE_DIAPERCHANGE_PEE,
|
context.resources.getStringArray(R.array.AmountLabels)[item.quantity - 1]
|
||||||
LunaEvent.TYPE_PUKE -> {
|
else ->
|
||||||
val array = context.resources.getStringArray(R.array.AmountLabels)
|
item.quantity
|
||||||
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 +82,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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -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>
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
<?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"
|
||||||
@@ -35,7 +36,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 +48,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"
|
||||||
@@ -24,34 +24,4 @@
|
|||||||
android:hint="@string/log_notes_dialog_note_hint"
|
android:hint="@string/log_notes_dialog_note_hint"
|
||||||
android:background="@drawable/textview_background"/>
|
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>
|
</LinearLayout>
|
||||||
@@ -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"
|
||||||
|
|||||||
22
app/src/main/res/layout/number_edit_dialog.xml
Normal file
22
app/src/main/res/layout/number_edit_dialog.xml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?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">
|
||||||
|
|
||||||
|
<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>
|
||||||
@@ -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>
|
||||||
@@ -8,15 +8,10 @@
|
|||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<Spinner
|
<Spinner
|
||||||
android:id="@+id/dialog_amount_value"
|
android:id="@+id/dialog_puke_value"
|
||||||
android:layout_width="250dp"
|
android:layout_width="250dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingHorizontal="16dp"/>
|
android:paddingHorizontal="16dp"
|
||||||
|
android:paddingVertical="8dp"/>
|
||||||
<TextView
|
|
||||||
android:id="@+id/dialog_date_picker"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="20dp"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
@@ -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" />
|
|
||||||
@@ -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>
|
||||||
@@ -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>
|
||||||
@@ -68,13 +77,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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -1,42 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string-array name="AmountLabels">
|
<string-array name="AmountLabels">
|
||||||
<item>@string/amount_unspecified</item>
|
|
||||||
<item>@string/amount_little</item>
|
<item>@string/amount_little</item>
|
||||||
<item>@string/amount_normal</item>
|
<item>@string/amount_normal</item>
|
||||||
<item>@string/amount_plenty</item>
|
<item>@string/amount_plenty</item>
|
||||||
</string-array>
|
</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>
|
</resources>
|
||||||
|
|||||||
@@ -3,9 +3,21 @@
|
|||||||
<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="log_puke_dialog_title">Puke</string>
|
||||||
|
<string name="log_puke_dialog_description">Select the amount</string>
|
||||||
|
|
||||||
<string name="event_bottle_type" translatable="false">🍼</string>
|
<string name="event_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 +30,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 +47,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,7 +75,6 @@
|
|||||||
<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_little">Little</string>
|
||||||
<string name="amount_normal">Normal</string>
|
<string name="amount_normal">Normal</string>
|
||||||
<string name="amount_plenty">Plenty</string>
|
<string name="amount_plenty">Plenty</string>
|
||||||
@@ -77,8 +84,6 @@
|
|||||||
<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 +114,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 +133,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>
|
||||||
|
|||||||
@@ -4,11 +4,6 @@
|
|||||||
<style name="Theme.LunaTracker" parent="Theme.AppCompat.NoActionBar">
|
<style name="Theme.LunaTracker" parent="Theme.AppCompat.NoActionBar">
|
||||||
<item name="colorAccent">@color/accent</item>
|
<item name="colorAccent">@color/accent</item>
|
||||||
<item name="android:textColor">@color/textColor</item>
|
<item name="android:textColor">@color/textColor</item>
|
||||||
|
|
||||||
<!-- make the screen not overlap with the system bars -->
|
|
||||||
<item name="android:fitsSystemWindows">true</item>
|
|
||||||
<item name="android:windowTranslucentStatus">true</item>
|
|
||||||
<item name="android:windowTranslucentNavigation">true</item>
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="OverflowMenuText">
|
<style name="OverflowMenuText">
|
||||||
|
|||||||
@@ -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,11 +9,8 @@ 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"
|
||||||
sardineAndroid = "v0.9"
|
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||||
@@ -33,9 +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" }
|
|
||||||
sardine-android = { module = "com.github.thegrizzlylabs:sardine-android", version.ref = "sardineAndroid" }
|
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ dependencyResolutionManagement {
|
|||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
maven(url = uri("https://jitpack.io"))
|
maven(url = "https://jitpack.io")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user