[lcenavigationview-adoption] Adopt LCENavigationView across 15 screens

Standardizes the back button to a single shared component
(AppBackButtonIcon, 32x32/14pt) instead of ~16 hand-duplicated
52x52/24pt copies, and wires each screen through LCENavigationView
per this project's mandatory-usage rule. Home and Store Detail
intentionally excluded - both have bespoke header designs (collapsing
header, hero-image overlay) this change would visually disrupt.
This commit is contained in:
Daniel Arantes Loverde
2026-08-24 14:35:48 -03:00
parent 59ec6ffd6f
commit 345618426f
17 changed files with 284 additions and 486 deletions

View File

@@ -1,5 +1,8 @@
import SwiftUI
import UIKit
#if canImport(LCEssentials)
import LCEssentials
#endif
struct CheckoutView: View {
@Binding var appState: AppState
@@ -106,33 +109,11 @@ struct CheckoutView: View {
}
var body: some View {
ScrollView(showsIndicators: false) {
VStack(alignment: .leading, spacing: 18) {
screenHeader
deliveryTypeSection
addressSection
orderSummarySection
paymentSection
if let errorMessage, errorMessage.isEmpty == false {
Text(errorMessage)
.font(.caption)
.foregroundStyle(Color.red)
}
if let addressValidationMessage, addressValidationMessage.isEmpty == false {
Text(addressValidationMessage)
.font(.caption)
.foregroundStyle(addressValidationBlocked ? Color.red : AppColors.primary)
}
}
.padding(.horizontal, 20)
.padding(.top, 16)
.padding(.bottom, 10)
LCENavigationView {
content
}
.background(AppColors.backgroundLight)
.appHiddenNavigationBar()
.navigationBarBackButtonHidden(true)
.setLeftButton(image: AnyView(AppBackButtonIcon())) { dismiss() }
.setTitle(text: Text("Finalizar Pedido").font(AppTypography.heading2).foregroundStyle(AppColors.textPrimary))
.appBottomSafeAreaInset {
bottomBar
}
@@ -232,25 +213,31 @@ struct CheckoutView: View {
}
}
private var screenHeader: some View {
ZStack {
Text("Finalizar Pedido")
.font(AppTypography.heading2)
.foregroundStyle(AppColors.textPrimary)
HStack {
Button(action: { dismiss() }) {
Image(systemName: "chevron.left")
.font(.system(size: 24, weight: .semibold))
.foregroundStyle(AppColors.textPrimary)
.frame(width: 52, height: 52)
.background(AppColors.surface)
.clipShape(Circle())
.shadow(color: .black.opacity(0.06), radius: 8, y: 2)
private var content: some View {
ScrollView(showsIndicators: false) {
VStack(alignment: .leading, spacing: 18) {
deliveryTypeSection
addressSection
orderSummarySection
paymentSection
if let errorMessage, errorMessage.isEmpty == false {
Text(errorMessage)
.font(.caption)
.foregroundStyle(Color.red)
}
if let addressValidationMessage, addressValidationMessage.isEmpty == false {
Text(addressValidationMessage)
.font(.caption)
.foregroundStyle(addressValidationBlocked ? Color.red : AppColors.primary)
}
.buttonStyle(.plain)
Spacer()
}
.padding(.horizontal, 20)
.padding(.top, 16)
.padding(.bottom, 10)
}
.background(AppColors.backgroundLight)
}
private var deliveryTypeSection: some View {
@@ -730,9 +717,59 @@ struct PaymentPixView: View {
}
var body: some View {
LCENavigationView {
content
}
.setLeftButton(image: AnyView(AppBackButtonIcon())) { dismiss() }
.setTitle(text: Text("Pagamento via PIX").font(AppTypography.heading2).foregroundStyle(AppColors.textPrimary))
.sheet(isPresented: $showChangePaymentSheet) {
ChangePaymentSheet(
pixContext: currentContext,
savedCards: savedCards,
appState: $appState,
onChanged: { newContext in
showChangePaymentSheet = false
if let newContext {
currentContext = newContext
tracker.stop()
tracker.start(orderId: newContext.orderId, jwt: DefaultTokenStore().jwt)
}
},
onConfirmed: {
showChangePaymentSheet = false
onPaymentConfirmed?()
openTrackingOnce()
}
)
}
.task {
tracker.onOrderUpdated = { updated in
latestOrder = updated
if updated.isPaymentConfirmed {
onPaymentConfirmed?()
openTrackingOnce()
}
}
tracker.start(orderId: currentContext.orderId, jwt: DefaultTokenStore().jwt)
}
.task {
while Task.isCancelled == false {
currentTime = Date()
if isPixExpired {
showPixExpiredSnackbar()
return
}
try? await Task.sleep(nanoseconds: 1_000_000_000)
}
}
.onDisappear {
tracker.stop()
}
}
private var content: some View {
ScrollView(showsIndicators: false) {
VStack(spacing: 14) {
screenHeader
RoundedRectangle(cornerRadius: AppLayout.radiusLG, style: .continuous)
.fill(AppColors.surface)
.overlay(
@@ -824,72 +861,6 @@ struct PaymentPixView: View {
.padding(20)
}
.background(AppColors.backgroundLight)
.appHiddenNavigationBar()
.navigationBarBackButtonHidden(true)
.sheet(isPresented: $showChangePaymentSheet) {
ChangePaymentSheet(
pixContext: currentContext,
savedCards: savedCards,
appState: $appState,
onChanged: { newContext in
showChangePaymentSheet = false
if let newContext {
currentContext = newContext
tracker.stop()
tracker.start(orderId: newContext.orderId, jwt: DefaultTokenStore().jwt)
}
},
onConfirmed: {
showChangePaymentSheet = false
onPaymentConfirmed?()
openTrackingOnce()
}
)
}
.task {
tracker.onOrderUpdated = { updated in
latestOrder = updated
if updated.isPaymentConfirmed {
onPaymentConfirmed?()
openTrackingOnce()
}
}
tracker.start(orderId: currentContext.orderId, jwt: DefaultTokenStore().jwt)
}
.task {
while Task.isCancelled == false {
currentTime = Date()
if isPixExpired {
showPixExpiredSnackbar()
return
}
try? await Task.sleep(nanoseconds: 1_000_000_000)
}
}
.onDisappear {
tracker.stop()
}
}
private var screenHeader: some View {
ZStack {
Text("Pagamento via PIX")
.font(AppTypography.heading2)
.foregroundStyle(AppColors.textPrimary)
HStack {
Button(action: { dismiss() }) {
Image(systemName: "chevron.left")
.font(.system(size: 24, weight: .semibold))
.foregroundStyle(AppColors.textPrimary)
.frame(width: 52, height: 52)
.background(AppColors.surface)
.clipShape(Circle())
.shadow(color: .black.opacity(0.06), radius: 8, y: 2)
}
.buttonStyle(.plain)
Spacer()
}
}
}
private func openTrackingOnce() {