Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#8: Separate user-defined properties into dedicated storage #18

Merged
merged 14 commits into from
Oct 25, 2023
9 changes: 2 additions & 7 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,8 @@ dependencies {
implementation 'androidx.preference:preference-ktx:1.2.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'

//implementation 'com.github.ARK-Builders:ark-filepicker:b2bfa01ea7'

implementation 'com.github.ark-builders:ark-filepicker:b2bfa01ea7'
implementation 'space.taran:arklib:0.1.0-SNAPSHOT-7df9a4e581'

implementation 'ch.acra:acra-http:5.9.5'
implementation 'ch.acra:acra-dialog:5.9.5'
implementation 'dev.arkbuilders:arkfilepicker:0.1.1'
implementation 'dev.arkbuilders:arklib:0.3.3'

implementation 'androidx.preference:preference:1.2.0'
implementation "com.google.dagger:hilt-android:2.42"
Expand Down
11 changes: 8 additions & 3 deletions app/src/main/java/space/taran/arkmemo/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package space.taran.arkmemo
import android.app.Application
import android.content.Context
import dagger.hilt.android.HiltAndroidApp
import dev.arkbuilders.arklib.initArkLib
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
Expand All @@ -11,13 +12,17 @@ import org.acra.config.httpSender
import org.acra.data.StringFormat
import org.acra.ktx.initAcra
import org.acra.sender.HttpSender
import dev.arkbuilders.arkfilepicker.folders.FoldersRepo
import space.taran.arkmemo.space.taran.arkmemo.utils.Config

@HiltAndroidApp
class App: Application() {

override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base)
override fun onCreate() {
super.onCreate()
System.loadLibrary("arklib")
initArkLib()
FoldersRepo.init(this)
initAcra()
}

Expand All @@ -41,4 +46,4 @@ class App: Application() {
}
}
}
}
}
3 changes: 2 additions & 1 deletion app/src/main/java/space/taran/arkmemo/data/ResourceMeta.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package space.taran.arkmemo.data

import dev.arkbuilders.arklib.ResourceId
import java.nio.file.attribute.FileTime

data class ResourceMeta(
val id: Long,
val id: ResourceId,
val name: String,
val extension: String,
val modified: FileTime,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package space.taran.arkmemo.data.repositories

import android.util.Log
import dev.arkbuilders.arklib.ResourceId
import dev.arkbuilders.arklib.computeId
import dev.arkbuilders.arklib.data.index.RootIndex
import dev.arkbuilders.arklib.user.properties.Properties
import dev.arkbuilders.arklib.user.properties.PropertiesStorage
import dev.arkbuilders.arklib.user.properties.PropertiesStorageRepo
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.job
import kotlinx.coroutines.withContext
import space.taran.arkmemo.data.ResourceMeta
import space.taran.arkmemo.models.TextNote
import java.nio.file.Files
import java.nio.file.Path
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.io.path.deleteIfExists
import kotlin.io.path.exists
import kotlin.io.path.extension
import kotlin.io.path.fileSize
import kotlin.io.path.forEachLine
import kotlin.io.path.getLastModifiedTime
import kotlin.io.path.moveTo
import kotlin.io.path.name
import kotlin.io.path.writeLines

@Singleton
class TextNotesRepo @Inject constructor() {

private val iODispatcher = Dispatchers.IO

private lateinit var propertiesStorage: PropertiesStorage
private lateinit var propertiesStorageRepo: PropertiesStorageRepo

private lateinit var root: Path

suspend fun init(root: Path, scope: CoroutineScope) {
this.root = root
propertiesStorageRepo = PropertiesStorageRepo(scope)
propertiesStorage = propertiesStorageRepo.provide(RootIndex.provide(root))
}

suspend fun save(note: TextNote) {
write(note)
}

suspend fun delete(note: TextNote) = withContext(iODispatcher) {
val path = root.resolve("${note.meta?.name}")
delete(path)
propertiesStorage.remove(note.meta?.id!!)
propertiesStorage.persist()
Log.d("text-repo", "${note.meta?.name!!} has been deleted")
}

suspend fun read(): List<TextNote> = withContext(Dispatchers.IO) {
val notes = mutableListOf<TextNote>()
Files.list(root).forEach { path ->
if (path.fileName.extension == NOTE_EXT) {
val data = StringBuilder()
path.forEachLine {
data.appendLine(it)
}
val size = path.fileSize()
val id = computeId(size, path)
val meta = ResourceMeta(
id,
path.fileName.name,
path.extension,
path.getLastModifiedTime(),
size
)
val titles = propertiesStorage.getProperties(id).titles
val content = TextNote.Content(titles.elementAt(0), data.toString())
val note = TextNote(content, meta)
notes.add(note)
}
}
Log.d("text-repo", "${notes.size} text note resources found")
notes
}

private suspend fun write(note: TextNote) = withContext(Dispatchers.IO) {
shubertm marked this conversation as resolved.
Show resolved Hide resolved
val tempPath = kotlin.io.path.createTempFile()
val lines = note.content.data.split('\n')
tempPath.writeLines(lines)
val size = tempPath.fileSize()
val id = computeId(size, tempPath)
Log.d("text-repo", "initial resource name ${tempPath.name}")
persistNoteProperties(resourceId = id, noteTitle = note.content.title)

val resourcePath = root.resolve("$id.$NOTE_EXT")
renameResourceWithNewResourceMeta(
note = note,
tempPath = tempPath,
resourcePath = resourcePath,
resourceId = id,
size = size
)
}

private suspend fun persistNoteProperties(resourceId: ResourceId, noteTitle: String) {
with(propertiesStorage) {
val properties = Properties(setOf(noteTitle), setOf())
setProperties(resourceId, properties)
persist()
}
}

private fun renameResourceWithNewResourceMeta(
note: TextNote,
tempPath: Path,
resourcePath: Path,
resourceId: ResourceId,
size: Long
) {
tempPath.moveTo(resourcePath)
note.meta = ResourceMeta(
id = resourceId,
name = resourcePath.fileName.name,
extension = resourcePath.extension,
modified = resourcePath.getLastModifiedTime(),
size = size
)
Log.d("notes-repo", "resource renamed to ${resourcePath.name} successfully")
}

private fun delete(path: Path) {
path.deleteIfExists()
}
}

private const val NOTE_EXT = "note"

This file was deleted.

This file was deleted.

Loading