Шифрование путей
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
package com.github.nullptroma.wallenc.app
|
||||
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.ILogger
|
||||
import timber.log.Timber
|
||||
|
||||
class Logger: ILogger {
|
||||
override fun debug(tag: String, msg: String) {
|
||||
Timber.tag(tag)
|
||||
Timber.d(msg)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.github.nullptroma.wallenc.app.di.modules.app
|
||||
|
||||
import com.github.nullptroma.wallenc.app.Logger
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.ILogger
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
class SingletonModule {
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideLogger(): ILogger {
|
||||
return Logger()
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@ package com.github.nullptroma.wallenc.app.di.modules.data
|
||||
|
||||
import android.content.Context
|
||||
import com.github.nullptroma.wallenc.app.di.modules.app.IoDispatcher
|
||||
import com.github.nullptroma.wallenc.data.vaults.local.LocalVault
|
||||
import com.github.nullptroma.wallenc.data.vaults.VaultsManager
|
||||
import com.github.nullptroma.wallenc.domain.models.IVaultsManager
|
||||
import com.github.nullptroma.wallenc.data.vaults.local.LocalVault
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package com.github.nullptroma.wallenc.app.di.modules.domain
|
||||
|
||||
import com.github.nullptroma.wallenc.domain.models.IVaultsManager
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager
|
||||
import com.github.nullptroma.wallenc.domain.usecases.GetAllRawStoragesUseCase
|
||||
import com.github.nullptroma.wallenc.domain.usecases.ManageLocalVaultUseCase
|
||||
import com.github.nullptroma.wallenc.domain.usecases.StorageFileManagementUseCase
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
@@ -18,6 +19,12 @@ class UseCasesModule {
|
||||
return GetAllRawStoragesUseCase(vaultsManager)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideManageLocalVaultUseCase(vaultsManager: IVaultsManager): ManageLocalVaultUseCase {
|
||||
return ManageLocalVaultUseCase(vaultsManager)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideStorageFileManagementUseCase(): StorageFileManagementUseCase {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.github.nullptroma.wallenc.data.vaults
|
||||
|
||||
import com.github.nullptroma.wallenc.data.vaults.local.LocalVault
|
||||
import com.github.nullptroma.wallenc.domain.models.IVault
|
||||
import com.github.nullptroma.wallenc.domain.models.IVaultsManager
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IVault
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
class VaultsManager(override val localVault: LocalVault) : IVaultsManager {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.github.nullptroma.wallenc.data.vaults.local
|
||||
|
||||
import com.github.nullptroma.wallenc.domain.models.IStorage
|
||||
import com.github.nullptroma.wallenc.domain.models.IStorageAccessor
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IStorage
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IStorageAccessor
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import java.util.UUID
|
||||
|
||||
@@ -8,9 +8,9 @@ import com.github.nullptroma.wallenc.data.vaults.local.entity.LocalFile
|
||||
import com.github.nullptroma.wallenc.data.vaults.local.entity.LocalMetaInfo
|
||||
import com.github.nullptroma.wallenc.domain.datatypes.DataPackage
|
||||
import com.github.nullptroma.wallenc.domain.datatypes.DataPage
|
||||
import com.github.nullptroma.wallenc.domain.models.IDirectory
|
||||
import com.github.nullptroma.wallenc.domain.models.IFile
|
||||
import com.github.nullptroma.wallenc.domain.models.IStorageAccessor
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IDirectory
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IFile
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IStorageAccessor
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@@ -50,11 +50,11 @@ class LocalStorageAccessor(
|
||||
private val _isAvailable = MutableStateFlow(false)
|
||||
override val isAvailable: StateFlow<Boolean> = _isAvailable
|
||||
|
||||
private val _filesUpdates = MutableSharedFlow<DataPackage<IFile>>()
|
||||
override val filesUpdates: SharedFlow<DataPackage<IFile>> = _filesUpdates
|
||||
private val _filesUpdates = MutableSharedFlow<DataPage<IFile>>()
|
||||
override val filesUpdates: SharedFlow<DataPage<IFile>> = _filesUpdates
|
||||
|
||||
private val _dirsUpdates = MutableSharedFlow<DataPackage<IDirectory>>()
|
||||
override val dirsUpdates: SharedFlow<DataPackage<IDirectory>> = _dirsUpdates
|
||||
private val _dirsUpdates = MutableSharedFlow<DataPage<IDirectory>>()
|
||||
override val dirsUpdates: SharedFlow<DataPage<IDirectory>> = _dirsUpdates
|
||||
|
||||
init {
|
||||
// запускам сканирование хранилища
|
||||
|
||||
@@ -3,8 +3,8 @@ package com.github.nullptroma.wallenc.data.vaults.local
|
||||
import android.content.Context
|
||||
import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey
|
||||
import com.github.nullptroma.wallenc.domain.enums.VaultType
|
||||
import com.github.nullptroma.wallenc.domain.models.IStorage
|
||||
import com.github.nullptroma.wallenc.domain.models.IVault
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IStorage
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IVault
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.github.nullptroma.wallenc.data.vaults.local.entity
|
||||
|
||||
import com.github.nullptroma.wallenc.domain.models.IDirectory
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IDirectory
|
||||
|
||||
data class LocalDirectory(
|
||||
override val metaInfo: LocalMetaInfo,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
package com.github.nullptroma.wallenc.data.vaults.local.entity
|
||||
|
||||
import com.github.nullptroma.wallenc.domain.models.IFile
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IFile
|
||||
|
||||
data class LocalFile(override val metaInfo: LocalMetaInfo) : IFile
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.github.nullptroma.wallenc.data.vaults.local.entity
|
||||
|
||||
import com.github.nullptroma.wallenc.domain.models.IMetaInfo
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IMetaInfo
|
||||
import java.time.Instant
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.github.nullptroma.wallenc.domain.datatypes
|
||||
|
||||
sealed class DataPackage<T>(
|
||||
class DataPackage<T>(
|
||||
val data: T,
|
||||
val isLoading: Boolean? = false,
|
||||
val isError: Boolean? = false
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
package com.github.nullptroma.wallenc.domain.datatypes
|
||||
|
||||
class EncryptKey(val key: String) {
|
||||
import java.security.MessageDigest
|
||||
|
||||
class EncryptKey(val key: String) {
|
||||
fun to32Bytes(): ByteArray {
|
||||
val digest = MessageDigest.getInstance("SHA-256")
|
||||
return digest.digest(key.toByteArray(Charsets.UTF_8))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.github.nullptroma.wallenc.domain.encrypt
|
||||
|
||||
import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.ILogger
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IStorage
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IStorageAccessor
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import java.util.UUID
|
||||
|
||||
class EncryptedStorage(
|
||||
source: IStorage,
|
||||
key: EncryptKey,
|
||||
logger: ILogger,
|
||||
ioDispatcher: CoroutineDispatcher
|
||||
) : IStorage {
|
||||
override val size: StateFlow<Long?>
|
||||
get() = TODO("Not yet implemented")
|
||||
override val numberOfFiles: StateFlow<Int?>
|
||||
get() = TODO("Not yet implemented")
|
||||
override val uuid: UUID
|
||||
get() = TODO("Not yet implemented")
|
||||
override val name: StateFlow<String>
|
||||
get() = TODO("Not yet implemented")
|
||||
override val isAvailable: StateFlow<Boolean>
|
||||
get() = TODO("Not yet implemented")
|
||||
override val accessor: IStorageAccessor =
|
||||
EncryptedStorageAccessor(source.accessor, key, logger, ioDispatcher)
|
||||
|
||||
override suspend fun rename(newName: String) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
package com.github.nullptroma.wallenc.domain.encrypt
|
||||
|
||||
import com.github.nullptroma.wallenc.domain.datatypes.DataPackage
|
||||
import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey
|
||||
import com.github.nullptroma.wallenc.domain.encrypt.entity.EncryptedDirectory
|
||||
import com.github.nullptroma.wallenc.domain.encrypt.entity.EncryptedFile
|
||||
import com.github.nullptroma.wallenc.domain.encrypt.entity.EncryptedMetaInfo
|
||||
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.IStorageAccessor
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.spec.IvParameterSpec
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
import kotlin.io.encoding.Base64
|
||||
import kotlin.io.encoding.ExperimentalEncodingApi
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.pathString
|
||||
import kotlin.random.Random
|
||||
|
||||
class EncryptedStorageAccessor(
|
||||
private val source: IStorageAccessor,
|
||||
private val key: EncryptKey,
|
||||
private val logger: ILogger,
|
||||
ioDispatcher: CoroutineDispatcher
|
||||
) : IStorageAccessor {
|
||||
override val size: StateFlow<Long?> = source.size
|
||||
override val numberOfFiles: StateFlow<Int?> = source.numberOfFiles
|
||||
override val isAvailable: StateFlow<Boolean> = source.isAvailable
|
||||
|
||||
private val _filesUpdates = MutableSharedFlow<DataPackage<List<IFile>>>()
|
||||
override val filesUpdates: SharedFlow<DataPackage<List<IFile>>> = _filesUpdates
|
||||
|
||||
private val _dirsUpdates = MutableSharedFlow<DataPackage<List<IDirectory>>>()
|
||||
override val dirsUpdates: SharedFlow<DataPackage<List<IDirectory>>> = _dirsUpdates
|
||||
|
||||
private val _secretKey = SecretKeySpec(key.to32Bytes(), "AES")
|
||||
|
||||
init {
|
||||
val enc = encryptPath("/hello/world/test.txt")
|
||||
val dec = decryptPath(enc)
|
||||
collectSourceState(CoroutineScope(ioDispatcher))
|
||||
}
|
||||
|
||||
private fun collectSourceState(coroutineScope: CoroutineScope) {
|
||||
coroutineScope.launch {
|
||||
launch {
|
||||
source.filesUpdates.collect {
|
||||
val files = it.data.map {
|
||||
val meta = it.metaInfo
|
||||
EncryptedFile(EncryptedMetaInfo(
|
||||
size = meta.size,
|
||||
isDeleted = meta.isDeleted,
|
||||
isHidden = meta.isHidden,
|
||||
lastModified = meta.lastModified,
|
||||
path = decryptPath(meta.path)
|
||||
))
|
||||
}
|
||||
_filesUpdates.emit(DataPackage(
|
||||
data = files,
|
||||
isLoading = it.isLoading,
|
||||
isError = it.isError
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
launch {
|
||||
source.dirsUpdates.collect {
|
||||
val dirs = it.data.map {
|
||||
val meta = it.metaInfo
|
||||
EncryptedDirectory(EncryptedMetaInfo(
|
||||
size = meta.size,
|
||||
isDeleted = meta.isDeleted,
|
||||
isHidden = meta.isHidden,
|
||||
lastModified = meta.lastModified,
|
||||
path = decryptPath(meta.path)
|
||||
), it.elementsCount)
|
||||
}
|
||||
_dirsUpdates.emit(DataPackage(
|
||||
data = dirs,
|
||||
isLoading = it.isLoading,
|
||||
isError = it.isError
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalEncodingApi::class)
|
||||
private fun encryptString(str: String): String {
|
||||
val cipher = Cipher.getInstance(AES_FOR_STRINGS)
|
||||
val iv = IvParameterSpec(Random.nextBytes(IV_LEN))
|
||||
cipher.init(Cipher.ENCRYPT_MODE, _secretKey, iv)
|
||||
val bytesToEncrypt = iv.iv + str.toByteArray(Charsets.UTF_8)
|
||||
val encryptedBytes = cipher.doFinal(bytesToEncrypt)
|
||||
return Base64.Default.encode(encryptedBytes).replace("/", ".")
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalEncodingApi::class)
|
||||
private fun decryptString(str: String): String {
|
||||
val cipher = Cipher.getInstance(AES_FOR_STRINGS)
|
||||
val bytesToDecrypt = Base64.Default.decode(str.replace(".", "/"))
|
||||
val iv = IvParameterSpec(bytesToDecrypt.take(IV_LEN).toByteArray())
|
||||
cipher.init(Cipher.DECRYPT_MODE, _secretKey, iv)
|
||||
val decryptedBytes = cipher.doFinal(bytesToDecrypt.drop(IV_LEN).toByteArray())
|
||||
return String(decryptedBytes, Charsets.UTF_8)
|
||||
}
|
||||
|
||||
private fun encryptPath(pathStr: String): String {
|
||||
val path = Path(pathStr)
|
||||
val segments = mutableListOf<String>()
|
||||
for (segment in path)
|
||||
segments.add(encryptString(segment.pathString))
|
||||
val res = Path("/",*(segments.toTypedArray()))
|
||||
logger.debug("encryptPath", "$pathStr to $res")
|
||||
return res.pathString
|
||||
}
|
||||
|
||||
private fun decryptPath(pathStr: String): String {
|
||||
val path = Path(pathStr)
|
||||
val segments = mutableListOf<String>()
|
||||
for (segment in path)
|
||||
segments.add(decryptString(segment.pathString))
|
||||
val res = Path("/",*(segments.toTypedArray()))
|
||||
logger.debug("decryptPath", "$pathStr to $res")
|
||||
return res.pathString
|
||||
}
|
||||
|
||||
override suspend fun getAllFiles(): List<IFile> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun getFiles(path: String): List<IFile> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun getFilesFlow(path: String): Flow<DataPackage<List<IFile>>> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun getAllDirs(): List<IDirectory> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun getDirs(path: String): List<IDirectory> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun getDirsFlow(path: String): Flow<DataPackage<List<IDirectory>>> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun touchFile(path: String) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun touchDir(path: String) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun delete(path: String) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun openWrite(path: String): OutputStream {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun openRead(path: String): InputStream {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun moveToTrash(path: String) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
private const val IV_LEN = 16
|
||||
private const val AES_FOR_STRINGS = "AES/CBC/PKCS5Padding"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.github.nullptroma.wallenc.domain.encrypt.entity
|
||||
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IDirectory
|
||||
|
||||
data class EncryptedDirectory(
|
||||
override val metaInfo: EncryptedMetaInfo,
|
||||
override val elementsCount: Int?
|
||||
) : IDirectory
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.github.nullptroma.wallenc.domain.encrypt.entity
|
||||
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IFile
|
||||
|
||||
data class EncryptedFile(override val metaInfo: EncryptedMetaInfo) : IFile
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.github.nullptroma.wallenc.domain.encrypt.entity
|
||||
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IMetaInfo
|
||||
import java.time.Instant
|
||||
|
||||
|
||||
data class EncryptedMetaInfo(
|
||||
override val size: Long,
|
||||
override val isDeleted: Boolean = false,
|
||||
override val isHidden: Boolean = false,
|
||||
override val lastModified: Instant = java.time.Clock.systemUTC().instant(),
|
||||
override val path: String
|
||||
) : IMetaInfo
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.github.nullptroma.wallenc.domain.models
|
||||
package com.github.nullptroma.wallenc.domain.interfaces
|
||||
|
||||
interface IDirectory {
|
||||
val metaInfo: IMetaInfo
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.github.nullptroma.wallenc.domain.interfaces
|
||||
|
||||
interface IFile {
|
||||
val metaInfo: IMetaInfo
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.github.nullptroma.wallenc.domain.interfaces
|
||||
|
||||
interface ILogger {
|
||||
fun debug(tag: String, msg: String)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.github.nullptroma.wallenc.domain.models
|
||||
package com.github.nullptroma.wallenc.domain.interfaces
|
||||
|
||||
import java.time.Instant
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.github.nullptroma.wallenc.domain.models
|
||||
package com.github.nullptroma.wallenc.domain.interfaces
|
||||
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import java.util.UUID
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.github.nullptroma.wallenc.domain.models
|
||||
package com.github.nullptroma.wallenc.domain.interfaces
|
||||
|
||||
import com.github.nullptroma.wallenc.domain.datatypes.DataPackage
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@@ -11,8 +11,8 @@ interface IStorageAccessor {
|
||||
val size: StateFlow<Long?>
|
||||
val numberOfFiles: StateFlow<Int?>
|
||||
val isAvailable: StateFlow<Boolean>
|
||||
val filesUpdates: SharedFlow<DataPackage<IFile>>
|
||||
val dirsUpdates: SharedFlow<DataPackage<IDirectory>>
|
||||
val filesUpdates: SharedFlow<DataPackage<List<IFile>>>
|
||||
val dirsUpdates: SharedFlow<DataPackage<List<IDirectory>>>
|
||||
|
||||
suspend fun getAllFiles(): List<IFile>
|
||||
suspend fun getFiles(path: String): List<IFile>
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.github.nullptroma.wallenc.domain.models
|
||||
package com.github.nullptroma.wallenc.domain.interfaces
|
||||
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.github.nullptroma.wallenc.domain.models
|
||||
package com.github.nullptroma.wallenc.domain.interfaces
|
||||
|
||||
import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey
|
||||
import java.util.UUID
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.github.nullptroma.wallenc.domain.models
|
||||
package com.github.nullptroma.wallenc.domain.interfaces
|
||||
|
||||
import com.github.nullptroma.wallenc.domain.enums.VaultType
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.github.nullptroma.wallenc.domain.models
|
||||
package com.github.nullptroma.wallenc.domain.interfaces
|
||||
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
package com.github.nullptroma.wallenc.domain.models
|
||||
|
||||
interface IFile {
|
||||
val metaInfo: IMetaInfo
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.github.nullptroma.wallenc.domain.usecases
|
||||
|
||||
import com.github.nullptroma.wallenc.domain.models.IVaultsManager
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager
|
||||
|
||||
class GetAllRawStoragesUseCase(private val manager: IVaultsManager) {
|
||||
// fun getStoragesFlow() = manager.remoteVaults.combine(manager.localVault) { remote, local ->
|
||||
@@ -9,6 +9,6 @@ class GetAllRawStoragesUseCase(private val manager: IVaultsManager) {
|
||||
// add(local)
|
||||
// }
|
||||
// }
|
||||
val localStorage
|
||||
get() = manager.localVault
|
||||
val localStorages
|
||||
get() = manager.localVault.storages
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.github.nullptroma.wallenc.domain.usecases
|
||||
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IVaultsManager
|
||||
|
||||
class ManageLocalVaultUseCase(private val manager: IVaultsManager) {
|
||||
val localStorages
|
||||
get() = manager.localVault.storages
|
||||
|
||||
suspend fun createStorage() {
|
||||
manager.localVault.createStorage()
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.github.nullptroma.wallenc.domain.usecases
|
||||
|
||||
import com.github.nullptroma.wallenc.domain.models.IDirectory
|
||||
import com.github.nullptroma.wallenc.domain.models.IFile
|
||||
import com.github.nullptroma.wallenc.domain.models.IStorage
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IDirectory
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IFile
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IStorage
|
||||
|
||||
class StorageFileManagementUseCase {
|
||||
private var _storage: IStorage? = null
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.github.nullptroma.wallenc.domain.usecases
|
||||
|
||||
import com.github.nullptroma.wallenc.domain.models.IMetaInfo
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IMetaInfo
|
||||
|
||||
class TestUseCase (val meta: IMetaInfo, val id: Int) {
|
||||
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
|
||||
@@ -20,10 +28,21 @@ fun LocalVaultScreen(modifier: Modifier = Modifier,
|
||||
viewModel: LocalVaultViewModel = hiltViewModel()) {
|
||||
|
||||
val uiState by viewModel.state.collectAsStateWithLifecycle()
|
||||
LazyColumn(modifier = modifier) {
|
||||
Scaffold(modifier = modifier, contentWindowInsets = WindowInsets(0.dp), floatingActionButton = {
|
||||
FloatingActionButton(
|
||||
onClick = {
|
||||
viewModel.createStorage()
|
||||
},
|
||||
) {
|
||||
Icon(Icons.Filled.Add, "Floating action button.")
|
||||
}
|
||||
}) { innerPadding ->
|
||||
LazyColumn(modifier = Modifier.padding(innerPadding)) {
|
||||
items(uiState.storagesList) {
|
||||
Card(modifier = Modifier.clickable {
|
||||
viewModel.printAllFilesToLog(it)
|
||||
Card(modifier = Modifier.pointerInput(Unit) {
|
||||
detectTapGestures(
|
||||
onTap = { _ -> viewModel.printAllFilesToLog(it) }
|
||||
)
|
||||
}) {
|
||||
val available by it.isAvailable.collectAsStateWithLifecycle()
|
||||
val numOfFiles by it.numberOfFiles.collectAsStateWithLifecycle()
|
||||
@@ -37,4 +56,5 @@ fun LocalVaultScreen(modifier: Modifier = Modifier,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault
|
||||
|
||||
import com.github.nullptroma.wallenc.domain.models.IStorage
|
||||
import com.github.nullptroma.wallenc.domain.interfaces.IStorage
|
||||
|
||||
data class LocalVaultScreenState(val storagesList: List<IStorage>)
|
||||
@@ -1,12 +1,11 @@
|
||||
package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault
|
||||
|
||||
import android.app.Activity
|
||||
import android.widget.Toast
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.github.nullptroma.wallenc.domain.models.IDirectory
|
||||
import com.github.nullptroma.wallenc.domain.models.IFile
|
||||
import com.github.nullptroma.wallenc.domain.models.IStorage
|
||||
import com.github.nullptroma.wallenc.domain.usecases.GetAllRawStoragesUseCase
|
||||
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.usecases.ManageLocalVaultUseCase
|
||||
import com.github.nullptroma.wallenc.domain.usecases.StorageFileManagementUseCase
|
||||
import com.github.nullptroma.wallenc.presentation.viewmodel.ViewModelBase
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
@@ -17,13 +16,13 @@ import kotlin.system.measureTimeMillis
|
||||
|
||||
@HiltViewModel
|
||||
class LocalVaultViewModel @Inject constructor(
|
||||
private val _getAllRawStoragesUseCase: GetAllRawStoragesUseCase,
|
||||
private val _storageFileManagementUseCase: StorageFileManagementUseCase
|
||||
private val _manageLocalVaultUseCase: ManageLocalVaultUseCase,
|
||||
private val _storageFileManagementUseCase: StorageFileManagementUseCase,
|
||||
) :
|
||||
ViewModelBase<LocalVaultScreenState>(LocalVaultScreenState(listOf())) {
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
_getAllRawStoragesUseCase.localStorage.storages.collect {
|
||||
_manageLocalVaultUseCase.localStorages.collect {
|
||||
val newState = state.value.copy(
|
||||
storagesList = it
|
||||
)
|
||||
@@ -52,4 +51,10 @@ class LocalVaultViewModel @Inject constructor(
|
||||
Timber.d("Time: $time ms")
|
||||
}
|
||||
}
|
||||
|
||||
fun createStorage() {
|
||||
viewModelScope.launch {
|
||||
_manageLocalVaultUseCase.createStorage()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user