Дерево хранилищ

This commit is contained in:
Пытков Роман
2025-02-05 21:29:16 +03:00
parent 2cb2dabe3f
commit c95c374852
5 changed files with 152 additions and 144 deletions

View File

@@ -1,13 +1,20 @@
package com.github.nullptroma.wallenc.presentation.elements package com.github.nullptroma.wallenc.presentation.elements
import android.widget.FrameLayout
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.indication
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
@@ -20,7 +27,9 @@ import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.ripple
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@@ -34,12 +43,12 @@ import androidx.compose.ui.text.PlatformTextStyle
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.compose.ui.zIndex
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
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
import com.github.nullptroma.wallenc.presentation.R import com.github.nullptroma.wallenc.presentation.R
import com.github.nullptroma.wallenc.presentation.elements.indication.ScaleIndication import com.github.nullptroma.wallenc.presentation.utils.debouncedLambda
import com.github.nullptroma.wallenc.presentation.extensions.clickableDebounced
@Composable @Composable
fun StorageTree( fun StorageTree(
@@ -50,24 +59,43 @@ fun StorageTree(
onRemove: (Tree<IStorageInfo>) -> Unit, onRemove: (Tree<IStorageInfo>) -> Unit,
) { ) {
val cur = tree.value val cur = tree.value
val cardShape = RoundedCornerShape(30.dp)
Column(modifier) {
Card(
modifier = Modifier
.fillMaxWidth()
.clip(cardShape)
.clickableDebounced(debounceMs = 500) {
onClick(tree)
},
shape = cardShape,
elevation = CardDefaults.cardElevation(
defaultElevation = 4.dp
),
) {
val available by cur.isAvailable.collectAsStateWithLifecycle() val available by cur.isAvailable.collectAsStateWithLifecycle()
val numOfFiles by cur.numberOfFiles.collectAsStateWithLifecycle() val numOfFiles by cur.numberOfFiles.collectAsStateWithLifecycle()
val size by cur.size.collectAsStateWithLifecycle() val size by cur.size.collectAsStateWithLifecycle()
val metaInfo by cur.metaInfo.collectAsStateWithLifecycle() val metaInfo by cur.metaInfo.collectAsStateWithLifecycle()
val borderColor =
if (cur.isVirtualStorage) MaterialTheme.colorScheme.secondary else MaterialTheme.colorScheme.primary
Column(modifier) {
Box(modifier = Modifier.height(IntrinsicSize.Min).zIndex(100f)) {
val interactionSource = remember { MutableInteractionSource() }
Box(
modifier = Modifier
.clip(
CardDefaults.shape
)
.padding(0.dp, 0.dp, 16.dp, 0.dp)
.fillMaxSize()
.background(borderColor)
.clickable(
interactionSource = interactionSource,
indication = ripple(),
enabled = false,
onClick = { }
)
)
Card(
interactionSource = interactionSource,
modifier = Modifier
.padding(8.dp, 0.dp, 0.dp, 0.dp)
.fillMaxWidth(),
elevation = CardDefaults.cardElevation(
defaultElevation = 4.dp
),
onClick = debouncedLambda(debounceMs = 500) {
onClick(tree)
}
) {
Row(modifier = Modifier.height(IntrinsicSize.Min)) { Row(modifier = Modifier.height(IntrinsicSize.Min)) {
Column(modifier = Modifier.padding(8.dp)) { Column(modifier = Modifier.padding(8.dp)) {
@@ -160,8 +188,9 @@ fun StorageTree(
} }
} }
} }
}
for (i in tree.children ?: listOf()) { for (i in tree.children ?: listOf()) {
StorageTree(Modifier.padding(16.dp, 0.dp, 0.dp, 0.dp), i, onClick, onRename, onRemove) StorageTree(Modifier.padding(16.dp, 0.dp, 0.dp, 0.dp).offset(y = (-4).dp), i, onClick, onRename, onRemove)
} }
} }
} }

View File

@@ -32,43 +32,3 @@ fun Modifier.ignoreVerticalParentPadding(vertical: Dp): Modifier {
} }
} }
} }
fun Modifier.clickableDebounced(
interactionSource: MutableInteractionSource? = null,
indication: Indication? = null,
enabled: Boolean = true,
onClickLabel: String? = null,
role: Role? = null,
debounceMs: Long = 300,
onClick: () -> Unit
): Modifier = composed(
inspectorInfo = debugInspectorInfo {
name = "clickableDebounced"
properties["enabled"] = enabled
properties["onClickLabel"] = onClickLabel
properties["role"] = role
properties["onClick"] = onClick
}
) {
var latest: Long = 0
val ind = indication ?: LocalIndication.current
val interSource = if (ind is IndicationNodeFactory) {
null
} else {
interactionSource ?: remember { MutableInteractionSource() }
}
return@composed this@clickableDebounced.clickable(
interactionSource = interSource,
indication = ind,
enabled = enabled,
onClickLabel = onClickLabel,
role = role,
onClick = {
val now = System.currentTimeMillis()
if (now - latest >= debounceMs) {
latest = now
onClick()
}
}
)
}

View File

@@ -1,6 +1,8 @@
package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
@@ -39,7 +41,7 @@ fun LocalVaultScreen(
LazyColumn(modifier = Modifier.padding(innerPadding)) { LazyColumn(modifier = Modifier.padding(innerPadding)) {
items(uiState.storagesList) { listItem -> items(uiState.storagesList) { listItem ->
StorageTree( StorageTree(
modifier = Modifier.padding(8.dp), modifier = Modifier.padding(8.dp, 8.dp, 8.dp, 0.dp),
tree = listItem, tree = listItem,
onClick = { onClick = {
openTextEdit(it.value.uuid.toString()) openTextEdit(it.value.uuid.toString())
@@ -52,6 +54,9 @@ fun LocalVaultScreen(
} }
) )
} }
item {
Spacer(modifier = Modifier.height(8.dp))
}
} }
} }
} }

View File

@@ -1,6 +1,7 @@
package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey
import com.github.nullptroma.wallenc.domain.datatypes.Tree import com.github.nullptroma.wallenc.domain.datatypes.Tree
import com.github.nullptroma.wallenc.domain.interfaces.IDirectory import com.github.nullptroma.wallenc.domain.interfaces.IDirectory
import com.github.nullptroma.wallenc.domain.interfaces.IFile import com.github.nullptroma.wallenc.domain.interfaces.IFile
@@ -73,7 +74,7 @@ class LocalVaultViewModel @Inject constructor(
fun createStorage() { fun createStorage() {
viewModelScope.launch { viewModelScope.launch {
manageLocalVaultUseCase.createStorage() manageLocalVaultUseCase.createStorage(EncryptKey("Hello"))
} }
} }

View File

@@ -0,0 +1,13 @@
package com.github.nullptroma.wallenc.presentation.utils
fun debouncedLambda(debounceMs: Long = 300, action: ()->Unit) : ()->Unit {
var latest: Long = 0
return {
val now = System.currentTimeMillis()
if (now - latest >= debounceMs) {
latest = now
action()
}
}
}