diff --git a/app/src/main/java/org/sopt/pingle/data/datasource/remote/JoinGroupCodeRemoteDataSource.kt b/app/src/main/java/org/sopt/pingle/data/datasource/remote/JoinGroupCodeRemoteDataSource.kt new file mode 100644 index 00000000..740070f3 --- /dev/null +++ b/app/src/main/java/org/sopt/pingle/data/datasource/remote/JoinGroupCodeRemoteDataSource.kt @@ -0,0 +1,8 @@ +package org.sopt.pingle.data.datasource.remote + +import org.sopt.pingle.data.model.remote.response.ResponseJoinGroupInfoDto +import org.sopt.pingle.util.base.BaseResponse + +interface JoinGroupCodeRemoteDataSource { + suspend fun getJoinGroupCodeInfo(teamId: Int): BaseResponse +} \ No newline at end of file diff --git a/app/src/main/java/org/sopt/pingle/data/datasourceimpl/remote/JoinGroupCodeRemoteDataSourceImpl.kt b/app/src/main/java/org/sopt/pingle/data/datasourceimpl/remote/JoinGroupCodeRemoteDataSourceImpl.kt new file mode 100644 index 00000000..eb566182 --- /dev/null +++ b/app/src/main/java/org/sopt/pingle/data/datasourceimpl/remote/JoinGroupCodeRemoteDataSourceImpl.kt @@ -0,0 +1,14 @@ +package org.sopt.pingle.data.datasourceimpl.remote + +import org.sopt.pingle.data.datasource.remote.JoinGroupCodeRemoteDataSource +import org.sopt.pingle.data.model.remote.response.ResponseJoinGroupInfoDto +import org.sopt.pingle.data.service.JoinGroupService +import org.sopt.pingle.util.base.BaseResponse +import javax.inject.Inject + +class JoinGroupCodeRemoteDataSourceImpl @Inject constructor( + private val joinGroupService: JoinGroupService +) : JoinGroupCodeRemoteDataSource { + override suspend fun getJoinGroupCodeInfo(teamId: Int): BaseResponse = + joinGroupService.getJoinGroupDetail(teamId = teamId) +} \ No newline at end of file diff --git a/app/src/main/java/org/sopt/pingle/data/model/remote/response/ResponseJoinGroupCodeDto.kt b/app/src/main/java/org/sopt/pingle/data/model/remote/response/ResponseJoinGroupCodeDto.kt deleted file mode 100644 index b5032ef6..00000000 --- a/app/src/main/java/org/sopt/pingle/data/model/remote/response/ResponseJoinGroupCodeDto.kt +++ /dev/null @@ -1,34 +0,0 @@ -package org.sopt.pingle.data.model.remote.response - -import kotlinx.serialization.SerialName -import org.sopt.pingle.domain.model.JoinGroupCodeEntity - -data class ResponseJoinGroupCodeDto( - @SerialName("code") - val code: Int, - @SerialName("message") - val message: String, - @SerialName("data") - val data: Data -) { - data class Data( - @SerialName("id") - val id: Int, - @SerialName("keyword") - val keyword: String, - @SerialName("name") - val name: String, - @SerialName("meetingCount") - val meetingCount: Int, - @SerialName("participantCount") - val participantCount: Int - ) { - fun toJoinGroupCodeEntity() = JoinGroupCodeEntity( - id = this.id, - keyword = this.keyword, - name = this.name, - meetingCount = this.meetingCount, - participantCount = this.participantCount - ) - } -} diff --git a/app/src/main/java/org/sopt/pingle/data/model/remote/response/ResponseJoinGroupInfoDto.kt b/app/src/main/java/org/sopt/pingle/data/model/remote/response/ResponseJoinGroupInfoDto.kt new file mode 100644 index 00000000..608ccf4b --- /dev/null +++ b/app/src/main/java/org/sopt/pingle/data/model/remote/response/ResponseJoinGroupInfoDto.kt @@ -0,0 +1,27 @@ +package org.sopt.pingle.data.model.remote.response + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import org.sopt.pingle.domain.model.JoinGroupInfoEntity + +@Serializable +data class ResponseJoinGroupInfoDto( + @SerialName("id") + val id: Int, + @SerialName("keyword") + val keyword: String, + @SerialName("name") + val name: String, + @SerialName("meetingCount") + val meetingCount: Int, + @SerialName("participantCount") + val participantCount: Int +) { + fun toJoinGroupCodeEntity() = JoinGroupInfoEntity( + id = this.id, + keyword = this.keyword, + name = this.name, + meetingCount = this.meetingCount, + participantCount = this.participantCount + ) +} diff --git a/app/src/main/java/org/sopt/pingle/data/repository/JoinGroupCodeRepositoryImpl.kt b/app/src/main/java/org/sopt/pingle/data/repository/JoinGroupCodeRepositoryImpl.kt new file mode 100644 index 00000000..c28f4f5a --- /dev/null +++ b/app/src/main/java/org/sopt/pingle/data/repository/JoinGroupCodeRepositoryImpl.kt @@ -0,0 +1,19 @@ +package org.sopt.pingle.data.repository + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import org.sopt.pingle.data.datasource.remote.JoinGroupCodeRemoteDataSource +import org.sopt.pingle.domain.model.JoinGroupInfoEntity +import org.sopt.pingle.domain.repository.JoinGroupCodeRepository +import javax.inject.Inject + +class JoinGroupCodeRepositoryImpl @Inject constructor( + private val joinGroupCodeRemoteDataSource: JoinGroupCodeRemoteDataSource +) : JoinGroupCodeRepository { + override fun getJoinGroupInfo(teamId: Int): Flow = flow { + val result = runCatching { + joinGroupCodeRemoteDataSource.getJoinGroupCodeInfo(teamId = teamId).data.toJoinGroupCodeEntity() + } + emit(result.getOrThrow()) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/sopt/pingle/data/service/JoinGroupService.kt b/app/src/main/java/org/sopt/pingle/data/service/JoinGroupService.kt new file mode 100644 index 00000000..0bb357f9 --- /dev/null +++ b/app/src/main/java/org/sopt/pingle/data/service/JoinGroupService.kt @@ -0,0 +1,19 @@ +package org.sopt.pingle.data.service + +import org.sopt.pingle.data.model.remote.response.ResponseJoinGroupInfoDto +import org.sopt.pingle.util.base.BaseResponse +import retrofit2.http.GET +import retrofit2.http.Path + +interface JoinGroupService { + @GET("$VERSION/$TEAMS/{$TEAM_ID}") + suspend fun getJoinGroupDetail( + @Path("$TEAM_ID") teamId: Int + ): BaseResponse + + companion object { + const val VERSION = "v1" + const val TEAMS = "teams" + const val TEAM_ID = "teamId" + } +} \ No newline at end of file diff --git a/app/src/main/java/org/sopt/pingle/domain/model/JoinGroupCodeEntity.kt b/app/src/main/java/org/sopt/pingle/domain/model/JoinGroupInfoEntity.kt similarity index 83% rename from app/src/main/java/org/sopt/pingle/domain/model/JoinGroupCodeEntity.kt rename to app/src/main/java/org/sopt/pingle/domain/model/JoinGroupInfoEntity.kt index 63283e91..0f2942b7 100644 --- a/app/src/main/java/org/sopt/pingle/domain/model/JoinGroupCodeEntity.kt +++ b/app/src/main/java/org/sopt/pingle/domain/model/JoinGroupInfoEntity.kt @@ -1,6 +1,6 @@ package org.sopt.pingle.domain.model -data class JoinGroupCodeEntity( +data class JoinGroupInfoEntity( val id: Int, val keyword: String, val name: String, diff --git a/app/src/main/java/org/sopt/pingle/domain/repository/JoinGroupCodeRepository.kt b/app/src/main/java/org/sopt/pingle/domain/repository/JoinGroupCodeRepository.kt new file mode 100644 index 00000000..114dc1b3 --- /dev/null +++ b/app/src/main/java/org/sopt/pingle/domain/repository/JoinGroupCodeRepository.kt @@ -0,0 +1,8 @@ +package org.sopt.pingle.domain.repository + +import kotlinx.coroutines.flow.Flow +import org.sopt.pingle.domain.model.JoinGroupInfoEntity + +interface JoinGroupCodeRepository { + fun getJoinGroupInfo(teamId: Int): Flow +} \ No newline at end of file diff --git a/app/src/main/java/org/sopt/pingle/domain/usecase/GetJoinGroupInfoUseCase.kt b/app/src/main/java/org/sopt/pingle/domain/usecase/GetJoinGroupInfoUseCase.kt new file mode 100644 index 00000000..ce1ada74 --- /dev/null +++ b/app/src/main/java/org/sopt/pingle/domain/usecase/GetJoinGroupInfoUseCase.kt @@ -0,0 +1,12 @@ +package org.sopt.pingle.domain.usecase + +import kotlinx.coroutines.flow.Flow +import org.sopt.pingle.domain.model.JoinGroupInfoEntity +import org.sopt.pingle.domain.repository.JoinGroupCodeRepository + +class GetJoinGroupInfoUseCase( + private val joinGroupCodeRepository: JoinGroupCodeRepository +) { + operator fun invoke(teamId: Int): Flow = + joinGroupCodeRepository.getJoinGroupInfo(teamId = teamId) +} \ No newline at end of file diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/joingroup/JoinGroupCodeActivity.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/joingroup/JoinGroupCodeActivity.kt index 24458ffb..30c1aa70 100644 --- a/app/src/main/java/org/sopt/pingle/presentation/ui/joingroup/JoinGroupCodeActivity.kt +++ b/app/src/main/java/org/sopt/pingle/presentation/ui/joingroup/JoinGroupCodeActivity.kt @@ -3,10 +3,16 @@ package org.sopt.pingle.presentation.ui.joingroup import android.content.Intent import android.os.Bundle import androidx.activity.viewModels +import androidx.lifecycle.flowWithLifecycle +import androidx.lifecycle.lifecycleScope import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import org.sopt.pingle.R import org.sopt.pingle.databinding.ActivityJoinGroupCodeBinding import org.sopt.pingle.util.base.BindingActivity +import org.sopt.pingle.util.view.UiState +import timber.log.Timber @AndroidEntryPoint class JoinGroupCodeActivity : @@ -15,16 +21,25 @@ class JoinGroupCodeActivity : override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - binding.joinViewModel = viewModel + initLayout() addListeners() addObservers() + collectData() + } + + private fun initLayout() { + binding.joinViewModel = viewModel + viewModel.getJoinGroupInfo(TEAM_ID) } private fun addListeners() { binding.btnJoinGroupCodeNext.setOnClickListener { - // TODO 초대코드 일치하지 않을 시 - // CustomSnackbar.makeSnackbar(binding.root, getString(R.string.join_group_code_snackbar_message), 97) +// PingleSnackbar.makeSnackbar( +// binding.root, +// getString(R.string.join_group_code_snackbar_message), +// 97 +// ) navigateToJoinGroupSuccess() } @@ -34,34 +49,52 @@ class JoinGroupCodeActivity : } private fun addObservers() { - viewModel.joinGroupData.observe(this) { joinGroupData -> - with(binding) { - tvJoinGroupCodeTag.text = joinGroupData.keyword - tvJoinGroupCodeGroupName.text = joinGroupData.name - tvJoinGroupCodeMeetingCount.text = - getString(R.string.join_group_code_meeting_count, joinGroupData.meetingCount) - tvJoinGroupCodeParticipantCount.text = - getString( - R.string.join_group_code_participant_count, - joinGroupData.participantCount - ) - } - } - viewModel.joinGroupCode.observe(this) { editText -> binding.btnJoinGroupCodeNext.isEnabled = editText.isNotEmpty() } } + private fun collectData() { + viewModel.joinGroupCodeUiState.flowWithLifecycle(lifecycle).onEach { uiState -> + when (uiState) { + is UiState.Success -> { + with(binding) { + tvJoinGroupCodeTag.text = uiState.data.keyword + tvJoinGroupCodeGroupName.text = uiState.data.name + tvJoinGroupCodeMeetingCount.text = + getString( + R.string.join_group_code_meeting_count, + uiState.data.meetingCount + ) + tvJoinGroupCodeParticipantCount.text = + getString( + R.string.join_group_code_participant_count, + uiState.data.participantCount + ) + } + } + + is UiState.Error -> Timber.tag(JOIN_GROUP_CODE_ACTIVITY).d(uiState.message) + + is UiState.Loading -> Timber.tag(JOIN_GROUP_CODE_ACTIVITY).d(LOADING) + + is UiState.Empty -> Timber.tag(JOIN_GROUP_CODE_ACTIVITY).d(EMPTY) + } + }.launchIn(lifecycleScope) + } + private fun navigateToJoinGroupSuccess() { Intent(this, JoinGroupSuccessActivity::class.java).apply { - // TODO 서버통신시 group name 가져와서 전달하기 - putExtra(GROUP_NAME, viewModel.joinGroupData.value?.name) + putExtra(GROUP_NAME, binding.tvJoinGroupCodeGroupName.text) startActivity(this) } } companion object { const val GROUP_NAME = "groupName" + const val TEAM_ID = 1 + const val LOADING = "Loding" + const val EMPTY = "Empty" + const val JOIN_GROUP_CODE_ACTIVITY = "JoinGroupCodeActivity" } } diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/joingroup/JoinViewModel.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/joingroup/JoinViewModel.kt index 57c05cc0..bd0047b7 100644 --- a/app/src/main/java/org/sopt/pingle/presentation/ui/joingroup/JoinViewModel.kt +++ b/app/src/main/java/org/sopt/pingle/presentation/ui/joingroup/JoinViewModel.kt @@ -2,14 +2,24 @@ package org.sopt.pingle.presentation.ui.joingroup import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow -import org.sopt.pingle.domain.model.JoinGroupCodeEntity +import kotlinx.coroutines.launch +import org.sopt.pingle.domain.model.JoinGroupInfoEntity import org.sopt.pingle.domain.model.JoinGroupSearchEntity +import org.sopt.pingle.domain.usecase.GetJoinGroupInfoUseCase +import org.sopt.pingle.util.view.UiState +import javax.inject.Inject -class JoinViewModel : ViewModel() { - private val _joinGroupData = MutableLiveData() - val joinGroupData get() = _joinGroupData +@HiltViewModel +class JoinViewModel @Inject constructor( + private val getJoinGroupInfoUseCase: GetJoinGroupInfoUseCase +) : ViewModel() { + private val _joinGroupCodeUiState = + MutableStateFlow>(UiState.Empty) + val joinGroupCodeUiState get() = _joinGroupCodeUiState.asStateFlow() private var _isJoinGroupCodeBtn = MutableLiveData(false) val isJoinGroupCodeBtn get() = _isJoinGroupCodeBtn @@ -27,9 +37,7 @@ class JoinViewModel : ViewModel() { private var oldPosition = DEFAULT_OLD_POSITION fun updateJoinGroupSearchList(newPosition: Int) { when (oldPosition) { - DEFAULT_OLD_POSITION -> { - setIsSelected(newPosition) - } + DEFAULT_OLD_POSITION -> setIsSelected(newPosition) newPosition -> { setIsSelected(newPosition) @@ -52,16 +60,23 @@ class JoinViewModel : ViewModel() { ) } + fun getJoinGroupInfo(teamId: Int) { + _joinGroupCodeUiState.value = UiState.Loading + viewModelScope.launch { + _joinGroupCodeUiState.value = UiState.Loading + runCatching { + getJoinGroupInfoUseCase.invoke(teamId = teamId).collect { joinGroupInfo -> + _joinGroupCodeUiState.value = UiState.Success(joinGroupInfo) + } + }.onFailure { + _joinGroupCodeUiState.value = UiState.Error(it.message) + } + } + } + private fun getIsSelected(position: Int) = _joinGroupSearchData.value[position].isSelected.get() init { - _joinGroupData.value = JoinGroupCodeEntity( - id = 0, - keyword = "연합동아리", - name = "SOPT", - meetingCount = 10, - participantCount = 200 - ) _joinGroupSearchData.value = listOf( JoinGroupSearchEntity(