Skip to content

Commit

Permalink
Extract methods to interfaces & change way of providing dependencies (#…
Browse files Browse the repository at this point in the history
…25)

* Extract methods to interfaces and provide dependencies

* Provide preferences and replace singleton

* Create module

* Extract methods to interfaces

* Replace singleton

* Use callback instead of using singleton

* Refactor and hook callback

* Rename method
  • Loading branch information
hieuwu authored Oct 30, 2023
1 parent 1c94c60 commit 50558c5
Show file tree
Hide file tree
Showing 10 changed files with 239 additions and 180 deletions.
Original file line number Diff line number Diff line change
@@ -1,138 +1,13 @@
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) {
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"
interface TextNotesRepo {
suspend fun init(root: Path, scope: CoroutineScope)
suspend fun save(note: TextNote)
suspend fun delete(note: TextNote): Int
suspend fun read(): List<TextNote>

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
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.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 kotlin.io.path.deleteIfExists
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

class TextNotesRepoImpl @Inject constructor(): TextNotesRepo {

private val iODispatcher = Dispatchers.IO

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

private lateinit var root: Path

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

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

override 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")
}

override 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) {
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"

15 changes: 15 additions & 0 deletions app/src/main/java/space/taran/arkmemo/di/PreferencesModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package space.taran.arkmemo.di

import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import space.taran.arkmemo.preferences.MemoPreferences
import space.taran.arkmemo.preferences.MemoPreferencesImpl

@InstallIn(SingletonComponent::class)
@Module
abstract class PreferencesModule {
@Binds
abstract fun bindMemoPreferences(impl: MemoPreferencesImpl): MemoPreferences
}
16 changes: 16 additions & 0 deletions app/src/main/java/space/taran/arkmemo/di/RepositoryModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package space.taran.arkmemo.di

import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import space.taran.arkmemo.data.repositories.TextNotesRepo
import space.taran.arkmemo.data.repositories.TextNotesRepoImpl


@InstallIn(SingletonComponent::class)
@Module
abstract class RepositoryModule {
@Binds
abstract fun bindRepository(impl: TextNotesRepoImpl): TextNotesRepo
}
Original file line number Diff line number Diff line change
@@ -1,47 +1,11 @@
package space.taran.arkmemo.preferences

import android.content.Context
import android.content.Context.MODE_PRIVATE
import java.io.File
import java.nio.file.Path

class MemoPreferences private constructor(context: Context) {
private val sharedPreferences = context.getSharedPreferences(NAME, MODE_PRIVATE)
private val prefEditor = sharedPreferences.edit()
interface MemoPreferences {
fun storePath(path: String)

fun storePath(path: String){
prefEditor.apply{
putString(CURRENT_NOTES_PATH, path)
apply()
}
}
fun getPathString(): String?

fun getPathString() = sharedPreferences.getString(CURRENT_NOTES_PATH, null)

fun getPath(): Path? {
val pathString = getPathString()
var path: Path? = null
try {
val file = File(pathString!!)
file.mkdir()
path = file.toPath()
} catch (e: Exception) {
e.printStackTrace()
}
return path
}

companion object{
private const val NAME = "memo_prefs"
private const val CURRENT_NOTES_PATH = "current_notes_path"
private var preferences: MemoPreferences? = null

fun getInstance(context: Context): MemoPreferences{
if(preferences == null)
preferences = MemoPreferences(context)
return preferences!!
}

fun getInstance() = preferences!!
}
fun getPath(): Path?
}
Loading

0 comments on commit 50558c5

Please sign in to comment.