8 Commits

15 changed files with 336 additions and 159 deletions

1
.gitignore vendored
View File

@ -106,3 +106,4 @@ app/release/output-metadata.json
# Other
app/src/main/java/it/danieleverducci/lunatracker/TemporaryHardcodedCredentials.kt
.kotlin/sessions/*

View File

@ -7,13 +7,18 @@ import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.EditText
import android.widget.NumberPicker
import android.widget.PopupWindow
import android.widget.Spinner
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.children
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.progressindicator.LinearProgressIndicator
@ -51,7 +56,7 @@ class MainActivity : AppCompatActivity() {
lateinit var handler: Handler
var savingEvent = false
val updateListRunnable: Runnable = Runnable {
loadLogbook()
loadLogbook(logbook.name)
handler.postDelayed(updateListRunnable, 1000*60)
}
var logbookRepo: LogbookRepository? = null
@ -78,6 +83,7 @@ class MainActivity : AppCompatActivity() {
recyclerView.adapter = adapter
// Set listeners
findViewById<View>(R.id.logbooks_add_button).setOnClickListener { showAddLogbookDialog(true) }
findViewById<View>(R.id.button_bottle).setOnClickListener { askBabyBottleContent() }
findViewById<View>(R.id.button_scale).setOnClickListener { askWeightValue() }
findViewById<View>(R.id.button_nipple_left).setOnClickListener { logEvent(
@ -116,10 +122,10 @@ class MainActivity : AppCompatActivity() {
showSettings()
})
findViewById<View>(R.id.button_no_connection_retry).setOnClickListener({
loadLogbook()
loadLogbook(logbook.name)
})
findViewById<View>(R.id.button_sync).setOnClickListener({
loadLogbook()
loadLogbook(logbook.name)
})
}
@ -305,14 +311,22 @@ class MainActivity : AppCompatActivity() {
alertDialog.show()
}
fun showAddLogbookDialog() {
fun showAddLogbookDialog(requestedByUser: Boolean) {
val d = AlertDialog.Builder(this)
d.setTitle(R.string.dialog_add_logbook_title)
val dialogView = layoutInflater.inflate(R.layout.dialog_add_logbook, null)
dialogView.findViewById<TextView>(R.id.dialog_add_logbook_message).text = getString(
if (requestedByUser) R.string.dialog_add_logbook_message else R.string.dialog_add_logbook_message_intro
)
val logbookNameEditText = dialogView.findViewById<EditText>(R.id.dialog_add_logbook_logbookname)
d.setView(dialogView)
d.setPositiveButton(android.R.string.ok) { dialogInterface, i -> addLogbook(logbookNameEditText.text.toString()) }
d.setNegativeButton(android.R.string.cancel) { dialogInterface, i -> dialogInterface.dismiss() }
if (requestedByUser) {
d.setCancelable(true)
d.setNegativeButton(android.R.string.cancel) { dialogInterface, i -> dialogInterface.dismiss() }
} else {
d.setCancelable(false)
}
val alertDialog = d.create()
alertDialog.show()
}
@ -322,36 +336,38 @@ class MainActivity : AppCompatActivity() {
logbookRepo?.listLogbooks(this, object: LogbookListObtainedListener {
override fun onLogbookListObtained(logbooksNames: ArrayList<String>) {
runOnUiThread({
// Show logbooks buttons
val logbooksButtonsContainer =
findViewById<ViewGroup>(R.id.logbooks_buttons_container)
logbooksButtonsContainer.removeAllViews()
for (lbn in logbooksNames) {
val lbnButton = layoutInflater.inflate(
R.layout.logbook_button,
logbooksButtonsContainer,
false
) as TextView
lbnButton.setText(
if (lbn.isEmpty()) getString(R.string.default_logbook_name) else lbn
)
lbnButton.setOnClickListener({
loadLogbook(lbn)
})
logbooksButtonsContainer.addView(lbnButton)
if (logbooksNames.isEmpty()) {
// First run, no logbook: create one
showAddLogbookDialog(false)
return@runOnUiThread
}
// Show "Add logbook" button
val addLogbookButton = layoutInflater.inflate(
R.layout.logbook_button,
logbooksButtonsContainer,
false
) as TextView
addLogbookButton.setText("+")
addLogbookButton.setOnClickListener({showAddLogbookDialog()})
logbooksButtonsContainer.addView(addLogbookButton)
// Show logbooks dropdown
val spinner = findViewById<Spinner>(R.id.logbooks_spinner)
val sAdapter = ArrayAdapter<String>(this@MainActivity, android.R.layout.simple_spinner_item)
sAdapter.setDropDownViewResource(R.layout.row_logbook_spinner)
for (ln in logbooksNames) {
sAdapter.add(
if (ln.isEmpty()) getString(R.string.default_logbook_name) else ln
)
}
spinner.adapter = sAdapter
spinner.onItemSelectedListener = object: AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
// Changed logbook: empty list
adapter.items.clear()
adapter.notifyDataSetChanged()
// Load logbook
loadLogbook(logbooksNames.get(position))
}
// Load logbook
loadLogbook()
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
})
}
@ -370,17 +386,54 @@ class MainActivity : AppCompatActivity() {
}
fun addLogbook(logbookName: String) {
this.logbook = Logbook(logbookName)
saveLogbook()
loadLogbookList()
val newLogbook = Logbook(logbookName)
setLoading(true)
logbookRepo?.saveLogbook(this, newLogbook, object: LogbookSavedListener{
override fun onLogbookSaved() {
Log.d(TAG, "Logbook $logbookName created")
runOnUiThread({
setLoading(false)
loadLogbookList()
Toast.makeText(this@MainActivity, getString(R.string.logbook_created) + logbookName, Toast.LENGTH_SHORT).show()
})
}
override fun onIOError(error: IOException) {
runOnUiThread({
onRepoError(getString(R.string.settings_network_error) + error.toString())
})
}
override fun onWebDAVError(error: SardineException) {
runOnUiThread({
onRepoError(
if(error.toString().contains("401")) {
getString(R.string.settings_webdav_error_denied)
} else {
getString(R.string.settings_webdav_error_generic) + error.toString()
}
)
})
}
override fun onJSONError(error: JSONException) {
runOnUiThread({
onRepoError(getString(R.string.settings_json_error) + error.toString())
})
}
override fun onError(error: Exception) {
runOnUiThread({
onRepoError(getString(R.string.settings_generic_error) + error.toString())
})
}
})
}
fun loadLogbook(name: String = LogbookRepository.DEFAULT_LOGBOOK_NAME) {
fun loadLogbook(name: String) {
if (savingEvent)
return
// TODO: Highlight logbook button
// Reset time counter
handler.removeCallbacks(updateListRunnable)
handler.postDelayed(updateListRunnable, UPDATE_EVERY_SECS*1000)

View File

@ -8,7 +8,9 @@ import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.progressindicator.LinearProgressIndicator
import com.thegrizzlylabs.sardineandroid.impl.SardineException
import it.danieleverducci.lunatracker.repository.FileLogbookRepository
import it.danieleverducci.lunatracker.repository.LocalSettingsRepository
import it.danieleverducci.lunatracker.repository.LogbookListObtainedListener
import it.danieleverducci.lunatracker.repository.LogbookRepository
import it.danieleverducci.lunatracker.repository.WebDAVLogbookRepository
import okio.IOException
@ -73,13 +75,34 @@ open class SettingsActivity : AppCompatActivity() {
textViewWebDAVPass.text.toString()
)
progressIndicator.visibility = View.VISIBLE
webDAVLogbookRepo.createLogbook(this, LogbookRepository.DEFAULT_LOGBOOK_NAME, object: WebDAVLogbookRepository.LogbookCreatedListener{
override fun onLogbookCreated() {
runOnUiThread({
progressIndicator.visibility = View.INVISIBLE
saveSettings()
Toast.makeText(this@SettingsActivity, R.string.settings_webdav_creation_ok, Toast.LENGTH_SHORT).show()
})
webDAVLogbookRepo.listLogbooks(this, object: LogbookListObtainedListener{
override fun onLogbookListObtained(logbooksNames: ArrayList<String>) {
if (logbooksNames.isEmpty()) {
// TODO: Ask the user if he wants to upload the local ones or to create a new one
copyLocalLogbooksToWebdav(webDAVLogbookRepo, object: OnCopyLocalLogbooksToWebdavFinishedListener {
override fun onCopyLocalLogbooksToWebdavFinished(errors: String?) {
runOnUiThread({
progressIndicator.visibility = View.INVISIBLE
if (errors == null) {
saveSettings()
Toast.makeText(this@SettingsActivity, R.string.settings_webdav_creation_ok, Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(this@SettingsActivity, errors, Toast.LENGTH_SHORT).show()
}
})
}
})
} else {
runOnUiThread({
progressIndicator.visibility = View.INVISIBLE
saveSettings()
Toast.makeText(this@SettingsActivity, R.string.settings_webdav_creation_ok, Toast.LENGTH_SHORT).show()
})
}
}
override fun onIOError(error: IOException) {
@ -100,6 +123,16 @@ open class SettingsActivity : AppCompatActivity() {
})
}
override fun onError(error: Exception) {
runOnUiThread({
progressIndicator.visibility = View.INVISIBLE
Toast.makeText(this@SettingsActivity, getString(R.string.settings_generic_error) + error.toString(), Toast.LENGTH_SHORT).show()
})
}
})
/*webDAVLogbookRepo.createLogbook(this, LogbookRepository.DEFAULT_LOGBOOK_NAME, object: WebDAVLogbookRepository.LogbookCreatedListener{
override fun onJSONError(error: JSONException) {
runOnUiThread({
progressIndicator.visibility = View.INVISIBLE
@ -107,14 +140,8 @@ open class SettingsActivity : AppCompatActivity() {
})
}
override fun onError(error: Exception) {
runOnUiThread({
progressIndicator.visibility = View.INVISIBLE
Toast.makeText(this@SettingsActivity, getString(R.string.settings_generic_error) + error.toString(), Toast.LENGTH_SHORT).show()
})
}
})
})*/
}
fun saveSettings() {
@ -130,4 +157,32 @@ open class SettingsActivity : AppCompatActivity() {
finish()
}
/**
* Copies the local logbooks to webdav.
* @return success
*/
private fun copyLocalLogbooksToWebdav(webDAVLogbookRepository: WebDAVLogbookRepository, listener: OnCopyLocalLogbooksToWebdavFinishedListener) {
Thread(Runnable {
var errors = StringBuilder()
val fileLogbookRepo = FileLogbookRepository()
val logbooks = fileLogbookRepo.getAllLogbooks(this)
for (logbook in logbooks) {
// Copy only if does not already exist
val error = webDAVLogbookRepository.uploadLogbookIfNotExists(this, logbook.name)
if (error != null) {
if (errors.isNotEmpty())
errors.append("\n")
errors.append(String.format(getString(R.string.settings_webdav_upload_error), logbook.name, error))
}
}
listener.onCopyLocalLogbooksToWebdavFinished(
if (errors.isEmpty()) null else errors.toString()
)
}).start()
}
private interface OnCopyLocalLogbooksToWebdavFinishedListener {
fun onCopyLocalLogbooksToWebdavFinished(errors: String?)
}
}

View File

@ -70,6 +70,18 @@ class FileLogbookRepository: LogbookRepository {
context: Context,
listener: LogbookListObtainedListener
) {
listener.onLogbookListObtained(listLogbooks(context))
}
fun getAllLogbooks(context: Context): List<Logbook> {
val logbooks = arrayListOf<Logbook>()
for (logbookName in listLogbooks(context)) {
logbooks.add(loadLogbook(context, logbookName))
}
return logbooks
}
private fun listLogbooks(context: Context): ArrayList<String> {
val logbooksFileNames = context.getFilesDir().list(object: FilenameFilter {
override fun accept(dir: File?, name: String?): Boolean {
if (name == null)
@ -80,8 +92,9 @@ class FileLogbookRepository: LogbookRepository {
}
})
if (logbooksFileNames == null || logbooksFileNames.isEmpty())
listener.onLogbookListObtained(arrayListOf())
if (logbooksFileNames == null || logbooksFileNames.isEmpty()) {
return arrayListOf()
}
val logbooksNames = arrayListOf<String>()
logbooksFileNames.forEach { it ->
@ -89,7 +102,7 @@ class FileLogbookRepository: LogbookRepository {
it.replace("${FILE_NAME_START}_", "").replace(FILE_NAME_START, "").replace(FILE_NAME_END, "")
)
}
listener.onLogbookListObtained(logbooksNames)
return logbooksNames
}
private fun getFileName(name: String): String {

View File

@ -137,47 +137,46 @@ class WebDAVLogbookRepository(val webDavURL: String, val username: String, val p
/**
* Connect to server and check if a logbook already exists.
* If it does not exist, try to upload the local one (or create a new one).
* If it does not exist, try to upload the local one.
* @return error, or null if no error
*/
fun createLogbook(context: Context, name: String, listener: LogbookCreatedListener) {
Thread(Runnable {
try {
loadLogbook(name)
listener.onLogbookCreated()
} catch (e: SardineException) {
if (e.toString().contains("404")) {
// Connection successful, but no existing save. Upload the local one.
try {
val flr = FileLogbookRepository()
val logbook = flr.loadLogbook(context, name)
saveLogbook(context, logbook)
Log.d(TAG, "Local logbook file found, uploaded")
listener.onLogbookCreated()
} catch (e: FileNotFoundException) {
Log.d(TAG, "No local logbook file found, uploading empty file")
saveLogbook(context, Logbook(name))
listener.onLogbookCreated()
} catch (e: SardineException) {
Log.e(TAG, "Unable to upload logbook: $e")
listener.onWebDAVError(e)
}
} else {
Log.e(TAG, e.toString())
listener.onWebDAVError(e)
fun uploadLogbookIfNotExists(context: Context, name: String): String? {
val flr = FileLogbookRepository()
try {
loadLogbook(name)
Log.d(TAG, "Logbook file $name already exist on the webDav share: will not overwrite it")
return null
} catch (e: SardineException) {
if (e.toString().contains("404")) {
// Connection successful, but logbook does not exist. Upload the local one.
try {
val logbook = flr.loadLogbook(context, name)
saveLogbook(context, logbook)
Log.d(TAG, "Local logbook file $name found, uploaded")
return null
} catch (e: FileNotFoundException) {
Log.e(TAG, "No local logbook file found, this should not happen!")
return "No local logbook file found, app is in inconsistent state, please delete and reinstall it"
} catch (e: SardineException) {
Log.e(TAG, "Unable to upload logbook: $e")
return e.toString()
}
} catch (e: IOException) {
} else {
Log.e(TAG, e.toString())
listener.onIOError(e)
} catch (e: SocketTimeoutException) {
Log.e(TAG, e.toString())
listener.onIOError(e)
} catch (e: JSONException) {
Log.e(TAG, e.toString())
listener.onJSONError(e)
} catch (e: Exception) {
listener.onError(e)
return e.toString()
}
}).start()
} catch (e: IOException) {
Log.e(TAG, e.toString())
return e.toString()
} catch (e: SocketTimeoutException) {
Log.e(TAG, e.toString())
return e.toString()
} catch (e: JSONException) {
Log.e(TAG, e.toString())
return e.toString()
} catch (e: Exception) {
return e.toString()
}
}
private fun getUrl(name: String): String {
@ -185,13 +184,4 @@ class WebDAVLogbookRepository(val webDavURL: String, val username: String, val p
Log.d(TAG, fileName)
return "$webDavURL/$fileName"
}
interface LogbookCreatedListener {
fun onLogbookCreated()
fun onIOError(error: okio.IOException)
fun onWebDAVError(error: SardineException)
fun onJSONError(error: JSONException)
fun onError(error: Exception)
}
}

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/dropdown_list_item_background_pressed"/>
<item android:drawable="@drawable/dropdown_list_item_background_released"/>
</selector>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke
android:width="2dp"
android:color="@color/grey" />
<solid
android:color="@color/grey" />
<corners android:radius="15dp" />
<padding
android:bottom="5dp"
android:left="5dp"
android:right="5dp"
android:top="5dp" />
</shape>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke
android:width="2dp"
android:color="@color/grey" />
<solid
android:color="@color/cardview_dark_background"/>
<corners android:radius="15dp" />
<padding
android:bottom="5dp"
android:left="5dp"
android:right="5dp"
android:top="5dp" />
</shape>

View File

@ -7,32 +7,77 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingTop="30dp"
android:paddingTop="10dp"
android:paddingLeft="15dp"
android:paddingRight="15dp">
<TextView
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/title"
android:textSize="30dp"
android:gravity="center_horizontal"/>
android:orientation="horizontal">
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp">
<LinearLayout
android:id="@+id/logbooks_buttons_container"
<ImageView
android:id="@+id/button_settings"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
android:padding="10dp"
android:layout_gravity="end"
android:src="@drawable/ic_settings"
app:tint="@color/grey"/>
</LinearLayout>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/title"
android:textSize="26dp"
android:gravity="center"/>
</HorizontalScrollView>
<ImageView
android:id="@+id/button_sync"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_gravity="start"
android:src="@drawable/ic_sync"
app:tint="@color/grey"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="38dp"
android:layout_margin="10dp"
android:orientation="horizontal"
android:gravity="center_vertical">
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/button_background">
<Spinner
android:id="@+id/logbooks_spinner"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
<TextView
android:id="@+id/logbooks_add_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:textStyle="bold"
android:textColor="@color/accent"
android:textSize="20dp"
android:text="+"
android:background="@drawable/button_background"/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
@ -180,24 +225,6 @@
</LinearLayout>
<ImageView
android:id="@+id/button_settings"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_gravity="end"
android:src="@drawable/ic_settings"
app:tint="@color/grey"/>
<ImageView
android:id="@+id/button_sync"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_gravity="start"
android:src="@drawable/ic_sync"
app:tint="@color/grey"/>
<LinearLayout
android:id="@+id/no_connection_screen"
android:layout_width="match_parent"

View File

@ -6,6 +6,7 @@
android:padding="20dp">
<TextView
android:id="@+id/dialog_add_logbook_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/dialog_add_logbook_message"/>

View File

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:background="@drawable/button_background"
android:textStyle="bold"
android:textColor="@color/accent"/>

View File

@ -15,7 +15,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="20dp"
android:background="@drawable/button_background"
android:background="@drawable/dropdown_list_item_background"
style="@style/OverflowMenuText"
android:text="@string/overflow_event_medicine"/>
@ -25,7 +25,7 @@
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:padding="20dp"
android:background="@drawable/button_background"
android:background="@drawable/dropdown_list_item_background"
style="@style/OverflowMenuText"
android:text="@string/overflow_event_enema"/>
@ -35,7 +35,7 @@
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:padding="20dp"
android:background="@drawable/button_background"
android:background="@drawable/dropdown_list_item_background"
style="@style/OverflowMenuText"
android:text="@string/overflow_event_note"/>
@ -45,7 +45,7 @@
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:padding="20dp"
android:background="@drawable/button_background"
android:background="@drawable/dropdown_list_item_background"
style="@style/OverflowMenuText"
android:text="@string/overflow_event_temperature"/>
@ -55,7 +55,7 @@
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:padding="20dp"
android:background="@drawable/button_background"
android:background="@drawable/dropdown_list_item_background"
style="@style/OverflowMenuText"
android:text="@string/overflow_event_colic"/>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="20dp"
android:paddingEnd="20dp"
android:paddingTop="20dp"
android:paddingBottom="20dp"
android:singleLine="true"
android:ellipsize="end"/>

View File

@ -66,6 +66,7 @@
<string name="settings_webdav_creation_ok">Connessione al server WebDAV avvenuta con successo</string>
<string name="settings_json_error">Sul server esiste un salvataggio, ma è corrotto o illeggibile. Cancellare il file </string>
<string name="settings_generic_error">Si è verificato un errore: </string>
<string name="settings_webdav_upload_error">Errore durante l\'upload del logbook locale %1$s su webdav: %2$s</string>
<string name="trim_logbook_dialog_title">Il tuo diario è bello grande!</string>
<string name="trim_logbook_dialog_message_local">Il file del tuo diario sta crescendo molto. Ti suggeriamo di cancellare gli eventi più vecchi per evitare problemi di memoria.</string>
@ -81,9 +82,10 @@
<string name="dialog_event_detail_title">Dettaglio evento</string>
<string name="dialog_add_logbook_title">Aggiungi diario</string>
<string name="dialog_add_logbook_logbookname">Nome del diario</string>
<string name="dialog_add_logbook_message">Scrivi un nome per identificare questo diario. Comparirà in cima allo schermo, e se usi WebDAV sarà incluso anche nel nome del file di salvataggio.</string>
<string name="dialog_add_logbook_logbookname">👶 Nome del diario</string>
<string name="dialog_add_logbook_message">Scrivi un nome per identificare questo diario. Comparirà in cima allo schermo, e se usi WebDAV sarà incluso anche nel nome del file di salvataggio.\nSe vuoi un\'icona, inserisci una emoji!</string>
<string name="default_logbook_name">Senza nome</string>
<string name="default_logbook_name">👶 Il mio primo diario</string>
<string name="logbook_created">Creato nuovo diario: </string>
</resources>

View File

@ -80,6 +80,7 @@
<string name="settings_webdav_creation_ok">Successfully connected with WebDAV server</string>
<string name="settings_json_error">There\'s a save file on the server, but is corrupted or unreadable. Please delete it </string>
<string name="settings_generic_error">Error: </string>
<string name="settings_webdav_upload_error">Error while uploading local logbook %1$s to webdav: %2$s</string>
<string name="trim_logbook_dialog_title">Your logbook is pretty big!</string>
<string name="trim_logbook_dialog_message_local">Your logbook file is growing a lot. We suggest trimming the oldest events to avoid crashes.</string>
@ -104,9 +105,11 @@
<string name="dialog_event_detail_title">Event detail</string>
<string name="dialog_add_logbook_title">Add logbook</string>
<string name="dialog_add_logbook_logbookname">Logbook name</string>
<string name="dialog_add_logbook_logbookname">👶 Logbook name</string>
<string name="dialog_add_logbook_message">Write a name to identify this logbook. This name will appear on top of the screen and, if you use WebDAV, will be in the save file name as well.</string>
<string name="dialog_add_logbook_message_intro">Welcome! To use this app you need to create at least one logbook. You would probably want to call it with your child\'s name.</string>
<string name="default_logbook_name">Unnamed</string>
<string name="default_logbook_name">👶 My first logbook</string>
<string name="logbook_created">New logbook created: </string>
</resources>