forked from penguin86/luna-tracker
		
	Support for multiple logbook files
This commit is contained in:
		@@ -314,7 +314,7 @@ class MainActivity : AppCompatActivity() {
 | 
			
		||||
 | 
			
		||||
        // Load data
 | 
			
		||||
        setLoading(true)
 | 
			
		||||
        logbookRepo?.loadLogbook(this, object: LogbookLoadedListener{
 | 
			
		||||
        logbookRepo?.loadLogbook(this, "", object: LogbookLoadedListener{
 | 
			
		||||
            override fun onLogbookLoaded(lb: Logbook) {
 | 
			
		||||
                runOnUiThread({
 | 
			
		||||
                    setLoading(false)
 | 
			
		||||
 
 | 
			
		||||
@@ -72,7 +72,7 @@ open class SettingsActivity : AppCompatActivity() {
 | 
			
		||||
            textViewWebDAVPass.text.toString()
 | 
			
		||||
        )
 | 
			
		||||
        progressIndicator.visibility = View.VISIBLE
 | 
			
		||||
        webDAVLogbookRepo.createLogbook(this, object: WebDAVLogbookRepository.LogbookCreatedListener{
 | 
			
		||||
        webDAVLogbookRepo.createLogbook(this, "", object: WebDAVLogbookRepository.LogbookCreatedListener{
 | 
			
		||||
            override fun onLogbookCreated() {
 | 
			
		||||
                runOnUiThread({
 | 
			
		||||
                    progressIndicator.visibility = View.INVISIBLE
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
package it.danieleverducci.lunatracker.entities
 | 
			
		||||
 | 
			
		||||
class Logbook {
 | 
			
		||||
class Logbook(val name: String) {
 | 
			
		||||
    companion object {
 | 
			
		||||
        val MAX_SAFE_LOGBOOK_SIZE = 30000
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -9,26 +9,30 @@ import org.json.JSONException
 | 
			
		||||
import java.io.File
 | 
			
		||||
import java.io.FileInputStream
 | 
			
		||||
import java.io.FileNotFoundException
 | 
			
		||||
import java.io.FilenameFilter
 | 
			
		||||
 | 
			
		||||
class FileLogbookRepository: LogbookRepository {
 | 
			
		||||
    companion object {
 | 
			
		||||
        val TAG = "FileLogbookRepository"
 | 
			
		||||
        val FILE_NAME_START = "data"
 | 
			
		||||
        val FILE_NAME_END = ".json"
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun loadLogbook(context: Context, listener: LogbookLoadedListener) {
 | 
			
		||||
    override fun loadLogbook(context: Context, name: String, listener: LogbookLoadedListener) {
 | 
			
		||||
        try {
 | 
			
		||||
            listener.onLogbookLoaded(loadLogbook(context))
 | 
			
		||||
            listener.onLogbookLoaded(loadLogbook(context, name))
 | 
			
		||||
        } catch (e: FileNotFoundException) {
 | 
			
		||||
            Log.d(TAG, "No logbook file found, create one")
 | 
			
		||||
            val newLogbook = Logbook()
 | 
			
		||||
            val newLogbook = Logbook(name)
 | 
			
		||||
            saveLogbook(context, newLogbook)
 | 
			
		||||
            listener.onLogbookLoaded(newLogbook)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun loadLogbook(context: Context): Logbook {
 | 
			
		||||
        val logbook = Logbook()
 | 
			
		||||
        val file = File(context.getFilesDir(), "data.json")
 | 
			
		||||
    fun loadLogbook(context: Context, name: String): Logbook {
 | 
			
		||||
        val logbook = Logbook(name)
 | 
			
		||||
        val fileName = "$FILE_NAME_START{${if (name.isNotEmpty()) "_" else ""}{$name}$FILE_NAME_END"
 | 
			
		||||
        val file = File(context.getFilesDir(), fileName)
 | 
			
		||||
        val json = FileInputStream(file).bufferedReader().use { it.readText() }
 | 
			
		||||
        val ja = JSONArray(json)
 | 
			
		||||
        for (i in 0 until ja.length()) {
 | 
			
		||||
@@ -53,11 +57,39 @@ class FileLogbookRepository: LogbookRepository {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun saveLogbook(context: Context, logbook: Logbook) {
 | 
			
		||||
        val file = File(context.getFilesDir(), "data.json")
 | 
			
		||||
        val name = logbook.name
 | 
			
		||||
        val fileName = "$FILE_NAME_START${if (name.isNotEmpty()) "_" else ""}${name}$FILE_NAME_END"
 | 
			
		||||
        val file = File(context.getFilesDir(), fileName)
 | 
			
		||||
        val ja = JSONArray()
 | 
			
		||||
        for (l in logbook.logs) {
 | 
			
		||||
            ja.put(l.toJson())
 | 
			
		||||
        }
 | 
			
		||||
        file.writeText(ja.toString())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun listLogbooks(
 | 
			
		||||
        context: Context,
 | 
			
		||||
        listener: LogbookListObtainedListener
 | 
			
		||||
    ): ArrayList<String> {
 | 
			
		||||
        val logbooksFileNames = context.getFilesDir().list(object: FilenameFilter {
 | 
			
		||||
            override fun accept(dir: File?, name: String?): Boolean {
 | 
			
		||||
                if (name == null)
 | 
			
		||||
                    return false
 | 
			
		||||
                if (name.startsWith(FILE_NAME_START) && name.endsWith(FILE_NAME_END))
 | 
			
		||||
                    return true
 | 
			
		||||
                return false
 | 
			
		||||
            }
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        if (logbooksFileNames == null || logbooksFileNames.isEmpty())
 | 
			
		||||
            return arrayListOf()
 | 
			
		||||
 | 
			
		||||
        val logbooksNames = arrayListOf<String>()
 | 
			
		||||
        logbooksFileNames.forEach { it ->
 | 
			
		||||
            logbooksNames.add(
 | 
			
		||||
                it.replace(FILE_NAME_START, "").replace("${FILE_NAME_START}_", "").replace(FILE_NAME_END, "")
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        return logbooksNames
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -7,8 +7,9 @@ import okio.IOException
 | 
			
		||||
import org.json.JSONException
 | 
			
		||||
 | 
			
		||||
interface LogbookRepository {
 | 
			
		||||
    fun loadLogbook(context: Context, listener: LogbookLoadedListener)
 | 
			
		||||
    fun saveLogbook(context: Context, logbook: Logbook, listener: LogbookSavedListener)
 | 
			
		||||
    fun loadLogbook(context: Context, name: String = "", listener: LogbookLoadedListener)
 | 
			
		||||
    fun saveLogbook(context: Context,logbook: Logbook, listener: LogbookSavedListener)
 | 
			
		||||
    fun listLogbooks(context: Context, listener: LogbookListObtainedListener): ArrayList<String>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface LogbookLoadedListener {
 | 
			
		||||
@@ -25,4 +26,11 @@ interface LogbookSavedListener {
 | 
			
		||||
    fun onWebDAVError(error: SardineException)
 | 
			
		||||
    fun onJSONError(error: JSONException)
 | 
			
		||||
    fun onError(error: Exception)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface LogbookListObtainedListener {
 | 
			
		||||
    fun onLogbookListObtained()
 | 
			
		||||
    fun onIOError(error: IOException)
 | 
			
		||||
    fun onWebDAVError(error: SardineException)
 | 
			
		||||
    fun onError(error: Exception)
 | 
			
		||||
}
 | 
			
		||||
@@ -2,6 +2,7 @@ package it.danieleverducci.lunatracker.repository
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.util.Log
 | 
			
		||||
import com.thegrizzlylabs.sardineandroid.DavResource
 | 
			
		||||
import com.thegrizzlylabs.sardineandroid.impl.OkHttpSardine
 | 
			
		||||
import com.thegrizzlylabs.sardineandroid.impl.SardineException
 | 
			
		||||
import it.danieleverducci.lunatracker.entities.Logbook
 | 
			
		||||
@@ -14,11 +15,13 @@ import java.io.FileNotFoundException
 | 
			
		||||
import java.io.IOException
 | 
			
		||||
import java.net.SocketTimeoutException
 | 
			
		||||
import kotlin.io.bufferedReader
 | 
			
		||||
import kotlin.text.replace
 | 
			
		||||
 | 
			
		||||
class WebDAVLogbookRepository(val webDavURL: String, val username: String, val password: String): LogbookRepository {
 | 
			
		||||
    companion object {
 | 
			
		||||
        val TAG = "LogbookRepository"
 | 
			
		||||
        val FILE_NAME = "lunatracker_logbook.json"
 | 
			
		||||
        val FILE_NAME_START = "lunatracker_logbook"
 | 
			
		||||
        val FILE_NAME_END = ".json"
 | 
			
		||||
    }
 | 
			
		||||
    val sardine: OkHttpSardine = OkHttpSardine()
 | 
			
		||||
 | 
			
		||||
@@ -29,10 +32,10 @@ class WebDAVLogbookRepository(val webDavURL: String, val username: String, val p
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun loadLogbook(context: Context, listener: LogbookLoadedListener) {
 | 
			
		||||
    override fun loadLogbook(context: Context, name: String, listener: LogbookLoadedListener) {
 | 
			
		||||
        Thread(Runnable {
 | 
			
		||||
            try {
 | 
			
		||||
                val logbook = loadLogbook(context)
 | 
			
		||||
                val logbook = loadLogbook(name)
 | 
			
		||||
                listener.onLogbookLoaded(logbook)
 | 
			
		||||
            } catch (e: SardineException) {
 | 
			
		||||
                Log.e(TAG, e.toString())
 | 
			
		||||
@@ -52,12 +55,12 @@ class WebDAVLogbookRepository(val webDavURL: String, val username: String, val p
 | 
			
		||||
        }).start()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun loadLogbook(context: Context): Logbook {
 | 
			
		||||
        val inputStream = sardine.get("$webDavURL/$FILE_NAME")
 | 
			
		||||
    private fun loadLogbook(name: String,): Logbook {
 | 
			
		||||
        val inputStream = sardine.get(getUrl(name))
 | 
			
		||||
        val json = inputStream.bufferedReader().use(BufferedReader::readText)
 | 
			
		||||
        inputStream.close()
 | 
			
		||||
        val ja = JSONArray(json)
 | 
			
		||||
        val logbook = Logbook()
 | 
			
		||||
        val logbook = Logbook(name)
 | 
			
		||||
        for (i in 0 until ja.length()) {
 | 
			
		||||
            try {
 | 
			
		||||
                val evt: LunaEvent = LunaEvent(ja.getJSONObject(i))
 | 
			
		||||
@@ -95,6 +98,21 @@ class WebDAVLogbookRepository(val webDavURL: String, val username: String, val p
 | 
			
		||||
        }).start()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun listLogbooks(
 | 
			
		||||
        context: Context,
 | 
			
		||||
        listener: LogbookListObtainedListener
 | 
			
		||||
    ): ArrayList<String> {
 | 
			
		||||
        val logbooksNames = arrayListOf<String>()
 | 
			
		||||
        for (dr: DavResource in sardine.list(webDavURL)){
 | 
			
		||||
            logbooksNames.add(
 | 
			
		||||
                dr.name.replace(FileLogbookRepository.Companion.FILE_NAME_START, "")
 | 
			
		||||
                    .replace("${FileLogbookRepository.Companion.FILE_NAME_START}_", "")
 | 
			
		||||
                    .replace(FileLogbookRepository.Companion.FILE_NAME_END, "")
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        return logbooksNames
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun saveLogbook(context: Context, logbook: Logbook) {
 | 
			
		||||
        // Lock logbook on WebDAV to avoid concurrent changes
 | 
			
		||||
        //sardine.lock(getUrl())
 | 
			
		||||
@@ -108,30 +126,30 @@ class WebDAVLogbookRepository(val webDavURL: String, val username: String, val p
 | 
			
		||||
        for (l in logbook.logs) {
 | 
			
		||||
            ja.put(l.toJson())
 | 
			
		||||
        }
 | 
			
		||||
        sardine.put(getUrl(), ja.toString().toByteArray())
 | 
			
		||||
        sardine.put(getUrl(logbook.name), ja.toString().toByteArray())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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).
 | 
			
		||||
     */
 | 
			
		||||
    fun createLogbook(context: Context, listener: LogbookCreatedListener) {
 | 
			
		||||
    fun createLogbook(context: Context, name: String, listener: LogbookCreatedListener) {
 | 
			
		||||
        Thread(Runnable {
 | 
			
		||||
            try {
 | 
			
		||||
                loadLogbook(context)
 | 
			
		||||
                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)
 | 
			
		||||
                        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())
 | 
			
		||||
                        saveLogbook(context, Logbook(name))
 | 
			
		||||
                        listener.onLogbookCreated()
 | 
			
		||||
                    } catch (e: SardineException) {
 | 
			
		||||
                        Log.e(TAG, "Unable to upload logbook: $e")
 | 
			
		||||
@@ -156,8 +174,10 @@ class WebDAVLogbookRepository(val webDavURL: String, val username: String, val p
 | 
			
		||||
        }).start()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun getUrl(): String {
 | 
			
		||||
        return "$webDavURL/$FILE_NAME"
 | 
			
		||||
    private fun getUrl(name: String): String {
 | 
			
		||||
        val fileName = "${FILE_NAME_START}${if (name.isNotEmpty()) "_" else ""}${name}${FILE_NAME_END}"
 | 
			
		||||
        Log.d(TAG, fileName)
 | 
			
		||||
        return "$webDavURL/$fileName"
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user