Compare commits
4 Commits
07393faf41
...
v0.6
Author | SHA1 | Date | |
---|---|---|---|
05c34178a4 | |||
0d3be20e1e | |||
4c5c7bcf1a | |||
9fddd37fe9 |
@ -12,8 +12,8 @@ android {
|
|||||||
applicationId = "it.danieleverducci.lunatracker"
|
applicationId = "it.danieleverducci.lunatracker"
|
||||||
minSdk = 21
|
minSdk = 21
|
||||||
targetSdk = 34
|
targetSdk = 34
|
||||||
versionCode = 3
|
versionCode = 4
|
||||||
versionName = "0.5"
|
versionName = "0.6"
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package it.danieleverducci.lunatracker
|
package it.danieleverducci.lunatracker
|
||||||
|
|
||||||
|
import android.app.DatePickerDialog
|
||||||
|
import android.app.TimePickerDialog
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
@ -19,7 +21,6 @@ import android.widget.Toast
|
|||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.children
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.google.android.material.progressindicator.LinearProgressIndicator
|
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
@ -40,6 +41,7 @@ import okio.IOException
|
|||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
import utils.NumericUtils
|
import utils.NumericUtils
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
|
import java.util.Calendar
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity() {
|
class MainActivity : AppCompatActivity() {
|
||||||
@ -50,14 +52,14 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var logbook: Logbook? = null
|
var logbook: Logbook? = null
|
||||||
lateinit var adapter: LunaEventRecyclerAdapter
|
var pauseLogbookUpdate = false
|
||||||
lateinit var progressIndicator: LinearProgressIndicator
|
lateinit var progressIndicator: LinearProgressIndicator
|
||||||
lateinit var buttonsContainer: ViewGroup
|
lateinit var buttonsContainer: ViewGroup
|
||||||
lateinit var recyclerView: RecyclerView
|
lateinit var recyclerView: RecyclerView
|
||||||
lateinit var handler: Handler
|
lateinit var handler: Handler
|
||||||
var savingEvent = false
|
var savingEvent = false
|
||||||
val updateListRunnable: Runnable = Runnable {
|
val updateListRunnable: Runnable = Runnable {
|
||||||
if (logbook != null)
|
if (logbook != null && !pauseLogbookUpdate)
|
||||||
loadLogbook(logbook!!.name)
|
loadLogbook(logbook!!.name)
|
||||||
handler.postDelayed(updateListRunnable, 1000*60)
|
handler.postDelayed(updateListRunnable, 1000*60)
|
||||||
}
|
}
|
||||||
@ -68,12 +70,6 @@ class MainActivity : AppCompatActivity() {
|
|||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
handler = Handler(mainLooper)
|
handler = Handler(mainLooper)
|
||||||
adapter = LunaEventRecyclerAdapter(this)
|
|
||||||
adapter.onItemClickListener = object: LunaEventRecyclerAdapter.OnItemClickListener{
|
|
||||||
override fun onItemClick(event: LunaEvent) {
|
|
||||||
showEventDetailDialog(event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show view
|
// Show view
|
||||||
setContentView(R.layout.activity_main)
|
setContentView(R.layout.activity_main)
|
||||||
@ -82,7 +78,6 @@ class MainActivity : AppCompatActivity() {
|
|||||||
buttonsContainer = findViewById<ViewGroup>(R.id.buttons_container)
|
buttonsContainer = findViewById<ViewGroup>(R.id.buttons_container)
|
||||||
recyclerView = findViewById<RecyclerView>(R.id.list_events)
|
recyclerView = findViewById<RecyclerView>(R.id.list_events)
|
||||||
recyclerView.setLayoutManager(LinearLayoutManager(applicationContext))
|
recyclerView.setLayoutManager(LinearLayoutManager(applicationContext))
|
||||||
recyclerView.adapter = adapter
|
|
||||||
|
|
||||||
// Set listeners
|
// Set listeners
|
||||||
findViewById<View>(R.id.logbooks_add_button).setOnClickListener { showAddLogbookDialog(true) }
|
findViewById<View>(R.id.logbooks_add_button).setOnClickListener { showAddLogbookDialog(true) }
|
||||||
@ -132,6 +127,16 @@ class MainActivity : AppCompatActivity() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setListAdapter(items: ArrayList<LunaEvent>) {
|
||||||
|
val adapter = LunaEventRecyclerAdapter(this, items)
|
||||||
|
adapter.onItemClickListener = object: LunaEventRecyclerAdapter.OnItemClickListener{
|
||||||
|
override fun onItemClick(event: LunaEvent) {
|
||||||
|
showEventDetailDialog(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
recyclerView.adapter = adapter
|
||||||
|
}
|
||||||
|
|
||||||
fun showSettings() {
|
fun showSettings() {
|
||||||
val i = Intent(this, SettingsActivity::class.java)
|
val i = Intent(this, SettingsActivity::class.java)
|
||||||
startActivity(i)
|
startActivity(i)
|
||||||
@ -142,9 +147,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
if (logbook == null)
|
if (logbook == null)
|
||||||
Log.w(TAG, "showLogbook(): logbook is null!")
|
Log.w(TAG, "showLogbook(): logbook is null!")
|
||||||
|
|
||||||
adapter.items.clear()
|
setListAdapter(logbook?.logs ?: arrayListOf())
|
||||||
adapter.items.addAll(logbook?.logs ?: listOf())
|
|
||||||
adapter.notifyDataSetChanged()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
@ -166,7 +169,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update list dates
|
// Update list dates
|
||||||
adapter.notifyDataSetChanged()
|
recyclerView.adapter?.notifyDataSetChanged()
|
||||||
|
|
||||||
if (logbook != null) {
|
if (logbook != null) {
|
||||||
// Already running: reload data for currently selected logbook
|
// Already running: reload data for currently selected logbook
|
||||||
@ -300,23 +303,57 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun showEventDetailDialog(event: LunaEvent) {
|
fun showEventDetailDialog(event: LunaEvent) {
|
||||||
|
// Do not update list while the detail is shown, to avoid changing the object below while it is changed by the user
|
||||||
|
pauseLogbookUpdate = true
|
||||||
val dateFormat = DateFormat.getDateTimeInstance();
|
val dateFormat = DateFormat.getDateTimeInstance();
|
||||||
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)
|
val dialogView = layoutInflater.inflate(R.layout.dialog_event_detail, null)
|
||||||
dialogView.findViewById<TextView>(R.id.dialog_event_detail_type_emoji).setText(event.getTypeEmoji(this))
|
dialogView.findViewById<TextView>(R.id.dialog_event_detail_type_emoji).setText(event.getTypeEmoji(this))
|
||||||
dialogView.findViewById<TextView>(R.id.dialog_event_detail_type_description).setText(event.getTypeDescription(this))
|
dialogView.findViewById<TextView>(R.id.dialog_event_detail_type_description).setText(event.getTypeDescription(this))
|
||||||
dialogView.findViewById<TextView>(R.id.dialog_event_detail_type_date).setText(dateFormat.format(Date(event.time * 1000)))
|
|
||||||
dialogView.findViewById<TextView>(R.id.dialog_event_detail_type_quantity).setText(
|
dialogView.findViewById<TextView>(R.id.dialog_event_detail_type_quantity).setText(
|
||||||
NumericUtils(this).formatEventQuantity(event)
|
NumericUtils(this).formatEventQuantity(event)
|
||||||
)
|
)
|
||||||
dialogView.findViewById<TextView>(R.id.dialog_event_detail_type_notes).setText(event.notes)
|
dialogView.findViewById<TextView>(R.id.dialog_event_detail_type_notes).setText(event.notes)
|
||||||
|
|
||||||
|
val currentDateTime = Calendar.getInstance()
|
||||||
|
currentDateTime.time = Date(event.time * 1000)
|
||||||
|
val dateTextView = dialogView.findViewById<TextView>(R.id.dialog_event_detail_type_date)
|
||||||
|
dateTextView.text = String.format(getString(R.string.dialog_event_detail_datetime_icon), dateFormat.format(currentDateTime.time))
|
||||||
|
dateTextView.setOnClickListener({
|
||||||
|
// Show datetime picker
|
||||||
|
val startYear = currentDateTime.get(Calendar.YEAR)
|
||||||
|
val startMonth = currentDateTime.get(Calendar.MONTH)
|
||||||
|
val startDay = currentDateTime.get(Calendar.DAY_OF_MONTH)
|
||||||
|
val startHour = currentDateTime.get(Calendar.HOUR_OF_DAY)
|
||||||
|
val startMinute = currentDateTime.get(Calendar.MINUTE)
|
||||||
|
|
||||||
|
DatePickerDialog(this, DatePickerDialog.OnDateSetListener { _, year, month, day ->
|
||||||
|
TimePickerDialog(this, TimePickerDialog.OnTimeSetListener { _, hour, minute ->
|
||||||
|
val pickedDateTime = Calendar.getInstance()
|
||||||
|
pickedDateTime.set(year, month, day, hour, minute)
|
||||||
|
currentDateTime.time = pickedDateTime.time
|
||||||
|
dateTextView.text = String.format(getString(R.string.dialog_event_detail_datetime_icon), dateFormat.format(currentDateTime.time))
|
||||||
|
|
||||||
|
// Save event and move it to the right position in the logbook
|
||||||
|
event.time = currentDateTime.time.time / 1000 // Seconds since epoch
|
||||||
|
logbook?.sort()
|
||||||
|
recyclerView.adapter?.notifyDataSetChanged()
|
||||||
|
saveLogbook()
|
||||||
|
}, startHour, startMinute, false).show()
|
||||||
|
}, startYear, startMonth, startDay).show()
|
||||||
|
})
|
||||||
|
|
||||||
d.setView(dialogView)
|
d.setView(dialogView)
|
||||||
d.setPositiveButton(android.R.string.ok) { dialogInterface, i -> dialogInterface.dismiss() }
|
d.setPositiveButton(R.string.dialog_event_detail_close_button) { dialogInterface, i -> dialogInterface.dismiss() }
|
||||||
d.setNeutralButton(R.string.dialog_event_detail_delete_button) { dialogInterface, i -> deleteEvent(event) }
|
d.setNeutralButton(R.string.dialog_event_detail_delete_button) { dialogInterface, i -> deleteEvent(event) }
|
||||||
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(ContextCompat.getColor(this, R.color.danger))
|
||||||
|
alertDialog.setOnDismissListener({
|
||||||
|
// Resume logbook update
|
||||||
|
pauseLogbookUpdate = false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fun showAddLogbookDialog(requestedByUser: Boolean) {
|
fun showAddLogbookDialog(requestedByUser: Boolean) {
|
||||||
@ -367,8 +404,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
id: Long
|
id: Long
|
||||||
) {
|
) {
|
||||||
// Changed logbook: empty list
|
// Changed logbook: empty list
|
||||||
adapter.items.clear()
|
setListAdapter(arrayListOf())
|
||||||
adapter.notifyDataSetChanged()
|
|
||||||
// Load logbook
|
// Load logbook
|
||||||
loadLogbook(logbooksNames.get(position))
|
loadLogbook(logbooksNames.get(position))
|
||||||
}
|
}
|
||||||
@ -538,12 +574,11 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
fun logEvent(event: LunaEvent) {
|
fun logEvent(event: LunaEvent) {
|
||||||
savingEvent(true)
|
savingEvent(true)
|
||||||
adapter.items.add(0, event)
|
|
||||||
adapter.notifyItemInserted(0)
|
|
||||||
recyclerView.smoothScrollToPosition(0)
|
|
||||||
|
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
logbook?.logs?.add(0, event)
|
logbook?.logs?.add(0, event)
|
||||||
|
recyclerView.adapter?.notifyItemInserted(0)
|
||||||
|
recyclerView.smoothScrollToPosition(0)
|
||||||
saveLogbook(event)
|
saveLogbook(event)
|
||||||
|
|
||||||
// Check logbook size to avoid OOM errors
|
// Check logbook size to avoid OOM errors
|
||||||
@ -555,12 +590,11 @@ class MainActivity : AppCompatActivity() {
|
|||||||
fun deleteEvent(event: LunaEvent) {
|
fun deleteEvent(event: LunaEvent) {
|
||||||
// Update view
|
// Update view
|
||||||
savingEvent(true)
|
savingEvent(true)
|
||||||
adapter.items.remove(event)
|
|
||||||
adapter.notifyDataSetChanged()
|
|
||||||
|
|
||||||
// Update data
|
// Update data
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
logbook?.logs?.remove(event)
|
logbook?.logs?.remove(event)
|
||||||
|
recyclerView.adapter?.notifyDataSetChanged()
|
||||||
saveLogbook()
|
saveLogbook()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -643,8 +677,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
setLoading(false)
|
setLoading(false)
|
||||||
|
|
||||||
Toast.makeText(this@MainActivity, R.string.toast_event_add_error, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this@MainActivity, R.string.toast_event_add_error, Toast.LENGTH_SHORT).show()
|
||||||
adapter.items.remove(event)
|
recyclerView.adapter?.notifyDataSetChanged()
|
||||||
adapter.notifyDataSetChanged()
|
|
||||||
savingEvent(false)
|
savingEvent(false)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -14,13 +14,14 @@ import utils.NumericUtils
|
|||||||
|
|
||||||
class LunaEventRecyclerAdapter: RecyclerView.Adapter<LunaEventRecyclerAdapter.LunaEventVH> {
|
class LunaEventRecyclerAdapter: RecyclerView.Adapter<LunaEventRecyclerAdapter.LunaEventVH> {
|
||||||
private val context: Context
|
private val context: Context
|
||||||
val items = ArrayList<LunaEvent>()
|
private val items: ArrayList<LunaEvent>
|
||||||
val numericUtils: NumericUtils
|
val numericUtils: NumericUtils
|
||||||
var onItemClickListener: OnItemClickListener? = null
|
var onItemClickListener: OnItemClickListener? = null
|
||||||
val layoutRes: Int
|
val layoutRes: Int
|
||||||
|
|
||||||
constructor(context: Context) {
|
constructor(context: Context, items: ArrayList<LunaEvent>) {
|
||||||
this.context = context
|
this.context = context
|
||||||
|
this.items = items
|
||||||
this.numericUtils = NumericUtils(context)
|
this.numericUtils = NumericUtils(context)
|
||||||
|
|
||||||
val fontScale = context.resources.configuration.fontScale
|
val fontScale = context.resources.configuration.fontScale
|
||||||
|
@ -16,4 +16,8 @@ class Logbook(val name: String) {
|
|||||||
fun trim() {
|
fun trim() {
|
||||||
logs.subList(MAX_SAFE_LOGBOOK_SIZE/2, logs.size).clear()
|
logs.subList(MAX_SAFE_LOGBOOK_SIZE/2, logs.size).clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun sort() {
|
||||||
|
logs.sortDescending()
|
||||||
|
}
|
||||||
}
|
}
|
@ -11,7 +11,7 @@ import java.util.Date
|
|||||||
* allow expandability and backwards compatibility (if a field is added in a
|
* allow expandability and backwards compatibility (if a field is added in a
|
||||||
* release, it is simply ignored by previous ones).
|
* release, it is simply ignored by previous ones).
|
||||||
*/
|
*/
|
||||||
class LunaEvent {
|
class LunaEvent: Comparable<LunaEvent> {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val TYPE_BABY_BOTTLE = "BABY_BOTTLE"
|
val TYPE_BABY_BOTTLE = "BABY_BOTTLE"
|
||||||
@ -130,4 +130,8 @@ class LunaEvent {
|
|||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "${type} qty: $quantity time: ${Date(time * 1000)}"
|
return "${type} qty: $quantity time: ${Date(time * 1000)}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun compareTo(other: LunaEvent): Int {
|
||||||
|
return (this.time - other.time).toInt()
|
||||||
|
}
|
||||||
}
|
}
|
5
app/src/main/res/drawable/ic_edit.xml
Normal file
5
app/src/main/res/drawable/ic_edit.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||||
|
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
|
||||||
|
|
||||||
|
</vector>
|
@ -25,19 +25,23 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/dialog_event_detail_type_date"
|
android:id="@+id/dialog_event_detail_type_date"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="40dp"
|
||||||
android:layout_marginTop="20dp"
|
android:layout_marginTop="20dp"
|
||||||
android:gravity="center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:drawableEnd="@drawable/ic_edit"
|
||||||
|
android:drawablePadding="10dp"
|
||||||
|
android:drawableTint="@color/accent"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:text="2020"/>
|
android:text="@string/dialog_event_detail_datetime_icon"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/dialog_event_detail_type_quantity"
|
android:id="@+id/dialog_event_detail_type_quantity"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:text="2020"/>
|
android:text="Quantity"/>
|
||||||
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -49,7 +53,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textStyle="italic"
|
android:textStyle="italic"
|
||||||
android:text="Lorem ipsum"/>
|
android:text="Notes"/>
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
@ -83,7 +83,7 @@
|
|||||||
<string name="log_notes_dialog_note_hint">Inserisci le note</string>
|
<string name="log_notes_dialog_note_hint">Inserisci le note</string>
|
||||||
|
|
||||||
<string name="dialog_event_detail_title">Dettaglio evento</string>
|
<string name="dialog_event_detail_title">Dettaglio evento</string>
|
||||||
<string name="dialog_event_detail_save_button">Salva</string>
|
<string name="dialog_event_detail_close_button">OK</string>
|
||||||
<string name="dialog_event_detail_delete_button">Elimina</string>
|
<string name="dialog_event_detail_delete_button">Elimina</string>
|
||||||
|
|
||||||
<string name="dialog_add_logbook_title">Aggiungi diario</string>
|
<string name="dialog_add_logbook_title">Aggiungi diario</string>
|
||||||
|
@ -107,7 +107,8 @@
|
|||||||
<string name="measurement_unit_temperature_base_metric" translatable="false">°C</string>
|
<string name="measurement_unit_temperature_base_metric" translatable="false">°C</string>
|
||||||
|
|
||||||
<string name="dialog_event_detail_title">Event detail</string>
|
<string name="dialog_event_detail_title">Event detail</string>
|
||||||
<string name="dialog_event_detail_save_button">Save</string>
|
<string name="dialog_event_detail_datetime_icon" translatable="false">🕒 %s1</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_add_logbook_title">Add logbook</string>
|
<string name="dialog_add_logbook_title">Add logbook</string>
|
||||||
|
Reference in New Issue
Block a user