Skip to content

Commit

Permalink
Merge pull request #45 from stslex/dev
Browse files Browse the repository at this point in the history
Fix bugs, add encrypted prefs
  • Loading branch information
stslex authored Nov 2, 2024
2 parents 7dc26ed + 04fda6d commit 7ee67ac
Show file tree
Hide file tree
Showing 26 changed files with 111 additions and 100 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ fun InitialApp(
LaunchedEffect(Unit) {
userStore.isAuthFlow.collect { isAuth ->
val currentScreen = navHostController.currentDestination
val authScreen = Screen.Auth::class.simpleName.orEmpty()
if (
isAuth.not() &&
currentScreen != null &&
currentScreen.route != Screen.Auth.serializer().toString()
currentScreen?.route?.contains(authScreen) == true
) {
navHostController.navigate(Screen.Auth)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.MainCoroutineDispatcher

class AppDispatcherImpl : AppDispatcher {
object AppDispatcherImpl : AppDispatcher {
override val io: CoroutineDispatcher = Dispatchers.IO
override val main: MainCoroutineDispatcher = Dispatchers.Main
override val default: CoroutineDispatcher = Dispatchers.Default
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package com.stslex.wizard.core.core

import org.koin.core.annotation.Module
import org.koin.core.module.dsl.singleOf
import org.koin.dsl.ModuleDeclaration

@Module
class ModuleCore : AppModule() {

override fun declaration(): ModuleDeclaration = {
singleOf<AppDispatcher>(::AppDispatcherImpl)
single<AppDispatcher> { AppDispatcherImpl }
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.stslex.wizard.core.core.coroutine

import com.stslex.wizard.core.core.AppDispatcher
import com.stslex.wizard.core.core.AppDispatcherImpl
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Job
Expand All @@ -21,6 +23,8 @@ interface AppCoroutineScope {
start: CoroutineStart = CoroutineStart.DEFAULT,
onError: suspend (Throwable) -> Unit = {},
onSuccess: suspend CoroutineScope.(T) -> Unit = {},
workDispatcher: CoroutineDispatcher = AppDispatcherImpl.default,
eachDispatcher: CoroutineDispatcher = AppDispatcherImpl.main.immediate,
action: suspend CoroutineScope.() -> T,
): Job

Expand All @@ -35,8 +39,10 @@ interface AppCoroutineScope {
* */
fun <T> launch(
flow: Flow<T>,
workDispatcher: CoroutineDispatcher = AppDispatcherImpl.default,
eachDispatcher: CoroutineDispatcher = AppDispatcherImpl.main.immediate,
onError: suspend (cause: Throwable) -> Unit = {},
each: suspend (T) -> Unit
each: suspend (T) -> Unit,
): Job
}

Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
package com.stslex.wizard.core.core.coroutine

import com.stslex.wizard.core.core.AppDispatcher
import com.stslex.wizard.core.core.Logger
import com.stslex.wizard.core.core.coroutineExceptionHandler
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class AppCoroutineScopeImpl(
private val scope: CoroutineScope,
private val appDispatcher: AppDispatcher
) : AppCoroutineScope {

private fun exceptionHandler(
eachDispatcher: CoroutineDispatcher,
onError: suspend (cause: Throwable) -> Unit = {},
) = CoroutineExceptionHandler { _, throwable ->
Logger.e(throwable)
scope.launch(appDispatcher.default + coroutineExceptionHandler) {
scope.launch(eachDispatcher) {
onError(throwable)
}
}
Expand All @@ -28,23 +28,34 @@ class AppCoroutineScopeImpl(
start: CoroutineStart,
onError: suspend (Throwable) -> Unit,
onSuccess: suspend CoroutineScope.(T) -> Unit,
action: suspend CoroutineScope.() -> T
workDispatcher: CoroutineDispatcher,
eachDispatcher: CoroutineDispatcher,
action: suspend CoroutineScope.() -> T,
): Job = scope.launch(
start = start,
context = exceptionHandler(onError) + appDispatcher.default,
context = exceptionHandler(eachDispatcher, onError) + workDispatcher,
block = {
onSuccess(action())
val result = action()
withContext(eachDispatcher) {
onSuccess(result)
}
}
)

override fun <T> launch(
flow: Flow<T>,
workDispatcher: CoroutineDispatcher,
eachDispatcher: CoroutineDispatcher,
onError: suspend (cause: Throwable) -> Unit,
each: suspend (T) -> Unit
): Job = scope.launch(
context = exceptionHandler(onError) + appDispatcher.default,
context = exceptionHandler(eachDispatcher, onError) + workDispatcher,
block = {
flow.collect(each)
flow.collect {
withContext(eachDispatcher) {
each(it)
}
}
}
)
}
3 changes: 3 additions & 0 deletions core/database/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,8 @@ kotlin {
implementation(project(":core:core"))
implementation(libs.multiplatformSettings)
}
androidMain.dependencies {
implementation(libs.androidx.security.crypto)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.stslex.wizard.core.database.di

import android.content.Context
import android.content.SharedPreferences
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey

internal fun createEncriptedSharedPreferences(
context: Context,
name: String
): SharedPreferences {
val masterKey: MasterKey = MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build()
return EncryptedSharedPreferences.create(
context,
"${name.lowercase()}_shared_prefs",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.stslex.wizard.core.database.di

import android.content.Context
import com.russhwolf.settings.SharedPreferencesSettings
import com.stslex.wizard.core.database.store.UserSettings
import com.stslex.wizard.core.database.store.UserSettingsImpl
Expand All @@ -9,8 +8,10 @@ import org.koin.core.module.Module

actual fun Module.declareUserSettingsStore() {
single<UserSettings> {
val delegate = androidContext()
.getSharedPreferences(UserSettings.NAME, Context.MODE_PRIVATE)
val delegate = createEncriptedSharedPreferences(
context = androidContext(),
name = UserSettings.NAME
)
val prefs = SharedPreferencesSettings(delegate)
UserSettingsImpl(prefs)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ package com.stslex.wizard.core.network.utils.token
import kotlinx.coroutines.flow.StateFlow

interface AuthController {

val isAuth: Boolean
val isAuthFlow: StateFlow<Boolean>
val accessToken: String
val refreshToken: String

suspend fun update(token: TokenModel)
suspend fun logOut()
suspend fun logout()
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.stslex.wizard.core.network.utils.token

import com.stslex.wizard.core.core.Logger
import com.stslex.wizard.core.database.store.UserStore
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
Expand All @@ -25,15 +26,21 @@ class AuthControllerImpl(
get() = userStore.refreshToken

override suspend fun update(token: TokenModel) {
Logger.d("update: $token", TAG)
userStore.accessToken = token.accessToken
userStore.refreshToken = token.refreshToken
userStore.username = token.username
userStore.uuid = token.uuid
_isAuthFlow.emit(token.accessToken.isNotEmpty())
}

override suspend fun logOut() {
override suspend fun logout() {
Logger.d("logout", TAG)
userStore.clear()
_isAuthFlow.emit(false)
}

companion object {
private const val TAG = "AuthController"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import com.stslex.wizard.core.network.utils.currentTimeMs
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

Expand Down Expand Up @@ -47,7 +46,7 @@ fun onClickDelay(
val clicker = remember(onClick) { Clicker(throttle) }
return remember(onClick) {
{
coroutineScope.launch(Dispatchers.Default) {
coroutineScope.launch {
delay(delay)
clicker.click(onClick = onClick)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ package com.stslex.wizard.core.ui.mvi
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.stslex.wizard.core.core.AppDispatcher
import com.stslex.wizard.core.core.AppDispatcherImpl
import com.stslex.wizard.core.core.Logger
import com.stslex.wizard.core.core.coroutine.AppCoroutineScope
import com.stslex.wizard.core.core.coroutine.AppCoroutineScopeImpl
import com.stslex.wizard.core.core.coroutineExceptionHandler
import com.stslex.wizard.core.ui.mvi.Store.Action
import com.stslex.wizard.core.ui.mvi.Store.Event
import com.stslex.wizard.core.ui.mvi.Store.State
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
Expand All @@ -23,21 +25,16 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

abstract class BaseStore<S : State, A : Action, E : Event>(
private val appDispatcher: AppDispatcher,
initialState: S
) : ViewModel(), Store<S, A, E> {
abstract class BaseStore<S : State, A : Action, E : Event>(initialState: S) : ViewModel(),
Store<S, A, E> {

private val _event: MutableSharedFlow<E> = MutableSharedFlow()
override val event: SharedFlow<E> = _event.asSharedFlow()

private val _state: MutableStateFlow<S> = MutableStateFlow(initialState)
override val state: StateFlow<S> = _state.asStateFlow()

protected val scope: AppCoroutineScope = AppCoroutineScopeImpl(
scope = viewModelScope,
appDispatcher = appDispatcher
)
protected val scope: AppCoroutineScope = AppCoroutineScopeImpl(viewModelScope)

private var _lastAction: A? = null
protected val lastAction: A?
Expand All @@ -57,7 +54,7 @@ abstract class BaseStore<S : State, A : Action, E : Event>(
onError: suspend (cause: Throwable) -> Unit = {},
) = CoroutineExceptionHandler { _, throwable ->
Logger.e(throwable)
viewModelScope.launch(appDispatcher.default + coroutineExceptionHandler) {
viewModelScope.launch(coroutineExceptionHandler) {
onError(throwable)
}
}
Expand All @@ -76,9 +73,7 @@ abstract class BaseStore<S : State, A : Action, E : Event>(
* @see AppDispatcher
* */
protected fun sendEvent(event: E) {
viewModelScope.launch(appDispatcher.default) {
this@BaseStore._event.emit(event)
}
viewModelScope.launch { _event.emit(event) }
}

/**
Expand All @@ -93,9 +88,13 @@ abstract class BaseStore<S : State, A : Action, E : Event>(
protected fun <T> launch(
onError: suspend (Throwable) -> Unit = {},
onSuccess: suspend CoroutineScope.(T) -> Unit = {},
workDispatcher: CoroutineDispatcher = AppDispatcherImpl.default,
eachDispatcher: CoroutineDispatcher = AppDispatcherImpl.main.immediate,
action: suspend CoroutineScope.() -> T,
): Job = scope.launch(
onError = onError,
workDispatcher = workDispatcher,
eachDispatcher = eachDispatcher,
onSuccess = onSuccess,
action = action
)
Expand All @@ -111,9 +110,13 @@ abstract class BaseStore<S : State, A : Action, E : Event>(
* */
protected fun <T> Flow<T>.launch(
onError: suspend (cause: Throwable) -> Unit = {},
workDispatcher: CoroutineDispatcher = AppDispatcherImpl.default,
eachDispatcher: CoroutineDispatcher = AppDispatcherImpl.main.immediate,
each: suspend (T) -> Unit
): Job = scope.launch(
flow = this,
workDispatcher = workDispatcher,
eachDispatcher = eachDispatcher,
onError = onError,
each = each,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@ class PagingWorkerFactoryImpl : PagingWorkerFactory {
delay: Long,
defaultLoadSize: Int,
queryLoadSize: Int
): PagingWorker {
return PagingWorkerImpl(
scope = scope,
delay = delay,
defaultLoadSize = defaultLoadSize,
queryLoadSize = queryLoadSize
)
}
): PagingWorker = PagingWorkerImpl(
scope = scope,
delay = delay,
defaultLoadSize = defaultLoadSize,
queryLoadSize = queryLoadSize
)
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.stslex.wizard.feature.auth.ui.store

import com.stslex.wizard.core.core.AppDispatcher
import com.stslex.wizard.core.ui.mvi.BaseStore
import com.stslex.wizard.core.ui.mvi.CommonEvents.Snackbar
import com.stslex.wizard.feature.auth.domain.AuthInteractor
Expand All @@ -14,12 +13,8 @@ import kotlinx.coroutines.delay

class AuthStoreImpl(
private val interactor: AuthInteractor,
dispatcher: AppDispatcher,
private val router: AuthRouter
) : BaseStore<State, Action, Event>(
appDispatcher = dispatcher,
initialState = State.INITIAL,
), AuthStore {
) : BaseStore<State, Action, Event>(State.INITIAL), AuthStore {

override fun process(action: Action) {
when (action) {
Expand Down Expand Up @@ -156,7 +151,7 @@ class AuthStoreImpl(
authFieldsState = AuthFieldsState.AUTH
)
}
process(Action.Navigation.HomeFeature)
sendAction(Action.Navigation.HomeFeature)
})
}

Expand Down
Loading

0 comments on commit 7ee67ac

Please sign in to comment.