Общий VaultScreen
This commit is contained in:
@@ -27,12 +27,15 @@ import com.github.nullptroma.wallenc.presentation.R
|
||||
import com.github.nullptroma.wallenc.presentation.navigation.NavBarItemData
|
||||
import com.github.nullptroma.wallenc.presentation.navigation.NavigationState
|
||||
import com.github.nullptroma.wallenc.presentation.navigation.rememberNavigationState
|
||||
import com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault.LocalVaultRoute
|
||||
import com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault.LocalVaultScreen
|
||||
import com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault.LocalVaultViewModel
|
||||
import com.github.nullptroma.wallenc.presentation.screens.main.screens.remotes.RemoteVaultsRoute
|
||||
import com.github.nullptroma.wallenc.presentation.screens.main.screens.remotes.RemoteVaultsScreen
|
||||
import com.github.nullptroma.wallenc.presentation.screens.main.screens.remotes.RemoteVaultsViewModel
|
||||
import com.github.nullptroma.wallenc.presentation.screens.main.screens.vault.LocalVaultRoute
|
||||
import com.github.nullptroma.wallenc.presentation.screens.main.screens.vault.LocalVaultScreen
|
||||
import com.github.nullptroma.wallenc.presentation.screens.main.screens.vault.LocalVaultViewModel
|
||||
import com.github.nullptroma.wallenc.presentation.screens.main.screens.vault.RemoteVaultViewModel
|
||||
import com.github.nullptroma.wallenc.presentation.screens.main.screens.vault.VaultBrowserRoute
|
||||
import com.github.nullptroma.wallenc.presentation.screens.main.screens.vault.VaultBrowserScreen
|
||||
import com.github.nullptroma.wallenc.presentation.screens.shared.TextEditRoute
|
||||
import com.github.nullptroma.wallenc.presentation.screens.shared.TextEditScreen
|
||||
|
||||
@@ -110,7 +113,24 @@ fun MainScreen(
|
||||
}) {
|
||||
RemoteVaultsScreen(
|
||||
modifier = Modifier.padding(innerPaddings),
|
||||
viewModel = remoteVaultsViewModel
|
||||
viewModel = remoteVaultsViewModel,
|
||||
onOpenVault = { item ->
|
||||
navState.push(VaultBrowserRoute(item.uuid.toString()))
|
||||
},
|
||||
)
|
||||
}
|
||||
composable<VaultBrowserRoute>(enterTransition = {
|
||||
fadeIn(tween(200))
|
||||
}, exitTransition = {
|
||||
fadeOut(tween(200))
|
||||
}) { entry ->
|
||||
val remoteVaultViewModel: RemoteVaultViewModel = hiltViewModel(entry)
|
||||
VaultBrowserScreen(
|
||||
modifier = Modifier.padding(innerPaddings),
|
||||
viewModel = remoteVaultViewModel,
|
||||
openTextEdit = { text ->
|
||||
navState.push(TextEditRoute(text))
|
||||
},
|
||||
)
|
||||
}
|
||||
composable<TextEditRoute> {
|
||||
|
||||
@@ -5,8 +5,8 @@ import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewmodel.compose.SavedStateHandleSaveableApi
|
||||
import androidx.lifecycle.viewmodel.compose.saveable
|
||||
import com.github.nullptroma.wallenc.presentation.screens.ScreenRoute
|
||||
import com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault.LocalVaultRoute
|
||||
import com.github.nullptroma.wallenc.presentation.screens.main.screens.remotes.RemoteVaultsRoute
|
||||
import com.github.nullptroma.wallenc.presentation.screens.main.screens.vault.LocalVaultRoute
|
||||
import com.github.nullptroma.wallenc.presentation.ViewModelBase
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
|
||||
|
||||
@@ -6,4 +6,4 @@ import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@Parcelize
|
||||
class RemoteVaultsRoute: MainRoute()
|
||||
class RemoteVaultsRoute : MainRoute()
|
||||
|
||||
@@ -34,6 +34,7 @@ import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -41,7 +42,6 @@ import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.github.nullptroma.wallenc.presentation.R
|
||||
@@ -52,6 +52,7 @@ import com.github.nullptroma.wallenc.vaultapi.VaultLinkOutcome
|
||||
fun RemoteVaultsScreen(
|
||||
modifier: Modifier = Modifier,
|
||||
viewModel: RemoteVaultsViewModel = hiltViewModel(),
|
||||
onOpenVault: (RemoteVaultListItem) -> Unit,
|
||||
) {
|
||||
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
||||
val context = LocalContext.current
|
||||
@@ -92,7 +93,13 @@ fun RemoteVaultsScreen(
|
||||
) {
|
||||
items(uiState.vaults, key = { it.uuid }) { item ->
|
||||
ElevatedCard(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(
|
||||
enabled = !uiState.isBusy,
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = null,
|
||||
) { onOpenVault(item) },
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
elevation = CardDefaults.elevatedCardElevation(defaultElevation = 2.dp),
|
||||
colors = CardDefaults.elevatedCardColors(
|
||||
|
||||
@@ -4,10 +4,10 @@ import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.AlertDialog
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.github.nullptroma.wallenc.presentation.screens.main.screens.tasks
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.github.nullptroma.wallenc.domain.tasks.ITaskOrchestrator
|
||||
import com.github.nullptroma.wallenc.domain.tasks.PipelineWork
|
||||
import com.github.nullptroma.wallenc.domain.tasks.TaskLogLevel
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault
|
||||
package com.github.nullptroma.wallenc.presentation.screens.main.screens.vault
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey
|
||||
@@ -6,8 +6,8 @@ import com.github.nullptroma.wallenc.domain.datatypes.Tree
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IDirectory
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IFile
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.ILogger
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IStorage
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IStorageInfo
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager
|
||||
import com.github.nullptroma.wallenc.domain.tasks.ITaskOrchestrator
|
||||
import com.github.nullptroma.wallenc.domain.tasks.TaskLogLevel
|
||||
import com.github.nullptroma.wallenc.domain.usecases.GetOpenedStoragesUseCase
|
||||
@@ -18,76 +18,66 @@ import com.github.nullptroma.wallenc.domain.usecases.RenameStorageUseCase
|
||||
import com.github.nullptroma.wallenc.domain.usecases.StorageFileManagementUseCase
|
||||
import com.github.nullptroma.wallenc.presentation.ViewModelBase
|
||||
import com.github.nullptroma.wallenc.presentation.extensions.toPrintable
|
||||
import com.github.nullptroma.wallenc.vaultapi.described
|
||||
import com.github.nullptroma.wallenc.vaultapi.locals
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@HiltViewModel
|
||||
class LocalVaultViewModel @Inject constructor(
|
||||
private val vaultsManager: IVaultsManager,
|
||||
private val manageVaultUseCase: ManageVaultUseCase,
|
||||
/**
|
||||
* Общая логика дерева storages для локального и удалённого vault (presentation).
|
||||
*/
|
||||
abstract class AbstractVaultBrowserViewModel(
|
||||
storagesFlow: Flow<List<IStorage>>,
|
||||
private val canAddStorage: Boolean,
|
||||
private val resolveCreateVaultUuid: () -> UUID?,
|
||||
private val removeStorageUseCase: RemoveStorageUseCase,
|
||||
private val getOpenedStoragesUseCase: GetOpenedStoragesUseCase,
|
||||
private val storageFileManagementUseCase: StorageFileManagementUseCase,
|
||||
private val manageStoragesEncryptionUseCase: ManageStoragesEncryptionUseCase,
|
||||
private val renameStorageUseCase: RenameStorageUseCase,
|
||||
private val manageVaultUseCase: ManageVaultUseCase,
|
||||
private val taskOrchestrator: ITaskOrchestrator,
|
||||
private val logger: ILogger
|
||||
) : ViewModelBase<LocalVaultScreenState>(LocalVaultScreenState(listOf(), true)) {
|
||||
private val logger: ILogger,
|
||||
) : ViewModelBase<VaultBrowserScreenState>(
|
||||
VaultBrowserScreenState(storagesList = emptyList(), isLoading = true, canAddStorage = canAddStorage),
|
||||
) {
|
||||
|
||||
private val localVaultUuid: UUID?
|
||||
get() = vaultsManager.vaults.value.described().locals.firstOrNull()?.uuid
|
||||
|
||||
private val localStoragesFlow = vaultsManager.vaults
|
||||
.map { vaults -> vaults.described().locals.firstOrNull() }
|
||||
.flatMapLatest { v -> v?.storages ?: flowOf(emptyList()) }
|
||||
private val _messages = MutableSharedFlow<String>()
|
||||
val messages: SharedFlow<String> = _messages
|
||||
|
||||
private var _taskCount: Int = 0
|
||||
private var tasksCount
|
||||
get() = _taskCount
|
||||
private var taskCount: Int = 0
|
||||
set(value) {
|
||||
_taskCount = value
|
||||
field = value
|
||||
updateStateLoading()
|
||||
}
|
||||
|
||||
private var _isLoading: Boolean = false
|
||||
private var isLoading
|
||||
get() = _isLoading
|
||||
private var storagesLoading: Boolean = false
|
||||
set(value) {
|
||||
_isLoading = value
|
||||
field = value
|
||||
updateStateLoading()
|
||||
}
|
||||
|
||||
init {
|
||||
collectFlows()
|
||||
collectFlows(storagesFlow)
|
||||
}
|
||||
|
||||
private fun updateStateLoading() {
|
||||
updateState(state.value.copy(
|
||||
isLoading = this.isLoading || this.tasksCount > 0
|
||||
))
|
||||
updateState(
|
||||
state.value.copy(
|
||||
isLoading = storagesLoading || taskCount > 0,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun collectFlows() {
|
||||
private fun collectFlows(storagesFlow: Flow<List<IStorage>>) {
|
||||
viewModelScope.launch {
|
||||
localStoragesFlow.combine(getOpenedStoragesUseCase.openedStorages) { local, opened ->
|
||||
storagesFlow.combine(getOpenedStoragesUseCase.openedStorages) { storages, opened ->
|
||||
val list = mutableListOf<Tree<IStorageInfo>>()
|
||||
for (storage in local) {
|
||||
for (storage in storages) {
|
||||
var tree = Tree<IStorageInfo>(storage)
|
||||
list.add(tree)
|
||||
while (opened.containsKey(tree.value.uuid)) {
|
||||
@@ -99,7 +89,7 @@ class LocalVaultViewModel @Inject constructor(
|
||||
}
|
||||
list
|
||||
}.collect { trees ->
|
||||
isLoading = false
|
||||
storagesLoading = false
|
||||
updateState(state.value.copy(storagesList = trees))
|
||||
}
|
||||
}
|
||||
@@ -135,13 +125,14 @@ class LocalVaultViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
fun createStorage() {
|
||||
if (!state.value.canAddStorage) return
|
||||
taskOrchestrator.enqueue(
|
||||
title = "Create storage",
|
||||
dispatcher = Dispatchers.IO,
|
||||
work = { ctx ->
|
||||
ctx.log(TaskLogLevel.Info, "Creating storage…")
|
||||
val uuid = localVaultUuid
|
||||
?: throw IllegalStateException("Local vault is not registered")
|
||||
val uuid = resolveCreateVaultUuid()
|
||||
?: throw IllegalStateException("Vault is not available")
|
||||
manageVaultUseCase.createStorage(uuid)
|
||||
ctx.log(TaskLogLevel.Info, "Storage created")
|
||||
},
|
||||
@@ -156,7 +147,7 @@ class LocalVaultViewModel @Inject constructor(
|
||||
synchronized(storageOpMutex) {
|
||||
if (runningStorages.contains(id)) return
|
||||
runningStorages.add(id)
|
||||
tasksCount++
|
||||
taskCount++
|
||||
}
|
||||
val key = EncryptKey(password)
|
||||
taskOrchestrator.enqueue(
|
||||
@@ -196,7 +187,7 @@ class LocalVaultViewModel @Inject constructor(
|
||||
} finally {
|
||||
synchronized(storageOpMutex) {
|
||||
runningStorages.remove(id)
|
||||
tasksCount--
|
||||
taskCount--
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -208,7 +199,7 @@ class LocalVaultViewModel @Inject constructor(
|
||||
synchronized(storageOpMutex) {
|
||||
if (runningStorages.contains(id)) return
|
||||
runningStorages.add(id)
|
||||
tasksCount++
|
||||
taskCount++
|
||||
}
|
||||
val key = EncryptKey(password)
|
||||
taskOrchestrator.enqueue(
|
||||
@@ -225,7 +216,7 @@ class LocalVaultViewModel @Inject constructor(
|
||||
} finally {
|
||||
synchronized(storageOpMutex) {
|
||||
runningStorages.remove(id)
|
||||
tasksCount--
|
||||
taskCount--
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault
|
||||
package com.github.nullptroma.wallenc.presentation.screens.main.screens.vault
|
||||
|
||||
import com.github.nullptroma.wallenc.presentation.screens.main.MainRoute
|
||||
import kotlinx.parcelize.Parcelize
|
||||
@@ -6,4 +6,4 @@ import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@Parcelize
|
||||
class LocalVaultRoute: MainRoute()
|
||||
class LocalVaultRoute : MainRoute()
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.github.nullptroma.wallenc.presentation.screens.main.screens.vault
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
|
||||
@Composable
|
||||
fun LocalVaultScreen(
|
||||
modifier: Modifier = Modifier,
|
||||
viewModel: LocalVaultViewModel = hiltViewModel(),
|
||||
openTextEdit: (String) -> Unit,
|
||||
) {
|
||||
VaultBrowserScreen(
|
||||
modifier = modifier,
|
||||
viewModel = viewModel,
|
||||
openTextEdit = openTextEdit,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.github.nullptroma.wallenc.presentation.screens.main.screens.vault
|
||||
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.ILogger
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager
|
||||
import com.github.nullptroma.wallenc.domain.tasks.ITaskOrchestrator
|
||||
import com.github.nullptroma.wallenc.domain.usecases.GetOpenedStoragesUseCase
|
||||
import com.github.nullptroma.wallenc.domain.usecases.ManageStoragesEncryptionUseCase
|
||||
import com.github.nullptroma.wallenc.domain.usecases.ManageVaultUseCase
|
||||
import com.github.nullptroma.wallenc.domain.usecases.RemoveStorageUseCase
|
||||
import com.github.nullptroma.wallenc.domain.usecases.RenameStorageUseCase
|
||||
import com.github.nullptroma.wallenc.domain.usecases.StorageFileManagementUseCase
|
||||
import com.github.nullptroma.wallenc.vaultapi.described
|
||||
import com.github.nullptroma.wallenc.vaultapi.locals
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
import javax.inject.Inject
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@HiltViewModel
|
||||
class LocalVaultViewModel @Inject constructor(
|
||||
vaultsManager: IVaultsManager,
|
||||
manageVaultUseCase: ManageVaultUseCase,
|
||||
removeStorageUseCase: RemoveStorageUseCase,
|
||||
getOpenedStoragesUseCase: GetOpenedStoragesUseCase,
|
||||
storageFileManagementUseCase: StorageFileManagementUseCase,
|
||||
manageStoragesEncryptionUseCase: ManageStoragesEncryptionUseCase,
|
||||
renameStorageUseCase: RenameStorageUseCase,
|
||||
taskOrchestrator: ITaskOrchestrator,
|
||||
logger: ILogger,
|
||||
) : AbstractVaultBrowserViewModel(
|
||||
storagesFlow = vaultsManager.vaults
|
||||
.map { vaults -> vaults.described().locals.firstOrNull() }
|
||||
.flatMapLatest { v -> v?.storages ?: flowOf(emptyList()) },
|
||||
canAddStorage = true,
|
||||
resolveCreateVaultUuid = { vaultsManager.vaults.value.described().locals.firstOrNull()?.uuid },
|
||||
removeStorageUseCase = removeStorageUseCase,
|
||||
getOpenedStoragesUseCase = getOpenedStoragesUseCase,
|
||||
storageFileManagementUseCase = storageFileManagementUseCase,
|
||||
manageStoragesEncryptionUseCase = manageStoragesEncryptionUseCase,
|
||||
renameStorageUseCase = renameStorageUseCase,
|
||||
manageVaultUseCase = manageVaultUseCase,
|
||||
taskOrchestrator = taskOrchestrator,
|
||||
logger = logger,
|
||||
)
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.github.nullptroma.wallenc.presentation.screens.main.screens.vault
|
||||
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.ILogger
|
||||
import com.github.nullptroma.wallenc.domain.tasks.ITaskOrchestrator
|
||||
import com.github.nullptroma.wallenc.domain.usecases.GetOpenedStoragesUseCase
|
||||
import com.github.nullptroma.wallenc.domain.usecases.ManageStoragesEncryptionUseCase
|
||||
import com.github.nullptroma.wallenc.domain.usecases.ManageVaultUseCase
|
||||
import com.github.nullptroma.wallenc.domain.usecases.RemoveStorageUseCase
|
||||
import com.github.nullptroma.wallenc.domain.usecases.RenameStorageUseCase
|
||||
import com.github.nullptroma.wallenc.domain.usecases.StorageFileManagementUseCase
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@HiltViewModel
|
||||
class RemoteVaultViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
manageVaultUseCase: ManageVaultUseCase,
|
||||
removeStorageUseCase: RemoveStorageUseCase,
|
||||
getOpenedStoragesUseCase: GetOpenedStoragesUseCase,
|
||||
storageFileManagementUseCase: StorageFileManagementUseCase,
|
||||
manageStoragesEncryptionUseCase: ManageStoragesEncryptionUseCase,
|
||||
renameStorageUseCase: RenameStorageUseCase,
|
||||
taskOrchestrator: ITaskOrchestrator,
|
||||
logger: ILogger,
|
||||
) : AbstractVaultBrowserViewModel(
|
||||
storagesFlow = manageVaultUseCase.storagesOf(savedStateHandle.requireVaultUuid()),
|
||||
canAddStorage = false,
|
||||
resolveCreateVaultUuid = { null },
|
||||
removeStorageUseCase = removeStorageUseCase,
|
||||
getOpenedStoragesUseCase = getOpenedStoragesUseCase,
|
||||
storageFileManagementUseCase = storageFileManagementUseCase,
|
||||
manageStoragesEncryptionUseCase = manageStoragesEncryptionUseCase,
|
||||
renameStorageUseCase = renameStorageUseCase,
|
||||
manageVaultUseCase = manageVaultUseCase,
|
||||
taskOrchestrator = taskOrchestrator,
|
||||
logger = logger,
|
||||
)
|
||||
|
||||
private fun SavedStateHandle.requireVaultUuid(): UUID {
|
||||
val raw = get<String>("vaultUuid") ?: error("Missing vault UUID in navigation arguments")
|
||||
return UUID.fromString(raw)
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.github.nullptroma.wallenc.presentation.screens.main.screens.vault
|
||||
|
||||
import com.github.nullptroma.wallenc.presentation.screens.ScreenRoute
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@Parcelize
|
||||
data class VaultBrowserRoute(val vaultUuid: String) : ScreenRoute()
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault
|
||||
package com.github.nullptroma.wallenc.presentation.screens.main.screens.vault
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.background
|
||||
@@ -27,18 +27,16 @@ import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.github.nullptroma.wallenc.presentation.elements.StorageTree
|
||||
import com.github.nullptroma.wallenc.presentation.extensions.gesturesDisabled
|
||||
|
||||
@Composable
|
||||
fun LocalVaultScreen(
|
||||
fun VaultBrowserScreen(
|
||||
modifier: Modifier = Modifier,
|
||||
viewModel: LocalVaultViewModel = hiltViewModel(),
|
||||
viewModel: AbstractVaultBrowserViewModel,
|
||||
openTextEdit: (String) -> Unit,
|
||||
) {
|
||||
|
||||
val uiState by viewModel.state.collectAsStateWithLifecycle()
|
||||
val context = LocalContext.current
|
||||
LaunchedEffect(Unit) {
|
||||
@@ -52,55 +50,44 @@ fun LocalVaultScreen(
|
||||
modifier = modifier,
|
||||
contentWindowInsets = WindowInsets(0.dp),
|
||||
floatingActionButton = {
|
||||
FloatingActionButton(
|
||||
onClick = {
|
||||
viewModel.createStorage()
|
||||
},
|
||||
if (uiState.canAddStorage) {
|
||||
FloatingActionButton(
|
||||
onClick = { viewModel.createStorage() },
|
||||
) {
|
||||
Icon(Icons.Filled.Add, contentDescription = null)
|
||||
}
|
||||
}
|
||||
},
|
||||
) { innerPadding ->
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.gesturesDisabled(uiState.isLoading),
|
||||
) {
|
||||
Icon(Icons.Filled.Add, "Floating action button.")
|
||||
}
|
||||
}) { innerPadding ->
|
||||
LazyColumn(modifier = Modifier.padding(innerPadding).gesturesDisabled(uiState.isLoading)) {
|
||||
items(uiState.storagesList) { listItem ->
|
||||
StorageTree(
|
||||
modifier = Modifier.padding(8.dp, 8.dp, 8.dp, 0.dp),
|
||||
tree = listItem,
|
||||
onClick = {
|
||||
openTextEdit(it.value.uuid.toString())
|
||||
},
|
||||
onRename = { tree, newName ->
|
||||
viewModel.rename(tree.value, newName)
|
||||
},
|
||||
onRemove = { tree ->
|
||||
viewModel.remove(tree.value)
|
||||
},
|
||||
onClick = { openTextEdit(it.value.uuid.toString()) },
|
||||
onRename = { tree, newName -> viewModel.rename(tree.value, newName) },
|
||||
onRemove = { tree -> viewModel.remove(tree.value) },
|
||||
onEncrypt = { tree, password, encryptPath ->
|
||||
viewModel.enableEncryption(tree.value, password, encryptPath)
|
||||
},
|
||||
onOpenEncrypted = { tree, password, remember ->
|
||||
viewModel.openEncryptedStorage(tree.value, password, remember)
|
||||
},
|
||||
onCloseEncrypted = { tree ->
|
||||
viewModel.closeEncryptedStorage(tree.value)
|
||||
},
|
||||
onDisableEncryption = { tree ->
|
||||
viewModel.disableEncryption(tree.value)
|
||||
},
|
||||
getStatusText = { tree ->
|
||||
viewModel.getStorageStatus(tree.value)
|
||||
},
|
||||
isEncryptionOpened = { tree ->
|
||||
viewModel.isEncryptionSessionOpen(tree.value)
|
||||
},
|
||||
onCloseEncrypted = { tree -> viewModel.closeEncryptedStorage(tree.value) },
|
||||
onDisableEncryption = { tree -> viewModel.disableEncryption(tree.value) },
|
||||
getStatusText = { tree -> viewModel.getStorageStatus(tree.value) },
|
||||
isEncryptionOpened = { tree -> viewModel.isEncryptionSessionOpen(tree.value) },
|
||||
)
|
||||
}
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
}
|
||||
item { Spacer(modifier = Modifier.height(8.dp)) }
|
||||
}
|
||||
}
|
||||
|
||||
if(uiState.isLoading) {
|
||||
if (uiState.isLoading) {
|
||||
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||
Box(modifier = Modifier.fillMaxSize().alpha(0.6f).background(Color.Black))
|
||||
CircularProgressIndicator(
|
||||
@@ -112,4 +99,3 @@ fun LocalVaultScreen(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault
|
||||
package com.github.nullptroma.wallenc.presentation.screens.main.screens.vault
|
||||
|
||||
import com.github.nullptroma.wallenc.domain.datatypes.Tree
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IStorageInfo
|
||||
|
||||
data class LocalVaultScreenState(val storagesList: List<Tree<IStorageInfo>>, val isLoading: Boolean)
|
||||
data class VaultBrowserScreenState(
|
||||
val storagesList: List<Tree<IStorageInfo>>,
|
||||
val isLoading: Boolean,
|
||||
val canAddStorage: Boolean = false,
|
||||
)
|
||||
Reference in New Issue
Block a user