Skip to content

Commit 45d8094

Browse files
authored
Merge pull request #87 from everymeals/feature/univ_save
[feature/univ_save] 대학 정보 저장 및 불러오기 구현
2 parents b38640b + 1dc2526 commit 45d8094

File tree

27 files changed

+298
-23
lines changed

27 files changed

+298
-23
lines changed

app/build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,7 @@ dependencies {
9393
// Serialization
9494
implementation(libs.serialization)
9595
implementation(libs.kotlin.serilization)
96+
97+
//DataStore
98+
implementation(libs.data.store)
9699
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.everymeal.everymeal_android.di
2+
3+
import android.content.Context
4+
import androidx.datastore.core.DataStore
5+
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
6+
import androidx.datastore.preferences.core.Preferences
7+
import androidx.datastore.preferences.preferencesDataStoreFile
8+
import dagger.Module
9+
import dagger.Provides
10+
import dagger.hilt.InstallIn
11+
import dagger.hilt.android.qualifiers.ApplicationContext
12+
import dagger.hilt.components.SingletonComponent
13+
import javax.inject.Singleton
14+
15+
@Module
16+
@InstallIn(SingletonComponent::class)
17+
object DataBaseModule {
18+
19+
private const val DATASTORE_NAME = "everymeal_datastore"
20+
21+
@Singleton
22+
@Provides
23+
fun providePreferencesDataStore(@ApplicationContext context: Context): DataStore<Preferences> =
24+
PreferenceDataStoreFactory.create(
25+
produceFile = { context.preferencesDataStoreFile(DATASTORE_NAME) }
26+
)
27+
}

app/src/main/java/com/everymeal/everymeal_android/di/NetworkModule.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,4 @@ object NetworkModule {
5353
fun provideAuthApi(retrofit: Retrofit): AuthApi {
5454
return retrofit.create(AuthApi::class.java)
5555
}
56-
}
56+
}

app/src/main/java/com/everymeal/everymeal_android/di/RepositoryModule.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@ package com.everymeal.everymeal_android.di
22

33
import com.everymeal.data.datasource.auth.AuthRemoteDataSource
44
import com.everymeal.data.datasource.auth.AuthRemoteRemoteDataSourceImpl
5+
import com.everymeal.data.datasource.local.LocalDataSource
6+
import com.everymeal.data.datasource.local.LocalDataSourceImpl
57
import com.everymeal.data.datasource.onboarding.OnboardingDataSource
68
import com.everymeal.data.datasource.onboarding.OnboardingDataSourceImpl
9+
import com.everymeal.data.repository.local.LocalRepositoryImpl
710
import com.everymeal.data.repository.DefaultAuthRepository
811
import com.everymeal.data.repository.onboarding.OnboardingRepositoryImpl
12+
import com.everymeal.domain.repository.local.LocalRepository
913
import com.everymeal.domain.repository.auth.AuthRepository
1014
import com.everymeal.domain.repository.onboarding.OnboardingRepository
1115
import dagger.Binds
@@ -30,6 +34,18 @@ abstract class RepositoryModule {
3034
onboardingDataSourceImpl: OnboardingDataSourceImpl
3135
): OnboardingDataSource
3236

37+
@Singleton
38+
@Binds
39+
abstract fun bindLocalRepository(
40+
localRepositoryImpl: LocalRepositoryImpl
41+
): LocalRepository
42+
43+
@Singleton
44+
@Binds
45+
abstract fun bindLocalDataSource(
46+
localDataSourceImpl: LocalDataSourceImpl
47+
): LocalDataSource
48+
3349
@Singleton
3450
@Binds
3551
abstract fun bindAuthRemoteDataSource(

data/build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,7 @@ dependencies {
4141
// Serialization
4242
implementation(libs.serialization)
4343
implementation(libs.kotlin.serilization)
44+
45+
//DataStore
46+
implementation(libs.data.store)
4447
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.everymeal.data.datasource.local
2+
3+
import kotlinx.coroutines.flow.Flow
4+
5+
interface LocalDataSource {
6+
suspend fun saveUniversity(index : Int, univName : String)
7+
8+
suspend fun getUniversityIndex() : Flow<String>
9+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.everymeal.data.datasource.local
2+
3+
import androidx.datastore.core.DataStore
4+
import androidx.datastore.preferences.core.Preferences
5+
import androidx.datastore.preferences.core.edit
6+
import androidx.datastore.preferences.core.emptyPreferences
7+
import androidx.datastore.preferences.core.stringPreferencesKey
8+
import kotlinx.coroutines.flow.Flow
9+
import kotlinx.coroutines.flow.catch
10+
import kotlinx.coroutines.flow.map
11+
import java.io.IOException
12+
import javax.inject.Inject
13+
14+
object DataStoreKey {
15+
val UNIVERSITY_INDEX = stringPreferencesKey("univ_index")
16+
val UNIVERSITY_NAME = stringPreferencesKey("univ_name")
17+
}
18+
19+
class LocalDataSourceImpl @Inject constructor(
20+
private val dataStore: DataStore<Preferences>
21+
) : LocalDataSource {
22+
override suspend fun saveUniversity(index: Int, univName: String) {
23+
dataStore.edit {
24+
it[DataStoreKey.UNIVERSITY_INDEX] = index.toString()
25+
it[DataStoreKey.UNIVERSITY_NAME] = univName
26+
}
27+
}
28+
29+
override suspend fun getUniversityIndex(): Flow<String> {
30+
return dataStore.data
31+
.catch { exception ->
32+
if (exception is IOException) {
33+
exception.printStackTrace()
34+
emit(emptyPreferences())
35+
} else {
36+
throw exception
37+
}
38+
}
39+
.map { prefs ->
40+
prefs[DataStoreKey.UNIVERSITY_INDEX].orEmpty()
41+
}
42+
}
43+
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.everymeal.data.datasource.onboarding
22

3-
import com.everymeal.data.model.onboarding.UniversityData
3+
import com.everymeal.data.model.onboarding.UniversityResponse
44

55
interface OnboardingDataSource {
6-
suspend fun getUniversity(): Result<List<UniversityData>>
6+
suspend fun getUniversity(): Result<List<UniversityResponse>>
77
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.everymeal.data.datasource.onboarding
22

3-
import com.everymeal.data.model.onboarding.UniversityData
3+
import com.everymeal.data.model.onboarding.UniversityResponse
44
import com.everymeal.data.model.unwrapData
55
import com.everymeal.data.service.onboarding.OnboardingApi
66
import javax.inject.Inject
@@ -9,7 +9,7 @@ class OnboardingDataSourceImpl @Inject constructor(
99
private val onboardingApi: OnboardingApi
1010
) : OnboardingDataSource {
1111

12-
override suspend fun getUniversity(): Result<List<UniversityData>> {
12+
override suspend fun getUniversity(): Result<List<UniversityResponse>> {
1313
return runCatching { onboardingApi.getUniversity() }.unwrapData()
1414
}
1515
}

data/src/main/java/com/everymeal/data/model/onboarding/GetUniversityData.kt renamed to data/src/main/java/com/everymeal/data/model/onboarding/GetUniversityResponse.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import com.everymeal.domain.model.onboarding.GetUniversityEntity
44
import kotlinx.serialization.Serializable
55

66
@Serializable
7-
data class UniversityData(
7+
data class UniversityResponse(
88
val idx: Int,
99
val universityName: String,
1010
val campusName: String,
1111
val universityShortName: String
1212
)
1313

14-
fun List<UniversityData>.toUniversityEntity(): GetUniversityEntity {
14+
fun List<UniversityResponse>.toUniversityEntity(): GetUniversityEntity {
1515
val universityDataList = this.map { result ->
1616
GetUniversityEntity.UniversityData(
1717
idx = result.idx,
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.everymeal.data.repository.local
2+
3+
import com.everymeal.data.datasource.local.LocalDataSource
4+
import com.everymeal.domain.repository.local.LocalRepository
5+
import kotlinx.coroutines.flow.Flow
6+
import javax.inject.Inject
7+
8+
class LocalRepositoryImpl @Inject constructor(
9+
private val localDataSource: LocalDataSource
10+
) : LocalRepository {
11+
12+
override suspend fun saveUniversity(index: Int, univName: String) {
13+
localDataSource.saveUniversity(index, univName)
14+
}
15+
16+
override suspend fun getUniversityIndex(): Flow<String> {
17+
return localDataSource.getUniversityIndex()
18+
}
19+
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package com.everymeal.data.service.onboarding
22

33
import com.everymeal.data.model.BaseResponse
4-
import com.everymeal.data.model.onboarding.UniversityData
4+
import com.everymeal.data.model.onboarding.UniversityResponse
55
import retrofit2.http.GET
66

77
interface OnboardingApi {
88

99
@GET("/api/v1/universities")
10-
suspend fun getUniversity(): BaseResponse<List<UniversityData>>
10+
suspend fun getUniversity(): BaseResponse<List<UniversityResponse>>
1111
}

domain/build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,7 @@ java {
1111
dependencies {
1212
// Hilt
1313
implementation(libs.hilt.core)
14+
15+
// Coroutines
16+
implementation(libs.kotlin.coroutines)
1417
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.everymeal.domain.repository.local
2+
3+
import kotlinx.coroutines.flow.Flow
4+
5+
interface LocalRepository {
6+
suspend fun saveUniversity(index : Int, univName : String)
7+
8+
suspend fun getUniversityIndex() : Flow<String>
9+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.everymeal.domain.usecase.local
2+
3+
import com.everymeal.domain.repository.local.LocalRepository
4+
import kotlinx.coroutines.flow.Flow
5+
import javax.inject.Inject
6+
7+
class GetUniversityIndexUseCase @Inject constructor(
8+
private val localRepository: LocalRepository
9+
) {
10+
suspend operator fun invoke() : Flow<String> {
11+
return localRepository.getUniversityIndex()
12+
}
13+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.everymeal.domain.usecase.local
2+
3+
import com.everymeal.domain.repository.local.LocalRepository
4+
import com.everymeal.domain.repository.onboarding.OnboardingRepository
5+
import javax.inject.Inject
6+
7+
class SaveUniversityUseCase @Inject constructor(
8+
private val localRepository: LocalRepository
9+
) {
10+
suspend operator fun invoke(
11+
index : Int,
12+
univName : String
13+
) {
14+
localRepository.saveUniversity(index, univName)
15+
}
16+
}
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package com.everymeal.domain.usecase.onboarding
22

3+
import com.everymeal.domain.model.onboarding.GetUniversityEntity
34
import com.everymeal.domain.repository.onboarding.OnboardingRepository
45
import javax.inject.Inject
56

67
class GetUniversityUseCase @Inject constructor(
78
private val onboardingRepository: OnboardingRepository
89
) {
9-
suspend operator fun invoke() = onboardingRepository.getUniversity()
10+
suspend operator fun invoke() :Result<GetUniversityEntity> {
11+
return onboardingRepository.getUniversity()
12+
}
1013
}

gradle/libs.versions.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ lottie = "6.1.0"
1919
compose-navigation = "2.7.4"
2020
accompanist = "0.33.0-alpha"
2121

22+
data-store = "1.0.0"
23+
kotlin-coroutines = "1.7.3"
24+
2225
[libraries]
2326
agp = { module = "com.android.tools.build:gradle", version.ref = "agp" }
2427
coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coil-compose" }
@@ -69,6 +72,11 @@ compose-lottie = { module = "com.airbnb.android:lottie-compose", version.ref = "
6972
#Compose-Navigation
7073
compose-navigation = { module = "androidx.navigation:navigation-compose", version.ref = "compose-navigation" }
7174

75+
#data-store
76+
data-store = { module = "androidx.datastore:datastore-preferences", version.ref = "data-store" }
77+
78+
#kotlin-coroutines
79+
kotlin-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlin-coroutines" }
7280

7381
[plugins]
7482
androidApplication = { id = "com.android.application", version.ref = "agp" }

presentation/src/main/java/com/everymeal/presentation/ui/onboarding/OnboardingScreen.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ fun OnboardingScreen(
121121
}
122122
Spacer(modifier = Modifier.size(30.dp))
123123
EveryMealMainButton(
124-
text = stringResource(id = R.string.next),
124+
text = stringResource(id = R.string.start),
125125
onClick = onNavigateToUnivSelect
126126
)
127127
}

presentation/src/main/java/com/everymeal/presentation/ui/signup/UnivSelectContract.kt

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ class UnivSelectContract {
1616
val univSelectLoadState: LoadState = LoadState.LOADING,
1717
val selectedUniv: String = "",
1818
val universities: List<UniversityData> = emptyList(),
19-
val networkErrorDialog: Boolean = true
19+
val networkErrorDialog: Boolean = true,
20+
val univIdx: Int = 0,
21+
val univSelectFullName: String = "",
22+
val campusName: String = ""
2023
) : ViewState
2124

2225
/*
@@ -25,9 +28,16 @@ class UnivSelectContract {
2528
*/
2629
sealed class UnivSelectEvent : ViewEvent {
2730
object InitUnivSelectScreen : UnivSelectEvent()
28-
object SelectButtonClicked : UnivSelectEvent()
31+
data class SelectButtonClicked(
32+
val univIdx: Int,
33+
val univSelectFullName: String,
34+
val campusName: String
35+
) : UnivSelectEvent()
2936
data class SelectedUniv(
30-
val selectedUniv: String
37+
val selectedUniv: String,
38+
val univIdx: Int,
39+
val univSelectFullName: String,
40+
val campusName: String
3141
) : UnivSelectEvent()
3242
data class NetworkErrorDialogClicked(
3343
val dialogStateChange: Boolean

presentation/src/main/java/com/everymeal/presentation/ui/signup/UnivSelectScreen.kt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,10 @@ fun UnivSelectScreen(
120120
index = index
121121
) {
122122
viewModel.setEvent(UnivSelectContract.UnivSelectEvent.SelectedUniv(
123-
"${item.universityShortName}+${item.campusName}")
123+
selectedUniv = "${item.universityShortName}+${item.campusName}",
124+
univIdx = item.idx,
125+
univSelectFullName = item.universityName,
126+
campusName = item.campusName)
124127
)
125128
}
126129
}
@@ -161,7 +164,11 @@ fun UnivSelectScreen(
161164
text = stringResource(R.string.select),
162165
enabled = viewState.selectedUniv.isNotEmpty(),
163166
) {
164-
viewModel.setEvent(UnivSelectContract.UnivSelectEvent.SelectButtonClicked)
167+
viewModel.setEvent(UnivSelectContract.UnivSelectEvent.SelectButtonClicked(
168+
univIdx = viewState.univIdx,
169+
univSelectFullName = viewState.univSelectFullName,
170+
campusName = viewState.campusName
171+
))
165172
}
166173
}
167174
}

0 commit comments

Comments
 (0)