-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[AN] 스터디 개설 뷰 리펙터링 #618
base: develop
Are you sure you want to change the base?
[AN] 스터디 개설 뷰 리펙터링 #618
Changes from 18 commits
43ed43d
bdcf283
602a632
23511e3
50f7950
7f3ba5d
26d6b1f
a9143f9
4c712f7
2c9120e
e9b0b52
d109ec5
e2221ad
0fa5b4f
5964bea
e6e10bf
345c394
771d091
eb5c465
773d28c
77cc089
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package com.created.team201.presentation.common | ||
|
||
import android.os.Bundle | ||
import android.view.LayoutInflater | ||
import android.view.View | ||
import android.view.ViewGroup | ||
import androidx.viewbinding.ViewBinding | ||
import com.created.team201.R | ||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment | ||
|
||
abstract class BindingViewBottomSheetFragment<VB : ViewBinding>( | ||
private val bindingInflater: (LayoutInflater) -> VB | ||
) : BottomSheetDialogFragment() { | ||
private var _binding: VB? = null | ||
val binding get() = _binding ?: error(R.string.error_baseFragment) | ||
|
||
override fun onCreateView( | ||
inflater: LayoutInflater, | ||
container: ViewGroup?, | ||
savedInstanceState: Bundle?, | ||
): View { | ||
_binding = bindingInflater(inflater) | ||
return binding.root | ||
} | ||
|
||
override fun onDestroyView() { | ||
super.onDestroyView() | ||
_binding = null | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,19 +4,19 @@ import androidx.lifecycle.ViewModel | |
import androidx.lifecycle.viewModelScope | ||
import com.created.domain.model.CreateStudy | ||
import com.created.team201.data.repository.CreateStudyRepository | ||
import com.created.team201.presentation.createStudy.model.CreateStudyUiState | ||
import com.created.team201.presentation.createStudy.model.FragmentState | ||
import com.created.team201.presentation.createStudy.model.FragmentState.FirstFragment | ||
import com.created.team201.presentation.createStudy.model.FragmentState.SecondFragment | ||
import dagger.hilt.android.lifecycle.HiltViewModel | ||
import kotlinx.coroutines.flow.Flow | ||
import kotlinx.coroutines.flow.MutableSharedFlow | ||
import kotlinx.coroutines.flow.MutableStateFlow | ||
import kotlinx.coroutines.flow.SharedFlow | ||
import kotlinx.coroutines.flow.SharingStarted | ||
import kotlinx.coroutines.flow.StateFlow | ||
import kotlinx.coroutines.flow.asSharedFlow | ||
import kotlinx.coroutines.flow.asStateFlow | ||
import kotlinx.coroutines.flow.combine | ||
import kotlinx.coroutines.flow.stateIn | ||
import kotlinx.coroutines.launch | ||
import javax.inject.Inject | ||
|
||
|
@@ -44,20 +44,22 @@ class CreateStudyViewModel @Inject constructor( | |
MutableStateFlow(DEFAULT_STRING_VALUE) | ||
val studyIntroduction: StateFlow<String> get() = _studyIntroduction.asStateFlow() | ||
|
||
val isEnableFirstCreateStudyNext: Flow<Boolean> = | ||
val isEnableFirstCreateStudyNext: StateFlow<Boolean> = | ||
combine(peopleCount, studyDate, cycle) { peopleCount, studyDate, cycle -> | ||
return@combine peopleCount != DEFAULT_INT_VALUE && studyDate != DEFAULT_INT_VALUE && cycle != DEFAULT_INT_VALUE | ||
} | ||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false) | ||
|
||
val isEnableSecondCreateStudyNext: Flow<Boolean> = | ||
val isEnableSecondCreateStudyNext: StateFlow<Boolean> = | ||
combine(studyName, studyIntroduction) { studyName, studyIntroduction -> | ||
return@combine studyName.isNotBlankAndEmpty() && studyIntroduction.isNotBlankAndEmpty() | ||
} | ||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), false) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 혹시 combine 블록 내부에
|
||
|
||
private val _createStudyUiState: MutableSharedFlow<CreateStudyUiState> = MutableSharedFlow() | ||
val createStudyUiState: SharedFlow<CreateStudyUiState> get() = _createStudyUiState.asSharedFlow() | ||
private val _createStudyState: MutableStateFlow<CreateStudyState> = | ||
MutableStateFlow(CreateStudyState.Idle) | ||
val createStudyState: StateFlow<CreateStudyState> get() = _createStudyState.asStateFlow() | ||
|
||
private var isOpenStudy: Boolean = false | ||
private val _createStudyEvent: MutableSharedFlow<Event> = MutableSharedFlow() | ||
val createStudyEvent: SharedFlow<Event> get() = _createStudyEvent.asSharedFlow() | ||
|
||
fun setPeopleCount(peopleCount: Int) { | ||
_peopleCount.value = peopleCount | ||
|
@@ -80,28 +82,29 @@ class CreateStudyViewModel @Inject constructor( | |
} | ||
|
||
fun navigateToNext() { | ||
when (_fragmentState.value) { | ||
is FirstFragment -> { | ||
_fragmentState.value = SecondFragment | ||
} | ||
viewModelScope.launch { | ||
when (_fragmentState.value) { | ||
is FirstFragment -> { | ||
_createStudyEvent.emit(Event.NavigateToNext(fragmentState.value)) | ||
_fragmentState.value = SecondFragment | ||
} | ||
|
||
else -> Unit | ||
else -> Unit | ||
} | ||
} | ||
} | ||
|
||
fun navigateToBefore() { | ||
when (_fragmentState.value) { | ||
is SecondFragment -> { | ||
_fragmentState.value = FirstFragment | ||
} | ||
|
||
else -> Unit | ||
viewModelScope.launch { | ||
_createStudyEvent.emit(Event.NavigateToBefore(fragmentState.value)) | ||
_fragmentState.value = FirstFragment | ||
} | ||
} | ||
|
||
fun createStudy() { | ||
if (isOpenStudy) return | ||
isOpenStudy = true | ||
if (createStudyState.value == CreateStudyState.Loading) | ||
return | ||
_createStudyState.value = CreateStudyState.Loading | ||
viewModelScope.launch { | ||
val study = CreateStudy( | ||
name = studyName.value.trim(), | ||
|
@@ -112,15 +115,34 @@ class CreateStudyViewModel @Inject constructor( | |
) | ||
createStudyRepository.createStudy(study) | ||
.onSuccess { studyId -> | ||
_createStudyUiState.emit(CreateStudyUiState.Success(studyId)) | ||
_createStudyEvent.emit(Event.CreateStudySuccess) | ||
_createStudyState.emit(CreateStudyState.Success(studyId)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 세터말고 emit한 이유가 뭔가요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. update vs setter vs emit There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. setter랑 emit 차이는 없는걸로 알고 있었는데 update는 첨보네요 굳 |
||
} | ||
.onFailure { | ||
_createStudyUiState.emit(CreateStudyUiState.Fail) | ||
_createStudyEvent.emit(Event.CreateStudyFailure) | ||
_createStudyState.emit(CreateStudyState.Failure) | ||
} | ||
} | ||
} | ||
|
||
private fun String.isNotBlankAndEmpty(): Boolean = isNotBlank().and(isNotEmpty()) | ||
private fun String.isNotBlankAndEmpty(): Boolean = isNotBlank() and isNotEmpty() | ||
|
||
sealed interface Event { | ||
object CreateStudySuccess : Event | ||
object CreateStudyFailure : Event | ||
data class NavigateToBefore(val fragmentState: FragmentState) : Event | ||
data class NavigateToNext(val fragmentState: FragmentState) : Event | ||
} | ||
Comment on lines
+130
to
+135
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 제가 참고했던 구글의 프로젝트에선 Event가 아닌 Action으로 정의하고 sealed class OnboardingNavigationAction {
object NavigateToMainScreen : OnboardingNavigationAction()
object NavigateToSignInDialog : OnboardingNavigationAction()
}
현재 코드는 행동과 이벤트(상황)가 혼합된 느낌이긴 합니다. |
||
|
||
sealed interface CreateStudyState { | ||
class Success(val studyId: Long) : CreateStudyState | ||
|
||
object Loading : CreateStudyState | ||
|
||
object Failure : CreateStudyState | ||
|
||
object Idle : CreateStudyState | ||
} | ||
Comment on lines
+130
to
+145
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아래 서로 다른 이유가 혹시 있을까요? |
||
|
||
companion object { | ||
private const val DEFAULT_INT_VALUE = -1 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
왜 collectLatest를 사용하셨나요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
State에 Loading과 Idle을 넣기 전에 중복 시도 시 이전 통신 값은 무시하고 마지막에 요청한거만 하도록 하려고 이렇게 했었슴다
지금은 collect든 collectLatest든 둘 다 동일한 동작을 수행할 거 같네용