From ad64de72067ea028c4627d5e0fd128a0b484ecd3 Mon Sep 17 00:00:00 2001 From: Reactor Scram Date: Wed, 31 Jul 2024 11:04:19 -0500 Subject: [PATCH] refactor(client/kotlin): remove interface layer that seemed redundant (#6102) I'm opening PRs for small refactors around the code I'm changing for adding the Favorites menu. Just anything where I read it and, as a Kotlin noobie, took longer than expected to understand --- .../firezone/android/core/data/Repository.kt | 175 +++++++++++++++--- .../android/core/data/RepositoryImpl.kt | 174 ----------------- .../firezone/android/core/di/DataModule.kt | 3 +- .../android/features/auth/ui/AuthViewModel.kt | 2 +- 4 files changed, 147 insertions(+), 207 deletions(-) delete mode 100644 kotlin/android/app/src/main/java/dev/firezone/android/core/data/RepositoryImpl.kt diff --git a/kotlin/android/app/src/main/java/dev/firezone/android/core/data/Repository.kt b/kotlin/android/app/src/main/java/dev/firezone/android/core/data/Repository.kt index 4be1276f2..99ea8aafa 100644 --- a/kotlin/android/app/src/main/java/dev/firezone/android/core/data/Repository.kt +++ b/kotlin/android/app/src/main/java/dev/firezone/android/core/data/Repository.kt @@ -1,59 +1,174 @@ /* Licensed under Apache 2.0 (C) 2024 Firezone, Inc. */ package dev.firezone.android.core.data +import android.content.Context +import android.content.SharedPreferences +import dev.firezone.android.BuildConfig import dev.firezone.android.core.data.model.Config +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOn +import java.security.MessageDigest +import javax.inject.Inject -interface Repository { - fun getConfigSync(): Config +internal class Repository + @Inject + constructor( + private val context: Context, + private val coroutineDispatcher: CoroutineDispatcher, + private val sharedPreferences: SharedPreferences, + ) { + fun getConfigSync(): Config { + return Config( + sharedPreferences.getString(AUTH_BASE_URL_KEY, null) + ?: BuildConfig.AUTH_BASE_URL, + sharedPreferences.getString(API_URL_KEY, null) + ?: BuildConfig.API_URL, + sharedPreferences.getString(LOG_FILTER_KEY, null) + ?: BuildConfig.LOG_FILTER, + ) + } - fun getConfig(): Flow + fun getConfig(): Flow = + flow { + emit(getConfigSync()) + }.flowOn(coroutineDispatcher) - fun getDefaultConfigSync(): Config + fun getDefaultConfigSync(): Config = + Config( + BuildConfig.AUTH_BASE_URL, + BuildConfig.API_URL, + BuildConfig.LOG_FILTER, + ) - fun getDefaultConfig(): Flow + fun getDefaultConfig(): Flow = + flow { + emit(getDefaultConfigSync()) + }.flowOn(coroutineDispatcher) - fun saveSettings( - authBaseUrl: String, - apiUrl: String, - logFilter: String, - ): Flow + fun saveSettings( + authBaseUrl: String, + apiUrl: String, + logFilter: String, + ): Flow = + flow { + emit( + sharedPreferences + .edit() + .putString(AUTH_BASE_URL_KEY, authBaseUrl) + .putString(API_URL_KEY, apiUrl) + .putString(LOG_FILTER_KEY, logFilter) + .apply(), + ) + }.flowOn(coroutineDispatcher) - fun saveDeviceIdSync(value: String): Unit + fun getDeviceIdSync(): String? = sharedPreferences.getString(DEVICE_ID_KEY, null) - fun getToken(): Flow + fun getToken(): Flow = + flow { + emit(sharedPreferences.getString(TOKEN_KEY, null)) + }.flowOn(coroutineDispatcher) - fun getTokenSync(): String? + fun getTokenSync(): String? = sharedPreferences.getString(TOKEN_KEY, null) - fun getStateSync(): String? + fun getStateSync(): String? = sharedPreferences.getString(STATE_KEY, null) - fun getNonceSync(): String? + fun getActorName(): Flow = + flow { + emit(getActorNameSync()) + }.flowOn(coroutineDispatcher) - fun getDeviceIdSync(): String? + fun getActorNameSync(): String? = + sharedPreferences.getString(ACTOR_NAME_KEY, null)?.let { + if (it.isNotEmpty()) "Signed in as $it" else "Signed in" + } - fun getActorName(): Flow + fun getNonceSync(): String? = sharedPreferences.getString(NONCE_KEY, null) - fun getActorNameSync(): String? + fun saveDeviceIdSync(value: String): Unit = + sharedPreferences + .edit() + .putString(DEVICE_ID_KEY, value) + .apply() - fun saveNonce(value: String): Flow + fun saveNonce(value: String): Flow = + flow { + emit(saveNonceSync(value)) + }.flowOn(coroutineDispatcher) - fun saveState(value: String): Flow + fun saveNonceSync(value: String) = sharedPreferences.edit().putString(NONCE_KEY, value).apply() - fun saveStateSync(value: String): Unit + fun saveState(value: String): Flow = + flow { + emit(saveStateSync(value)) + }.flowOn(coroutineDispatcher) - fun saveNonceSync(value: String): Unit + fun saveStateSync(value: String) = sharedPreferences.edit().putString(STATE_KEY, value).apply() - fun saveToken(value: String): Flow + fun saveToken(value: String): Flow = + flow { + val nonce = sharedPreferences.getString(NONCE_KEY, "").orEmpty() + emit( + sharedPreferences + .edit() + .putString(TOKEN_KEY, nonce.plus(value)) + .apply(), + ) + }.flowOn(coroutineDispatcher) - fun saveActorName(value: String): Flow + fun saveActorName(value: String): Flow = + flow { + emit( + sharedPreferences + .edit() + .putString(ACTOR_NAME_KEY, value) + .apply(), + ) + }.flowOn(coroutineDispatcher) - fun validateState(value: String): Flow + fun validateState(value: String): Flow = + flow { + val state = sharedPreferences.getString(STATE_KEY, "").orEmpty() + emit(MessageDigest.isEqual(state.toByteArray(), value.toByteArray())) + }.flowOn(coroutineDispatcher) - fun clearToken() + fun clearToken() { + sharedPreferences.edit().apply { + remove(TOKEN_KEY) + apply() + } + } - fun clearNonce() + fun clearNonce() { + sharedPreferences.edit().apply { + remove(NONCE_KEY) + apply() + } + } - fun clearState() + fun clearState() { + sharedPreferences.edit().apply { + remove(STATE_KEY) + apply() + } + } - fun clearActorName() -} + fun clearActorName() { + sharedPreferences.edit().apply { + remove(ACTOR_NAME_KEY) + apply() + } + } + + companion object { + private const val AUTH_BASE_URL_KEY = "authBaseUrl" + private const val ACTOR_NAME_KEY = "actorName" + private const val API_URL_KEY = "apiUrl" + private const val LOG_FILTER_KEY = "logFilter" + private const val TOKEN_KEY = "token" + private const val NONCE_KEY = "nonce" + private const val STATE_KEY = "state" + private const val DEVICE_ID_KEY = "deviceId" + } + } diff --git a/kotlin/android/app/src/main/java/dev/firezone/android/core/data/RepositoryImpl.kt b/kotlin/android/app/src/main/java/dev/firezone/android/core/data/RepositoryImpl.kt deleted file mode 100644 index d1d908d56..000000000 --- a/kotlin/android/app/src/main/java/dev/firezone/android/core/data/RepositoryImpl.kt +++ /dev/null @@ -1,174 +0,0 @@ -/* Licensed under Apache 2.0 (C) 2024 Firezone, Inc. */ -package dev.firezone.android.core.data - -import android.content.Context -import android.content.SharedPreferences -import dev.firezone.android.BuildConfig -import dev.firezone.android.core.data.model.Config -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.flow.flowOn -import java.security.MessageDigest -import javax.inject.Inject - -internal class RepositoryImpl - @Inject - constructor( - private val context: Context, - private val coroutineDispatcher: CoroutineDispatcher, - private val sharedPreferences: SharedPreferences, - ) : Repository { - override fun getConfigSync(): Config { - return Config( - sharedPreferences.getString(AUTH_BASE_URL_KEY, null) - ?: BuildConfig.AUTH_BASE_URL, - sharedPreferences.getString(API_URL_KEY, null) - ?: BuildConfig.API_URL, - sharedPreferences.getString(LOG_FILTER_KEY, null) - ?: BuildConfig.LOG_FILTER, - ) - } - - override fun getConfig(): Flow = - flow { - emit(getConfigSync()) - }.flowOn(coroutineDispatcher) - - override fun getDefaultConfigSync(): Config = - Config( - BuildConfig.AUTH_BASE_URL, - BuildConfig.API_URL, - BuildConfig.LOG_FILTER, - ) - - override fun getDefaultConfig(): Flow = - flow { - emit(getDefaultConfigSync()) - }.flowOn(coroutineDispatcher) - - override fun saveSettings( - authBaseUrl: String, - apiUrl: String, - logFilter: String, - ): Flow = - flow { - emit( - sharedPreferences - .edit() - .putString(AUTH_BASE_URL_KEY, authBaseUrl) - .putString(API_URL_KEY, apiUrl) - .putString(LOG_FILTER_KEY, logFilter) - .apply(), - ) - }.flowOn(coroutineDispatcher) - - override fun getDeviceIdSync(): String? = sharedPreferences.getString(DEVICE_ID_KEY, null) - - override fun getToken(): Flow = - flow { - emit(sharedPreferences.getString(TOKEN_KEY, null)) - }.flowOn(coroutineDispatcher) - - override fun getTokenSync(): String? = sharedPreferences.getString(TOKEN_KEY, null) - - override fun getStateSync(): String? = sharedPreferences.getString(STATE_KEY, null) - - override fun getActorName(): Flow = - flow { - emit(getActorNameSync()) - }.flowOn(coroutineDispatcher) - - override fun getActorNameSync(): String? = - sharedPreferences.getString(ACTOR_NAME_KEY, null)?.let { - if (it.isNotEmpty()) "Signed in as $it" else "Signed in" - } - - override fun getNonceSync(): String? = sharedPreferences.getString(NONCE_KEY, null) - - override fun saveDeviceIdSync(value: String): Unit = - sharedPreferences - .edit() - .putString(DEVICE_ID_KEY, value) - .apply() - - override fun saveNonce(value: String): Flow = - flow { - emit(saveNonceSync(value)) - }.flowOn(coroutineDispatcher) - - override fun saveNonceSync(value: String) = sharedPreferences.edit().putString(NONCE_KEY, value).apply() - - override fun saveState(value: String): Flow = - flow { - emit(saveStateSync(value)) - }.flowOn(coroutineDispatcher) - - override fun saveStateSync(value: String) = sharedPreferences.edit().putString(STATE_KEY, value).apply() - - override fun saveToken(value: String): Flow = - flow { - val nonce = sharedPreferences.getString(NONCE_KEY, "").orEmpty() - emit( - sharedPreferences - .edit() - .putString(TOKEN_KEY, nonce.plus(value)) - .apply(), - ) - }.flowOn(coroutineDispatcher) - - override fun saveActorName(value: String): Flow = - flow { - emit( - sharedPreferences - .edit() - .putString(ACTOR_NAME_KEY, value) - .apply(), - ) - }.flowOn(coroutineDispatcher) - - override fun validateState(value: String): Flow = - flow { - val state = sharedPreferences.getString(STATE_KEY, "").orEmpty() - emit(MessageDigest.isEqual(state.toByteArray(), value.toByteArray())) - }.flowOn(coroutineDispatcher) - - override fun clearToken() { - sharedPreferences.edit().apply { - remove(TOKEN_KEY) - apply() - } - } - - override fun clearNonce() { - sharedPreferences.edit().apply { - remove(NONCE_KEY) - apply() - } - } - - override fun clearState() { - sharedPreferences.edit().apply { - remove(STATE_KEY) - apply() - } - } - - override fun clearActorName() { - sharedPreferences.edit().apply { - remove(ACTOR_NAME_KEY) - apply() - } - } - - companion object { - private const val AUTH_BASE_URL_KEY = "authBaseUrl" - private const val ACTOR_NAME_KEY = "actorName" - private const val API_URL_KEY = "apiUrl" - private const val LOG_FILTER_KEY = "logFilter" - private const val TOKEN_KEY = "token" - private const val NONCE_KEY = "nonce" - private const val STATE_KEY = "state" - private const val DEVICE_ID_KEY = "deviceId" - } - } diff --git a/kotlin/android/app/src/main/java/dev/firezone/android/core/di/DataModule.kt b/kotlin/android/app/src/main/java/dev/firezone/android/core/di/DataModule.kt index 8bfa60850..d7317d8c9 100644 --- a/kotlin/android/app/src/main/java/dev/firezone/android/core/di/DataModule.kt +++ b/kotlin/android/app/src/main/java/dev/firezone/android/core/di/DataModule.kt @@ -11,7 +11,6 @@ import dagger.hilt.InstallIn import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent import dev.firezone.android.core.data.Repository -import dev.firezone.android.core.data.RepositoryImpl import kotlinx.coroutines.CoroutineDispatcher @Module @@ -28,7 +27,7 @@ class DataModule { @IoDispatcher coroutineDispatcher: CoroutineDispatcher, sharedPreferences: SharedPreferences, ): Repository = - RepositoryImpl( + Repository( context, coroutineDispatcher, sharedPreferences, diff --git a/kotlin/android/app/src/main/java/dev/firezone/android/features/auth/ui/AuthViewModel.kt b/kotlin/android/app/src/main/java/dev/firezone/android/features/auth/ui/AuthViewModel.kt index 2bf71fe0d..6576c6fd1 100644 --- a/kotlin/android/app/src/main/java/dev/firezone/android/features/auth/ui/AuthViewModel.kt +++ b/kotlin/android/app/src/main/java/dev/firezone/android/features/auth/ui/AuthViewModel.kt @@ -28,7 +28,7 @@ internal class AuthViewModel val nonce = generateRandomString(NONCE_LENGTH) repo.saveNonceSync(nonce) repo.saveStateSync(state) - val config = repo.getConfigSync()!! + val config = repo.getConfigSync() val token = repo.getTokenSync() actionMutableLiveData.postValue(