Диалог изменения имени

This commit is contained in:
Пытков Роман
2025-01-28 20:53:14 +03:00
parent e1e7b48989
commit b375189e55
15 changed files with 239 additions and 69 deletions

View File

@@ -33,5 +33,5 @@
]
}
],
"minSdkVersionForDexing": 24
"minSdkVersionForDexing": 26
}

View File

@@ -4,6 +4,7 @@ import com.github.nullptroma.wallenc.domain.interfaces.IUnlockManager
import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager
import com.github.nullptroma.wallenc.domain.usecases.GetOpenedStoragesUseCase
import com.github.nullptroma.wallenc.domain.usecases.ManageLocalVaultUseCase
import com.github.nullptroma.wallenc.domain.usecases.RenameStorageUseCase
import com.github.nullptroma.wallenc.domain.usecases.StorageFileManagementUseCase
import dagger.Module
import dagger.Provides
@@ -31,4 +32,10 @@ class UseCasesModule {
fun provideStorageFileManagementUseCase(): StorageFileManagementUseCase {
return StorageFileManagementUseCase()
}
@Provides
@Singleton
fun provideRenameStorageUseCase(): RenameStorageUseCase {
return RenameStorageUseCase()
}
}

View File

@@ -35,7 +35,7 @@ class LocalStorage(
private val _accessor = LocalStorageAccessor(absolutePath, ioDispatcher)
override val accessor: IStorageAccessor = _accessor
override val isVirtualStorage: Boolean = false
private val metaInfoFileName: String = "$uuid$ENC_INFO_FILE_POSTFIX"
private val metaInfoFileName: String = "$uuid$STORAGE_INFO_FILE_POSTFIX"
suspend fun init() {
_accessor.init()
@@ -91,7 +91,7 @@ class LocalStorage(
}
companion object {
const val ENC_INFO_FILE_POSTFIX = ".enc-info"
const val STORAGE_INFO_FILE_POSTFIX = ".storage-info"
private val jackson = jacksonObjectMapper().apply { findAndRegisterModules() }
}
}

View File

@@ -0,0 +1,12 @@
package com.github.nullptroma.wallenc.domain.usecases
import com.github.nullptroma.wallenc.domain.interfaces.IStorage
import com.github.nullptroma.wallenc.domain.interfaces.IStorageInfo
class RenameStorageUseCase {
suspend fun rename(storage: IStorageInfo, newName: String) {
when (storage) {
is IStorage -> storage.rename(newName)
}
}
}

View File

@@ -1,4 +1,4 @@
package com.github.nullptroma.wallenc.presentation.viewmodel
package com.github.nullptroma.wallenc.presentation
import androidx.lifecycle.ViewModel

View File

@@ -7,7 +7,6 @@ import androidx.lifecycle.viewmodel.compose.saveable
import com.github.nullptroma.wallenc.presentation.screens.ScreenRoute
import com.github.nullptroma.wallenc.presentation.screens.main.MainRoute
import com.github.nullptroma.wallenc.presentation.screens.settings.SettingsRoute
import com.github.nullptroma.wallenc.presentation.viewmodel.ViewModelBase
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlin.collections.set

View File

@@ -0,0 +1,188 @@
package com.github.nullptroma.wallenc.presentation.elements
import android.app.Dialog
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material3.BasicAlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Divider
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.PlatformTextStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
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
@Composable
fun StorageTree(
modifier: Modifier,
tree: Tree<IStorageInfo>,
onClick: (Tree<IStorageInfo>) -> Unit,
onRename: (Tree<IStorageInfo>, String) -> Unit,
) {
val cur = tree.value
val cardShape = RoundedCornerShape(30.dp)
Column(modifier) {
Card(
modifier = Modifier
.fillMaxWidth()
.clip(cardShape)
.clickable {
onClick(tree)
//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(modifier = Modifier.height(IntrinsicSize.Min)) {
Column(modifier = Modifier.padding(8.dp)) {
Text(metaInfo.name ?: stringResource(R.string.no_name))
Text(
text = "IsAvailable: $available"
)
Text("Files: $numOfFiles")
Text("Size: $size")
Text("IsVirtual: ${cur.isVirtualStorage}")
}
Column(
modifier = Modifier,
horizontalAlignment = Alignment.End
) {
Box(modifier = Modifier.padding(0.dp, 8.dp, 8.dp, 0.dp)) {
var expanded by remember { mutableStateOf(false) }
var showRenameDialog by remember { mutableStateOf(false) }
IconButton(onClick = { expanded = !expanded }) {
Icon(
Icons.Default.MoreVert,
contentDescription = stringResource(R.string.show_storage_item_menu)
)
}
DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false }
) {
DropdownMenuItem(
onClick = {
expanded = false
showRenameDialog = true
},
text = { Text(stringResource(R.string.rename)) }
)
}
if (showRenameDialog) {
RenameDialog(
onDismiss = { showRenameDialog = false },
onConfirmation = { newName ->
showRenameDialog = false
onRename(tree, newName)
},
startName = tree.value.metaInfo.value.name ?: ""
)
}
}
Spacer(modifier = Modifier.weight(1f))
Text(
modifier = Modifier
.fillMaxWidth()
.padding(0.dp, 0.dp, 12.dp, 8.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()) {
StorageTree(Modifier.padding(16.dp, 0.dp, 0.dp, 0.dp), i, onClick, onRename)
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun RenameDialog(onDismiss: () -> Unit, onConfirmation: (String) -> Unit, startName: String = "") {
var name by remember { mutableStateOf(startName) }
BasicAlertDialog(
onDismissRequest = { onDismiss() }
) {
Card {
Column(modifier = Modifier.padding(12.dp)) {
Text("New name", style = MaterialTheme.typography.titleLarge)
TextField(name, {
name = it
})
Spacer(modifier = Modifier.height(24.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly,
) {
Button(modifier = Modifier.weight(1f), onClick = onDismiss) {
Text("Cancel")
}
Spacer(modifier = Modifier.width(12.dp))
Button(modifier = Modifier.weight(1f), onClick = {
onConfirmation(name)
}) {
Text("Ok")
}
}
}
}
}
}

View File

@@ -7,7 +7,7 @@ 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.viewmodel.ViewModelBase
import com.github.nullptroma.wallenc.presentation.ViewModelBase
import dagger.hilt.android.lifecycle.HiltViewModel
@HiltViewModel

View File

@@ -47,6 +47,7 @@ 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 com.github.nullptroma.wallenc.presentation.elements.StorageTree
import kotlin.random.Random
@OptIn(ExperimentalMaterial3Api::class)
@@ -54,7 +55,7 @@ import kotlin.random.Random
fun LocalVaultScreen(
modifier: Modifier = Modifier,
viewModel: LocalVaultViewModel = hiltViewModel(),
openTextEdit: (String)->Unit
openTextEdit: (String) -> Unit
) {
val uiState by viewModel.state.collectAsStateWithLifecycle()
@@ -68,66 +69,19 @@ fun LocalVaultScreen(
}
}) { innerPadding ->
LazyColumn(modifier = Modifier.padding(innerPadding)) {
items(uiState.storagesList) { tree ->
Storage(Modifier.padding(8.dp), tree) {
items(uiState.storagesList) { listItem ->
StorageTree(
modifier = Modifier.padding(8.dp),
tree = listItem,
onClick = {
openTextEdit(it.value.uuid.toString())
}
}
}
}
}
@Composable
fun Storage(modifier: Modifier, tree: Tree<IStorageInfo>, onClick: (Tree<IStorageInfo>) -> Unit) {
val cur = tree.value
val cardShape = RoundedCornerShape(30.dp)
Column(modifier) {
Card(
modifier = Modifier
.fillMaxWidth()
.clip(cardShape)
.clickable {
onClick(tree)
//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("Size: $size")
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
)
)
onRename = { tree, newName ->
viewModel.rename(tree.value, newName)
}
)
}
}
}
for(i in tree.children ?: listOf()) {
Storage(Modifier.padding(16.dp,0.dp,0.dp,0.dp), i, onClick)
}
}
}

View File

@@ -1,7 +1,6 @@
package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault
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.interfaces.IDirectory
import com.github.nullptroma.wallenc.domain.interfaces.IFile
@@ -9,9 +8,10 @@ import com.github.nullptroma.wallenc.domain.interfaces.ILogger
import com.github.nullptroma.wallenc.domain.interfaces.IStorageInfo
import com.github.nullptroma.wallenc.domain.usecases.GetOpenedStoragesUseCase
import com.github.nullptroma.wallenc.domain.usecases.ManageLocalVaultUseCase
import com.github.nullptroma.wallenc.domain.usecases.RenameStorageUseCase
import com.github.nullptroma.wallenc.domain.usecases.StorageFileManagementUseCase
import com.github.nullptroma.wallenc.presentation.extensions.toPrintable
import com.github.nullptroma.wallenc.presentation.viewmodel.ViewModelBase
import com.github.nullptroma.wallenc.presentation.ViewModelBase
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
@@ -24,6 +24,7 @@ class LocalVaultViewModel @Inject constructor(
private val manageLocalVaultUseCase: ManageLocalVaultUseCase,
private val getOpenedStoragesUseCase: GetOpenedStoragesUseCase,
private val storageFileManagementUseCase: StorageFileManagementUseCase,
private val renameStorageUseCase: RenameStorageUseCase,
private val logger: ILogger
) : ViewModelBase<LocalVaultScreenState>(LocalVaultScreenState(listOf())) {
init {
@@ -75,4 +76,10 @@ class LocalVaultViewModel @Inject constructor(
manageLocalVaultUseCase.createStorage()
}
}
fun rename(storage: IStorageInfo, newName: String) {
viewModelScope.launch {
renameStorageUseCase.rename(storage, newName)
}
}
}

View File

@@ -1,6 +1,6 @@
package com.github.nullptroma.wallenc.presentation.screens.main.screens.remotes
import com.github.nullptroma.wallenc.presentation.viewmodel.ViewModelBase
import com.github.nullptroma.wallenc.presentation.ViewModelBase
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject

View File

@@ -1,6 +1,6 @@
package com.github.nullptroma.wallenc.presentation.screens.settings
import com.github.nullptroma.wallenc.presentation.viewmodel.ViewModelBase
import com.github.nullptroma.wallenc.presentation.ViewModelBase
import dagger.hilt.android.lifecycle.HiltViewModel
@HiltViewModel

View File

@@ -7,4 +7,7 @@
<string name="settings_title">Settings Screen Title!</string>
<string name="no_name">&lt;noname&gt;</string>
<string name="show_storage_item_menu">Show storage item menu</string>
<string name="rename">Rename</string>
</resources>