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

Refactor architecture to separate data, domain, and presentation layers #520

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
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
@@ -0,0 +1,19 @@
package com.softartdev.notedelight.shared.data

import com.softartdev.notedelight.shared.db.DatabaseHolder
import com.softartdev.notedelight.shared.db.NoteDb
import com.softartdev.notedelight.shared.db.NoteQueries

class SQLDelightDatabaseSource(
private val databaseHolder: DatabaseHolder
) {
val noteDb: NoteDb
get() = databaseHolder.noteDb

val noteQueries: NoteQueries
get() = databaseHolder.noteQueries

fun close() {
databaseHolder.close()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.softartdev.notedelight.shared.data

import com.softartdev.notedelight.shared.db.DatabaseHolder
import com.softartdev.notedelight.shared.db.NoteDAO
import com.softartdev.notedelight.shared.db.PlatformSQLiteThrowable
import com.softartdev.notedelight.shared.db.SafeRepo
import com.softartdev.notedelight.shared.PlatformSQLiteState

class SQLDelightSafeRepository(
private val databaseHolder: DatabaseHolder,
override val noteDAO: NoteDAO
) : SafeRepo() {

override val databaseState: PlatformSQLiteState
get() = databaseHolder.databaseState

override val dbPath: String
get() = databaseHolder.dbPath

override fun buildDbIfNeed(passphrase: CharSequence): DatabaseHolder {
return databaseHolder.buildDbIfNeed(passphrase)
}

override fun decrypt(oldPass: CharSequence) {
try {
databaseHolder.decrypt(oldPass)
} catch (throwable: Throwable) {
throw PlatformSQLiteThrowable(throwable.message.orEmpty())
}
}

override fun rekey(oldPass: CharSequence, newPass: CharSequence) {
try {
databaseHolder.rekey(oldPass, newPass)
} catch (throwable: Throwable) {
throw PlatformSQLiteThrowable(throwable.message.orEmpty())
}
}

override fun encrypt(newPass: CharSequence) {
try {
databaseHolder.encrypt(newPass)
} catch (throwable: Throwable) {
throw PlatformSQLiteThrowable(throwable.message.orEmpty())
}
}

override fun closeDatabase() {
databaseHolder.closeDatabase()
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.softartdev.notedelight.shared.di

import com.softartdev.notedelight.shared.db.NoteDAO
import com.softartdev.notedelight.shared.db.SafeRepo
import com.softartdev.notedelight.shared.domain.repository.NoteDAO
import com.softartdev.notedelight.shared.domain.repository.SafeRepository
import com.softartdev.notedelight.shared.presentation.main.MainViewModel
import com.softartdev.notedelight.shared.presentation.note.DeleteViewModel
import com.softartdev.notedelight.shared.presentation.note.NoteViewModel
Expand All @@ -13,13 +13,13 @@ import com.softartdev.notedelight.shared.presentation.settings.security.enter.En
import com.softartdev.notedelight.shared.presentation.signin.SignInViewModel
import com.softartdev.notedelight.shared.presentation.splash.SplashViewModel
import com.softartdev.notedelight.shared.presentation.title.EditTitleViewModel
import com.softartdev.notedelight.shared.usecase.crypt.ChangePasswordUseCase
import com.softartdev.notedelight.shared.usecase.crypt.CheckPasswordUseCase
import com.softartdev.notedelight.shared.usecase.crypt.CheckSqlCipherVersionUseCase
import com.softartdev.notedelight.shared.usecase.note.CreateNoteUseCase
import com.softartdev.notedelight.shared.usecase.note.DeleteNoteUseCase
import com.softartdev.notedelight.shared.usecase.note.SaveNoteUseCase
import com.softartdev.notedelight.shared.usecase.note.UpdateTitleUseCase
import com.softartdev.notedelight.shared.domain.usecase.crypt.ChangePasswordUseCase
import com.softartdev.notedelight.shared.domain.usecase.crypt.CheckPasswordUseCase
import com.softartdev.notedelight.shared.domain.usecase.crypt.CheckSqlCipherVersionUseCase
import com.softartdev.notedelight.shared.domain.usecase.note.CreateNoteUseCase
import com.softartdev.notedelight.shared.domain.usecase.note.DeleteNoteUseCase
import com.softartdev.notedelight.shared.domain.usecase.note.SaveNoteUseCase
import com.softartdev.notedelight.shared.domain.usecase.note.UpdateTitleUseCase
import org.koin.core.module.Module
import org.koin.core.module.dsl.factoryOf
import org.koin.core.module.dsl.viewModelOf
Expand All @@ -29,12 +29,12 @@ val sharedModules: List<Module>
get() = repoModule + daoModule + useCaseModule + viewModelModule

/**
Provide the [SafeRepo]
Provide the [SafeRepository]
*/
expect val repoModule: Module

val daoModule: Module = module {
factory<NoteDAO> { get<SafeRepo>().noteDAO }
factory<NoteDAO> { get<SafeRepository>().noteDAO }
}

val useCaseModule: Module = module {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.softartdev.notedelight.shared.domain.model

enum class DatabaseState {
DOES_NOT_EXIST,
UNENCRYPTED,
ENCRYPTED
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.softartdev.notedelight.shared.domain.model

import kotlinx.datetime.LocalDateTime
import kotlinx.serialization.Serializable

@Serializable
data class Note(
val id: Long,
val title: String,
val text: String,
val dateCreated: LocalDateTime,
val dateModified: LocalDateTime
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.softartdev.notedelight.shared.domain.repository

import com.softartdev.notedelight.shared.domain.model.DatabaseState
import com.softartdev.notedelight.shared.domain.model.Note

interface SafeRepository {

val databaseState: DatabaseState

val noteDAO: NoteDAO

val dbPath: String

var relaunchListFlowCallback: (() -> Any)?

fun buildDbIfNeed(passphrase: CharSequence = ""): DatabaseHolder

fun decrypt(oldPass: CharSequence)

fun rekey(oldPass: CharSequence, newPass: CharSequence)

fun encrypt(newPass: CharSequence)

fun closeDatabase()

companion object {
const val DB_NAME = "notes.db"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.softartdev.notedelight.shared.domain.usecase

import com.softartdev.notedelight.shared.domain.repository.SafeRepository

class ChangePasswordUseCase(private val safeRepository: SafeRepository) {

operator fun invoke(oldPassword: CharSequence?, newPassword: CharSequence) {
if (oldPassword == null) {
safeRepository.encrypt(newPassword)
} else {
safeRepository.rekey(oldPassword, newPassword)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.softartdev.notedelight.shared.domain.usecase

import com.softartdev.notedelight.shared.domain.repository.SafeRepository

class CheckPasswordUseCase(private val safeRepository: SafeRepository) {

operator fun invoke(password: CharSequence): Boolean {
return try {
safeRepository.buildDbIfNeed(password)
true
} catch (e: Throwable) {
false
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.softartdev.notedelight.shared.domain.usecase

import com.softartdev.notedelight.shared.db.SafeRepo

class CheckSqlCipherVersionUseCase(private val safeRepo: SafeRepo) {

operator fun invoke(): String? {
return safeRepo.databaseState.name
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.softartdev.notedelight.shared.domain.usecase

import com.softartdev.notedelight.shared.domain.model.Note
import com.softartdev.notedelight.shared.domain.repository.NoteDAO
import kotlinx.datetime.Clock

class CreateNoteUseCase(private val noteDAO: NoteDAO) {

operator fun invoke(): Long {
val note = Note(
id = 0L,
title = "",
text = "",
dateCreated = Clock.System.now().toLocalDateTime(),
dateModified = Clock.System.now().toLocalDateTime()
)
return noteDAO.insert(note)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.softartdev.notedelight.shared.presentation

import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.lifecycle.viewmodel.compose.viewModel
import com.softartdev.notedelight.shared.presentation.note.NoteViewModel
import com.softartdev.notedelight.shared.presentation.note.NoteResult

@Composable
fun NoteDetailScreen(
noteViewModel: NoteViewModel = viewModel()
) {
val noteResult by noteViewModel.stateFlow.collectAsState()

when (noteResult) {
is NoteResult.Loading -> {
// Show loading indicator
}
is NoteResult.Success -> {
val note = (noteResult as NoteResult.Success).note
// Display the note details
}
is NoteResult.Error -> {
val errorMessage = (noteResult as NoteResult.Error).message
// Show error message
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.softartdev.notedelight.shared.presentation

import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.lifecycle.viewmodel.compose.viewModel
import com.softartdev.notedelight.shared.presentation.main.MainViewModel
import com.softartdev.notedelight.shared.presentation.main.NoteListResult

@Composable
fun NoteListScreen(
mainViewModel: MainViewModel = viewModel()
) {
val noteListResult by mainViewModel.stateFlow.collectAsState()

when (noteListResult) {
is NoteListResult.Loading -> {
// Show loading indicator
}
is NoteListResult.Success -> {
val notes = (noteListResult as NoteListResult.Success).result
// Display the list of notes
}
is NoteListResult.Error -> {
val errorMessage = (noteListResult as NoteListResult.Error).message
// Show error message
}
}
}
Loading