Skip to content
3 changes: 1 addition & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ android {
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'

buildConfigField "boolean", "MOCK_AUTH", "false"
buildConfigField "String", "GOODROAD_SERVER_URL", "\"https://93.77.188.216.nip.io/\""
}
buildConfigField "String", "GOODROAD_SERVER_URL", "\"http://10.0.2.2:8080/\"" }

buildTypes {
release {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ import com.example.goodroad.ui.theme.BackgroundLight
import com.example.goodroad.ui.theme.UrbanBrown
import com.example.goodroad.ui.theme.SafeGreen
import com.example.goodroad.ui.theme.AlertRed
import androidx.compose.ui.graphics.Color
import com.example.goodroad.ui.buttons.PrimaryButton
import com.example.goodroad.ui.theme.TextPrimary


@Composable
fun RewardDetailScreen(
viewModel: RewardsViewModel,
Expand All @@ -31,16 +31,15 @@ fun RewardDetailScreen(
onBack: () -> Unit
) {
val state by viewModel.state.collectAsStateWithLifecycle()

var showConfirmation by remember { mutableStateOf(false) }
var isPurchasing by remember { mutableStateOf(false) }

val account = state.account

LaunchedEffect(state.purchaseResult) {
if (state.purchaseResult != null && isPurchasing) {
LaunchedEffect(state.error, state.purchaseResult) {
if (state.error != null || state.purchaseResult != null) {
isPurchasing = false
onPurchaseComplete()
viewModel.clearPurchaseResult()
}
}

Expand All @@ -53,6 +52,7 @@ fun RewardDetailScreen(
.fillMaxSize()
.padding(24.dp)
) {

Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
Expand Down Expand Up @@ -84,19 +84,24 @@ fun RewardDetailScreen(
colors = CardDefaults.cardColors(
containerColor = UrbanBrown.copy(alpha = 0.06f)
),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp)
elevation = CardDefaults.cardElevation(
defaultElevation = 0.dp
)
) {
Column(
modifier = Modifier.padding(24.dp)
) {

Text(
text = "ПАРТНЁР",
fontSize = 14.sp,
fontWeight = FontWeight.Medium,
color = UrbanBrown.copy(alpha = 1.5f),
letterSpacing = 1.sp
)

Spacer(modifier = Modifier.height(4.dp))

Text(
text = reward.partnerName,
fontSize = 20.sp,
Expand All @@ -120,7 +125,9 @@ fun RewardDetailScreen(
color = UrbanBrown.copy(alpha = 1.5f),
letterSpacing = 1.sp
)

Spacer(modifier = Modifier.height(8.dp))

Text(
text = reward.description ?: "Нет описания",
fontSize = 16.sp,
Expand All @@ -142,13 +149,15 @@ fun RewardDetailScreen(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {

Text(
text = "СТОИМОСТЬ",
fontSize = 14.sp,
fontWeight = FontWeight.Medium,
color = UrbanBrown.copy(alpha = 1.6f),
letterSpacing = 1.sp
)

Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(6.dp)
Expand All @@ -157,6 +166,7 @@ fun RewardDetailScreen(
text = "⭐",
fontSize = 28.sp
)

Text(
text = "${reward.price}",
fontSize = 32.sp,
Expand All @@ -171,14 +181,17 @@ fun RewardDetailScreen(
Spacer(modifier = Modifier.height(24.dp))

if (account != null) {

Card(
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(12.dp)),
colors = CardDefaults.cardColors(
containerColor = SafeGreen.copy(alpha = 0.08f)
),
elevation = CardDefaults.cardElevation(defaultElevation = 0.dp)
elevation = CardDefaults.cardElevation(
defaultElevation = 0.dp
)
) {
Row(
modifier = Modifier
Expand All @@ -187,12 +200,14 @@ fun RewardDetailScreen(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {

Text(
text = "Ваш баланс",
fontSize = 16.sp,
fontWeight = FontWeight.Medium,
color = UrbanBrown
)

Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(4.dp)
Expand All @@ -201,6 +216,7 @@ fun RewardDetailScreen(
text = "⭐",
fontSize = 20.sp
)

Text(
text = "${account.balance}",
fontSize = 24.sp,
Expand All @@ -216,6 +232,7 @@ fun RewardDetailScreen(
val canBuy = account.balance >= reward.price

if (isPurchasing) {

Box(
modifier = Modifier
.fillMaxWidth()
Expand All @@ -228,23 +245,37 @@ fun RewardDetailScreen(
color = UrbanBrown
)
}

} else {

PrimaryButton(
text = if (canBuy) "Купить за ${reward.price} баллов" else "Недостаточно баллов",
backgroundColor = if (canBuy) SafeGreen else UrbanBrown,
text = if (canBuy) {
"Купить за ${reward.price} баллов"
} else {
"Недостаточно баллов"
},
backgroundColor = if (canBuy) {
SafeGreen
} else {
UrbanBrown
},
modifier = Modifier
.fillMaxWidth()
.height(56.dp),
enabled = canBuy,
onClick = { showConfirmation = true }
onClick = {
showConfirmation = true
}
)
}
}

if (state.error != null) {

Spacer(modifier = Modifier.height(12.dp))

Text(
text = state.error ?: "Ошибка",
text = mapRewardError(state.error),
color = AlertRed,
fontSize = 14.sp,
modifier = Modifier.fillMaxWidth()
Expand All @@ -254,21 +285,27 @@ fun RewardDetailScreen(
}

if (showConfirmation) {

AlertDialog(
onDismissRequest = { showConfirmation = false },
onDismissRequest = {
showConfirmation = false
},

title = {
Text(
text = "Подтверждение покупки",
fontWeight = FontWeight.Bold,
color = UrbanBrown
)
},

text = {
Text(
text = "Вы уверены, что хотите купить \"${reward.title}\" за ${reward.price} баллов?",
color = UrbanBrown.copy(alpha = 0.8f)
)
},

confirmButton = {
TextButton(
onClick = {
Expand All @@ -277,15 +314,69 @@ fun RewardDetailScreen(
viewModel.purchaseReward(reward.id)
}
) {
Text("Купить", color = SafeGreen, fontWeight = FontWeight.SemiBold)
Text(
text = "Купить",
color = SafeGreen,
fontWeight = FontWeight.SemiBold
)
}
},

dismissButton = {
TextButton(onClick = { showConfirmation = false }) {
Text("Отмена", color = UrbanBrown)
TextButton(
onClick = {
showConfirmation = false
}
) {
Text(
text = "Отмена",
color = UrbanBrown
)
}
},

shape = RoundedCornerShape(16.dp)
)
}
}
}


private fun mapRewardError(error: String?): String {
return when (error) {
"REWARD_OUT_OF_STOCK" ->
"Эта награда закончилась"

"REWARD_NOT_FOUND" ->
"Награда не найдена"

"REWARD_PURCHASE_NOT_CONFIRMED" ->
"Подтвердите покупку награды"

"USER_REWARD_NOT_FOUND" ->
"Купленная награда не найдена"

"USER_REWARD_NOT_ACTIVE" ->
"Эта награда уже неактивна"

"USER_REWARD_EXPIRED" ->
"Срок действия награды истёк"

"INSUFFICIENT_POINTS" ->
"Недостаточно баллов для покупки"

"USER_PHONE_NOT_FOUND" ->
"Пользователь не найден"

"REWARD_ID_INVALID" ->
"Некорректный идентификатор награды"

"REWARD_PRICE_FILTER_INVALID" ->
"Указан некорректный диапазон стоимости"

"REWARD_SORT_INVALID" ->
"Некорректный тип сортировки"

else ->
error ?: "Не удалось выполнить покупку"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ class AuthViewModel(private val context: Context) : ViewModel() {
}
}

fun setError(message: String) {
_error.value = message
}

private enum class AuthAction {
LOGIN,
REGISTER,
Expand Down
Loading