Skip to content

Commit

Permalink
Merge pull request #151 from Nexters/feature/Boolti-150
Browse files Browse the repository at this point in the history
Feature/boolti 150 QA 디자인 수정 및 입장 예외 정의
  • Loading branch information
mangbaam authored Feb 18, 2024
2 parents 148ad34 + 1f5d1ec commit 7526b45
Show file tree
Hide file tree
Showing 13 changed files with 97 additions and 62 deletions.
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

<application
android:name=".ui.BooltiApplication"
android:allowBackup="true"
android:allowBackup="false"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:hardwareAccelerated="true"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import com.nexters.boolti.data.datasource.HostDataSource
import com.nexters.boolti.data.datasource.TicketDataSource
import com.nexters.boolti.domain.exception.ManagerCodeErrorType
import com.nexters.boolti.domain.exception.ManagerCodeException
import com.nexters.boolti.domain.exception.QrErrorType
import com.nexters.boolti.domain.exception.QrScanException
import com.nexters.boolti.domain.extension.errorType
import com.nexters.boolti.domain.model.Ticket
import com.nexters.boolti.domain.repository.TicketRepository
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ data class ManagerCodeException(
) : Exception(errorType?.name)

enum class ManagerCodeErrorType {
Unknown, Mismatch, NotToday;
Unknown, Mismatch, ShowNotToday;

companion object {
fun fromString(type: String?): ManagerCodeErrorType {
return when (type?.trim()?.uppercase()) {
"SHOW_MANAGER_CODE_MISMATCH" -> Mismatch
"SHOW_NOT_TODAY" -> NotToday
"SHOW_NOT_TODAY" -> ShowNotToday
else -> Unknown
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ data class QrScanException(
) : Exception(errorType?.name)

enum class QrErrorType {
SHOW_NOT_TODAY;
ShowNotToday, UsedTicket, TicketNotFound;

companion object {
fun fromString(type: String?): QrErrorType? = QrErrorType.entries.find {
type?.trim()?.uppercase() == it.name
fun fromString(type: String?): QrErrorType? = when (type?.trim()?.uppercase()) {
"SHOW_NOT_TODAY" -> ShowNotToday
"USED_TICKET" -> UsedTicket
"TICKET_NOT_FOUND" -> TicketNotFound
else -> null
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ fun CopyButton(
Row(
modifier = modifier
.clip(shape = RoundedCornerShape(4.dp))
.clickable(onClick = onClick)
.height(30.dp)
.background(color = Grey85)
.padding(horizontal = 12.dp)
.clickable(onClick = onClick),
.padding(horizontal = 12.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ private fun HostedShowItem(
show: Show,
onClick: (showId: String, showName: String) -> Unit,
) {
val enable = show.date.toLocalDate().toEpochDay() < LocalDate.now().toEpochDay()
val enable = LocalDate.now().toEpochDay() <= show.date.toLocalDate().toEpochDay()
val tint = if (enable) White else Grey60

Row(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,12 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
Expand Down Expand Up @@ -57,8 +54,11 @@ fun QrScanScreen(
var showEntryCodeDialog by remember { mutableStateOf(false) }
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
val successMessage = stringResource(R.string.entry_code_validated)
val notTodayErrMessage = stringResource(R.string.entry_code_not_today)

val successMessage = stringResource(R.string.message_ticket_validated)
val notTodayErrMessage = stringResource(R.string.error_show_not_today)
val usedTicketErrMessage = stringResource(R.string.error_used_ticket)
val notMatchedErrMessage = stringResource(R.string.error_ticket_not_matched)

val uiState by viewModel.uiState.collectAsStateWithLifecycle()

Expand All @@ -69,15 +69,18 @@ fun QrScanScreen(
LaunchedEffect(viewModel.event) {
scope.launch {
viewModel.event.collect { event ->
when (event) {
val errMessage = when (event) {
is QrScanEvent.ScanError -> {
when (event.errorType) {
QrErrorType.SHOW_NOT_TODAY -> snackbarHostState.showSnackbar(notTodayErrMessage)
QrErrorType.ShowNotToday -> notTodayErrMessage
QrErrorType.UsedTicket -> usedTicketErrMessage
QrErrorType.TicketNotFound -> notMatchedErrMessage
}
}

is QrScanEvent.ScanSuccess -> snackbarHostState.showSnackbar(successMessage)
is QrScanEvent.ScanSuccess -> successMessage
}
snackbarHostState.showSnackbar(errMessage)
}
}
}
Expand Down Expand Up @@ -109,27 +112,35 @@ fun QrScanScreen(
}
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun QrScanToolbar(
showName: String,
onClickClose: () -> Unit,
) {
TopAppBar(
modifier = Modifier.height(44.dp),
title = {
Text(text = showName, overflow = TextOverflow.Ellipsis, style = MaterialTheme.typography.titleLarge)
},
colors = TopAppBarDefaults.topAppBarColors(containerColor = MaterialTheme.colorScheme.background),
actions = {
IconButton(onClick = onClickClose) {
Icon(
painter = painterResource(R.drawable.ic_close),
contentDescription = stringResource(R.string.description_close_button),
)
}
Row(
modifier = Modifier
.background(MaterialTheme.colorScheme.background)
.height(44.dp)
.padding(horizontal = 20.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Text(
modifier = Modifier
.padding(end = 20.dp)
.weight(1f),
text = showName,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.titleLarge,
color = MaterialTheme.colorScheme.onBackground,
)
IconButton(onClick = onClickClose) {
Icon(
painter = painterResource(R.drawable.ic_close),
tint = MaterialTheme.colorScheme.onBackground,
contentDescription = stringResource(R.string.description_close_button),
)
}
)
}
}

@Composable
Expand All @@ -144,12 +155,13 @@ private fun QrScanBottombar(onClick: () -> Unit) {
modifier = Modifier
.clickable(onClick = onClick)
.padding(20.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center,
) {
Icon(
modifier = Modifier
.size(20.dp)
.padding(end = 4.dp),
.padding(top = 2.dp, end = 4.dp),
painter = painterResource(id = R.drawable.ic_book),
tint = Grey50,
contentDescription = stringResource(R.string.show_entry_code),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,10 +291,11 @@ private fun ShowDetailAppBar(
.wrapContentSize(Alignment.TopEnd),
) {
DropdownMenu(
modifier = Modifier.background(Grey20),
expanded = isContextMenuVisible,
onDismissRequest = { isContextMenuVisible = false }) {
onDismissRequest = { isContextMenuVisible = false },
) {
DropdownMenuItem(
modifier = Modifier.background(Grey20),
text = {
Text(
text = stringResource(id = R.string.report),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ private fun Title(
) {
Text(
modifier = Modifier.weight(1f),
text = stringResource(R.string.ticket_title, ticketName, count),
text = if (count > 1) stringResource(R.string.ticket_title, ticketName, count) else ticketName,
style = MaterialTheme.typography.bodySmall,
color = Grey80,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
Expand Down Expand Up @@ -99,7 +98,7 @@ fun ManagerCodeDialog(
val message = when (error) {
ManagerCodeErrorType.Unknown -> stringResource(R.string.message_unknown_error)
ManagerCodeErrorType.Mismatch -> stringResource(R.string.enter_code_dialog_error_mismatch)
ManagerCodeErrorType.NotToday -> stringResource(R.string.enter_code_dialog_error_not_today)
ManagerCodeErrorType.ShowNotToday -> stringResource(R.string.error_show_not_today)
}
Text(
text = message,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import coil.compose.AsyncImage
import com.nexters.boolti.domain.model.TicketState
import com.nexters.boolti.presentation.R
import com.nexters.boolti.presentation.component.BTDialog
import com.nexters.boolti.presentation.component.DottedDivider
import com.nexters.boolti.presentation.component.ToastSnackbarHost
import com.nexters.boolti.presentation.extension.dayOfWeekString
Expand All @@ -100,6 +101,7 @@ import com.nexters.boolti.presentation.util.TicketShape
import com.nexters.boolti.presentation.util.asyncImageBlurModel
import com.nexters.boolti.presentation.util.rememberQrBitmapPainter
import kotlinx.coroutines.launch
import java.time.LocalDate
import java.time.LocalDateTime

@OptIn(ExperimentalMaterial3Api::class)
Expand Down Expand Up @@ -131,7 +133,7 @@ fun TicketDetailScreen(

val pullToRefreshState = rememberPullToRefreshState()

val entranceSuccessMsg = stringResource(R.string.entry_code_validated)
val entranceSuccessMsg = stringResource(R.string.message_ticket_validated)
LaunchedEffect(viewModel.event) {
viewModel.event.collect {
when (it) {
Expand Down Expand Up @@ -285,16 +287,18 @@ fun TicketDetailScreen(
Spacer(modifier = Modifier.size(20.dp))
RefundPolicySection(uiState.refundPolicy)

Text(
modifier = Modifier
.padding(top = 20.dp, bottom = 60.dp)
.align(Alignment.CenterHorizontally)
.clickable { showEnterCodeDialog = true },
text = stringResource(R.string.input_enter_code_button),
style = MaterialTheme.typography.bodySmall,
color = Grey50,
textDecoration = TextDecoration.Underline,
)
if (uiState.ticket.ticketState == TicketState.Ready) {
Text(
modifier = Modifier
.padding(top = 20.dp, bottom = 60.dp)
.align(Alignment.CenterHorizontally)
.clickable { showEnterCodeDialog = true },
text = stringResource(R.string.input_enter_code_button),
style = MaterialTheme.typography.bodySmall,
color = Grey50,
textDecoration = TextDecoration.Underline,
)
}
}
PullToRefreshContainer(
modifier = Modifier.align(Alignment.TopCenter),
Expand All @@ -304,13 +308,28 @@ fun TicketDetailScreen(
}

if (showEnterCodeDialog) {
ManagerCodeDialog(
managerCode = managerCodeState.code,
onManagerCodeChanged = viewModel::setManagerCode,
error = managerCodeState.error,
onDismiss = { showEnterCodeDialog = false },
onClickConfirm = { viewModel.requestEntrance(it) }
)
if (LocalDate.now().toEpochDay() < uiState.ticket.showDate.toLocalDate().toEpochDay()) {
// 아직 공연일 아님
BTDialog(
showCloseButton = false,
onClickPositiveButton = { showEnterCodeDialog = false },
onDismiss = { showEnterCodeDialog = false },
) {
Text(
text = stringResource(R.string.error_show_not_today),
style = MaterialTheme.typography.titleLarge,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
} else if (uiState.ticket.ticketState == TicketState.Ready) {
ManagerCodeDialog(
managerCode = managerCodeState.code,
onManagerCodeChanged = viewModel::setManagerCode,
error = managerCodeState.error,
onDismiss = { showEnterCodeDialog = false },
onClickConfirm = { viewModel.requestEntrance(it) }
)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,8 @@ private fun DeposorSection(
Row(
modifier = Modifier
.padding(start = 20.dp)
.clickable(role = Role.Checkbox, onClick = onClickSameContact)
.clickable(role = Role.Checkbox, onClick = onClickSameContact),
verticalAlignment = Alignment.CenterVertically,
) {
if (isSameContactInfo) {
Icon(
Expand Down
8 changes: 5 additions & 3 deletions presentation/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
<string name="description_expand">확장하기</string>
<string name="description_qr_icon">QR 스캔 아이콘</string>

<string name="error_show_not_today">아직 공연일이 아니에요</string>
<string name="error_used_ticket">이미 사용된 티켓이에요</string>
<string name="error_ticket_not_matched">이 공연의 티켓이 아니에요</string>

<!-- 유효성 검사 -->
<string name="validation_name">이름을 올바르게 입력해 주세요</string>
<string name="validation_contact">연락처를 올바르게 입력해 주세요</string>
Expand Down Expand Up @@ -133,7 +137,6 @@
<string name="enter_code_dialog_desc">입장 코드는 주최자 계정의 마이 > QR 스캔 > 해당 공연 스캐너에서 확인 가능해요.</string>
<string name="enter_code_dialog_placeholder">입장 코드를 입력해 주세요</string>
<string name="enter_code_dialog_error_mismatch">올바른 입장 코드를 입력해 주세요</string>
<string name="enter_code_dialog_error_not_today">오늘 공연이 아닙니다</string>
<string name="show_entry_code">입장코드 보기</string>

<!-- 결제 -->
Expand All @@ -160,8 +163,7 @@
<string name="hostedShowsTitle">QR 스캔</string>
<string name="hosted_shows_empty_label">주최한 공연이 없어요</string>
<string name="hosted_shows_empty_desc">공연을 주최하고 QR 스캐너로\n관객 입장을 관리해 보세요</string>
<string name="entry_code_validated">입장을 확인했어요</string>
<string name="entry_code_not_today">입장 확인은 공연 당일에만 가능해요</string>
<string name="message_ticket_validated">사용되었어요</string>

<!-- 예매 내역 -->
<string name="reservations_empty">예매 내역이 없어요</string>
Expand Down

0 comments on commit 7526b45

Please sign in to comment.