Skip to content
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
1 change: 1 addition & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ ktlint_standard_property-naming = disabled
ktlint_standard_import-ordering = disabled
ktlint_standard_no-multi-spaces = disabled
ktlint_standard_chain-method-continuation = disabled
ktlint_standard_class-signature = disabled



Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import io.writeopia.notemenu.navigation.NAVIGATION_TYPE
import io.writeopia.notemenu.navigation.navigateToNotes
import io.writeopia.notemenu.ui.screen.menu.EditFileScreen
import io.writeopia.notemenu.ui.screen.menu.RoundedVerticalDivider
import io.writeopia.sdk.persistence.core.di.RepositoryInjector
import io.writeopia.sql.WriteopiaDb
import io.writeopia.sqldelight.di.SqlDelightDaoInjector
import io.writeopia.sqldelight.di.WriteopiaDbInjector
Expand Down Expand Up @@ -81,6 +82,8 @@ fun DesktopApp(
WriteopiaDbInjector.initialize(writeopiaDb)
}

RepositoryInjector.initialize(SqlDelightDaoInjector.singleton())

val editorInjector = remember {
EditorKmpInjector.desktop(
selectionState = selectionState,
Expand All @@ -100,7 +103,7 @@ fun DesktopApp(
}

val documentsGraphInjection =
DocumentsGraphInjection(repositoryInjection = SqlDelightDaoInjector.singleton())
DocumentsGraphInjection(repositoryInjection = RepositoryInjector.singleton())

val globalShellViewModel: GlobalShellViewModel =
sideMenuInjector.provideSideMenuViewModel(keyboardEventFlow)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import io.writeopia.persistence.room.injection.AppRoomDaosInjection
import io.writeopia.persistence.room.injection.RoomRepositoryInjection
import io.writeopia.persistence.room.injection.WriteopiaRoomInjector
import io.writeopia.sdk.network.injector.WriteopiaConnectionInjector
import io.writeopia.sdk.persistence.core.di.RepositoryInjector
import io.writeopia.ui.image.ImageLoadConfig

class NavigationActivity : ComponentActivity() {
Expand Down Expand Up @@ -66,19 +67,19 @@ fun NavigationGraph(
SharedPreferencesInjector.init(sharedPreferences)
WriteopiaRoomInjector.init(database)

RepositoryInjector.initialize(RoomRepositoryInjection.singleton())

val uiConfigInjection = UiConfigurationInjector.singleton()

val appDaosInjection = AppRoomDaosInjection.singleton()
WriteopiaConnectionInjector.setBaseUrl(BuildConfig.BASE_URL)
val uiConfigViewModel = uiConfigInjection.provideUiConfigurationViewModel()
val repositoryInjection = RoomRepositoryInjection.singleton()
val editorInjector = EditorKmpInjector.mobile(repositoryInjection)
val notesMenuInjection = NotesMenuKmpInjection.mobile(repositoryInjection)
val editorInjector = EditorKmpInjector.mobile()
val notesMenuInjection = NotesMenuKmpInjection.mobile()

val searchInjector = remember {
MobileSearchInjection(
appRoomDaosInjection = appDaosInjection,
roomInjector = repositoryInjection
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import io.writeopia.navigation.MobileNavigationViewModel
import io.writeopia.notemenu.di.NotesMenuKmpInjection
import io.writeopia.notemenu.di.UiConfigurationInjector
import io.writeopia.notemenu.navigation.navigateToNotes
import io.writeopia.sdk.persistence.core.di.RepositoryInjector
import io.writeopia.sqldelight.database.DatabaseCreation
import io.writeopia.sqldelight.database.DatabaseFactory
import io.writeopia.sqldelight.database.driver.DriverFactory
Expand All @@ -41,19 +42,19 @@ fun MainViewController() = ComposeUIViewController {
val database = databaseState.writeopiaDb

WriteopiaDbInjector.initialize(database)
RepositoryInjector.initialize(SqlDelightDaoInjector.singleton())

val uiConfigurationInjector = remember { UiConfigurationInjector.singleton() }
val sqlDelightDaoInjector = remember { SqlDelightDaoInjector.singleton() }
val searchInjection = remember { KmpSearchInjection.singleton() }

val uiConfigurationViewModel = uiConfigurationInjector
.provideUiConfigurationViewModel()

val notesMenuInjection = remember {
NotesMenuKmpInjection.mobile(sqlDelightDaoInjector)
NotesMenuKmpInjection.mobile()
}

val editorInjector = EditorKmpInjector.mobile(sqlDelightDaoInjector)
val editorInjector = EditorKmpInjector.mobile()

val navigationViewModel = viewModel { MobileNavigationViewModel() }

Expand Down
2 changes: 1 addition & 1 deletion application/core/documents/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ kotlin {
implementation(project(":writeopia"))
implementation(project(":writeopia_models"))
implementation(project(":plugins:writeopia_persistence_core"))

implementation(project(":plugins:writeopia_serialization"))
implementation(project(":plugins:writeopia_network"))

implementation(project(":application:core:utils"))
implementation(project(":application:core:auth_core"))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package io.writeopia.core.folders.di

import io.writeopia.auth.core.di.AuthCoreInjectionNeo
import io.writeopia.core.folders.api.DocumentsApi
import io.writeopia.core.folders.sync.DocumentConflictHandler
import io.writeopia.core.folders.sync.WorkspaceSync
import io.writeopia.di.AppConnectionInjection
import io.writeopia.sdk.network.injector.WriteopiaConnectionInjector
import io.writeopia.sdk.persistence.core.di.RepositoryInjector

class WorkspaceInjection private constructor(
private val authCoreInjection: AuthCoreInjectionNeo = AuthCoreInjectionNeo.singleton(),
private val appConnectionInjection: AppConnectionInjection = AppConnectionInjection.singleton(),
private val connectionInjector: WriteopiaConnectionInjector =
WriteopiaConnectionInjector.singleton(),
private val repositoryInjection: RepositoryInjector = RepositoryInjector.singleton(),
) {

fun provideWorkspaceSync(): WorkspaceSync {
val documentRepo = repositoryInjection.provideDocumentRepository()
return WorkspaceSync(
folderRepository = FoldersInjector.singleton().provideFoldersRepository(),
documentRepository = documentRepo,
authRepository = authCoreInjection.provideAuthRepository(),
documentsApi = DocumentsApi(
appConnectionInjection.provideHttpClient(),
connectionInjector.baseUrl()
),
documentConflictHandler = DocumentConflictHandler(
documentRepository = documentRepo,
folderRepository = FoldersInjector.singleton().provideFoldersRepository(),
authCoreInjection.provideAuthRepository()
),
)
}

companion object {
private var instance: WorkspaceInjection? = null

fun singleton() = instance ?: WorkspaceInjection().also {
instance = it
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,8 @@ class RoomFolderRepository(
SelectedIds.ids.remove(parentId)
}

override suspend fun localOutDatedFolders(workspaceId: String): List<Folder> {
TODO("Not yet implemented")
}
override suspend fun localOutDatedFolders(workspaceId: String): List<Folder> =
folderRoomDao.getFoldersForWorkspace(workspaceId)

override suspend fun search(query: String, workspaceId: String): List<Folder> =
folderRoomDao.search(query, workspaceId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class WorkspaceSync(

suspend fun syncWorkspace(workspaceId: String): ResultData<Unit> {
try {
println("start to sync workspace")
val authToken = authRepository.getAuthToken() ?: return ResultData.Error(null)
val workspace = authRepository.getWorkspace() ?: return ResultData.Idle()

Expand All @@ -37,7 +38,8 @@ class WorkspaceSync(
documentRepository.loadOutdatedDocumentsForWorkspace(workspaceId)
val localOutdatedFolders = folderRepository.localOutDatedFolders(workspaceId)

println("local outdated docs: ${localOutdatedFolders.size}")
println("local outdated folders: ${localOutdatedFolders.size}")
println("local outdated docs: ${localOutdatedDocs.size}")

val documentsNotSent = documentConflictHandler.handleConflict(
localOutdatedDocs,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,33 +17,27 @@ class FolderDaoDelegator(
delegate.upsertFolder(folderEntity.toRoomEntity().toEntity())
}

override suspend fun getFolderById(id: String): Folder? {
return delegate.getFolderById(id)?.toCommonEntity()?.toModel(0)
}
override suspend fun getFolderById(id: String): Folder? =
delegate.getFolderById(id)?.toCommonEntity()?.toModel(0)

override suspend fun search(query: String, workspaceId: String): List<Folder> {
return delegate.search(query, workspaceId).map { it.toCommonEntity().toModel(0) }
}
override suspend fun search(query: String, workspaceId: String): List<Folder> =
delegate.search(query, workspaceId).map { it.toCommonEntity().toModel(0) }

override suspend fun getLastUpdated(): List<Folder> {
return delegate.getLastUpdated().map { it.toCommonEntity().toModel(0) }
}
override suspend fun getFoldersForWorkspace(workspaceId: String): List<Folder> =
delegate.getFoldersByWorkspaceId(workspaceId).map { it.toCommonEntity().toModel(0) }

override suspend fun getFolderByParentId(id: String): List<Folder> {
return delegate.getFolderByParentId(id).map { it.toCommonEntity().toModel(0) }
}
override suspend fun getLastUpdated(): List<Folder> =
delegate.getLastUpdated().map { it.toCommonEntity().toModel(0) }

override fun listenForFolderByParentId(id: String): Flow<List<Folder>> {
return delegate.listenForFolderByParentId(id).map { list ->
override suspend fun getFolderByParentId(id: String): List<Folder> =
delegate.getFolderByParentId(id).map { it.toCommonEntity().toModel(0) }

override fun listenForFolderByParentId(id: String): Flow<List<Folder>> =
delegate.listenForFolderByParentId(id).map { list ->
list.map { it.toCommonEntity().toModel(0) }
}
}

override suspend fun deleteById(id: String): Int {
return delegate.deleteById(id)
}
override suspend fun deleteById(id: String): Int = delegate.deleteById(id)

override suspend fun deleteByParentId(id: String): Int {
return delegate.deleteByParentId(id)
}
override suspend fun deleteByParentId(id: String): Int = delegate.deleteByParentId(id)
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ interface FolderRoomDao {
@Query("SELECT * FROM $FOLDER_ENTITY ORDER BY last_updated_at LIMIT 15")
suspend fun getLastUpdated(): List<FolderEntity>

@Query("SELECT * FROM $FOLDER_ENTITY WHERE workspace_id = :workspaceId")
fun getFoldersByWorkspaceId(workspaceId: String): List<FolderEntity>

@Query("SELECT * FROM $FOLDER_ENTITY WHERE parent_id = :id")
suspend fun getFolderByParentId(id: String): List<FolderEntity>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ class SqlDelightDaoInjector(
companion object {
private var instance: SqlDelightDaoInjector? = null

fun noop() = SqlDelightDaoInjector(null)

fun singleton(): SqlDelightDaoInjector =
instance ?: SqlDelightDaoInjector(WriteopiaDbInjector.singleton()?.database).also {
instance = it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ interface FolderCommonDao {

suspend fun search(query: String, workspaceId: String): List<Folder>

suspend fun getFoldersForWorkspace(workspaceId: String): List<Folder>

suspend fun getLastUpdated(): List<Folder>

suspend fun getFolderByParentId(id: String): List<Folder>
Expand Down
1 change: 1 addition & 0 deletions application/features/account/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ kotlin {
implementation(project(":application:core:common_ui"))
implementation(project(":application:core:ollama"))
implementation(project(":application:core:resources"))
implementation(project(":application:core:documents"))

implementation(libs.kotlinx.datetime)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import io.writeopia.account.viewmodel.AccountMenuKmpViewModel
import io.writeopia.account.viewmodel.AccountMenuViewModel
import io.writeopia.auth.core.di.AuthCoreInjectionNeo
import io.writeopia.core.folders.di.WorkspaceInjection

class AccountMenuKmpInjector private constructor() {
class AccountMenuKmpInjector private constructor(
private val workspaceInjection: WorkspaceInjection = WorkspaceInjection.singleton(),
) {

private fun provideAccountMenuKmpViewModel(): AccountMenuKmpViewModel =
AccountMenuKmpViewModel(
authRepository = AuthCoreInjectionNeo.singleton().provideAuthRepository()
authRepository = AuthCoreInjectionNeo.singleton().provideAuthRepository(),
workspaceSync = workspaceInjection.provideWorkspaceSync()
)

@Composable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ fun AccountMenuScreen(
ollamaModelsRetry = {},
downloadModel = {},
deleteModel = {},
syncWorkspace = {}
syncWorkspace = accountMenuViewModel::syncWorkspace,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,9 @@ private fun WorkspaceSection(

CommonButton(
text = "Sync workspace",
clickListener = syncWorkspace
clickListener = {
syncWorkspace()
}
)

if (lastSync.isNotEmpty()) {
Expand Down Expand Up @@ -583,7 +585,6 @@ private fun AiSection(
}
}


@Composable
private fun SelectModels(
ollamaAvailableModels: Flow<ResultData<List<String>>>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,67 @@ package io.writeopia.account.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import io.writeopia.auth.core.manager.AuthRepository
import io.writeopia.core.folders.sync.WorkspaceSync
import io.writeopia.sdk.models.utils.toBoolean
import io.writeopia.sdk.models.user.WriteopiaUser
import io.writeopia.sdk.models.utils.ResultData
import io.writeopia.sdk.models.workspace.Workspace
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.datetime.Clock
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toLocalDateTime

internal class AccountMenuKmpViewModel(
private val authRepository: AuthRepository,
private val workspaceSync: WorkspaceSync,
) : AccountMenuViewModel, ViewModel() {

private val _lastWorkspaceSync = MutableStateFlow("")
override val lastWorkspaceSync: StateFlow<String> = _lastWorkspaceSync.asStateFlow()

override val isLoggedIn: StateFlow<ResultData<Boolean>> by lazy {
authRepository.listenForUser().map {
ResultData.Complete(it.id != WriteopiaUser.DISCONNECTED)
}.stateIn(viewModelScope, SharingStarted.Lazily, ResultData.Loading())
}

override fun logout(onLogOutSuccess: () -> Unit) {
viewModelScope.launch {
viewModelScope.launch(Dispatchers.Default) {
authRepository.unselectAllWorkspaces()
val result = authRepository.logout()

if (result.toBoolean()) {
onLogOutSuccess()
withContext(Dispatchers.Main) {
onLogOutSuccess()
}
}
}
}

override fun syncWorkspace() {
viewModelScope.launch(Dispatchers.Default) {
val workspace = authRepository.getWorkspace() ?: Workspace.disconnectedWorkspace()
val workspaceId = workspace.id
val result = workspaceSync.syncWorkspace(workspaceId)

_lastWorkspaceSync.value = if (result is ResultData.Complete) {
val lastSync = Clock.System
.now()
.toLocalDateTime(TimeZone.currentSystemDefault())
.toString()

"Last sync: $lastSync"
} else {
println("result error: $result")
"Error in sync"
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,9 @@ interface AccountMenuViewModel {

val isLoggedIn: StateFlow<ResultData<Boolean>>

val lastWorkspaceSync: StateFlow<String>

fun logout(onLogOutSuccess: () -> Unit)

fun syncWorkspace()
}
Loading