Начат LocalStorage, выкинут мусор из UiState

This commit is contained in:
Roman Pytkov
2024-12-17 23:41:05 +03:00
parent b5462dfd2f
commit 576fc4020c
26 changed files with 284 additions and 35 deletions

View File

@@ -53,6 +53,9 @@ android {
} }
dependencies { dependencies {
// Timber
implementation(libs.timber)
// Yandex // Yandex
implementation(libs.yandex.oauth) implementation(libs.yandex.oauth)
@@ -76,6 +79,6 @@ dependencies {
//androidTestImplementation(libs.androidx.ui.test.junit4) //androidTestImplementation(libs.androidx.ui.test.junit4)
implementation(project(":domain")) implementation(project(":domain"))
implementation(project(":data"))
implementation(project(":presentation")) implementation(project(":presentation"))
runtimeOnly(project(":data"))
} }

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,37 @@
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.github.nullptroma.wallenc.app",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 1,
"versionName": "1.0",
"outputFile": "app-release.apk"
}
],
"elementType": "File",
"baselineProfiles": [
{
"minApi": 28,
"maxApi": 30,
"baselineProfiles": [
"baselineProfiles/1/app-release.dm"
]
},
{
"minApi": 31,
"maxApi": 2147483647,
"baselineProfiles": [
"baselineProfiles/0/app-release.dm"
]
}
],
"minSdkVersionForDexing": 24
}

View File

@@ -6,8 +6,8 @@ import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import com.github.nullptroma.wallenc.presentation.WallencUi import com.github.nullptroma.wallenc.presentation.WallencUi
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import timber.log.Timber
class Container<T>(val value: T)
@AndroidEntryPoint @AndroidEntryPoint
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
@@ -15,12 +15,13 @@ class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
enableEdgeToEdge() enableEdgeToEdge()
Timber.plant(Timber.DebugTree())
// val sdk = YandexAuthSdk.create(YandexAuthOptions(applicationContext, true)) // val sdk = YandexAuthSdk.create(YandexAuthOptions(applicationContext, true))
// val launcher = // val launcher =
// registerForActivityResult(sdk.contract) { result -> handleResult(result) } // registerForActivityResult(sdk.contract) { result -> handleResult(result) }
// val loginOptions = YandexAuthLoginOptions(LoginType.CHROME_TAB) // val loginOptions = YandexAuthLoginOptions(LoginType.CHROME_TAB)
val cont1 = Container(true)
var cont2 = Container<Boolean>(true)
setContent { setContent {
WallencUi() WallencUi()
} }

View File

@@ -0,0 +1,29 @@
package com.github.nullptroma.wallenc.app.di.modules.app
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import javax.inject.Qualifier
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class MainDispatcher
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class IoDispatcher
@Module
@InstallIn(SingletonComponent::class)
class DispatchersModule {
@MainDispatcher
@Provides
fun providesMainDispatcher(): CoroutineDispatcher = Dispatchers.Main
@IoDispatcher
@Provides
fun providesIoDispatcher(): CoroutineDispatcher = Dispatchers.IO
}

View File

@@ -0,0 +1,31 @@
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 dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.CoroutineDispatcher
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
class SingletonModule {
@Provides
@Singleton
fun provideLocalVault(@IoDispatcher ioDispatcher: CoroutineDispatcher,
@ApplicationContext context: Context): LocalVault {
return LocalVault(ioDispatcher, context)
}
@Provides
@Singleton
fun provideVaultsManager(localVault: LocalVault): IVaultsManager {
return VaultsManager(localVault)
}
}

View File

@@ -1,7 +1,7 @@
package com.github.nullptroma.wallenc.app.di.modules.domain package com.github.nullptroma.wallenc.app.di.modules.domain
import com.github.nullptroma.wallenc.domain.models.IMetaInfo import com.github.nullptroma.wallenc.domain.models.IVaultsManager
import com.github.nullptroma.wallenc.domain.usecases.TestUseCase import com.github.nullptroma.wallenc.domain.usecases.GetAllRawStoragesUseCase
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
@@ -11,11 +11,9 @@ import javax.inject.Singleton
@Module @Module
@InstallIn(SingletonComponent::class) @InstallIn(SingletonComponent::class)
class UseCasesModule { class UseCasesModule {
var count = 0
@Provides @Provides
@Singleton @Singleton
fun provideTestUseCase(meta: IMetaInfo): TestUseCase { fun provideGetAllRawStoragesUseCase(vaultsManager: IVaultsManager): GetAllRawStoragesUseCase {
return TestUseCase(meta, count++) return GetAllRawStoragesUseCase(vaultsManager)
} }
} }

View File

@@ -34,6 +34,9 @@ android {
} }
dependencies { dependencies {
// Timber
implementation(libs.timber)
// Room // Room
implementation(libs.room.ktx) implementation(libs.room.ktx)
implementation(libs.room.runtime) implementation(libs.room.runtime)

View File

@@ -0,0 +1,23 @@
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")
}
}

View File

@@ -1,5 +1,16 @@
package com.github.nullptroma.wallenc.data.vaults package com.github.nullptroma.wallenc.data.vaults
class VaultsManager { 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 kotlinx.coroutines.flow.StateFlow
class VaultsManager(override val localVault: LocalVault) : IVaultsManager {
override val remoteVaults: StateFlow<List<IVault>>
get() = TODO("Not yet implemented")
override fun addYandexVault(email: String, token: String) {
TODO("Not yet implemented")
}
} }

View File

@@ -0,0 +1,77 @@
package com.github.nullptroma.wallenc.data.vaults.local
import com.github.nullptroma.wallenc.domain.datatypes.DataPackage
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 kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import java.io.InputStream
import java.io.OutputStream
import java.net.URI
class LocalStorageAccessor : IStorageAccessor {
override val isAvailable: StateFlow<Boolean>
get() = TODO("Not yet implemented")
override val filesUpdates: SharedFlow<DataPackage<IFile>>
get() = TODO("Not yet implemented")
override val dirsUpdates: SharedFlow<DataPackage<IDirectory>>
get() = TODO("Not yet implemented")
override suspend fun getAllFiles(): List<IFile> {
TODO("Not yet implemented")
}
override suspend fun getFiles(path: URI): List<IFile> {
TODO("Not yet implemented")
}
override fun getFilesFlow(path: URI): Flow<DataPackage<IFile>> {
TODO("Not yet implemented")
}
override suspend fun getAllDirs(): List<IDirectory> {
TODO("Not yet implemented")
}
override suspend fun getDirs(path: URI): List<IDirectory> {
TODO("Not yet implemented")
}
override fun getDirsFlow(path: URI): Flow<DataPackage<IDirectory>> {
TODO("Not yet implemented")
}
override suspend fun touchFile(path: URI) {
TODO("Not yet implemented")
}
override suspend fun touchDir(path: URI) {
TODO("Not yet implemented")
}
override suspend fun delete(path: URI) {
TODO("Not yet implemented")
}
override suspend fun getFileInfo(path: URI) {
TODO("Not yet implemented")
}
override suspend fun getDirInfo(path: URI) {
TODO("Not yet implemented")
}
override suspend fun openWrite(path: URI): InputStream {
TODO("Not yet implemented")
}
override suspend fun openRead(path: URI): OutputStream {
TODO("Not yet implemented")
}
override suspend fun moveToTrash(path: URI) {
TODO("Not yet implemented")
}
}

View File

@@ -1,21 +1,37 @@
package com.github.nullptroma.wallenc.data.vaults 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
import com.github.nullptroma.wallenc.domain.models.IVault import com.github.nullptroma.wallenc.domain.models.IVault
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
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.util.UUID import java.util.UUID
import kotlin.io.path.Path
import kotlin.io.path.createDirectory
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 _storages = MutableStateFlow(listOf<IStorage>())
init { init {
CoroutineScope(ioDispatcher).launch { CoroutineScope(ioDispatcher).launch {
if(path == null)
return@launch
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()
} }
} }
@@ -46,7 +62,7 @@ class LocalVault(private val ioDispatcher: CoroutineDispatcher, context: Context
override val uuid: UUID override val uuid: UUID
get() = TODO("Not yet implemented") get() = TODO("Not yet implemented")
override val storages: StateFlow<List<IStorage>> override val storages: StateFlow<List<IStorage>>
get() = TODO("Not yet implemented") get() = _storages
override val isAvailable: StateFlow<Boolean> override val isAvailable: StateFlow<Boolean>
get() = TODO("Not yet implemented") get() = TODO("Not yet implemented")

View File

@@ -3,7 +3,7 @@ package com.github.nullptroma.wallenc.domain.models
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
interface IVaultsManager { interface IVaultsManager {
val localVault: StateFlow<IVault> val localVault: IVault
val remoteVaults: StateFlow<List<IVault>> val remoteVaults: StateFlow<List<IVault>>
fun addYandexVault(email: String, token: String) fun addYandexVault(email: String, token: String)

View File

@@ -1,14 +1,14 @@
package com.github.nullptroma.wallenc.domain.usecases package com.github.nullptroma.wallenc.domain.usecases
import com.github.nullptroma.wallenc.domain.models.IVault
import com.github.nullptroma.wallenc.domain.models.IVaultsManager import com.github.nullptroma.wallenc.domain.models.IVaultsManager
import kotlinx.coroutines.flow.combine
class GetAllRawStoragesUseCase(val manager: IVaultsManager) { class GetAllRawStoragesUseCase(private val manager: IVaultsManager) {
fun getStoragesFlow() = manager.remoteVaults.combine(manager.localVault) { remote, local -> // fun getStoragesFlow() = manager.remoteVaults.combine(manager.localVault) { remote, local ->
mutableListOf<IVault>().apply { // mutableListOf<IVault>().apply {
addAll(remote) // addAll(remote)
add(local) // add(local)
} // }
} // }
val localStorage
get() = manager.localVault
} }

View File

@@ -13,6 +13,7 @@ activityCompose = "1.9.3"
composeBom = "2024.10.01" composeBom = "2024.10.01"
navigation = "2.8.3" navigation = "2.8.3"
hiltNavigation = "1.2.0" hiltNavigation = "1.2.0"
timber = "5.0.1"
yandexAuthSdk = "3.1.2" yandexAuthSdk = "3.1.2"
daggerHilt = "2.52" daggerHilt = "2.52"
ksp = "2.0.10-1.0.24" ksp = "2.0.10-1.0.24"
@@ -29,6 +30,7 @@ kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-c
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" } kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
navigation = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigation" } navigation = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigation" }
navigation-hilt-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "hiltNavigation" } navigation-hilt-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "hiltNavigation" }
timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" }
# Yandex # Yandex
yandex-oauth = { group = "com.yandex.android", name = "authsdk", version.ref = "yandexAuthSdk" } yandex-oauth = { group = "com.yandex.android", name = "authsdk", version.ref = "yandexAuthSdk" }

View File

@@ -1,3 +1,3 @@
package com.github.nullptroma.wallenc.presentation.screens.main package com.github.nullptroma.wallenc.presentation.screens.main
data class MainScreenState(val value: String) class MainScreenState

View File

@@ -12,7 +12,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
@HiltViewModel @HiltViewModel
class MainViewModel @javax.inject.Inject constructor(savedStateHandle: SavedStateHandle) : class MainViewModel @javax.inject.Inject constructor(savedStateHandle: SavedStateHandle) :
ViewModelBase<MainScreenState>(MainScreenState("default string")) { ViewModelBase<MainScreenState>(MainScreenState()) {
@OptIn(SavedStateHandleSaveableApi::class) @OptIn(SavedStateHandleSaveableApi::class)
var routes by savedStateHandle.saveable { var routes by savedStateHandle.saveable {

View File

@@ -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 androidx.compose.foundation.layout.Column
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
@@ -15,5 +16,9 @@ fun LocalVaultScreen(modifier: Modifier = Modifier,
viewModel: LocalVaultViewModel = hiltViewModel()) { viewModel: LocalVaultViewModel = hiltViewModel()) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle() val uiState by viewModel.uiState.collectAsStateWithLifecycle()
Text(uiState.value) Column {
for(storage in uiState.storagesList) {
Text(storage.uuid.toString())
}
}
} }

View File

@@ -1,3 +1,5 @@
package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault package com.github.nullptroma.wallenc.presentation.screens.main.screens.local.vault
data class LocalVaultScreenState(val value: String) import com.github.nullptroma.wallenc.domain.models.IStorage
data class LocalVaultScreenState(val storagesList: List<IStorage>)

View File

@@ -1,11 +1,22 @@
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 com.github.nullptroma.wallenc.domain.usecases.GetAllRawStoragesUseCase
import com.github.nullptroma.wallenc.presentation.viewmodel.ViewModelBase import com.github.nullptroma.wallenc.presentation.viewmodel.ViewModelBase
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
class LocalVaultViewModel @Inject constructor() class LocalVaultViewModel @Inject constructor(private val getAllRawStoragesUseCase: GetAllRawStoragesUseCase) :
: ViewModelBase<LocalVaultScreenState>(LocalVaultScreenState("default")) { ViewModelBase<LocalVaultScreenState>(LocalVaultScreenState(listOf())) {
init {
viewModelScope.launch {
getAllRawStoragesUseCase.localStorage.storages.collect {
mutableUiState.value = mutableUiState.value.copy(
storagesList = it
)
}
}
}
} }

View File

@@ -1,3 +1,3 @@
package com.github.nullptroma.wallenc.presentation.screens.main.screens.remotes package com.github.nullptroma.wallenc.presentation.screens.main.screens.remotes
data class RemoteVaultsScreenState(val value: String) class RemoteVaultsScreenState

View File

@@ -6,6 +6,6 @@ import javax.inject.Inject
@HiltViewModel @HiltViewModel
class RemoteVaultsViewModel @Inject constructor() : class RemoteVaultsViewModel @Inject constructor() :
ViewModelBase<RemoteVaultsScreenState>(RemoteVaultsScreenState("")) { ViewModelBase<RemoteVaultsScreenState>(RemoteVaultsScreenState()) {
} }

View File

@@ -1,3 +1,3 @@
package com.github.nullptroma.wallenc.presentation.screens.settings package com.github.nullptroma.wallenc.presentation.screens.settings
data class SettingsScreenState(val value: String) class SettingsScreenState

View File

@@ -5,5 +5,5 @@ import dagger.hilt.android.lifecycle.HiltViewModel
@HiltViewModel @HiltViewModel
class SettingsViewModel @javax.inject.Inject constructor() : class SettingsViewModel @javax.inject.Inject constructor() :
ViewModelBase<SettingsScreenState>(SettingsScreenState("default string")) { ViewModelBase<SettingsScreenState>(SettingsScreenState()) {
} }

View File

@@ -2492,7 +2492,7 @@ existing classes or even new classes with specific responsibilities.</val>
<val>localVault</val> <val>localVault</val>
</name> </name>
<typeValue> <typeValue>
<val>StateFlow&lt;IVault&gt;</val> <val>IVault</val>
</typeValue> </typeValue>
</Property> </Property>
<Property id="29e33324-96f0-11ef-9427-3ba703bb2331"> <Property id="29e33324-96f0-11ef-9427-3ba703bb2331">