First working sync (with hardcoded credentials and no concurrent modification checks)
This commit is contained in:
@ -1,22 +1,25 @@
|
||||
package it.danieleverducci.lunatracker
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.preference.PreferenceManager
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.NumberPicker
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.edit
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
import it.danieleverducci.lunatracker.adapters.LunaEventRecyclerAdapter
|
||||
import it.danieleverducci.lunatracker.entities.Logbook
|
||||
import it.danieleverducci.lunatracker.entities.LunaEvent
|
||||
import it.danieleverducci.lunatracker.entities.LunaEventType
|
||||
import it.danieleverducci.lunatracker.repository.LogbookLoadedListener
|
||||
import it.danieleverducci.lunatracker.repository.LogbookRepository
|
||||
import it.danieleverducci.lunatracker.repository.LogbookSavedListener
|
||||
import it.danieleverducci.lunatracker.repository.WebDAVLogbookRepository
|
||||
import kotlinx.coroutines.Runnable
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
@ -28,28 +31,30 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
lateinit var logbook: Logbook
|
||||
lateinit var adapter: LunaEventRecyclerAdapter
|
||||
lateinit var progressIndicator: LinearProgressIndicator
|
||||
lateinit var recyclerView: RecyclerView
|
||||
lateinit var handler: Handler
|
||||
val updateListRunnable: Runnable = Runnable {
|
||||
adapter.notifyDataSetChanged()
|
||||
handler.postDelayed(updateListRunnable, 1000*30)
|
||||
loadLogbook()
|
||||
handler.postDelayed(updateListRunnable, 1000*60)
|
||||
}
|
||||
val logbookRepo: LogbookRepository = WebDAVLogbookRepository( // TODO: support also FileLogbookRepository
|
||||
TemporaryHardcodedCredentials.URL,
|
||||
TemporaryHardcodedCredentials.USERNAME,
|
||||
TemporaryHardcodedCredentials.PASSWORD
|
||||
)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
handler = Handler(mainLooper)
|
||||
|
||||
// Load data
|
||||
logbook = Logbook.load(this)
|
||||
adapter = LunaEventRecyclerAdapter(this)
|
||||
|
||||
// Show view
|
||||
setContentView(R.layout.activity_main)
|
||||
|
||||
// Show logbook
|
||||
progressIndicator = findViewById<LinearProgressIndicator>(R.id.progress_indicator)
|
||||
recyclerView = findViewById<RecyclerView>(R.id.list_events)
|
||||
recyclerView.setLayoutManager(LinearLayoutManager(this))
|
||||
adapter = LunaEventRecyclerAdapter(this)
|
||||
adapter.items.addAll(logbook.logs)
|
||||
recyclerView.setLayoutManager(LinearLayoutManager(applicationContext))
|
||||
recyclerView.adapter = adapter
|
||||
|
||||
// Set listeners
|
||||
@ -82,11 +87,18 @@ class MainActivity : AppCompatActivity() {
|
||||
) }
|
||||
}
|
||||
|
||||
fun showLogbook() {
|
||||
// Show logbook
|
||||
adapter.items.clear()
|
||||
adapter.items.addAll(logbook.logs)
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
|
||||
// Update list dates
|
||||
adapter.notifyDataSetChanged()
|
||||
loadLogbook()
|
||||
handler.postDelayed(updateListRunnable, 1000*30)
|
||||
}
|
||||
|
||||
@ -138,13 +150,52 @@ class MainActivity : AppCompatActivity() {
|
||||
alertDialog.show()
|
||||
}
|
||||
|
||||
fun loadLogbook() {
|
||||
// Load data
|
||||
progressIndicator.visibility = View.VISIBLE
|
||||
logbookRepo.loadLogbook(this, object: LogbookLoadedListener{
|
||||
override fun onLogbookLoaded(lb: Logbook) {
|
||||
runOnUiThread({
|
||||
progressIndicator.visibility = View.INVISIBLE
|
||||
logbook = lb
|
||||
showLogbook()
|
||||
})
|
||||
}
|
||||
|
||||
override fun onError(error: String) {
|
||||
runOnUiThread({
|
||||
progressIndicator.visibility = View.INVISIBLE
|
||||
Log.e(TAG, "Unable to load logbook. Create a new one.")
|
||||
logbook = Logbook()
|
||||
showLogbook()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun logEvent(event: LunaEvent) {
|
||||
adapter.items.add(0, event)
|
||||
adapter.notifyItemInserted(0)
|
||||
recyclerView.smoothScrollToPosition(0)
|
||||
|
||||
progressIndicator.visibility = View.VISIBLE
|
||||
logbook.logs.add(0, event)
|
||||
logbook.save(this)
|
||||
logbookRepo.saveLogbook(this, logbook, object: LogbookSavedListener{
|
||||
override fun onLogbookSaved() {
|
||||
Log.d(TAG, "Logbook saved")
|
||||
runOnUiThread({
|
||||
progressIndicator.visibility = View.INVISIBLE
|
||||
})
|
||||
}
|
||||
|
||||
override fun onError(error: String) {
|
||||
Log.e(TAG, "ERROR: Logbook was NOT saved!")
|
||||
runOnUiThread({
|
||||
progressIndicator.visibility = View.INVISIBLE
|
||||
})
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
Toast.makeText(this, R.string.toast_event_added, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
@ -1,42 +1,5 @@
|
||||
package it.danieleverducci.lunatracker.entities
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import org.json.JSONArray
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileNotFoundException
|
||||
|
||||
class Logbook {
|
||||
companion object {
|
||||
val TAG = "Logbook"
|
||||
|
||||
fun load(context: Context): Logbook {
|
||||
val logbook = Logbook()
|
||||
val file = File(context.getFilesDir(), "data.json")
|
||||
try {
|
||||
val json = FileInputStream(file).bufferedReader().use { it.readText() }
|
||||
val ja = JSONArray(json)
|
||||
for (i in 0 until ja.length()) {
|
||||
val jo = ja.getJSONObject(i)
|
||||
val evt = LunaEvent.fromJson(jo)
|
||||
logbook.logs.add(evt)
|
||||
}
|
||||
} catch (e: FileNotFoundException) {
|
||||
Log.d(TAG, "No logbook file found")
|
||||
}
|
||||
return logbook
|
||||
}
|
||||
}
|
||||
|
||||
val logs = ArrayList<LunaEvent>()
|
||||
|
||||
fun save(context: Context) {
|
||||
val file = File(context.getFilesDir(), "data.json")
|
||||
val ja = JSONArray()
|
||||
for (l in logs) {
|
||||
ja.put(l.toJson())
|
||||
}
|
||||
file.writeText(ja.toString())
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package it.danieleverducci.lunatracker.repository
|
||||
|
||||
import android.content.Context
|
||||
import it.danieleverducci.lunatracker.entities.Logbook
|
||||
import android.util.Log
|
||||
import it.danieleverducci.lunatracker.entities.LunaEvent
|
||||
import org.json.JSONArray
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileNotFoundException
|
||||
|
||||
class FileLogbookRepository: LogbookRepository {
|
||||
companion object {
|
||||
val TAG = "FileLogbookRepository"
|
||||
}
|
||||
|
||||
override fun loadLogbook(context: Context, listener: LogbookLoadedListener) {
|
||||
val logbook = Logbook()
|
||||
val file = File(context.getFilesDir(), "data.json")
|
||||
try {
|
||||
val json = FileInputStream(file).bufferedReader().use { it.readText() }
|
||||
val ja = JSONArray(json)
|
||||
for (i in 0 until ja.length()) {
|
||||
val jo = ja.getJSONObject(i)
|
||||
val evt = LunaEvent.fromJson(jo)
|
||||
logbook.logs.add(evt)
|
||||
}
|
||||
} catch (e: FileNotFoundException) {
|
||||
Log.d(TAG, "No logbook file found")
|
||||
listener.onError(e.toString())
|
||||
}
|
||||
listener.onLogbookLoaded(logbook)
|
||||
}
|
||||
|
||||
override fun saveLogbook(
|
||||
context: Context,
|
||||
logbook: Logbook,
|
||||
listener: LogbookSavedListener
|
||||
) {
|
||||
val file = File(context.getFilesDir(), "data.json")
|
||||
val ja = JSONArray()
|
||||
for (l in logbook.logs) {
|
||||
ja.put(l.toJson())
|
||||
}
|
||||
file.writeText(ja.toString())
|
||||
listener.onLogbookSaved()
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package it.danieleverducci.lunatracker.repository
|
||||
|
||||
import android.content.Context
|
||||
import it.danieleverducci.lunatracker.entities.Logbook
|
||||
|
||||
interface LogbookRepository {
|
||||
fun loadLogbook(context: Context, listener: LogbookLoadedListener)
|
||||
fun saveLogbook(context: Context, logbook: Logbook, listener: LogbookSavedListener)
|
||||
}
|
||||
|
||||
interface LogbookLoadedListener {
|
||||
fun onLogbookLoaded(logbook: Logbook)
|
||||
fun onError(error: String)
|
||||
}
|
||||
|
||||
interface LogbookSavedListener {
|
||||
fun onLogbookSaved()
|
||||
fun onError(error: String)
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package it.danieleverducci.lunatracker.repository
|
||||
|
||||
import android.content.Context
|
||||
import com.thegrizzlylabs.sardineandroid.impl.OkHttpSardine
|
||||
import com.thegrizzlylabs.sardineandroid.impl.SardineException
|
||||
import it.danieleverducci.lunatracker.TemporaryHardcodedCredentials
|
||||
import it.danieleverducci.lunatracker.entities.Logbook
|
||||
import it.danieleverducci.lunatracker.entities.LunaEvent
|
||||
import kotlinx.coroutines.Runnable
|
||||
import org.json.JSONArray
|
||||
import java.io.BufferedReader
|
||||
import kotlin.io.bufferedReader
|
||||
|
||||
class WebDAVLogbookRepository(val webDavURL: String, val username: String, val password: String): LogbookRepository {
|
||||
companion object {
|
||||
val TAG = "LogbookRepository"
|
||||
val FILE_NAME = "lunatracker_logbook.json"
|
||||
}
|
||||
val sardine: OkHttpSardine = OkHttpSardine()
|
||||
|
||||
init {
|
||||
sardine.setCredentials(
|
||||
username,
|
||||
password
|
||||
)
|
||||
}
|
||||
|
||||
override fun loadLogbook(context: Context, listener: LogbookLoadedListener) {
|
||||
Thread(Runnable {
|
||||
try {
|
||||
val inputStream = sardine.get("$webDavURL/$FILE_NAME")
|
||||
val json = inputStream.bufferedReader().use(BufferedReader::readText)
|
||||
val ja = JSONArray(json)
|
||||
val logbook = Logbook()
|
||||
for (i in 0 until ja.length()) {
|
||||
val jo = ja.getJSONObject(i)
|
||||
val evt = LunaEvent.fromJson(jo)
|
||||
logbook.logs.add(evt)
|
||||
}
|
||||
listener.onLogbookLoaded(logbook)
|
||||
} catch (e: SardineException) {
|
||||
listener.onError(e.toString())
|
||||
}
|
||||
}).start()
|
||||
}
|
||||
|
||||
override fun saveLogbook(context: Context, logbook: Logbook, listener: LogbookSavedListener) {
|
||||
Thread(Runnable {
|
||||
// Lock logbook on WebDAV to avoid concurrent changes
|
||||
//sardine.lock(getUrl())
|
||||
// Reload logbook from WebDAV
|
||||
// Merge logbooks (based on time)
|
||||
// Write logbook
|
||||
// Unlock logbook on WebDAV
|
||||
//sardine.unlock(getUrl())
|
||||
|
||||
val ja = JSONArray()
|
||||
for (l in logbook.logs) {
|
||||
ja.put(l.toJson())
|
||||
}
|
||||
try {
|
||||
sardine.put(getUrl(), ja.toString().toByteArray())
|
||||
listener.onLogbookSaved()
|
||||
} catch (e: SardineException) {
|
||||
listener.onError(e.toString())
|
||||
}
|
||||
|
||||
}).start()
|
||||
}
|
||||
|
||||
private fun getUrl(): String {
|
||||
return "${TemporaryHardcodedCredentials.URL}/$FILE_NAME"
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user