Начало LocalVault
This commit is contained in:
@@ -1,23 +0,0 @@
|
|||||||
package com.github.nullptroma.wallenc.data
|
|
||||||
|
|
||||||
import com.github.nullptroma.wallenc.domain.models.IStorage
|
|
||||||
import com.github.nullptroma.wallenc.domain.models.IStorageAccessor
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
|
||||||
import java.util.UUID
|
|
||||||
|
|
||||||
class MockStorage(
|
|
||||||
override val size: StateFlow<Int?> = MutableStateFlow(null),
|
|
||||||
override val numberOfFiles: StateFlow<Int?> = MutableStateFlow(null),
|
|
||||||
override val uuid: UUID,
|
|
||||||
override val name: StateFlow<String> = MutableStateFlow(""),
|
|
||||||
override val totalSpace: StateFlow<Int?> = MutableStateFlow(null),
|
|
||||||
override val availableSpace: StateFlow<Int?> = MutableStateFlow(null),
|
|
||||||
override val isAvailable: StateFlow<Boolean> = MutableStateFlow(false),
|
|
||||||
override val accessor: IStorageAccessor
|
|
||||||
) : IStorage {
|
|
||||||
|
|
||||||
override suspend fun rename(newName: String) {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.github.nullptroma.wallenc.data.vaults
|
||||||
|
|
||||||
|
interface IStorageCallbackHandler {
|
||||||
|
fun changeSize(delta: Int)
|
||||||
|
fun changeNumOfFiles(delta: Int)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
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 kotlinx.coroutines.CoroutineDispatcher
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
|
||||||
|
class LocalStorage(
|
||||||
|
override val uuid: UUID,
|
||||||
|
absolutePath: String,
|
||||||
|
ioDispatcher: CoroutineDispatcher
|
||||||
|
) : IStorage {
|
||||||
|
override val size: StateFlow<Long?>
|
||||||
|
get() = accessor.size
|
||||||
|
override val numberOfFiles: StateFlow<Int?>
|
||||||
|
get() = accessor.numberOfFiles
|
||||||
|
override val name: StateFlow<String>
|
||||||
|
get() = TODO("Добавить класс в Domain, который с помощью accessor будет читать и сохранять имя в скрытую папку")
|
||||||
|
override val isAvailable: StateFlow<Boolean>
|
||||||
|
get() = accessor.isAvailable
|
||||||
|
override val accessor: IStorageAccessor = LocalStorageAccessor(absolutePath, ioDispatcher)
|
||||||
|
|
||||||
|
override suspend fun rename(newName: String) {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,30 +4,92 @@ import com.github.nullptroma.wallenc.domain.datatypes.DataPackage
|
|||||||
import com.github.nullptroma.wallenc.domain.models.IDirectory
|
import com.github.nullptroma.wallenc.domain.models.IDirectory
|
||||||
import com.github.nullptroma.wallenc.domain.models.IFile
|
import com.github.nullptroma.wallenc.domain.models.IFile
|
||||||
import com.github.nullptroma.wallenc.domain.models.IStorageAccessor
|
import com.github.nullptroma.wallenc.domain.models.IStorageAccessor
|
||||||
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.SharedFlow
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import java.io.File
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.net.URI
|
import kotlin.io.path.Path
|
||||||
|
import kotlin.io.path.fileSize
|
||||||
|
|
||||||
class LocalStorageAccessor : IStorageAccessor {
|
class LocalStorageAccessor(
|
||||||
|
private val absolutePath: String,
|
||||||
|
private val ioDispatcher: CoroutineDispatcher
|
||||||
|
) : IStorageAccessor {
|
||||||
|
private val _size = MutableStateFlow<Long?>(null)
|
||||||
|
private val _numberOfFiles = MutableStateFlow<Int?>(null)
|
||||||
|
private val _isAvailable = MutableStateFlow(false)
|
||||||
|
|
||||||
|
override val size: StateFlow<Long?>
|
||||||
|
get() = _size
|
||||||
|
override val numberOfFiles: StateFlow<Int?>
|
||||||
|
get() = _numberOfFiles
|
||||||
override val isAvailable: StateFlow<Boolean>
|
override val isAvailable: StateFlow<Boolean>
|
||||||
get() = TODO("Not yet implemented")
|
get() = _isAvailable
|
||||||
override val filesUpdates: SharedFlow<DataPackage<IFile>>
|
override val filesUpdates: SharedFlow<DataPackage<IFile>>
|
||||||
get() = TODO("Not yet implemented")
|
get() = TODO("Not yet implemented")
|
||||||
override val dirsUpdates: SharedFlow<DataPackage<IDirectory>>
|
override val dirsUpdates: SharedFlow<DataPackage<IDirectory>>
|
||||||
get() = TODO("Not yet implemented")
|
get() = TODO("Not yet implemented")
|
||||||
|
|
||||||
|
init {
|
||||||
|
CoroutineScope(ioDispatcher).launch {
|
||||||
|
scanStorage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkAvailable(): Boolean {
|
||||||
|
_isAvailable.value = File(absolutePath).exists()
|
||||||
|
return _isAvailable.value
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun forAllFiles(dir: File, callback: (File) -> Unit) {
|
||||||
|
if (dir.exists() == false)
|
||||||
|
return
|
||||||
|
callback(dir)
|
||||||
|
|
||||||
|
val nextDirs = dir.listFiles()
|
||||||
|
if (nextDirs != null) {
|
||||||
|
for (nextDir in nextDirs) {
|
||||||
|
forAllFiles(nextDir, callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun scanStorage() = withContext(ioDispatcher) {
|
||||||
|
_isAvailable.value = File(absolutePath).exists()
|
||||||
|
|
||||||
|
var size = 0L
|
||||||
|
var numOfFiles = 0
|
||||||
|
|
||||||
|
forAllFiles(File(absolutePath)) {
|
||||||
|
if (it.isFile) {
|
||||||
|
numOfFiles++
|
||||||
|
size += Path(it.path).fileSize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_size.value = size
|
||||||
|
_numberOfFiles.value = numOfFiles
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun getAllFiles(): List<IFile> {
|
override suspend fun getAllFiles(): List<IFile> {
|
||||||
|
if(checkAvailable() == false)
|
||||||
|
return listOf()
|
||||||
|
|
||||||
|
val list = mutableListOf<IFile>()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getFiles(path: String): List<IFile> {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getFiles(path: URI): List<IFile> {
|
override fun getFilesFlow(path: String): Flow<DataPackage<IFile>> {
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getFilesFlow(path: URI): Flow<DataPackage<IFile>> {
|
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,43 +97,43 @@ class LocalStorageAccessor : IStorageAccessor {
|
|||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getDirs(path: URI): List<IDirectory> {
|
override suspend fun getDirs(path: String): List<IDirectory> {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getDirsFlow(path: URI): Flow<DataPackage<IDirectory>> {
|
override fun getDirsFlow(path: String): Flow<DataPackage<IDirectory>> {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun touchFile(path: URI) {
|
override suspend fun touchFile(path: String) {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun touchDir(path: URI) {
|
override suspend fun touchDir(path: String) {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun delete(path: URI) {
|
override suspend fun delete(path: String) {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getFileInfo(path: URI) {
|
override suspend fun getFileInfo(path: String) {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getDirInfo(path: URI) {
|
override suspend fun getDirInfo(path: String) {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun openWrite(path: URI): InputStream {
|
override suspend fun openWrite(path: String): InputStream {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun openRead(path: URI): OutputStream {
|
override suspend fun openRead(path: String): OutputStream {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun moveToTrash(path: URI) {
|
override suspend fun moveToTrash(path: String) {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.github.nullptroma.wallenc.data.vaults.local
|
package com.github.nullptroma.wallenc.data.vaults.local
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.github.nullptroma.wallenc.data.MockStorage
|
|
||||||
import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey
|
import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey
|
||||||
import com.github.nullptroma.wallenc.domain.enums.VaultType
|
import com.github.nullptroma.wallenc.domain.enums.VaultType
|
||||||
import com.github.nullptroma.wallenc.domain.models.IStorage
|
import com.github.nullptroma.wallenc.domain.models.IStorage
|
||||||
@@ -12,42 +11,64 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
|||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import java.io.File
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import kotlin.io.path.Path
|
import kotlin.io.path.Path
|
||||||
import kotlin.io.path.createDirectory
|
import kotlin.io.path.createDirectory
|
||||||
|
import kotlin.io.path.pathString
|
||||||
|
|
||||||
class LocalVault(private val ioDispatcher: CoroutineDispatcher, context: Context) : IVault {
|
class LocalVault(private val ioDispatcher: CoroutineDispatcher, context: Context) : IVault {
|
||||||
private val path = context.getExternalFilesDir("LocalVault")
|
private val _path = MutableStateFlow<File?>(null)
|
||||||
private val _storages = MutableStateFlow(listOf<IStorage>())
|
private val _storages = MutableStateFlow(listOf<IStorage>())
|
||||||
|
private val _totalSpace = MutableStateFlow(null)
|
||||||
|
private val _availableSpace = MutableStateFlow(null)
|
||||||
|
private val _isAvailable = MutableStateFlow(false)
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
CoroutineScope(ioDispatcher).launch {
|
CoroutineScope(ioDispatcher).launch {
|
||||||
if(path == null)
|
_path.value = context.getExternalFilesDir("LocalVault")
|
||||||
return@launch
|
_isAvailable.value = _path.value != null
|
||||||
|
readStorages()
|
||||||
val dirs = path.listFiles()?.filter { it.isDirectory }
|
|
||||||
if(dirs != null)
|
|
||||||
_storages.value = dirs.map {
|
|
||||||
MockStorage(uuid = UUID.fromString(it.name), accessor = LocalStorageAccessor())
|
|
||||||
}
|
|
||||||
val next = Path(path.path, UUID.randomUUID().toString())
|
|
||||||
next.createDirectory()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun createStorage(name: String): IStorage = withContext(ioDispatcher) {
|
private fun readStorages() {
|
||||||
TODO("Not yet implemented")
|
val path = _path.value
|
||||||
|
if (path == null || _isAvailable.value == false)
|
||||||
|
return
|
||||||
|
|
||||||
|
val dirs = path.listFiles()?.filter { it.isDirectory }
|
||||||
|
if (dirs != null) {
|
||||||
|
_storages.value = dirs.map {
|
||||||
|
val uuid = UUID.fromString(it.name)
|
||||||
|
LocalStorage(uuid, it.path, ioDispatcher)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun createStorage(): IStorage = withContext(ioDispatcher) {
|
||||||
|
val path = _path.value
|
||||||
|
if (path == null || _isAvailable.value == false)
|
||||||
|
throw Exception("Not available")
|
||||||
|
|
||||||
|
val uuid = UUID.randomUUID()
|
||||||
|
val next = Path(path.path, uuid.toString())
|
||||||
|
next.createDirectory()
|
||||||
|
val newStorage = LocalStorage(uuid, next.pathString, ioDispatcher)
|
||||||
|
_storages.value = _storages.value.toMutableList().apply {
|
||||||
|
add(newStorage)
|
||||||
|
}
|
||||||
|
return@withContext newStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun createStorage(
|
override suspend fun createStorage(
|
||||||
name: String,
|
|
||||||
key: EncryptKey
|
key: EncryptKey
|
||||||
): IStorage = withContext(ioDispatcher) {
|
): IStorage = withContext(ioDispatcher) {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun createStorage(
|
override suspend fun createStorage(
|
||||||
name: String,
|
|
||||||
key: EncryptKey,
|
key: EncryptKey,
|
||||||
uuid: UUID
|
uuid: UUID
|
||||||
): IStorage = withContext(ioDispatcher) {
|
): IStorage = withContext(ioDispatcher) {
|
||||||
@@ -64,6 +85,9 @@ class LocalVault(private val ioDispatcher: CoroutineDispatcher, context: Context
|
|||||||
override val storages: StateFlow<List<IStorage>>
|
override val storages: StateFlow<List<IStorage>>
|
||||||
get() = _storages
|
get() = _storages
|
||||||
override val isAvailable: StateFlow<Boolean>
|
override val isAvailable: StateFlow<Boolean>
|
||||||
get() = TODO("Not yet implemented")
|
get() = _isAvailable
|
||||||
|
override val totalSpace: StateFlow<Int?>
|
||||||
|
get() = _totalSpace
|
||||||
|
override val availableSpace: StateFlow<Int?>
|
||||||
|
get() = _availableSpace
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.github.nullptroma.wallenc.data.vaults.local.entity
|
||||||
|
|
||||||
|
import com.github.nullptroma.wallenc.domain.models.IDirectory
|
||||||
|
|
||||||
|
class LocalDirectory(
|
||||||
|
override val metaInfo: LocalMetaInfo,
|
||||||
|
override val elementsCount: Int
|
||||||
|
) : IDirectory
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.github.nullptroma.wallenc.data.vaults.local.entity
|
||||||
|
|
||||||
|
import com.github.nullptroma.wallenc.domain.models.IFile
|
||||||
|
|
||||||
|
class LocalFile(override val metaInfo: LocalMetaInfo) : IFile
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.github.nullptroma.wallenc.data.vaults.local.entity
|
||||||
|
|
||||||
|
import com.github.nullptroma.wallenc.domain.models.IMetaInfo
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
|
||||||
|
class LocalMetaInfo : IMetaInfo {
|
||||||
|
init {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override val name: String
|
||||||
|
get() = TODO("Not yet implemented")
|
||||||
|
override val size: Int
|
||||||
|
get() = TODO("Not yet implemented")
|
||||||
|
override val isDeleted: Boolean
|
||||||
|
get() = TODO("Not yet implemented")
|
||||||
|
override val isHidden: Boolean
|
||||||
|
get() = TODO("Not yet implemented")
|
||||||
|
override val lastModified: LocalDateTime
|
||||||
|
get() = TODO("Not yet implemented")
|
||||||
|
override val path: String
|
||||||
|
get() = TODO("Not yet implemented")
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.github.nullptroma.wallenc.domain.models
|
package com.github.nullptroma.wallenc.domain.models
|
||||||
|
|
||||||
import java.net.URI
|
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
|
|
||||||
|
|
||||||
@@ -10,5 +9,5 @@ interface IMetaInfo {
|
|||||||
val isDeleted: Boolean
|
val isDeleted: Boolean
|
||||||
val isHidden: Boolean
|
val isHidden: Boolean
|
||||||
val lastModified: LocalDateTime
|
val lastModified: LocalDateTime
|
||||||
val path: URI
|
val path: String
|
||||||
}
|
}
|
||||||
@@ -4,12 +4,10 @@ import kotlinx.coroutines.flow.StateFlow
|
|||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
interface IStorage {
|
interface IStorage {
|
||||||
val size: StateFlow<Int?>
|
val size: StateFlow<Long?>
|
||||||
val numberOfFiles: StateFlow<Int?>
|
val numberOfFiles: StateFlow<Int?>
|
||||||
val uuid: UUID
|
val uuid: UUID
|
||||||
val name: StateFlow<String>
|
val name: StateFlow<String>
|
||||||
val totalSpace: StateFlow<Int?>
|
|
||||||
val availableSpace: StateFlow<Int?>
|
|
||||||
val isAvailable: StateFlow<Boolean>
|
val isAvailable: StateFlow<Boolean>
|
||||||
val accessor: IStorageAccessor
|
val accessor: IStorageAccessor
|
||||||
|
|
||||||
|
|||||||
@@ -6,37 +6,38 @@ import kotlinx.coroutines.flow.SharedFlow
|
|||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.net.URI
|
|
||||||
|
|
||||||
interface IStorageAccessor {
|
interface IStorageAccessor {
|
||||||
|
val size: StateFlow<Long?>
|
||||||
|
val numberOfFiles: StateFlow<Int?>
|
||||||
val isAvailable: StateFlow<Boolean>
|
val isAvailable: StateFlow<Boolean>
|
||||||
val filesUpdates: SharedFlow<DataPackage<IFile>>
|
val filesUpdates: SharedFlow<DataPackage<IFile>>
|
||||||
val dirsUpdates: SharedFlow<DataPackage<IDirectory>>
|
val dirsUpdates: SharedFlow<DataPackage<IDirectory>>
|
||||||
|
|
||||||
suspend fun getAllFiles(): List<IFile>
|
suspend fun getAllFiles(): List<IFile>
|
||||||
suspend fun getFiles(path: URI): List<IFile>
|
suspend fun getFiles(path: String): List<IFile>
|
||||||
/**
|
/**
|
||||||
* Получение списка файлов в директории
|
* Получение списка файлов в директории
|
||||||
* @param path Путь к директории
|
* @param path Путь к директории
|
||||||
* @return Поток файлов
|
* @return Поток файлов
|
||||||
*/
|
*/
|
||||||
fun getFilesFlow(path: URI): Flow<DataPackage<IFile>>
|
fun getFilesFlow(path: String): Flow<DataPackage<IFile>>
|
||||||
|
|
||||||
suspend fun getAllDirs(): List<IDirectory>
|
suspend fun getAllDirs(): List<IDirectory>
|
||||||
suspend fun getDirs(path: URI): List<IDirectory>
|
suspend fun getDirs(path: String): List<IDirectory>
|
||||||
/**
|
/**
|
||||||
* Получение списка директорий в директории
|
* Получение списка директорий в директории
|
||||||
* @param path Путь к директории
|
* @param path Путь к директории
|
||||||
* @return Поток директорий
|
* @return Поток директорий
|
||||||
*/
|
*/
|
||||||
fun getDirsFlow(path: URI): Flow<DataPackage<IDirectory>>
|
fun getDirsFlow(path: String): Flow<DataPackage<IDirectory>>
|
||||||
|
|
||||||
suspend fun touchFile(path: URI)
|
suspend fun touchFile(path: String)
|
||||||
suspend fun touchDir(path: URI)
|
suspend fun touchDir(path: String)
|
||||||
suspend fun delete(path: URI)
|
suspend fun delete(path: String)
|
||||||
suspend fun getFileInfo(path: URI)
|
suspend fun getFileInfo(path: String)
|
||||||
suspend fun getDirInfo(path: URI)
|
suspend fun getDirInfo(path: String)
|
||||||
suspend fun openWrite(path: URI): InputStream
|
suspend fun openWrite(path: String): InputStream
|
||||||
suspend fun openRead(path: URI): OutputStream
|
suspend fun openRead(path: String): OutputStream
|
||||||
suspend fun moveToTrash(path: URI)
|
suspend fun moveToTrash(path: String)
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
package com.github.nullptroma.wallenc.domain.models
|
package com.github.nullptroma.wallenc.domain.models
|
||||||
|
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
interface IStorageExplorer {
|
interface IStorageExplorer {
|
||||||
val currentPath: StateFlow<URL>
|
val currentPath: StateFlow<String>
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
// пока бесполезный интерфейс
|
// пока бесполезный интерфейс
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import com.github.nullptroma.wallenc.domain.datatypes.EncryptKey
|
|||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
interface IVault : IVaultInfo {
|
interface IVault : IVaultInfo {
|
||||||
suspend fun createStorage(name: String): IStorage
|
suspend fun createStorage(): IStorage
|
||||||
suspend fun createStorage(name: String, key: EncryptKey): IStorage
|
suspend fun createStorage(key: EncryptKey): IStorage
|
||||||
suspend fun createStorage(name: String, key: EncryptKey, uuid: UUID): IStorage
|
suspend fun createStorage(key: EncryptKey, uuid: UUID): IStorage
|
||||||
suspend fun remove(storage: IStorage)
|
suspend fun remove(storage: IStorage)
|
||||||
}
|
}
|
||||||
@@ -9,4 +9,6 @@ interface IVaultInfo {
|
|||||||
val uuid: UUID
|
val uuid: UUID
|
||||||
val storages: StateFlow<List<IStorage>>
|
val storages: StateFlow<List<IStorage>>
|
||||||
val isAvailable: StateFlow<Boolean>
|
val isAvailable: StateFlow<Boolean>
|
||||||
|
val totalSpace: StateFlow<Int?>
|
||||||
|
val availableSpace: StateFlow<Int?>
|
||||||
}
|
}
|
||||||
@@ -47,6 +47,9 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
// Timber
|
||||||
|
implementation(libs.timber)
|
||||||
|
|
||||||
implementation(libs.navigation)
|
implementation(libs.navigation)
|
||||||
implementation(libs.navigation.hilt.compose)
|
implementation(libs.navigation.hilt.compose)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
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.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@@ -9,16 +12,22 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun LocalVaultScreen(modifier: Modifier = Modifier,
|
fun LocalVaultScreen(modifier: Modifier = Modifier,
|
||||||
viewModel: LocalVaultViewModel = hiltViewModel()) {
|
viewModel: LocalVaultViewModel = hiltViewModel()) {
|
||||||
|
|
||||||
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
val uiState by viewModel.state.collectAsStateWithLifecycle()
|
||||||
Column {
|
LazyColumn(modifier = modifier) {
|
||||||
for(storage in uiState.storagesList) {
|
items(uiState.storagesList) {
|
||||||
Text(storage.uuid.toString())
|
Card {
|
||||||
|
Column {
|
||||||
|
Text(it.uuid.toString())
|
||||||
|
Text("IsAvailable: ${it.isAvailable.value}")
|
||||||
|
Text("Files: ${it.numberOfFiles.value}")
|
||||||
|
Text("Size: ${it.size.value}")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,9 +13,10 @@ class LocalVaultViewModel @Inject constructor(private val getAllRawStoragesUseCa
|
|||||||
init {
|
init {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
getAllRawStoragesUseCase.localStorage.storages.collect {
|
getAllRawStoragesUseCase.localStorage.storages.collect {
|
||||||
mutableUiState.value = mutableUiState.value.copy(
|
val newState = state.value.copy(
|
||||||
storagesList = it
|
storagesList = it
|
||||||
)
|
)
|
||||||
|
updateState(newState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,19 @@ package com.github.nullptroma.wallenc.presentation.viewmodel
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import timber.log.Timber
|
||||||
|
|
||||||
abstract class ViewModelBase<TState>(initState: TState) : ViewModel() {
|
abstract class ViewModelBase<TState>(initState: TState) : ViewModel() {
|
||||||
protected val mutableUiState = MutableStateFlow<TState>(initState)
|
private val _state = MutableStateFlow<TState>(initState)
|
||||||
|
|
||||||
val uiState: StateFlow<TState>
|
init {
|
||||||
get() = mutableUiState.asStateFlow()
|
Timber.d("Init ViewModel ${this.javaClass.name}")
|
||||||
|
}
|
||||||
|
|
||||||
|
val state: StateFlow<TState>
|
||||||
|
get() = _state
|
||||||
|
|
||||||
|
protected fun updateState(newState: TState) {
|
||||||
|
_state.value = newState
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user