Skip to content

Commit

Permalink
Issues #287 feat: data-preference 분리
Browse files Browse the repository at this point in the history
  • Loading branch information
audxo112 committed Feb 9, 2023
1 parent a8033a8 commit 397c72b
Show file tree
Hide file tree
Showing 15 changed files with 419 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.lighthouse.common.di

import com.google.firebase.auth.FirebaseAuth
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@Suppress("unused")
@Module
@InstallIn(SingletonComponent::class)
internal object AuthModule {
@Provides
@Singleton
fun provideFirebaseAuth(): FirebaseAuth = FirebaseAuth.getInstance()
}
1 change: 1 addition & 0 deletions data/data-preference/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
24 changes: 24 additions & 0 deletions data/data-preference/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
@Suppress("DSL_SCOPE_VIOLATION")
plugins {
id("beep.android.library")
id("beep.android.hilt")
alias(libs.plugins.ksp)
}

android {
namespace = "com.lighthouse.data.preference"
}

dependencies {
implementation(projects.core)
implementation(projects.coreAndroid)
implementation(projects.model)
implementation(projects.common)
implementation(projects.commonAndroid)
implementation(projects.commonLocation)
implementation(projects.commonRecognizer)
implementation(projects.data)

implementation(libs.androidX.datastore.preferences)
implementation(libs.javax.inject)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.lighthouse.data.preference.di

import com.lighthouse.data.preference.repository.UserPreferenceRepositoryImpl
import com.lighthouse.repository.user.UserPreferenceRepository
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent

@Suppress("unused")
@Module
@InstallIn(SingletonComponent::class)
internal abstract class DataModule {

@Binds
abstract fun bindsUserPreferenceRepository(
repository: UserPreferenceRepositoryImpl
): UserPreferenceRepository
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.lighthouse.data.preference.di

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.preferencesDataStoreFile
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@Suppress("unused")
@Module
@InstallIn(SingletonComponent::class)
internal object PreferenceModule {

private const val USER_PREFERENCES = "user_preferences"

@Singleton
@Provides
fun providePreferencesDataStore(@ApplicationContext context: Context): DataStore<Preferences> {
return PreferenceDataStoreFactory.create(
produceFile = { context.preferencesDataStoreFile(USER_PREFERENCES) }
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.lighthouse.data.preference.exception

internal class PrefNotFoundException(message: String = "데이터를 찾을 수 없습니다.") : Exception(message)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.lighthouse.data.preference.ext

import com.lighthouse.beep.model.exception.common.NotFoundException
import com.lighthouse.data.preference.exception.PrefNotFoundException

internal inline fun <T, R> T.runCatchingPref(block: T.() -> R): Result<R> {
return try {
Result.success(block())
} catch (e: PrefNotFoundException) {
Result.failure(NotFoundException(e.message))
} catch (e: Throwable) {
Result.failure(e)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
@file:Suppress("unused")

package com.lighthouse.data.preference.ext

import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.byteArrayPreferencesKey
import androidx.datastore.preferences.core.doublePreferencesKey
import androidx.datastore.preferences.core.floatPreferencesKey
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.longPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.core.stringSetPreferencesKey

private fun createKey(userId: String, key: String): String {
return "${userId}_$key"
}

internal fun intKey(userId: String, key: String): Preferences.Key<Int> {
return intPreferencesKey(createKey(userId, key))
}

internal fun doubleKey(userId: String, key: String): Preferences.Key<Double> {
return doublePreferencesKey(createKey(userId, key))
}

internal fun stringKey(userId: String, key: String): Preferences.Key<String> {
return stringPreferencesKey(createKey(userId, key))
}

internal fun booleanKey(userId: String, key: String): Preferences.Key<Boolean> {
return booleanPreferencesKey(createKey(userId, key))
}

internal fun floatKey(userId: String, key: String): Preferences.Key<Float> {
return floatPreferencesKey(createKey(userId, key))
}

internal fun longKey(userId: String, key: String): Preferences.Key<Long> {
return longPreferencesKey(createKey(userId, key))
}

internal fun stringSetKey(userId: String, key: String): Preferences.Key<Set<String>> {
return stringSetPreferencesKey(createKey(userId, key))
}

internal fun byteArrayKey(userId: String, key: String): Preferences.Key<ByteArray> {
return byteArrayPreferencesKey(createKey(userId, key))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package com.lighthouse.data.preference.repository

import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import com.lighthouse.beep.model.user.SecurityOption
import com.lighthouse.data.preference.exception.PrefNotFoundException
import com.lighthouse.data.preference.ext.booleanKey
import com.lighthouse.data.preference.ext.byteArrayKey
import com.lighthouse.data.preference.ext.runCatchingPref
import com.lighthouse.data.preference.ext.stringKey
import com.lighthouse.repository.user.UserPreferenceRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import javax.inject.Inject

internal class UserPreferenceRepositoryImpl @Inject constructor(
private val dataStore: DataStore<Preferences>
) : UserPreferenceRepository {

override suspend fun getIV(userId: String): Result<ByteArray?> = runCatchingPref {
val key = byteArrayKey(userId, KEY_NAME_IV)
dataStore.data.first()[key]
}

override suspend fun setIV(
userId: String,
iv: ByteArray
): Result<Unit> = runCatchingPref {
val key = byteArrayKey(userId, KEY_NAME_IV)
dataStore.edit { pref ->
pref[key] = iv
}
}

override suspend fun setPinPassword(
userId: String,
pinPassword: ByteArray
): Result<Unit> = runCatchingPref {
val key = byteArrayKey(userId, KEY_NAME_PIN_PASSWORD)
dataStore.edit { pref ->
pref[key] = pinPassword
}
}

override suspend fun confirmPinPassword(
userId: String,
pinPassword: ByteArray
): Result<Boolean> = runCatchingPref {
val key = byteArrayKey(userId, KEY_NAME_PIN_PASSWORD)
val savedPinPassword = dataStore.data.first()[key]
savedPinPassword.contentEquals(pinPassword)
}

override suspend fun setSecurityOption(
userId: String,
securityOption: SecurityOption
): Result<Unit> = runCatchingPref {
val key = stringKey(userId, KEY_NAME_SECURITY_OPTION)
dataStore.edit { pref ->
pref[key] = securityOption.name
}
}

override fun getSecurityOption(
userId: String
): Result<Flow<SecurityOption>> = runCatchingPref {
val key = stringKey(userId, KEY_NAME_SECURITY_OPTION)
dataStore.data.map { pref ->
val value = pref[key] ?: throw PrefNotFoundException("Security 값이 없습니다.")
SecurityOption.valueOf(value)
}
}

override suspend fun setNotificationEnable(
userId: String,
enable: Boolean
): Result<Unit> = runCatchingPref {
val key = booleanKey(userId, KEY_NAME_NOTIFICATION_ENABLE)
dataStore.edit { pref ->
pref[key] = enable
}
}

override fun getNotificationEnable(
userId: String
): Result<Flow<Boolean>> = runCatchingPref {
val key = booleanKey(userId, KEY_NAME_NOTIFICATION_ENABLE)
dataStore.data.map { pref ->
pref[key] ?: throw PrefNotFoundException("Notification Enable 값이 없습니다.")
}
}

override suspend fun transferData(
oldUserId: String,
newUserId: String
): Result<Unit> = runCatchingPref {
val data = dataStore.data.first()
val iv = data[byteArrayKey(oldUserId, KEY_NAME_IV)]
val pin = data[byteArrayKey(oldUserId, KEY_NAME_PIN_PASSWORD)]
val securityOption = data[stringKey(oldUserId, KEY_NAME_SECURITY_OPTION)]?.let {
SecurityOption.valueOf(it)
} ?: throw PrefNotFoundException("Security 값이 없습니다.")
val notificationEnable = data[booleanKey(oldUserId, KEY_NAME_NOTIFICATION_ENABLE)]

dataStore.edit { pref ->
if (iv != null) {
pref[byteArrayKey(newUserId, KEY_NAME_IV)] = iv
}
if (pin != null) {
pref[byteArrayKey(newUserId, KEY_NAME_PIN_PASSWORD)] = pin
}
pref[stringKey(newUserId, KEY_NAME_SECURITY_OPTION)] = securityOption.name
pref[booleanKey(newUserId, KEY_NAME_NOTIFICATION_ENABLE)] = notificationEnable ?: false
}

clearData(oldUserId)
}

override suspend fun clearData(userId: String): Result<Unit> = runCatchingPref {
dataStore.edit { pref ->
pref.remove(byteArrayKey(userId, KEY_NAME_IV))
pref.remove(byteArrayKey(userId, KEY_NAME_PIN_PASSWORD))
pref.remove(byteArrayKey(userId, KEY_NAME_SECURITY_OPTION))
pref.remove(byteArrayKey(userId, KEY_NAME_NOTIFICATION_ENABLE))
}
}

companion object {
private const val KEY_NAME_PIN_PASSWORD = "PinPassword"
private const val KEY_NAME_IV = "IV"
private const val KEY_NAME_SECURITY_OPTION = "SecurityOption"
private const val KEY_NAME_NOTIFICATION_ENABLE = "NotificationEnable"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.lighthouse.repository.user

import kotlinx.coroutines.flow.Flow
import javax.crypto.spec.IvParameterSpec

interface AuthRepository {

fun isGuest(): Flow<Boolean>

fun getCurrentUserId(): String

fun encrypt(pin: String, iv: IvParameterSpec)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.lighthouse.repository.user

import com.lighthouse.beep.model.user.SecurityOption
import kotlinx.coroutines.flow.Flow

interface UserPreferenceRepository {

suspend fun getIV(userId: String): Result<ByteArray?>

suspend fun setIV(userId: String, iv: ByteArray): Result<Unit>

suspend fun setPinPassword(
userId: String,
pinPassword: ByteArray
): Result<Unit>

suspend fun confirmPinPassword(
userId: String,
pinPassword: ByteArray
): Result<Boolean>

suspend fun setSecurityOption(
userId: String,
securityOption: SecurityOption
): Result<Unit>

fun getSecurityOption(userId: String): Result<Flow<SecurityOption>>

suspend fun setNotificationEnable(
userId: String,
enable: Boolean
): Result<Unit>

fun getNotificationEnable(userId: String): Result<Flow<Boolean>>

suspend fun transferData(
oldUserId: String,
newUserId: String
): Result<Unit>

suspend fun clearData(userId: String): Result<Unit>
}
Loading

0 comments on commit 397c72b

Please sign in to comment.