Поправлен клик сквозь экран загрузки

This commit is contained in:
Пытков Роман
2025-02-09 22:03:14 +03:00
parent 4404ef2ff4
commit e1646611c2
9 changed files with 122 additions and 44 deletions

View File

@@ -46,7 +46,13 @@ class EncryptedStorage private constructor(
override val isAvailable: StateFlow<Boolean> override val isAvailable: StateFlow<Boolean>
get() = source.isAvailable get() = source.isAvailable
override val accessor: EncryptedStorageAccessor = override val accessor: EncryptedStorageAccessor =
EncryptedStorageAccessor(source.accessor, encInfo.pathIv, key, "${uuid.toString().take(8)}$SYSTEM_HIDDEN_DIRNAME_POSTFIX", scope) EncryptedStorageAccessor(
source = source.accessor,
pathIv = encInfo.pathIv,
key = key,
systemHiddenDirName = "${uuid.toString().take(8)}$SYSTEM_HIDDEN_DIRNAME_POSTFIX",
scope = scope
)
private suspend fun init() { private suspend fun init() {
checkKey() checkKey()

View File

@@ -51,7 +51,6 @@ class EncryptedStorageAccessor(
private val dataEncryptor = Encryptor(key.toAesKey()) private val dataEncryptor = Encryptor(key.toAesKey())
private val pathEncryptor: EncryptorWithStaticIv? = if(pathIv != null) EncryptorWithStaticIv(key.toAesKey(), pathIv) else null private val pathEncryptor: EncryptorWithStaticIv? = if(pathIv != null) EncryptorWithStaticIv(key.toAesKey(), pathIv) else null
private var systemHiddenFiles: List<IFile>? = null
private var systemHiddenFilesIsActual = false private var systemHiddenFilesIsActual = false
init { init {

View File

@@ -4,7 +4,7 @@ import com.github.nullptroma.wallenc.domain.datatypes.StorageEncryptionInfo
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
interface IVault : IVaultInfo { interface IVault : IVaultInfo {
override val storages: StateFlow<List<IStorage>> override val storages: StateFlow<List<IStorage>?>
suspend fun createStorage(): IStorage suspend fun createStorage(): IStorage
suspend fun createStorage(enc: StorageEncryptionInfo): IStorage suspend fun createStorage(enc: StorageEncryptionInfo): IStorage

View File

@@ -7,7 +7,7 @@ import java.util.UUID
sealed interface IVaultInfo { sealed interface IVaultInfo {
val type: VaultType val type: VaultType
val uuid: UUID val uuid: UUID
val storages: StateFlow<List<IStorageInfo>> val storages: StateFlow<List<IStorageInfo>?>
val isAvailable: StateFlow<Boolean> val isAvailable: StateFlow<Boolean>
val totalSpace: StateFlow<Int?> val totalSpace: StateFlow<Int?>
val availableSpace: StateFlow<Int?> val availableSpace: StateFlow<Int?>

View File

@@ -10,7 +10,7 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
class ManageLocalVaultUseCase(private val manager: IVaultsManager, private val unlockManager: IUnlockManager) { class ManageLocalVaultUseCase(private val manager: IVaultsManager, private val unlockManager: IUnlockManager) {
val localStorages: StateFlow<List<IStorageInfo>> val localStorages: StateFlow<List<IStorageInfo>?>
get() = manager.localVault.storages get() = manager.localVault.storages
suspend fun createStorage() { suspend fun createStorage() {

View File

@@ -8,6 +8,9 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.composed import androidx.compose.ui.composed
import androidx.compose.ui.input.pointer.PointerEventPass
import androidx.compose.ui.input.pointer.PointerInputChange
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.layout import androidx.compose.ui.layout.layout
import androidx.compose.ui.platform.debugInspectorInfo import androidx.compose.ui.platform.debugInspectorInfo
import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.Role
@@ -32,3 +35,19 @@ fun Modifier.ignoreVerticalParentPadding(vertical: Dp): Modifier {
} }
} }
} }
fun Modifier.gesturesDisabled(disabled: Boolean = true) =
if (disabled) {
pointerInput(Unit) {
awaitPointerEventScope {
// we should wait for all new pointer events
while (true) {
awaitPointerEvent(pass = PointerEventPass.Initial)
.changes
.forEach(PointerInputChange::consume)
}
}
}
} else {
this
}

View File

@@ -1,26 +1,39 @@
package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault
import android.widget.ProgressBar
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Add
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.github.nullptroma.wallenc.presentation.elements.StorageTree import com.github.nullptroma.wallenc.presentation.elements.StorageTree
import com.github.nullptroma.wallenc.presentation.extensions.gesturesDisabled
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun LocalVaultScreen( fun LocalVaultScreen(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
@@ -29,6 +42,7 @@ fun LocalVaultScreen(
) { ) {
val uiState by viewModel.state.collectAsStateWithLifecycle() val uiState by viewModel.state.collectAsStateWithLifecycle()
Box {
Scaffold(modifier = modifier, contentWindowInsets = WindowInsets(0.dp), floatingActionButton = { Scaffold(modifier = modifier, contentWindowInsets = WindowInsets(0.dp), floatingActionButton = {
FloatingActionButton( FloatingActionButton(
onClick = { onClick = {
@@ -38,7 +52,7 @@ fun LocalVaultScreen(
Icon(Icons.Filled.Add, "Floating action button.") Icon(Icons.Filled.Add, "Floating action button.")
} }
}) { innerPadding -> }) { innerPadding ->
LazyColumn(modifier = Modifier.padding(innerPadding)) { LazyColumn(modifier = Modifier.padding(innerPadding).gesturesDisabled(uiState.isLoading)) {
items(uiState.storagesList) { listItem -> items(uiState.storagesList) { listItem ->
StorageTree( StorageTree(
modifier = Modifier.padding(8.dp, 8.dp, 8.dp, 0.dp), modifier = Modifier.padding(8.dp, 8.dp, 8.dp, 0.dp),
@@ -62,5 +76,17 @@ fun LocalVaultScreen(
} }
} }
} }
if(uiState.isLoading) {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Box(modifier = Modifier.fillMaxSize().alpha(0.6f).background(Color.Black))
CircularProgressIndicator(
modifier = Modifier.width(64.dp),
color = MaterialTheme.colorScheme.secondary,
trackColor = MaterialTheme.colorScheme.surfaceVariant,
)
}
}
}
} }

View File

@@ -3,4 +3,4 @@ package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.va
import com.github.nullptroma.wallenc.domain.datatypes.Tree import com.github.nullptroma.wallenc.domain.datatypes.Tree
import com.github.nullptroma.wallenc.domain.interfaces.IStorageInfo import com.github.nullptroma.wallenc.domain.interfaces.IStorageInfo
data class LocalVaultScreenState(val storagesList: List<Tree<IStorageInfo>>) data class LocalVaultScreenState(val storagesList: List<Tree<IStorageInfo>>, val isLoading: Boolean)

View File

@@ -29,15 +29,43 @@ class LocalVaultViewModel @Inject constructor(
private val manageStoragesEncryptionUseCase: ManageStoragesEncryptionUseCase, private val manageStoragesEncryptionUseCase: ManageStoragesEncryptionUseCase,
private val renameStorageUseCase: RenameStorageUseCase, private val renameStorageUseCase: RenameStorageUseCase,
private val logger: ILogger private val logger: ILogger
) : ViewModelBase<LocalVaultScreenState>(LocalVaultScreenState(listOf())) { ) : ViewModelBase<LocalVaultScreenState>(LocalVaultScreenState(listOf(), true)) {
private var _taskCount: Int = 0
private var tasksCount
get() = _taskCount
set(value) {
_taskCount = value
updateStateLoading()
}
private var _isLoading: Boolean = false
private var isLoading
get() = _isLoading
set(value) {
_isLoading = value
updateStateLoading()
}
init { init {
collectFlows()
}
private fun updateStateLoading() {
updateState(state.value.copy(
isLoading = this.isLoading || this.tasksCount > 0
))
}
private fun collectFlows() {
viewModelScope.launch { viewModelScope.launch {
manageLocalVaultUseCase.localStorages.combine(getOpenedStoragesUseCase.openedStorages) { local, opened -> manageLocalVaultUseCase.localStorages.combine(getOpenedStoragesUseCase.openedStorages) { local, opened ->
if(local == null || opened == null)
return@combine null
val list = mutableListOf<Tree<IStorageInfo>>() val list = mutableListOf<Tree<IStorageInfo>>()
for (storage in local) { for (storage in local) {
var tree = Tree(storage) var tree = Tree(storage)
list.add(tree) list.add(tree)
while(opened != null && opened.containsKey(tree.value.uuid)) { while(opened.containsKey(tree.value.uuid)) {
val child = opened.getValue(tree.value.uuid) val child = opened.getValue(tree.value.uuid)
val nextTree = Tree(child) val nextTree = Tree(child)
tree.children = listOf(nextTree) tree.children = listOf(nextTree)
@@ -46,17 +74,13 @@ class LocalVaultViewModel @Inject constructor(
} }
return@combine list return@combine list
}.collectLatest { }.collectLatest {
isLoading = it == null
val newState = state.value.copy( val newState = state.value.copy(
storagesList = it storagesList = it ?: listOf()
) )
updateState(newState) updateState(newState)
} }
} }
viewModelScope.launch {
getOpenedStoragesUseCase.openedStorages.collectLatest {
logger.debug("ViewModel", "Collected opened: ${it?.size}")
}
}
} }
fun printStorageInfoToLog(storage: IStorageInfo) { fun printStorageInfoToLog(storage: IStorageInfo) {
@@ -80,8 +104,10 @@ class LocalVaultViewModel @Inject constructor(
} }
fun createStorage() { fun createStorage() {
tasksCount++
viewModelScope.launch { viewModelScope.launch {
manageLocalVaultUseCase.createStorage() manageLocalVaultUseCase.createStorage()
tasksCount--
} }
} }
@@ -89,6 +115,7 @@ class LocalVaultViewModel @Inject constructor(
fun enableEncryptionAndOpenStorage(storage: IStorageInfo) { fun enableEncryptionAndOpenStorage(storage: IStorageInfo) {
if(runningStorages.contains(storage)) if(runningStorages.contains(storage))
return return
tasksCount++
runningStorages.add(storage) runningStorages.add(storage)
val key = EncryptKey("Hello") val key = EncryptKey("Hello")
viewModelScope.launch { viewModelScope.launch {
@@ -98,6 +125,7 @@ class LocalVaultViewModel @Inject constructor(
} }
finally { finally {
runningStorages.remove(storage) runningStorages.remove(storage)
tasksCount--
} }
} }
} }