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

Extract methods to interfaces & change way of providing dependencies #25

Merged
merged 8 commits into from
Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
interface TextNotesRepo {
interface NotesRepo {

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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
class TextNotesRepoImpl @Inject constructor(): TextNotesRepo {
class TextNotesRepo @Inject constructor(): NotesRepo {


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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
abstract fun bindRepository(impl: TextNotesRepoImpl): TextNotesRepo
abstract fun bindRepository(impl: TextNotesRepo): NotesRepo

}
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