Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,23 @@ class NewsViewModel(
private val lostItemRepository: LostItemRepository,
) : ViewModel() {
private val _noticeUiState: MutableStateFlow<NoticeUiState> =
MutableStateFlow(NoticeUiState.InitialLoading)
MutableStateFlow(NoticeUiState(content = NoticeUiState.Content.InitialLoading))
val noticeUiState: StateFlow<NoticeUiState> = _noticeUiState.asStateFlow()

private val _faqUiState: MutableStateFlow<FAQUiState> =
MutableStateFlow(FAQUiState.InitialLoading)
val faqUiState: StateFlow<FAQUiState> = _faqUiState.asStateFlow()

private val _lostUiState: MutableStateFlow<LostUiState> =
MutableStateFlow(LostUiState.InitialLoading)
MutableStateFlow(LostUiState(content = LostUiState.Content.InitialLoading))
val lostUiState: StateFlow<LostUiState> = _lostUiState.asStateFlow()

private var noticeIdToExpand: Long? = null

init {
loadAllNotices(NoticeUiState.InitialLoading)
loadAllNotices(NoticeUiState(content = NoticeUiState.Content.InitialLoading))
loadAllFAQs(FAQUiState.InitialLoading)
loadAllLostItems(LostUiState.InitialLoading)
loadAllLostItems(LostUiState(content = LostUiState.Content.InitialLoading))
}

fun loadAllNotices(state: NoticeUiState) {
Expand All @@ -71,10 +71,13 @@ class NewsViewModel(
if (it == -1) DEFAULT_POSITION else it
}
_noticeUiState.value =
NoticeUiState.Success(updatedNotices, expandPosition)
NoticeUiState(
content =
NoticeUiState.Content.Success(updatedNotices, expandPosition),
)
noticeIdToExpand = null
}.onFailure {
_noticeUiState.value = NoticeUiState.Error(it)
_noticeUiState.value = NoticeUiState(content = NoticeUiState.Content.Error(it))
}
}
}
Expand All @@ -93,14 +96,9 @@ class NewsViewModel(

fun expandNotice(noticeIdToExpand: Long) {
this.noticeIdToExpand = noticeIdToExpand
val notices =
when (val currentState = _noticeUiState.value) {
is NoticeUiState.Refreshing -> currentState.oldNotices
is NoticeUiState.Success -> currentState.notices
else -> return
}

loadAllNotices(NoticeUiState.Refreshing(notices))
if (_noticeUiState.value.content !is NoticeUiState.Content.InitialLoading) {
loadAllNotices(_noticeUiState.value)
}
}

fun toggleFAQ(faqItem: FAQItemUiModel) {
Expand Down Expand Up @@ -140,7 +138,7 @@ class NewsViewModel(
null -> LostUiModel.Guide()
}
}
_lostUiState.value = LostUiState.Success(lostUiModels)
_lostUiState.value = LostUiState(content = LostUiState.Content.Success(lostUiModels))
}
}

Expand All @@ -160,14 +158,19 @@ class NewsViewModel(
}

private fun updateNoticeUiState(onUpdate: (List<NoticeUiModel>) -> List<NoticeUiModel>) {
val currentState = _noticeUiState.value
_noticeUiState.value =
when (val currentState = _noticeUiState.value) {
is NoticeUiState.Success ->
when (val currentContent = currentState.content) {
is NoticeUiState.Content.Success -> {
currentState.copy(
notices = onUpdate(currentState.notices),
content =
currentContent.copy(notices = onUpdate(currentContent.notices)),
)
}

else -> currentState
else -> {
return
}
}
}

Expand All @@ -182,10 +185,18 @@ class NewsViewModel(

private fun updateLostUiState(onUpdate: (List<LostUiModel>) -> List<LostUiModel>) {
val currentState = _lostUiState.value
val currentContent = currentState.content
_lostUiState.value =
when (currentState) {
is LostUiState.Success -> currentState.copy(lostItems = onUpdate(currentState.lostItems))
else -> currentState
when (currentContent) {
is LostUiState.Content.Success -> {
_lostUiState.value.copy(
content = currentContent.copy(lostItems = onUpdate(currentContent.lostItems)),
)
}

else -> {
currentState
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,33 +35,26 @@ fun NewsScreen(
val faqUiState by newsViewModel.faqUiState.collectAsStateWithLifecycle()
val currentOnShowErrorSnackbar by rememberUpdatedState(onShowErrorSnackbar)

val isNoticeRefreshing = noticeUiState is NoticeUiState.Refreshing
val isLostItemRefreshing = lostUiState is LostUiState.Refreshing

LaunchedEffect(noticeUiState) {
when (val uiState = noticeUiState) {
is NoticeUiState.Success -> {
when (val content = noticeUiState.content) {
is NoticeUiState.Content.Success -> {
pageState.animateScrollToPage(NewsTab.NOTICE.ordinal)
}

is NoticeUiState.Error -> {
currentOnShowErrorSnackbar(uiState.throwable)
is NoticeUiState.Content.Error -> {
currentOnShowErrorSnackbar(content.throwable)
}

else -> {
Unit
}
else -> {}
}
}
LaunchedEffect(lostUiState) {
when (val uiState = lostUiState) {
is LostUiState.Error -> {
currentOnShowErrorSnackbar(uiState.throwable)
when (val content = lostUiState.content) {
is LostUiState.Content.Error -> {
currentOnShowErrorSnackbar(content.throwable)
}

else -> {
Unit
}
else -> {}
}
}

Expand All @@ -71,9 +64,7 @@ fun NewsScreen(
currentOnShowErrorSnackbar(uiState.throwable)
}

else -> {
Unit
}
else -> {}
}
}

Expand All @@ -90,17 +81,13 @@ fun NewsScreen(
noticeUiState = noticeUiState,
faqUiState = faqUiState,
lostUiState = lostUiState,
isNoticeRefreshing = isNoticeRefreshing,
isLostItemRefreshing = isLostItemRefreshing,
onNoticeRefresh = {
val oldNotices =
(noticeUiState as? NoticeUiState.Success)?.notices ?: emptyList()
newsViewModel.loadAllNotices(NoticeUiState.Refreshing(oldNotices))
val currentUiState = noticeUiState.copy(isRefreshing = true)
newsViewModel.loadAllNotices(currentUiState)
},
onLostItemRefresh = {
val oldLostItems =
(lostUiState as? LostUiState.Success)?.lostItems ?: emptyList()
newsViewModel.loadAllLostItems(LostUiState.Refreshing(oldLostItems))
val currentUiState = lostUiState.copy(isRefreshing = true)
newsViewModel.loadAllLostItems(currentUiState)
},
onNoticeClick = { newsViewModel.toggleNotice(it) },
onFaqClick = { newsViewModel.toggleFAQ(it) },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ fun NewsTabPage(
lostUiState: LostUiState,
onNoticeRefresh: () -> Unit,
onLostItemRefresh: () -> Unit,
isNoticeRefreshing: Boolean,
isLostItemRefreshing: Boolean,
onNoticeClick: (NoticeUiModel) -> Unit,
onFaqClick: (FAQItemUiModel) -> Unit,
onLostGuideClick: () -> Unit,
Expand All @@ -41,30 +39,31 @@ fun NewsTabPage(
) { index ->
val tab = NewsTab.entries[index]
when (tab) {
NewsTab.NOTICE ->
NewsTab.NOTICE -> {
NoticeScreen(
uiState = noticeUiState,
onNoticeClick = onNoticeClick,
isRefreshing = isNoticeRefreshing,
onRefresh = onNoticeRefresh,
modifier = Modifier.padding(horizontal = festabookSpacing.paddingScreenGutter),
)
}

NewsTab.FAQ ->
NewsTab.FAQ -> {
FAQScreen(
uiState = faqUiState,
onFaqClick = onFaqClick,
modifier = Modifier.padding(horizontal = festabookSpacing.paddingScreenGutter),
)
}

NewsTab.LOST_ITEM ->
NewsTab.LOST_ITEM -> {
LostItemScreen(
lostUiState = lostUiState,
onLostGuideClick = onLostGuideClick,
isRefreshing = isLostItemRefreshing,
onRefresh = onLostItemRefresh,
modifier = Modifier.padding(horizontal = festabookSpacing.paddingScreenGutter),
)
}
}
}
}
Expand All @@ -74,13 +73,11 @@ fun NewsTabPage(
private fun NewsTabPagePreview() {
NewsTabPage(
pageState = rememberPagerState { 3 },
noticeUiState = NoticeUiState.Success(emptyList(), 0),
noticeUiState = NoticeUiState(content = NoticeUiState.Content.Success(emptyList(), 0)),
faqUiState = FAQUiState.Success(emptyList()),
lostUiState = LostUiState.Success(emptyList()),
lostUiState = LostUiState(content = LostUiState.Content.Success(emptyList())),
onNoticeRefresh = {},
onLostItemRefresh = {},
isNoticeRefreshing = false,
isLostItemRefreshing = false,
onNoticeClick = {},
onFaqClick = {},
onLostGuideClick = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ package com.daedan.festabook.presentation.news.faq.component

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.daedan.festabook.R
import com.daedan.festabook.presentation.common.component.EmptyStateScreen
import com.daedan.festabook.presentation.common.component.ErrorStateScreen
import com.daedan.festabook.presentation.common.component.LoadingStateScreen
import com.daedan.festabook.presentation.news.component.NewsItem
import com.daedan.festabook.presentation.news.faq.FAQUiState
Expand All @@ -27,12 +27,13 @@ fun FAQScreen(
) {
when (uiState) {
is FAQUiState.Error -> {
LaunchedEffect(uiState) {
Timber.w(uiState.throwable.stackTraceToString())
}
Timber.w(uiState.throwable.stackTraceToString())
ErrorStateScreen(modifier = modifier.fillMaxSize())
}

is FAQUiState.InitialLoading -> LoadingStateScreen()
is FAQUiState.InitialLoading -> {
LoadingStateScreen()
}

is FAQUiState.Success -> {
if (uiState.faqs.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@ package com.daedan.festabook.presentation.news.lost

import com.daedan.festabook.presentation.news.lost.model.LostUiModel

sealed interface LostUiState {
data object InitialLoading : LostUiState
data class LostUiState(
val content: Content,
val isRefreshing: Boolean = false,
) {
sealed interface Content {
data object InitialLoading : Content

data class Refreshing(
val oldLostItems: List<LostUiModel>,
) : LostUiState
data class Success(
val lostItems: List<LostUiModel>,
) : Content

data class Success(
val lostItems: List<LostUiModel>,
) : LostUiState

data class Error(
val throwable: Throwable,
) : LostUiState
data class Error(
val throwable: Throwable,
) : Content
}
}
Loading