Отображение хранилищ как деревья
This commit is contained in:
@@ -6,7 +6,7 @@ plugins {
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "com.github.nullptroma.wallenc.data"
|
namespace = "com.github.nullptroma.wallenc.data"
|
||||||
compileSdk = 34
|
compileSdk = 35
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdk = 26
|
minSdk = 26
|
||||||
|
|||||||
@@ -28,4 +28,7 @@ interface StorageMetaInfoDao {
|
|||||||
|
|
||||||
@Delete
|
@Delete
|
||||||
suspend fun delete(metaInfo: DbStorageMetaInfo)
|
suspend fun delete(metaInfo: DbStorageMetaInfo)
|
||||||
|
|
||||||
|
@Query("DELETE FROM storage_meta_infos WHERE uuid == :uuid")
|
||||||
|
suspend fun delete(uuid: UUID)
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,7 @@ package com.github.nullptroma.wallenc.data.db.app.repository
|
|||||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||||
import com.github.nullptroma.wallenc.data.db.app.dao.StorageMetaInfoDao
|
import com.github.nullptroma.wallenc.data.db.app.dao.StorageMetaInfoDao
|
||||||
import com.github.nullptroma.wallenc.data.db.app.model.DbStorageMetaInfo
|
import com.github.nullptroma.wallenc.data.db.app.model.DbStorageMetaInfo
|
||||||
|
import com.github.nullptroma.wallenc.data.utils.IProvider
|
||||||
import com.github.nullptroma.wallenc.domain.common.impl.CommonStorageMetaInfo
|
import com.github.nullptroma.wallenc.domain.common.impl.CommonStorageMetaInfo
|
||||||
import kotlinx.coroutines.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
@@ -34,6 +35,11 @@ class StorageMetaInfoRepository(
|
|||||||
dao.add(DbStorageMetaInfo(uuid, json))
|
dao.add(DbStorageMetaInfo(uuid, json))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun delete(uuid: UUID) = withContext(ioDispatcher) {
|
||||||
|
dao.delete(uuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fun createSingleStorageProvider(uuid: UUID): SingleStorageMetaInfoProvider {
|
fun createSingleStorageProvider(uuid: UUID): SingleStorageMetaInfoProvider {
|
||||||
return SingleStorageMetaInfoProvider(this, uuid)
|
return SingleStorageMetaInfoProvider(this, uuid)
|
||||||
}
|
}
|
||||||
@@ -41,9 +47,10 @@ class StorageMetaInfoRepository(
|
|||||||
class SingleStorageMetaInfoProvider (
|
class SingleStorageMetaInfoProvider (
|
||||||
private val repo: StorageMetaInfoRepository,
|
private val repo: StorageMetaInfoRepository,
|
||||||
val uuid: UUID
|
val uuid: UUID
|
||||||
) {
|
) : IProvider<CommonStorageMetaInfo> {
|
||||||
suspend fun get(): CommonStorageMetaInfo? = repo.getMeta(uuid)
|
override suspend fun get(): CommonStorageMetaInfo? = repo.getMeta(uuid)
|
||||||
suspend fun set(metaInfo: CommonStorageMetaInfo) = repo.setMeta(uuid, metaInfo)
|
override suspend fun clear() = repo.delete(uuid)
|
||||||
|
override suspend fun set(value: CommonStorageMetaInfo) = repo.setMeta(uuid, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.github.nullptroma.wallenc.data.utils
|
||||||
|
|
||||||
|
interface IProvider<T> {
|
||||||
|
suspend fun get(): T?
|
||||||
|
suspend fun set(value: T)
|
||||||
|
suspend fun clear()
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package com.github.nullptroma.wallenc.domain.datatypes
|
||||||
|
|
||||||
|
class Tree<T>(val value: T, var children: List<Tree<T>>? = null)
|
||||||
@@ -1,32 +1,60 @@
|
|||||||
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.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.gestures.detectTapGestures
|
import androidx.compose.foundation.gestures.detectTapGestures
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
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
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
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.Card
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.CardDefaults
|
||||||
|
import androidx.compose.material3.CardElevation
|
||||||
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.LocalTextStyle
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.input.pointer.pointerInput
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.PlatformTextStyle
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.font.FontStyle
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.text.style.TextDecoration
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
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.domain.datatypes.Tree
|
||||||
|
import com.github.nullptroma.wallenc.domain.interfaces.IStorageInfo
|
||||||
|
import com.github.nullptroma.wallenc.presentation.R
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun LocalVaultScreen(modifier: Modifier = Modifier,
|
fun LocalVaultScreen(
|
||||||
viewModel: LocalVaultViewModel = hiltViewModel()) {
|
modifier: Modifier = Modifier,
|
||||||
|
viewModel: LocalVaultViewModel = hiltViewModel()
|
||||||
|
) {
|
||||||
|
|
||||||
val uiState by viewModel.state.collectAsStateWithLifecycle()
|
val uiState by viewModel.state.collectAsStateWithLifecycle()
|
||||||
Scaffold(modifier = modifier, contentWindowInsets = WindowInsets(0.dp), floatingActionButton = {
|
Scaffold(modifier = modifier, contentWindowInsets = WindowInsets(0.dp), floatingActionButton = {
|
||||||
@@ -39,27 +67,63 @@ fun LocalVaultScreen(modifier: Modifier = Modifier,
|
|||||||
}
|
}
|
||||||
}) { innerPadding ->
|
}) { innerPadding ->
|
||||||
LazyColumn(modifier = Modifier.padding(innerPadding)) {
|
LazyColumn(modifier = Modifier.padding(innerPadding)) {
|
||||||
items(uiState.storagesList) {
|
items(uiState.storagesList) { tree ->
|
||||||
Card(modifier = Modifier.clickable { }.pointerInput(Unit) {
|
Storage(Modifier.padding(8.dp), tree)
|
||||||
detectTapGestures(
|
}
|
||||||
onTap = { _ -> viewModel.printStorageInfoToLog(it) }
|
}
|
||||||
)
|
}
|
||||||
}.padding(8.dp)) {
|
}
|
||||||
val available by it.isAvailable.collectAsStateWithLifecycle()
|
|
||||||
val numOfFiles by it.numberOfFiles.collectAsStateWithLifecycle()
|
|
||||||
val size by it.size.collectAsStateWithLifecycle()
|
|
||||||
val metaInfo by it.metaInfo.collectAsStateWithLifecycle()
|
|
||||||
|
|
||||||
val enc = metaInfo.encInfo
|
@Composable
|
||||||
Column(modifier = Modifier.padding(4.dp)) {
|
fun Storage(modifier: Modifier, tree: Tree<IStorageInfo>) {
|
||||||
Text(it.uuid.toString())
|
val cur = tree.value
|
||||||
Text("IsAvailable: $available")
|
val cardShape = RoundedCornerShape(30.dp)
|
||||||
|
Column(modifier) {
|
||||||
|
Card(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clip(cardShape)
|
||||||
|
.clickable {
|
||||||
|
//viewModel.printStorageInfoToLog(cur)
|
||||||
|
},
|
||||||
|
shape = cardShape,
|
||||||
|
elevation = CardDefaults.cardElevation(
|
||||||
|
defaultElevation = 4.dp
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
val available by cur.isAvailable.collectAsStateWithLifecycle()
|
||||||
|
val numOfFiles by cur.numberOfFiles.collectAsStateWithLifecycle()
|
||||||
|
val size by cur.size.collectAsStateWithLifecycle()
|
||||||
|
val metaInfo by cur.metaInfo.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
|
Row {
|
||||||
|
Column(modifier = Modifier.padding(8.dp)) {
|
||||||
|
Text(metaInfo.name ?: stringResource(R.string.no_name))
|
||||||
|
Text(
|
||||||
|
text = "IsAvailable: $available"
|
||||||
|
)
|
||||||
Text("Files: $numOfFiles")
|
Text("Files: $numOfFiles")
|
||||||
Text("Size: $size")
|
Text("Size: $size")
|
||||||
Text("Enc: $enc")
|
Text("IsVirtual: ${cur.isVirtualStorage}")
|
||||||
|
Text(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(0.dp,0.dp,8.dp,0.dp)
|
||||||
|
.align(Alignment.End),
|
||||||
|
text = cur.uuid.toString(),
|
||||||
|
textAlign = TextAlign.End,
|
||||||
|
fontSize = 8.sp,
|
||||||
|
style = LocalTextStyle.current.copy(
|
||||||
|
platformStyle = PlatformTextStyle(
|
||||||
|
includeFontPadding = true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for(i in tree.children ?: listOf()) {
|
||||||
|
Storage(Modifier.padding(16.dp,0.dp,0.dp,0.dp), i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault
|
package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault
|
||||||
|
|
||||||
|
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<IStorageInfo>)
|
data class LocalVaultScreenState(val storagesList: List<Tree<IStorageInfo>>)
|
||||||
@@ -2,6 +2,7 @@ package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.va
|
|||||||
|
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey
|
import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey
|
||||||
|
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
|
||||||
import com.github.nullptroma.wallenc.domain.interfaces.ILogger
|
import com.github.nullptroma.wallenc.domain.interfaces.ILogger
|
||||||
@@ -24,12 +25,22 @@ class LocalVaultViewModel @Inject constructor(
|
|||||||
private val getOpenedStoragesUseCase: GetOpenedStoragesUseCase,
|
private val getOpenedStoragesUseCase: GetOpenedStoragesUseCase,
|
||||||
private val storageFileManagementUseCase: StorageFileManagementUseCase,
|
private val storageFileManagementUseCase: StorageFileManagementUseCase,
|
||||||
private val logger: ILogger
|
private val logger: ILogger
|
||||||
) :
|
) : ViewModelBase<LocalVaultScreenState>(LocalVaultScreenState(listOf())) {
|
||||||
ViewModelBase<LocalVaultScreenState>(LocalVaultScreenState(listOf())) {
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
manageLocalVaultUseCase.localStorages.combine(getOpenedStoragesUseCase.openedStorages) { local, opened ->
|
manageLocalVaultUseCase.localStorages.combine(getOpenedStoragesUseCase.openedStorages) { local, opened ->
|
||||||
local + (opened?.map { it.value } ?: listOf())
|
val list = mutableListOf<Tree<IStorageInfo>>()
|
||||||
|
for (storage in local) {
|
||||||
|
var tree = Tree(storage)
|
||||||
|
list.add(tree)
|
||||||
|
while(opened != null && opened.containsKey(tree.value.uuid)) {
|
||||||
|
val child = opened.getValue(tree.value.uuid)
|
||||||
|
val nextTree = Tree(child)
|
||||||
|
tree.children = listOf(nextTree)
|
||||||
|
tree = nextTree
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return@combine list
|
||||||
}.collectLatest {
|
}.collectLatest {
|
||||||
val newState = state.value.copy(
|
val newState = state.value.copy(
|
||||||
storagesList = it
|
storagesList = it
|
||||||
@@ -61,7 +72,7 @@ class LocalVaultViewModel @Inject constructor(
|
|||||||
|
|
||||||
fun createStorage() {
|
fun createStorage() {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
manageLocalVaultUseCase.createStorage(EncryptKey("hello"))
|
manageLocalVaultUseCase.createStorage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,4 +6,5 @@
|
|||||||
<string name="nav_label_settings">Settings</string>
|
<string name="nav_label_settings">Settings</string>
|
||||||
|
|
||||||
<string name="settings_title">Settings Screen Title!</string>
|
<string name="settings_title">Settings Screen Title!</string>
|
||||||
|
<string name="no_name"><noname></string>
|
||||||
</resources>
|
</resources>
|
||||||
Reference in New Issue
Block a user