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
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.eatssu.android.data.remote.dto.request

import kotlinx.serialization.Serializable

@Serializable
data class LanguageRequest(
val language: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.eatssu.android.data.remote.dto.response

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class LanguageResponse(
@SerialName("language") val language: String? = null,
)
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.eatssu.android.data.model.orElse
import com.eatssu.android.data.model.orEmptyList
import com.eatssu.android.data.model.orNull
import com.eatssu.android.data.remote.dto.request.ChangeNicknameRequest
import com.eatssu.android.data.remote.dto.request.LanguageRequest
import com.eatssu.android.data.remote.dto.request.UserDepartmentRequest
import com.eatssu.android.data.remote.dto.response.toDomain
import com.eatssu.android.data.remote.service.UserService
Expand Down Expand Up @@ -67,4 +68,12 @@ class UserRepositoryImpl @Inject constructor(
return userService.setUserDepartment(UserDepartmentRequest(departmentId)).isSuccess()
}

override suspend fun getUserLanguage(): String {
return userService.getUserLanguage().map { it.language }.orNull() ?: ""
}

override suspend fun patchUserLanguage(language: String): Boolean {
return userService.patchUserLanguage(LanguageRequest(language)).isSuccess()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package com.eatssu.android.data.remote.service

import com.eatssu.android.data.model.ApiResult
import com.eatssu.android.data.remote.dto.request.ChangeNicknameRequest
import com.eatssu.android.data.remote.dto.request.LanguageRequest
import com.eatssu.android.data.remote.dto.request.UserDepartmentRequest
import com.eatssu.android.data.remote.dto.response.CollegeResponse
import com.eatssu.android.data.remote.dto.response.DepartmentResponse
import com.eatssu.android.data.remote.dto.response.LanguageResponse
import com.eatssu.android.data.remote.dto.response.MyPageResponse
import com.eatssu.android.data.remote.dto.response.PartnershipResponse
import com.eatssu.android.data.remote.dto.response.UserCollegeDepartmentResponse
Expand Down Expand Up @@ -52,4 +54,13 @@ interface UserService {
@GET("users/department/partnerships") // 유저 학과의 제휴 조회
suspend fun getUserDepartmentPartnerships(): ApiResult<List<PartnershipResponse>>

@GET("users/language") // 언어 설정 조회
suspend fun getUserLanguage(): ApiResult<LanguageResponse>

@PATCH("users/language") // 언어 설정 변경
suspend fun patchUserLanguage(
@Body language: LanguageRequest,
): ApiResult<Unit>


}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,10 @@ interface UserRepository {
suspend fun setUserDepartment(
departmentId: Int,
): Boolean

suspend fun getUserLanguage(): String

suspend fun patchUserLanguage(
language: String,
): Boolean
}
20 changes: 18 additions & 2 deletions app/src/main/java/com/eatssu/android/presentation/MainViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.eatssu.android.R
import com.eatssu.android.analytics.AnalyticsIdentityManager
import com.eatssu.android.data.local.SettingDataStore
import com.eatssu.android.domain.repository.UserRepository
import com.eatssu.android.domain.usecase.auth.LogoutUseCase
import com.eatssu.android.domain.usecase.user.GetUserCollegeDepartmentUseCase
Expand All @@ -22,6 +23,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import timber.log.Timber
import java.time.LocalDate
Expand All @@ -36,6 +38,7 @@ class MainViewModel @Inject constructor(
private val getUserCollegeDepartmentUseCase: GetUserCollegeDepartmentUseCase,
private val getUserEmailUseCase: GetUserEmailUseCase,
private val analyticsIdentityManager: AnalyticsIdentityManager,
private val settingDataStore: SettingDataStore,
) : ViewModel() {

private val _uiState: MutableStateFlow<UiState<MainState>> = MutableStateFlow(UiState.Init)
Expand All @@ -47,7 +50,8 @@ class MainViewModel @Inject constructor(
init {
viewModelScope.launch {
loadStoredUserDepartment()
getUserDepartment()
syncLanguageState()
loadUserDepartmentFromServer()
fetchAndCheckNickname()
}
}
Expand All @@ -63,6 +67,12 @@ class MainViewModel @Inject constructor(
}
}

fun refreshUserDepartmentFromServer() {
viewModelScope.launch {
loadUserDepartmentFromServer()
}
}

private suspend fun fetchAndCheckNickname() {
val nickname = getUserNickNameUseCase()

Expand Down Expand Up @@ -110,7 +120,7 @@ class MainViewModel @Inject constructor(
)
}

private suspend fun getUserDepartment() {
private suspend fun loadUserDepartmentFromServer() {
val (college, department) = userRepository.getUserCollegeDepartment() ?: run {
_uiEvent.emit(
UiEvent.ShowToast(
Expand Down Expand Up @@ -145,6 +155,12 @@ class MainViewModel @Inject constructor(
department = userInfo.userDepartment,
)
}

private suspend fun syncLanguageState() {
// 어떤 이유로 앱과 서버의 언어가 다를 수 있기 때문에, 앱 언어 설정을 서버에 전송
val language = settingDataStore.appLanguage.first()
userRepository.patchUserLanguage(language.code.uppercase())
}
}


Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.eatssu.android.presentation.mypage

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
Expand All @@ -9,6 +10,7 @@ import android.provider.Settings
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.getValue
Expand Down Expand Up @@ -65,6 +67,12 @@ class MyPageFragment : Fragment() {
private val myPageViewModel: MyPageViewModel by viewModels()
private val mainViewModel: MainViewModel by activityViewModels()
private var lastNotificationPermissionState: Boolean? = null
private val languageSelectorLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
mainViewModel.refreshUserDepartmentFromServer()
}
}

override fun onCreateView(
inflater: LayoutInflater,
Expand Down Expand Up @@ -123,7 +131,7 @@ class MyPageFragment : Fragment() {
)
},
onLanguageSettingClick = {
startActivity(
languageSelectorLauncher.launch(
Intent(
requireContext(),
LanguageSelectorActivity::class.java
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,66 @@ package com.eatssu.android.presentation.mypage.language
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.eatssu.android.analytics.ProvideAnalyticsTracker
import com.eatssu.common.analytics.AnalyticsTracker
import com.eatssu.design_system.theme.EatssuTheme
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import javax.inject.Inject

@AndroidEntryPoint
class LanguageSelectorActivity : ComponentActivity() {

companion object {
private const val KEY_LANGUAGE_CHANGED = "KEY_LANGUAGE_CHANGED"
}

@Inject
lateinit var analyticsTracker: AnalyticsTracker

private val viewModel: LanguageSelectorViewModel by viewModels()
private var hasLanguageChanged = false

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
hasLanguageChanged = savedInstanceState?.getBoolean(KEY_LANGUAGE_CHANGED) ?: false
updateResultIfNeeded()
collectLanguageChanged()
setContent {
ProvideAnalyticsTracker(analyticsTracker) {
EatssuTheme {
LanguageSelectorScreen(
viewModel = viewModel,
onBack = { finish() }
)
}
}
}
}

override fun onSaveInstanceState(outState: Bundle) {
outState.putBoolean(KEY_LANGUAGE_CHANGED, hasLanguageChanged)
super.onSaveInstanceState(outState)
}

private fun collectLanguageChanged() {
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.languageChanged.collect {
hasLanguageChanged = true
updateResultIfNeeded()
}
}
}
}

private fun updateResultIfNeeded() {
if (hasLanguageChanged) {
setResult(RESULT_OK)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
Expand All @@ -15,7 +14,7 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.eatssu.android.R
import com.eatssu.common.enums.AppLanguage
import com.eatssu.design_system.component.EatSsuRadioButtonGroup
import com.eatssu.design_system.component.EatSsuRadioCheckBoxGroup
import com.eatssu.design_system.component.EatSsuTopBar
import com.eatssu.design_system.theme.EatssuTheme

Expand Down Expand Up @@ -63,13 +62,13 @@ fun LanguageSelectorContent(
.fillMaxSize()
.padding(horizontal = 24.dp)
) {
Text(
text = stringResource(R.string.language_select_description),
style = EatssuTheme.typography.body2,
modifier = Modifier.padding(vertical = 20.dp)
)
// Text(
// text = stringResource(R.string.language_select_description),
// style = EatssuTheme.typography.body2,
// modifier = Modifier.padding(vertical = 20.dp)
// )
Comment on lines +65 to +69
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

주석 처리된 코드는 삭제하여 코드의 가독성을 높이는 것이 좋습니다. 필요하다면 Git 히스토리를 통해 나중에 확인할 수 있습니다.


EatSsuRadioButtonGroup(
EatSsuRadioCheckBoxGroup(
options = languageOptions,
selectedOption = selectedOption,
onOptionSelected = { selected ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,30 @@ import androidx.core.os.LocaleListCompat
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.eatssu.android.data.local.SettingDataStore
import com.eatssu.android.domain.repository.UserRepository
import com.eatssu.common.enums.AppLanguage
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class LanguageSelectorViewModel @Inject constructor(
private val settingDataStore: SettingDataStore
private val settingDataStore: SettingDataStore,
private val userRepository: UserRepository,
) : ViewModel() {

private val _selectedLanguage = MutableStateFlow(AppLanguage.KOREAN)
val selectedLanguage: StateFlow<AppLanguage> = _selectedLanguage.asStateFlow()

private val _languageChanged = MutableSharedFlow<Unit>()
val languageChanged: SharedFlow<Unit> = _languageChanged.asSharedFlow()

init {
viewModelScope.launch {
settingDataStore.appLanguage.collect { language ->
Expand All @@ -31,8 +39,13 @@ class LanguageSelectorViewModel @Inject constructor(

fun selectLanguage(language: AppLanguage) {
viewModelScope.launch {
val previousLanguage = selectedLanguage.value
settingDataStore.setAppLanguage(language)
val isPatched = userRepository.patchUserLanguage(language.code.uppercase())
_selectedLanguage.value = language
if (isPatched && previousLanguage != language) {
_languageChanged.emit(Unit)
}
applyLanguage(language)
}
}
Expand Down
Loading
Loading