From fa292fb269bc63426ce557f953b23d7719d295ac Mon Sep 17 00:00:00 2001 From: HamBP Date: Sat, 7 Dec 2024 17:49:09 +0900 Subject: [PATCH 1/5] =?UTF-8?q?refactor=20:=20show=20detail=20preview?= =?UTF-8?q?=EB=A5=BC=20=EC=9C=84=ED=95=9C=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../screen/showdetail/ShowDetailScreen.kt | 125 +++++++++++++----- 1 file changed, 95 insertions(+), 30 deletions(-) diff --git a/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailScreen.kt b/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailScreen.kt index ba5448f1..0a066502 100644 --- a/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailScreen.kt +++ b/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailScreen.kt @@ -109,6 +109,7 @@ import java.time.LocalDate import java.time.LocalDateTime import kotlin.math.ceil +@OptIn(ExperimentalFoundationApi::class) @Composable fun ShowDetailScreen( onBack: () -> Unit, @@ -133,19 +134,11 @@ fun ShowDetailScreen( viewModel: ShowDetailViewModel = hiltViewModel(), ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() - val showState by flow { - while (true) { - emit(uiState.showDetail.state) - delay(200) - } - }.collectAsStateWithLifecycle(uiState.showDetail.state) val isLoggedIn by viewModel.loggedIn.collectAsStateWithLifecycle() - val scope = rememberCoroutineScope() - var showBottomSheet by remember { mutableStateOf(null) } - - val window = LocalContext.current.requireActivity().window - window.statusBarColor = MaterialTheme.colorScheme.surface.toArgb() + BackHandler { + viewModel.sendEvent(ShowDetailEvent.PopBackStack) + } LaunchedEffect(Unit) { viewModel.events.collect { event -> @@ -162,16 +155,69 @@ fun ShowDetailScreen( } } - BackHandler { - viewModel.sendEvent(ShowDetailEvent.PopBackStack) + CompositionLocalProvider(LocalOverscrollConfiguration provides null) { + ShowDetailScreen( + uiState = uiState, + onBack = onBack, + onClickHome = onClickHome, + onClickContent = onClickContent, + navigateToLogin = navigateToLogin, + navigateToImages = { viewModel.sendEvent(ShowDetailEvent.NavigateToImages(it)) }, + onTicketSelected = onTicketSelected, + onGiftTicketSelected = onGiftTicketSelected, + navigateToReport = navigateToReport, + navigateToProfile = navigateToProfile, + isLoggedIn = isLoggedIn == true, + onSelectTab = viewModel::selectTab, + modifier = modifier, + ) } +} + +@Composable +fun ShowDetailScreen( + uiState: ShowDetailUiState, + onBack: () -> Unit, + onClickHome: () -> Unit, + onClickContent: () -> Unit, + navigateToLogin: () -> Unit, + navigateToImages: (index: Int) -> Unit, + onTicketSelected: ( + showId: String, + ticketId: String, + ticketCount: Int, + isInviteTicket: Boolean, + ) -> Unit, + onGiftTicketSelected: ( + showId: String, + ticketId: String, + ticketCount: Int, + ) -> Unit, + navigateToReport: () -> Unit, + navigateToProfile: (userCode: String) -> Unit, + isLoggedIn: Boolean, + onSelectTab: (index: Int) -> Unit, + modifier: Modifier = Modifier, +) { + val showState by flow { + while (true) { + emit(uiState.showDetail.state) + delay(200) + } + }.collectAsStateWithLifecycle(uiState.showDetail.state) + + val scope = rememberCoroutineScope() + var showBottomSheet by remember { mutableStateOf(null) } + + val window = LocalContext.current.requireActivity().window + window.statusBarColor = MaterialTheme.colorScheme.surface.toArgb() Scaffold( modifier = modifier, topBar = { ShowDetailAppBar( showDetail = uiState.showDetail, - onBack = { viewModel.sendEvent(ShowDetailEvent.PopBackStack) }, + onBack = onBack, onClickHome = onClickHome, navigateToReport = navigateToReport, ) @@ -210,7 +256,7 @@ fun ShowDetailScreen( ) .background(color = MaterialTheme.colorScheme.surface) .padding(top = paddingTop), - navigateToImages = { viewModel.sendEvent(ShowDetailEvent.NavigateToImages(it)) }, + navigateToImages = navigateToImages, title = uiState.showDetail.name, images = uiState.showDetail.images.map { it.originImage } ) @@ -220,7 +266,7 @@ fun ShowDetailScreen( ContentTabRow( modifier = Modifier.padding(top = 20.dp), selectedTabIndex = uiState.selectedTab, - onSelectTab = viewModel::selectTab, + onSelectTab = onSelectTab, ) } @@ -242,7 +288,7 @@ fun ShowDetailScreen( val onTicketClicked: (TicketBottomSheetType) -> Unit = { type -> scope.launch { - if (isLoggedIn == true) { + if (isLoggedIn) { showBottomSheet = type } else { navigateToLogin() @@ -681,19 +727,17 @@ fun LazyListScope.CastTab( * 중첩 Lazy 레이아웃 처리를 위해 높이 고정 필요 */ val gridHeight = memberHeight * rows + spacedBySize * (rows - 1) - CompositionLocalProvider(LocalOverscrollConfiguration provides null) { - LazyVerticalGrid( - modifier = Modifier.height(gridHeight), - columns = GridCells.Fixed(spanCount), - verticalArrangement = Arrangement.spacedBy(spacedBySize), - horizontalArrangement = Arrangement.spacedBy(16.dp), - ) { - items(team.members) { member -> - Cast( - memberHeight, - member, - onClick = { onClickMember(member.userCode) }) - } + LazyVerticalGrid( + modifier = Modifier.height(gridHeight), + columns = GridCells.Fixed(spanCount), + verticalArrangement = Arrangement.spacedBy(spacedBySize), + horizontalArrangement = Arrangement.spacedBy(16.dp), + ) { + items(team.members) { member -> + Cast( + memberHeight, + member, + onClick = { onClickMember(member.userCode) }) } } } @@ -855,6 +899,27 @@ private fun CountDownBanner( } } +@Preview +@Composable +private fun ShowDetailScreenPreview() { + BooltiTheme { + ShowDetailScreen( + uiState = ShowDetailUiState(), + onBack = {}, + onClickHome = {}, + onClickContent = {}, + navigateToLogin = {}, + navigateToImages = {}, + onTicketSelected = { _, _, _, _ -> }, + onGiftTicketSelected = { _, _, _ -> }, + navigateToReport = {}, + navigateToProfile = {}, + isLoggedIn = true, + onSelectTab = {}, + ) + } +} + @Preview @Composable private fun CountDownBannerPreview() { From 0d1a3739a182a9ab45611df477969c452d88bac5 Mon Sep 17 00:00:00 2001 From: HamBP Date: Sun, 15 Dec 2024 20:40:45 +0900 Subject: [PATCH 2/5] =?UTF-8?q?fix=20:=20showId=20=EA=B0=80=200=20?= =?UTF-8?q?=EB=93=A4=EC=96=B4=EA=B0=80=EB=8D=98=20=EB=B2=84=EA=B7=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/screen/showdetail/ShowDetailScreen.kt | 7 ++++++- .../presentation/screen/showdetail/ShowDetailViewModel.kt | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailScreen.kt b/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailScreen.kt index 0a066502..5b532c0f 100644 --- a/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailScreen.kt +++ b/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailScreen.kt @@ -157,6 +157,7 @@ fun ShowDetailScreen( CompositionLocalProvider(LocalOverscrollConfiguration provides null) { ShowDetailScreen( + showId = viewModel.showId, uiState = uiState, onBack = onBack, onClickHome = onClickHome, @@ -176,6 +177,7 @@ fun ShowDetailScreen( @Composable fun ShowDetailScreen( + showId: String, uiState: ShowDetailUiState, onBack: () -> Unit, onClickHome: () -> Unit, @@ -220,6 +222,7 @@ fun ShowDetailScreen( onBack = onBack, onClickHome = onClickHome, navigateToReport = navigateToReport, + showId = showId, ) }, containerColor = MaterialTheme.colorScheme.background, @@ -352,6 +355,7 @@ private fun ShowDetailAppBar( onBack: () -> Unit, onClickHome: () -> Unit, navigateToReport: () -> Unit, + showId: String, ) { val context = LocalContext.current var isContextMenuVisible by rememberSaveable { @@ -360,7 +364,7 @@ private fun ShowDetailAppBar( val dateString = "${showDetail.date.showDateTimeString} -" val addressString = "${showDetail.placeName} / ${showDetail.streetAddress}, ${showDetail.detailAddress}" - val previewUrl = "https://preview.boolti.in/show/${showDetail.id}" + val previewUrl = "https://preview.boolti.in/show/${showId}" val sharingText = stringResource( R.string.show_share_format, showDetail.name, @@ -904,6 +908,7 @@ private fun CountDownBanner( private fun ShowDetailScreenPreview() { BooltiTheme { ShowDetailScreen( + showId = "1", uiState = ShowDetailUiState(), onBack = {}, onClickHome = {}, diff --git a/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailViewModel.kt b/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailViewModel.kt index 5c788ce8..c1dd1ee7 100644 --- a/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailViewModel.kt +++ b/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailViewModel.kt @@ -27,7 +27,7 @@ class ShowDetailViewModel @Inject constructor( private val showRepository: ShowRepository, authRepository: AuthRepository, ) : ViewModel() { - private val showId: String = checkNotNull(savedStateHandle["showId"]) + val showId: String = checkNotNull(savedStateHandle["showId"]) private val _uiState = MutableStateFlow(ShowDetailUiState()) val uiState: StateFlow = _uiState.asStateFlow() From f43bad8389ae09fd978217912da34a151012f334 Mon Sep 17 00:00:00 2001 From: HamBP Date: Sun, 15 Dec 2024 21:16:07 +0900 Subject: [PATCH 3/5] =?UTF-8?q?fix=20:=20=EC=83=81=EC=84=B8=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=20=ED=94=84=EB=A1=9C=EA=B7=B8=EB=A0=88=EC=8A=A4=20?= =?UTF-8?q?=EB=B0=94=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../showdetail/ShowDetailContentScreen.kt | 2 +- .../screen/showdetail/ShowDetailScreen.kt | 82 +++++++++++-------- .../screen/showdetail/ShowDetailUiState.kt | 9 +- .../screen/showdetail/ShowDetailViewModel.kt | 3 +- .../screen/showdetail/ShowImagesScreen.kt | 4 +- 5 files changed, 61 insertions(+), 39 deletions(-) diff --git a/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailContentScreen.kt b/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailContentScreen.kt index 14c8ca6f..440dee09 100644 --- a/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailContentScreen.kt +++ b/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailContentScreen.kt @@ -29,7 +29,7 @@ fun ShowDetailContentScreen( val uriHandler = LocalUriHandler.current val scrollState = rememberScrollState() val uiState by viewModel.uiState.collectAsStateWithLifecycle() - val notice = uiState.showDetail.notice + val notice = uiState.showDetail!!.notice val urlParser = UrlParser(notice) Scaffold( diff --git a/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailScreen.kt b/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailScreen.kt index 5b532c0f..69a01008 100644 --- a/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailScreen.kt +++ b/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailScreen.kt @@ -77,6 +77,7 @@ import com.nexters.boolti.domain.model.ShowDetail import com.nexters.boolti.presentation.R import com.nexters.boolti.presentation.component.BtAppBar import com.nexters.boolti.presentation.component.BtAppBarDefaults +import com.nexters.boolti.presentation.component.BtCircularProgressIndicator import com.nexters.boolti.presentation.component.ShowInquiry import com.nexters.boolti.presentation.component.SmallButton import com.nexters.boolti.presentation.component.UserThumbnail @@ -156,29 +157,42 @@ fun ShowDetailScreen( } CompositionLocalProvider(LocalOverscrollConfiguration provides null) { - ShowDetailScreen( - showId = viewModel.showId, - uiState = uiState, - onBack = onBack, - onClickHome = onClickHome, - onClickContent = onClickContent, - navigateToLogin = navigateToLogin, - navigateToImages = { viewModel.sendEvent(ShowDetailEvent.NavigateToImages(it)) }, - onTicketSelected = onTicketSelected, - onGiftTicketSelected = onGiftTicketSelected, - navigateToReport = navigateToReport, - navigateToProfile = navigateToProfile, - isLoggedIn = isLoggedIn == true, - onSelectTab = viewModel::selectTab, - modifier = modifier, - ) + if (uiState.isLoading) { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + BtCircularProgressIndicator() + } + } else if (uiState.showDetail != null) { + ShowDetailScreen( + showId = viewModel.showId, + showDetail = uiState.showDetail!!, + castTeams = uiState.castTeams, + selectedTab = uiState.selectedTab, + onBack = onBack, + onClickHome = onClickHome, + onClickContent = onClickContent, + navigateToLogin = navigateToLogin, + navigateToImages = { viewModel.sendEvent(ShowDetailEvent.NavigateToImages(it)) }, + onTicketSelected = onTicketSelected, + onGiftTicketSelected = onGiftTicketSelected, + navigateToReport = navigateToReport, + navigateToProfile = navigateToProfile, + isLoggedIn = isLoggedIn == true, + onSelectTab = viewModel::selectTab, + modifier = modifier, + ) + } } } @Composable fun ShowDetailScreen( showId: String, - uiState: ShowDetailUiState, + showDetail: ShowDetail, + castTeams: List, + selectedTab: Int, onBack: () -> Unit, onClickHome: () -> Unit, onClickContent: () -> Unit, @@ -203,10 +217,10 @@ fun ShowDetailScreen( ) { val showState by flow { while (true) { - emit(uiState.showDetail.state) + emit(showDetail.state) delay(200) } - }.collectAsStateWithLifecycle(uiState.showDetail.state) + }.collectAsStateWithLifecycle(showDetail.state) val scope = rememberCoroutineScope() var showBottomSheet by remember { mutableStateOf(null) } @@ -218,7 +232,7 @@ fun ShowDetailScreen( modifier = modifier, topBar = { ShowDetailAppBar( - showDetail = uiState.showDetail, + showDetail = showDetail, onBack = onBack, onClickHome = onClickHome, navigateToReport = navigateToReport, @@ -233,11 +247,11 @@ fun ShowDetailScreen( .padding(innerPadding), ) { val showCountdownBanner = - uiState.showDetail.salesEndDateTime.toLocalDate() == LocalDate.now() + showDetail.salesEndDateTime.toLocalDate() == LocalDate.now() val host = stringResource( id = R.string.ticketing_host_format, - uiState.showDetail.hostName, - uiState.showDetail.hostPhoneNumber, + showDetail.hostName, + showDetail.hostPhoneNumber, ) var buttonsHeight by remember { mutableStateOf(0.dp) } @@ -260,28 +274,28 @@ fun ShowDetailScreen( .background(color = MaterialTheme.colorScheme.surface) .padding(top = paddingTop), navigateToImages = navigateToImages, - title = uiState.showDetail.name, - images = uiState.showDetail.images.map { it.originImage } + title = showDetail.name, + images = showDetail.images.map { it.originImage } ) } item { ContentTabRow( modifier = Modifier.padding(top = 20.dp), - selectedTabIndex = uiState.selectedTab, + selectedTabIndex = selectedTab, onSelectTab = onSelectTab, ) } - when (uiState.selectedTab) { + when (selectedTab) { 0 -> ShowInfoTab( - showDetail = uiState.showDetail, + showDetail = showDetail, host = host, onClickContent = onClickContent, ) 1 -> CastTab( - teams = uiState.castTeams, + teams = castTeams, onClickMember = navigateToProfile, ) } @@ -315,7 +329,7 @@ fun ShowDetailScreen( if (showCountdownBanner) { CountDownBanner( - deadlineDateTime = uiState.showDetail.salesEndDateTime, + deadlineDateTime = showDetail.salesEndDateTime, ) } } @@ -326,7 +340,7 @@ fun ShowDetailScreen( onTicketingClicked = { ticket, count -> Timber.tag("MANGBAAM-(TicketScreen)").d("선택된 티켓: $ticket") onTicketSelected( - uiState.showDetail.id, + showDetail.id, ticket.id, count, ticket.isInviteTicket, @@ -335,7 +349,7 @@ fun ShowDetailScreen( }, onGiftTicketClicked = { ticket, count -> onGiftTicketSelected( - uiState.showDetail.id, + showDetail.id, ticket.id, count, ) @@ -909,7 +923,9 @@ private fun ShowDetailScreenPreview() { BooltiTheme { ShowDetailScreen( showId = "1", - uiState = ShowDetailUiState(), + showDetail = ShowDetail(), + castTeams = emptyList(), + selectedTab = 0, onBack = {}, onClickHome = {}, onClickContent = {}, diff --git a/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailUiState.kt b/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailUiState.kt index 186d1368..3c707d5b 100644 --- a/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailUiState.kt +++ b/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailUiState.kt @@ -1,10 +1,15 @@ package com.nexters.boolti.presentation.screen.showdetail +import androidx.compose.runtime.Stable import com.nexters.boolti.domain.model.CastTeams import com.nexters.boolti.domain.model.ShowDetail +@Stable data class ShowDetailUiState( - val showDetail: ShowDetail = ShowDetail(), + val showDetail: ShowDetail? = null, val selectedTab: Int = 0, val castTeams: List = emptyList(), -) + val isLoading: Boolean = true +) { + val isError: Boolean = !isLoading && showDetail == null +} diff --git a/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailViewModel.kt b/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailViewModel.kt index c1dd1ee7..9af9ba3f 100644 --- a/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailViewModel.kt +++ b/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailViewModel.kt @@ -52,9 +52,10 @@ class ShowDetailViewModel @Inject constructor( viewModelScope.launch { showRepository.searchById(id = showId) .onSuccess { newShowDetail -> - _uiState.update { it.copy(showDetail = newShowDetail) } + _uiState.update { it.copy(showDetail = newShowDetail, isLoading = false) } } .onFailure { + _uiState.update { it.copy(isLoading = false) } Firebase.crashlytics.recordException(it) Timber.e(it) } diff --git a/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowImagesScreen.kt b/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowImagesScreen.kt index 174d60ea..3b39ce59 100644 --- a/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowImagesScreen.kt +++ b/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowImagesScreen.kt @@ -33,7 +33,7 @@ fun ShowImagesScreen( val pageState = rememberPagerState( initialPage = index, initialPageOffsetFraction = 0f - ) { uiState.showDetail.images.size } + ) { uiState.showDetail!!.images.size } Scaffold( topBar = { BtCloseableAppBar(onClickClose = onBackPressed) }, @@ -57,7 +57,7 @@ fun ShowImagesScreen( modifier = Modifier .fillMaxSize() .zoomable(rememberZoomState()), - model = uiState.showDetail.images[it].originImage, + model = uiState.showDetail!!.images[it].originImage, contentDescription = null, contentScale = ContentScale.Fit, ) From 03a6a838ae10d62735dfbee12d9bca33fe0f06ee Mon Sep 17 00:00:00 2001 From: HamBP Date: Sun, 15 Dec 2024 21:36:00 +0900 Subject: [PATCH 4/5] =?UTF-8?q?fix=20:=20showDetail=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=EA=B0=80=20=ED=95=84=EC=9A=94=ED=95=9C=20=EB=B6=80=EB=B6=84?= =?UTF-8?q?=EC=9D=80=20=EB=A1=9C=EB=94=A9=20=ED=9B=84=20=EB=85=B8=EC=B6=9C?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../screen/showdetail/ShowDetailScreen.kt | 348 +++++++++--------- 1 file changed, 168 insertions(+), 180 deletions(-) diff --git a/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailScreen.kt b/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailScreen.kt index 69a01008..869e7fef 100644 --- a/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailScreen.kt +++ b/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailScreen.kt @@ -157,44 +157,50 @@ fun ShowDetailScreen( } CompositionLocalProvider(LocalOverscrollConfiguration provides null) { - if (uiState.isLoading) { - Box( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.Center - ) { - BtCircularProgressIndicator() + Scaffold( + modifier = modifier, + topBar = { + ShowDetailAppBar( + showDetail = uiState.showDetail, + onBack = onBack, + onClickHome = onClickHome, + navigateToReport = navigateToReport, + ) + }, + containerColor = MaterialTheme.colorScheme.background, + ) { innerPadding -> + if (uiState.isLoading) { + Box( + modifier = Modifier.padding(innerPadding).fillMaxSize(), + contentAlignment = Alignment.Center + ) { + BtCircularProgressIndicator() + } + } else if (uiState.showDetail != null) { + ShowDetailScreen( + modifier = Modifier.padding(innerPadding), + showDetail = uiState.showDetail!!, + castTeams = uiState.castTeams, + selectedTab = uiState.selectedTab, + onClickContent = onClickContent, + navigateToLogin = navigateToLogin, + navigateToImages = { viewModel.sendEvent(ShowDetailEvent.NavigateToImages(it)) }, + onTicketSelected = onTicketSelected, + onGiftTicketSelected = onGiftTicketSelected, + navigateToProfile = navigateToProfile, + isLoggedIn = isLoggedIn == true, + onSelectTab = viewModel::selectTab, + ) } - } else if (uiState.showDetail != null) { - ShowDetailScreen( - showId = viewModel.showId, - showDetail = uiState.showDetail!!, - castTeams = uiState.castTeams, - selectedTab = uiState.selectedTab, - onBack = onBack, - onClickHome = onClickHome, - onClickContent = onClickContent, - navigateToLogin = navigateToLogin, - navigateToImages = { viewModel.sendEvent(ShowDetailEvent.NavigateToImages(it)) }, - onTicketSelected = onTicketSelected, - onGiftTicketSelected = onGiftTicketSelected, - navigateToReport = navigateToReport, - navigateToProfile = navigateToProfile, - isLoggedIn = isLoggedIn == true, - onSelectTab = viewModel::selectTab, - modifier = modifier, - ) } } } @Composable fun ShowDetailScreen( - showId: String, showDetail: ShowDetail, castTeams: List, selectedTab: Int, - onBack: () -> Unit, - onClickHome: () -> Unit, onClickContent: () -> Unit, navigateToLogin: () -> Unit, navigateToImages: (index: Int) -> Unit, @@ -209,7 +215,6 @@ fun ShowDetailScreen( ticketId: String, ticketCount: Int, ) -> Unit, - navigateToReport: () -> Unit, navigateToProfile: (userCode: String) -> Unit, isLoggedIn: Boolean, onSelectTab: (index: Int) -> Unit, @@ -228,164 +233,137 @@ fun ShowDetailScreen( val window = LocalContext.current.requireActivity().window window.statusBarColor = MaterialTheme.colorScheme.surface.toArgb() - Scaffold( - modifier = modifier, - topBar = { - ShowDetailAppBar( - showDetail = showDetail, - onBack = onBack, - onClickHome = onClickHome, - navigateToReport = navigateToReport, - showId = showId, - ) - }, - containerColor = MaterialTheme.colorScheme.background, - ) { innerPadding -> - Box( - modifier = Modifier - .fillMaxSize() - .padding(innerPadding), - ) { - val showCountdownBanner = - showDetail.salesEndDateTime.toLocalDate() == LocalDate.now() - val host = stringResource( - id = R.string.ticketing_host_format, - showDetail.hostName, - showDetail.hostPhoneNumber, - ) + Box( + modifier = Modifier.fillMaxSize(), + ) { + val showCountdownBanner = + showDetail.salesEndDateTime.toLocalDate() == LocalDate.now() + val host = stringResource( + id = R.string.ticketing_host_format, + showDetail.hostName, + showDetail.hostPhoneNumber, + ) - var buttonsHeight by remember { mutableStateOf(0.dp) } + var buttonsHeight by remember { mutableStateOf(0.dp) } - LazyColumn( - modifier = Modifier, - ) { - item { - val paddingTop = if (showCountdownBanner) (38 + 40).dp else 16.dp - - Poster( - modifier = modifier - .fillMaxWidth() - .clip( - shape = RoundedCornerShape( - bottomStart = 20.dp, - bottomEnd = 20.dp - ) + LazyColumn( + modifier = Modifier, + ) { + item { + val paddingTop = if (showCountdownBanner) (38 + 40).dp else 16.dp + + Poster( + modifier = modifier + .fillMaxWidth() + .clip( + shape = RoundedCornerShape( + bottomStart = 20.dp, + bottomEnd = 20.dp ) - .background(color = MaterialTheme.colorScheme.surface) - .padding(top = paddingTop), - navigateToImages = navigateToImages, - title = showDetail.name, - images = showDetail.images.map { it.originImage } - ) - } - - item { - ContentTabRow( - modifier = Modifier.padding(top = 20.dp), - selectedTabIndex = selectedTab, - onSelectTab = onSelectTab, - ) - } - - when (selectedTab) { - 0 -> ShowInfoTab( - showDetail = showDetail, - host = host, - onClickContent = onClickContent, - ) - - 1 -> CastTab( - teams = castTeams, - onClickMember = navigateToProfile, - ) - } - - item { Spacer(modifier = Modifier.size(buttonsHeight)) } + ) + .background(color = MaterialTheme.colorScheme.surface) + .padding(top = paddingTop), + navigateToImages = navigateToImages, + title = showDetail.name, + images = showDetail.images.map { it.originImage } + ) } - val onTicketClicked: (TicketBottomSheetType) -> Unit = { type -> - scope.launch { - if (isLoggedIn) { - showBottomSheet = type - } else { - navigateToLogin() - } - } + item { + ContentTabRow( + modifier = Modifier.padding(top = 20.dp), + selectedTabIndex = selectedTab, + onSelectTab = onSelectTab, + ) } - AnimatedVisibility( - modifier = Modifier.align(Alignment.BottomCenter), - visible = !showState.isClosedOrFinished, - enter = EnterTransition.None, - exit = fadeOut() + shrinkOut(shrinkTowards = Alignment.TopCenter), - ) { - ShowDetailButtons( - showState = showState, - onTicketingClicked = { onTicketClicked(TicketBottomSheetType.PURCHASE) }, - onGiftClicked = { onTicketClicked(TicketBottomSheetType.GIFT) }, - onHeightChanged = { buttonsHeight = it }, + when (selectedTab) { + 0 -> ShowInfoTab( + showDetail = showDetail, + host = host, + onClickContent = onClickContent, ) - } - if (showCountdownBanner) { - CountDownBanner( - deadlineDateTime = showDetail.salesEndDateTime, + 1 -> CastTab( + teams = castTeams, + onClickMember = navigateToProfile, ) } + + item { Spacer(modifier = Modifier.size(buttonsHeight)) } } - showBottomSheet?.let { type -> - ChooseTicketBottomSheet( - ticketType = type, - onTicketingClicked = { ticket, count -> - Timber.tag("MANGBAAM-(TicketScreen)").d("선택된 티켓: $ticket") - onTicketSelected( - showDetail.id, - ticket.id, - count, - ticket.isInviteTicket, - ) - showBottomSheet = null - }, - onGiftTicketClicked = { ticket, count -> - onGiftTicketSelected( - showDetail.id, - ticket.id, - count, - ) - showBottomSheet = null - }, - onDismissRequest = { - showBottomSheet = null + val onTicketClicked: (TicketBottomSheetType) -> Unit = { type -> + scope.launch { + if (isLoggedIn) { + showBottomSheet = type + } else { + navigateToLogin() } + } + } + + AnimatedVisibility( + modifier = Modifier.align(Alignment.BottomCenter), + visible = !showState.isClosedOrFinished, + enter = EnterTransition.None, + exit = fadeOut() + shrinkOut(shrinkTowards = Alignment.TopCenter), + ) { + ShowDetailButtons( + showState = showState, + onTicketingClicked = { onTicketClicked(TicketBottomSheetType.PURCHASE) }, + onGiftClicked = { onTicketClicked(TicketBottomSheetType.GIFT) }, + onHeightChanged = { buttonsHeight = it }, + ) + } + + if (showCountdownBanner) { + CountDownBanner( + deadlineDateTime = showDetail.salesEndDateTime, ) } } + + showBottomSheet?.let { type -> + ChooseTicketBottomSheet( + ticketType = type, + onTicketingClicked = { ticket, count -> + Timber.tag("MANGBAAM-(TicketScreen)").d("선택된 티켓: $ticket") + onTicketSelected( + showDetail.id, + ticket.id, + count, + ticket.isInviteTicket, + ) + showBottomSheet = null + }, + onGiftTicketClicked = { ticket, count -> + onGiftTicketSelected( + showDetail.id, + ticket.id, + count, + ) + showBottomSheet = null + }, + onDismissRequest = { + showBottomSheet = null + } + ) + } + } @Composable private fun ShowDetailAppBar( - showDetail: ShowDetail, + showDetail: ShowDetail?, onBack: () -> Unit, onClickHome: () -> Unit, navigateToReport: () -> Unit, - showId: String, ) { val context = LocalContext.current var isContextMenuVisible by rememberSaveable { mutableStateOf(false) } - val dateString = "${showDetail.date.showDateTimeString} -" - val addressString = - "${showDetail.placeName} / ${showDetail.streetAddress}, ${showDetail.detailAddress}" - val previewUrl = "https://preview.boolti.in/show/${showId}" - val sharingText = stringResource( - R.string.show_share_format, - showDetail.name, - dateString, - addressString, - previewUrl - ) BtAppBar( colors = BtAppBarDefaults.appBarColors( @@ -404,25 +382,39 @@ private fun ShowDetailAppBar( ) }, actionButtons = { - BtAppBarDefaults.AppBarIconButton( - iconRes = R.drawable.ic_share, - description = stringResource(id = R.string.ticketing_share), - onClick = { - val sendIntent = Intent().apply { - action = Intent.ACTION_SEND - putExtra(Intent.EXTRA_TEXT, sharingText) - type = "text/plain" - } - val shareIntent = Intent.createChooser(sendIntent, null) + if (showDetail != null) { + val dateString = "${showDetail.date.showDateTimeString} -" + val addressString = + "${showDetail.placeName} / ${showDetail.streetAddress}, ${showDetail.detailAddress}" + val previewUrl = "https://preview.boolti.in/show/${showDetail.id}" + val sharingText = stringResource( + R.string.show_share_format, + showDetail.name, + dateString, + addressString, + previewUrl + ) - context.startActivity(shareIntent) - }, - ) - BtAppBarDefaults.AppBarIconButton( - iconRes = R.drawable.ic_verticle_more, - description = stringResource(id = R.string.description_more_menu), - onClick = { isContextMenuVisible = true }, - ) + BtAppBarDefaults.AppBarIconButton( + iconRes = R.drawable.ic_share, + description = stringResource(id = R.string.ticketing_share), + onClick = { + val sendIntent = Intent().apply { + action = Intent.ACTION_SEND + putExtra(Intent.EXTRA_TEXT, sharingText) + type = "text/plain" + } + val shareIntent = Intent.createChooser(sendIntent, null) + + context.startActivity(shareIntent) + }, + ) + BtAppBarDefaults.AppBarIconButton( + iconRes = R.drawable.ic_verticle_more, + description = stringResource(id = R.string.description_more_menu), + onClick = { isContextMenuVisible = true }, + ) + } }, ) @@ -922,18 +914,14 @@ private fun CountDownBanner( private fun ShowDetailScreenPreview() { BooltiTheme { ShowDetailScreen( - showId = "1", showDetail = ShowDetail(), castTeams = emptyList(), selectedTab = 0, - onBack = {}, - onClickHome = {}, onClickContent = {}, navigateToLogin = {}, navigateToImages = {}, onTicketSelected = { _, _, _, _ -> }, onGiftTicketSelected = { _, _, _ -> }, - navigateToReport = {}, navigateToProfile = {}, isLoggedIn = true, onSelectTab = {}, From c55ff7bfb17d9f95f48c3c113b28f1da6cf65707 Mon Sep 17 00:00:00 2001 From: HamBP Date: Sun, 15 Dec 2024 21:39:16 +0900 Subject: [PATCH 5/5] =?UTF-8?q?fix=20:=20!!=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../screen/showdetail/ShowDetailContentScreen.kt | 2 +- .../presentation/screen/showdetail/ShowImagesScreen.kt | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailContentScreen.kt b/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailContentScreen.kt index 440dee09..9a9d6f0a 100644 --- a/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailContentScreen.kt +++ b/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowDetailContentScreen.kt @@ -29,7 +29,7 @@ fun ShowDetailContentScreen( val uriHandler = LocalUriHandler.current val scrollState = rememberScrollState() val uiState by viewModel.uiState.collectAsStateWithLifecycle() - val notice = uiState.showDetail!!.notice + val notice = uiState.showDetail?.notice ?: return val urlParser = UrlParser(notice) Scaffold( diff --git a/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowImagesScreen.kt b/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowImagesScreen.kt index 3b39ce59..ed1ee7be 100644 --- a/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowImagesScreen.kt +++ b/presentation/src/main/java/com/nexters/boolti/presentation/screen/showdetail/ShowImagesScreen.kt @@ -30,10 +30,11 @@ fun ShowImagesScreen( viewModel: ShowDetailViewModel = hiltViewModel(), ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val showDetail = uiState.showDetail ?: return val pageState = rememberPagerState( initialPage = index, initialPageOffsetFraction = 0f - ) { uiState.showDetail!!.images.size } + ) { showDetail.images.size } Scaffold( topBar = { BtCloseableAppBar(onClickClose = onBackPressed) }, @@ -57,7 +58,7 @@ fun ShowImagesScreen( modifier = Modifier .fillMaxSize() .zoomable(rememberZoomState()), - model = uiState.showDetail!!.images[it].originImage, + model = showDetail.images[it].originImage, contentDescription = null, contentScale = ContentScale.Fit, )