Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions app/src/main/java/com/yapp/app/official/YappOfficialApplication.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.yapp.app.official

import android.app.Application
import android.content.Context
import android.content.res.Configuration
import dagger.hilt.android.HiltAndroidApp
import timber.log.Timber

Expand All @@ -14,4 +16,12 @@ class YappOfficialApplication : Application() {
Timber.plant(Timber.DebugTree())
}
}

// 앱 기본 폰트 크기를 1.0f로 고정합니다.
override fun attachBaseContext(base: Context?) {
val configuration = Configuration(base?.resources?.configuration)
configuration.fontScale = 1.0f
val context = base?.createConfigurationContext(configuration)
super.attachBaseContext(context)
}
}
3 changes: 2 additions & 1 deletion app/src/main/java/com/yapp/app/official/ui/Navigator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.yapp.feature.home.navigation.navigateToHome
import com.yapp.feature.login.navigation.LoginRoute
import com.yapp.feature.login.navigation.navigateToLogin
import com.yapp.feature.notice.navigation.navigateToNotice
import com.yapp.feature.signup.navigation.SignUpRoute
import com.yapp.feature.signup.navigation.navigateToSignUp


Expand All @@ -31,7 +32,7 @@ class NavigatorState(
@Composable get() = navController
.currentBackStackEntryAsState().value?.destination

val startDestination = HomeRoute
val startDestination = SignUpRoute

fun navigateLoginScreen() {
navController.navigateToLogin()
Expand Down
17 changes: 0 additions & 17 deletions app/src/test/java/com/yapp/official/ExampleUnitTest.kt

This file was deleted.

1 change: 1 addition & 0 deletions core/data-api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ plugins {

dependencies {
implementation(project(":core:model"))
implementation(libs.kotlinx.coroutines.core)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.yapp.dataapi

import kotlinx.coroutines.flow.Flow

interface ConfigRepository {
fun getPositionConfigs(): Flow<List<String>>
}
17 changes: 17 additions & 0 deletions core/data/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import com.yapp.app.setNamespace
import org.gradle.internal.extensions.stdlib.capitalized
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
id("yapp.android.library")
Expand All @@ -20,6 +22,21 @@ protobuf {
register("java") {
option("lite")
}
register("kotlin") {
option("lite")
}
}
}
}
}

// https://stackoverflow.com/questions/78634960/ksp-error-when-upgrading-android-project-to-compose-compiler-2-0-0
androidComponents {
onVariants(selector().all()) { variant ->
afterEvaluate {
val capName = variant.name.capitalized()
tasks.getByName<KotlinCompile>("ksp${capName}Kotlin") {
setSource(tasks.getByName("generate${capName}Proto").outputs)
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions core/data/src/main/java/com/yapp/core/data/data/YappDispatcher.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.yapp.core.data.data

import javax.inject.Qualifier

@Qualifier
annotation class Dispatcher(val yappDispatcher: YappDispatchers)

enum class YappDispatchers {
IO,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.yapp.core.data.data.di

import com.yapp.core.data.data.Dispatcher
import com.yapp.core.data.data.YappDispatchers
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers

@Module
@InstallIn(SingletonComponent::class)
object DispatchersModule {
@Provides
@Dispatcher(YappDispatchers.IO)
fun providesIODispatcher(): CoroutineDispatcher = Dispatchers.IO
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.yapp.core.data.data.di

import com.yapp.core.data.data.repository.AuthorizedUserRepositoryImpl
import com.yapp.core.data.data.repository.ConfigRepositoryImpl
import com.yapp.core.data.data.repository.UnAuthorizedUserRepositoryImpl
import com.yapp.dataapi.AuthorizedUserRepository
import com.yapp.dataapi.ConfigRepository
import com.yapp.dataapi.UnAuthorizedUserRepository
import dagger.Binds
import dagger.Module
Expand All @@ -22,4 +24,9 @@ internal abstract class RepositoryModule {
abstract fun bindAuthorizedUserRepositoryImpl(
repositoryImpl: AuthorizedUserRepositoryImpl,
): AuthorizedUserRepository

@Binds
abstract fun bindConfigRepositoryImpl(
repositoryImpl: ConfigRepositoryImpl,
): ConfigRepository
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.yapp.core.data.data.repository

import androidx.datastore.core.DataStore
import com.yapp.core.data.PositionConfigs
import com.yapp.core.data.data.Dispatcher
import com.yapp.core.data.data.YappDispatchers
import com.yapp.core.data.remote.api.ConfigApi
import com.yapp.core.data.remote.model.response.PositionConfigResponse
import com.yapp.dataapi.ConfigRepository
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import javax.inject.Inject

internal class ConfigRepositoryImpl @Inject constructor(
private val configApi: ConfigApi,
private val dataStore: DataStore<PositionConfigs>,
@Dispatcher(YappDispatchers.IO) private val ioDispatcher: CoroutineDispatcher,
) : ConfigRepository {

override fun getPositionConfigs(): Flow<List<String>> = flow {
val localPositionConfigs = dataStore.data.firstOrNull()
if (localPositionConfigs != null) {
emit(localPositionConfigs.configsList.map { it.label })
}

val remotePositionConfigs = configApi.getPositionConfigs()
emit(remotePositionConfigs.positions.map { it.label })

updatePositionConfigs(remotePositionConfigs)
}.flowOn(ioDispatcher)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dispatcher 주입하니까 너무 깔끔하네요.. 굳...


private suspend fun updatePositionConfigs(positionConfigs: PositionConfigResponse) {
dataStore.updateData { currentData ->
currentData.toBuilder()
.clearConfigs()
.addAllConfigs(positionConfigs.toProto())
.build()
}
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
package com.yapp.core.data.data.repository

import androidx.datastore.core.DataStore
import com.yapp.core.data.PositionConfigs
import com.yapp.core.data.local.SecurityPreferences
import com.yapp.core.data.remote.api.UnAuthorizedUserApi
import com.yapp.core.data.remote.model.request.toData
import com.yapp.core.data.remote.model.response.toModel
import com.yapp.dataapi.UnAuthorizedUserRepository
import com.yapp.model.SignUpInfo
import com.yapp.model.SignUpResult
import kotlinx.coroutines.flow.firstOrNull
import javax.inject.Inject
import kotlin.jvm.optionals.getOrNull

internal class UnAuthorizedUserRepositoryImpl @Inject constructor(
private val api: UnAuthorizedUserApi,
private val securityPreferences: SecurityPreferences,
private val dataStore: DataStore<PositionConfigs>,
): UnAuthorizedUserRepository {

override suspend fun signUp(request: SignUpInfo): SignUpResult {
val positionConfigs = dataStore.data.firstOrNull() ?: PositionConfigs.getDefaultInstance()

val response = api.signUp(
request.toData()
request.toData(positionConfigs)
)

response.getOrNull()?.let {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package com.yapp.core.data.local
package com.yapp.core.data.local.di

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.core.DataStoreFactory
import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler
import androidx.datastore.dataStoreFile
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.emptyPreferences
import androidx.datastore.preferences.preferencesDataStoreFile
import com.yapp.core.data.PositionConfigs
import com.yapp.core.data.local.proto.PositionConfigSerializer
import com.yapp.core.data.local.SecurityPreferences
import com.yapp.core.data.local.generateSecurityPreferences
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
Expand All @@ -31,6 +37,18 @@ internal object DataStoreModule {
)
}

@Provides
@Singleton
fun providesPositionConfigPreferencesDataStore(
@ApplicationContext context: Context,
serializer: PositionConfigSerializer,
): DataStore<PositionConfigs> =
DataStoreFactory.create(
serializer = serializer,
) {
context.dataStoreFile(POSITION_CONFIG_NAME)
}

@EncryptedDataStore
@Singleton
@Provides
Expand All @@ -51,6 +69,7 @@ internal object DataStoreModule {

private const val DATASTORE_NAME = "yapp-datastore"
private const val ENCRYPTED_DATASTORE_NAME = "yapp-datastore-encrypted"
private const val POSITION_CONFIG_NAME = "position_config.pb"
}

@Qualifier
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.yapp.core.data.local.proto

import androidx.datastore.core.CorruptionException
import androidx.datastore.core.Serializer
import com.google.protobuf.InvalidProtocolBufferException
import com.yapp.core.data.PositionConfigs
import java.io.InputStream
import java.io.OutputStream
import javax.inject.Inject

class PositionConfigSerializer @Inject constructor() : Serializer<PositionConfigs> {
override val defaultValue: PositionConfigs = PositionConfigs.getDefaultInstance()

override suspend fun readFrom(input: InputStream): PositionConfigs {
return try {
PositionConfigs.parseFrom(input)
} catch (e: InvalidProtocolBufferException) {
throw CorruptionException("Cannot read proto.", e)
}
}

override suspend fun writeTo(t: PositionConfigs, output: OutputStream) {
t.writeTo(output)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.yapp.core.data.remote.api

import com.yapp.core.data.remote.model.response.PositionConfigResponse
import retrofit2.http.GET

internal interface ConfigApi {
@GET("v1/positions")
suspend fun getPositionConfigs(): PositionConfigResponse
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import retrofit2.http.Body
import retrofit2.http.POST
import java.util.Optional

interface UnAuthorizedUserApi {
internal interface UnAuthorizedUserApi {
@POST("v1/auth/sign-up")
suspend fun signUp(
@Body request: SignUpRequest,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.yapp.core.data.remote.di

import com.yapp.core.data.remote.api.ConfigApi
import com.yapp.core.data.remote.api.UnAuthorizedUserApi
import dagger.Module
import dagger.Provides
Expand All @@ -10,11 +11,17 @@ import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object ApiServiceModule {
internal object ApiModule {

@Singleton
@Provides
fun provideUnAuthorizedUserApi(retrofit: Retrofit): UnAuthorizedUserApi {
return retrofit.create(UnAuthorizedUserApi::class.java)
}

@Singleton
@Provides
fun provideConfigApi(retrofit: Retrofit): ConfigApi {
return retrofit.create(ConfigApi::class.java)
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package com.yapp.core.data.remote.model.request

import com.yapp.core.data.PositionConfigs
import com.yapp.model.SignUpInfo
import kotlinx.serialization.Serializable

@Serializable
data class SignUpRequest(
internal data class SignUpRequest(
val email: String,
val password: String,
val name: String,
Expand All @@ -13,20 +14,20 @@ data class SignUpRequest(
)

@Serializable
data class ActivityUnit(
internal data class ActivityUnit(
val generation: Int,
val position: String
)

fun SignUpInfo.toData() = SignUpRequest(
internal fun SignUpInfo.toData(positionConfigs: PositionConfigs) = SignUpRequest(
email = email.trim(),
password = password.trim(),
name = name.trim(),
activityUnits = activityUnits.map { it.toData() },
activityUnits = activityUnits.map { it.toData(positionConfigs) },
signUpCode = signUpCode.trim()
)

fun com.yapp.model.ActivityUnit.toData() = ActivityUnit(
internal fun com.yapp.model.ActivityUnit.toData(positionConfigs: PositionConfigs) = ActivityUnit(
generation = generation ?: throw IllegalArgumentException("Generation must not be null"),
position = position ?: throw IllegalArgumentException("Position must not be null"),
position = positionConfigs.configsList.find { it.label == position }?.name ?: throw IllegalArgumentException("Invalid position: must not be null or undefined"),
)
Loading