Skip to content

Commit

Permalink
[AN/USER] refactor: LiveData to Flow 리팩터링 (티켓 목록, 티켓 예매, 티켓 기록, 홈화면) (#…
Browse files Browse the repository at this point in the history
…495)

* refactor: TicketList uiState StateFlow 로 변경

* refactor: TicketListFragment 에서 uiState 를 수집하도록 변경

* refactor: TicketList 에서 event 가 sharedFlow 사용하도록 변경

* refactor: Flow 적용 테스트 리팩터링

* refactor: 티켓 제시 이벤트 테스트 리팩터링

* refactor: 티켓 예매 화면 uiState 에 StateFlow 적용

* refactor: 티켓 예매 화면 event 에 SharedFlow 적용

* refactor: 티켓 예매 화면 테스트 리팩터링

* refactor: 티켓 목록 화면 테스트 이벤트 취소 로직 추가

* refactor: 티켓 기록 화면 uiState StateFlow 로 리팩터링

* refactor: 티켓 기록 화면 테스트 리팩터링

* refactor: 홈 화면 event SharedFlow 적용

* refactor: 홈 화면 테스트 event sharedFlow 리팩터링

* refactor: 테스트에서 cancelAndIgnoreRemainingEvents 제거

* refactor: uiState 가 더 이상 nullable 하지 않음 반영
  • Loading branch information
SeongHoonC authored and BGuga committed Oct 17, 2023
1 parent 55aea7e commit c5d3472
Show file tree
Hide file tree
Showing 14 changed files with 224 additions and 183 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import com.festago.festago.presentation.ui.home.festivallist.FestivalListFragmen
import com.festago.festago.presentation.ui.home.mypage.MyPageFragment
import com.festago.festago.presentation.ui.home.ticketlist.TicketListFragment
import com.festago.festago.presentation.ui.signin.SignInActivity
import com.festago.festago.presentation.util.repeatOnStarted
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
Expand Down Expand Up @@ -48,12 +49,14 @@ class HomeActivity : AppCompatActivity() {
}

private fun initObserve() {
vm.event.observe(this) { event ->
when (event) {
is HomeEvent.ShowFestivalList -> showFestivalList()
is HomeEvent.ShowTicketList -> showTicketList()
is HomeEvent.ShowMyPage -> showMyPage()
is HomeEvent.ShowSignIn -> showSignIn()
repeatOnStarted(this) {
vm.event.collect { event ->
when (event) {
is HomeEvent.ShowFestivalList -> showFestivalList()
is HomeEvent.ShowTicketList -> showTicketList()
is HomeEvent.ShowMyPage -> showMyPage()
is HomeEvent.ShowSignIn -> showSignIn()
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,32 @@
package com.festago.festago.presentation.ui.home

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.festago.festago.presentation.ui.home.HomeItemType.FESTIVAL_LIST
import com.festago.festago.presentation.ui.home.HomeItemType.MY_PAGE
import com.festago.festago.presentation.ui.home.HomeItemType.TICKET_LIST
import com.festago.festago.presentation.util.MutableSingleLiveData
import com.festago.festago.presentation.util.SingleLiveData
import com.festago.festago.repository.AuthRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class HomeViewModel @Inject constructor(private val authRepository: AuthRepository) : ViewModel() {

private val _event = MutableSingleLiveData<HomeEvent>()
val event: SingleLiveData<HomeEvent> = _event
private val _event = MutableSharedFlow<HomeEvent>()
val event: SharedFlow<HomeEvent> = _event.asSharedFlow()

fun loadHomeItem(homeItemType: HomeItemType) {
when {
homeItemType == FESTIVAL_LIST -> _event.setValue(HomeEvent.ShowFestivalList)
!authRepository.isSigned -> _event.setValue(HomeEvent.ShowSignIn)
homeItemType == TICKET_LIST -> _event.setValue(HomeEvent.ShowTicketList)
homeItemType == MY_PAGE -> _event.setValue(HomeEvent.ShowMyPage)
viewModelScope.launch {
when {
homeItemType == FESTIVAL_LIST -> _event.emit(HomeEvent.ShowFestivalList)
!authRepository.isSigned -> _event.emit(HomeEvent.ShowSignIn)
homeItemType == TICKET_LIST -> _event.emit(HomeEvent.ShowTicketList)
homeItemType == MY_PAGE -> _event.emit(HomeEvent.ShowMyPage)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import androidx.fragment.app.viewModels
import com.festago.festago.R
import com.festago.festago.databinding.FragmentTicketListBinding
import com.festago.festago.presentation.ui.ticketentry.TicketEntryActivity
import com.festago.festago.presentation.util.repeatOnStarted
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
Expand Down Expand Up @@ -44,12 +45,16 @@ class TicketListFragment : Fragment(R.layout.fragment_ticket_list) {
}

private fun initObserve() {
vm.uiState.observe(viewLifecycleOwner) {
binding.uiState = it
updateUi(it)
repeatOnStarted(viewLifecycleOwner) {
vm.uiState.collect {
binding.uiState = it
updateUi(it)
}
}
vm.event.observe(viewLifecycleOwner) { event ->
handleEvent(event)
repeatOnStarted(viewLifecycleOwner) {
vm.event.collect { event ->
handleEvent(event)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
package com.festago.festago.presentation.ui.home.ticketlist

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.festago.festago.analytics.AnalyticsHelper
import com.festago.festago.analytics.logNetworkFailure
import com.festago.festago.presentation.util.MutableSingleLiveData
import com.festago.festago.presentation.util.SingleLiveData
import com.festago.festago.repository.TicketRepository
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

Expand All @@ -19,11 +21,11 @@ class TicketListViewModel @Inject constructor(
private val analyticsHelper: AnalyticsHelper,
) : ViewModel() {

private val _uiState = MutableLiveData<TicketListUiState>(TicketListUiState.Loading)
val uiState: LiveData<TicketListUiState> = _uiState
private val _uiState = MutableStateFlow<TicketListUiState>(TicketListUiState.Loading)
val uiState: StateFlow<TicketListUiState> = _uiState.asStateFlow()

private val _event = MutableSingleLiveData<TicketListEvent>()
val event: SingleLiveData<TicketListEvent> = _event
private val _event = MutableSharedFlow<TicketListEvent>()
val event: SharedFlow<TicketListEvent> = _event.asSharedFlow()

fun loadCurrentTickets() {
viewModelScope.launch {
Expand All @@ -40,7 +42,9 @@ class TicketListViewModel @Inject constructor(
}

fun showTicketEntry(ticketId: Long) {
_event.setValue(TicketListEvent.ShowTicketEntry(ticketId))
viewModelScope.launch {
_event.emit(TicketListEvent.ShowTicketEntry(ticketId))
}
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import com.festago.festago.databinding.ActivityTicketHistoryBinding
import com.festago.festago.presentation.util.repeatOnStarted
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
Expand All @@ -30,17 +31,19 @@ class TicketHistoryActivity : AppCompatActivity() {
}

private fun initObserve() {
vm.uiState.observe(this) { uiState ->
when (uiState) {
is TicketHistoryUiState.Loading,
is TicketHistoryUiState.Error,
-> Unit

is TicketHistoryUiState.Success -> {
adapter.submitList(uiState.tickets)
repeatOnStarted(this) {
vm.uiState.collect { uiState ->
when (uiState) {
is TicketHistoryUiState.Loading,
is TicketHistoryUiState.Error,
-> Unit

is TicketHistoryUiState.Success -> {
adapter.submitList(uiState.tickets)
}
}
binding.uiState = uiState
}
binding.uiState = uiState
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package com.festago.festago.presentation.ui.tickethistory

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.festago.festago.analytics.AnalyticsHelper
import com.festago.festago.analytics.logNetworkFailure
import com.festago.festago.repository.TicketRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import javax.inject.Inject

Expand All @@ -17,14 +18,13 @@ class TicketHistoryViewModel @Inject constructor(
private val analyticsHelper: AnalyticsHelper,
) : ViewModel() {

private val _uiState = MutableLiveData<TicketHistoryUiState>()
val uiState: LiveData<TicketHistoryUiState> = _uiState
private val _uiState = MutableStateFlow<TicketHistoryUiState>(TicketHistoryUiState.Loading)
val uiState: StateFlow<TicketHistoryUiState> = _uiState.asStateFlow()

fun loadTicketHistories(size: Int = 100, refresh: Boolean = false) {
fun loadTicketHistories(size: Int = SIZE_TICKET_HISTORY, refresh: Boolean = false) {
if (!refresh && uiState.value is TicketHistoryUiState.Success) return

viewModelScope.launch {
_uiState.value = TicketHistoryUiState.Loading
ticketRepository.loadHistoryTickets(size)
.onSuccess { tickets ->
_uiState.value = TicketHistoryUiState.Success(
Expand All @@ -42,5 +42,6 @@ class TicketHistoryViewModel @Inject constructor(

companion object {
private const val KEY_LOAD_TICKET_HISTORIES_LOG = "ticket_histories"
private const val SIZE_TICKET_HISTORY = 100
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import com.festago.festago.presentation.ui.ticketreserve.adapter.TicketReserveAd
import com.festago.festago.presentation.ui.ticketreserve.adapter.TicketReserveHeaderAdapter
import com.festago.festago.presentation.ui.ticketreserve.bottomsheet.BottomSheetReservationTicketArg
import com.festago.festago.presentation.ui.ticketreserve.bottomsheet.TicketReserveBottomSheetFragment
import com.festago.festago.presentation.util.repeatOnStarted
import dagger.hilt.android.AndroidEntryPoint
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
Expand Down Expand Up @@ -53,12 +54,16 @@ class TicketReserveActivity : AppCompatActivity() {
}

private fun initObserve() {
vm.uiState.observe(this) { uiState ->
updateUi(uiState)
binding.uiState = uiState
repeatOnStarted(this) {
vm.uiState.collect { uiState ->
updateUi(uiState)
binding.uiState = uiState
}
}
vm.event.observe(this) { event ->
handleEvent(event)
repeatOnStarted(this) {
vm.event.collect { event ->
handleEvent(event)
}
}
}

Expand Down Expand Up @@ -89,7 +94,7 @@ class TicketReserveActivity : AppCompatActivity() {
id = it.id,
remainAmount = it.remainAmount,
ticketType = it.ticketType,
totalAmount = it.totalAmount
totalAmount = it.totalAmount,
)
},
).show(supportFragmentManager, TicketReserveBottomSheetFragment::class.java.name)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
package com.festago.festago.presentation.ui.ticketreserve

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.festago.festago.analytics.AnalyticsHelper
import com.festago.festago.analytics.logNetworkFailure
import com.festago.festago.model.ReservationStage
import com.festago.festago.presentation.util.MutableSingleLiveData
import com.festago.festago.presentation.util.SingleLiveData
import com.festago.festago.repository.AuthRepository
import com.festago.festago.repository.FestivalRepository
import com.festago.festago.repository.ReservationTicketRepository
import com.festago.festago.repository.TicketRepository
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 java.time.LocalDateTime
import javax.inject.Inject
Expand All @@ -26,28 +28,26 @@ class TicketReserveViewModel @Inject constructor(
private val authRepository: AuthRepository,
private val analyticsHelper: AnalyticsHelper,
) : ViewModel() {
private val _uiState = MutableLiveData<TicketReserveUiState>(TicketReserveUiState.Loading)
val uiState: LiveData<TicketReserveUiState> = _uiState
private val _uiState = MutableStateFlow<TicketReserveUiState>(TicketReserveUiState.Loading)
val uiState: StateFlow<TicketReserveUiState> = _uiState.asStateFlow()

private val _event = MutableSingleLiveData<TicketReserveEvent>()
val event: SingleLiveData<TicketReserveEvent> = _event
private val _event = MutableSharedFlow<TicketReserveEvent>()
val event: SharedFlow<TicketReserveEvent> = _event.asSharedFlow()

fun loadReservation(festivalId: Long = 0, refresh: Boolean = false) {
if (!refresh && uiState.value is TicketReserveUiState.Success) return
viewModelScope.launch {
festivalRepository.loadFestivalDetail(festivalId)
.onSuccess {
_uiState.setValue(
TicketReserveUiState.Success(
festival = ReservationFestivalUiState(
id = it.id,
name = it.name,
thumbnail = it.thumbnail,
endDate = it.endDate,
startDate = it.startDate,
),
stages = it.reservationStages.toTicketReserveItems(),
_uiState.value = TicketReserveUiState.Success(
festival = ReservationFestivalUiState(
id = it.id,
name = it.name,
thumbnail = it.thumbnail,
endDate = it.endDate,
startDate = it.startDate,
),
stages = it.reservationStages.toTicketReserveItems(),
)
}.onFailure {
_uiState.value = TicketReserveUiState.Error
Expand All @@ -64,17 +64,17 @@ class TicketReserveViewModel @Inject constructor(
if (authRepository.isSigned) {
reservationTicketRepository.loadTicketTypes(stageId)
.onSuccess { tickets ->
_event.setValue(
_event.emit(
TicketReserveEvent.ShowTicketTypes(
stageStartTime,
tickets,
),
)
}.onFailure {
_uiState.setValue(TicketReserveUiState.Error)
_uiState.value = TicketReserveUiState.Error
}
} else {
_event.setValue(TicketReserveEvent.ShowSignIn)
_event.emit(TicketReserveEvent.ShowSignIn)
}
}
}
Expand All @@ -83,9 +83,9 @@ class TicketReserveViewModel @Inject constructor(
viewModelScope.launch {
ticketRepository.reserveTicket(ticketId)
.onSuccess {
_event.setValue(TicketReserveEvent.ReserveTicketSuccess(it))
_event.emit(TicketReserveEvent.ReserveTicketSuccess(it))
}.onFailure {
_event.setValue(TicketReserveEvent.ReserveTicketFailed)
_event.emit(TicketReserveEvent.ReserveTicketFailed)
}
}
}
Expand Down
Loading

0 comments on commit c5d3472

Please sign in to comment.