Lixo
@@ -928,3 +928,5 @@ Para dashboard da loja e análise de produto, usar:
|
|||||||
**Compatibilidade Store:**
|
**Compatibilidade Store:**
|
||||||
- O painel `/store/reviews` segue funcional com os campos legados (`rate`, `message`, `itemFeedback`, `improvementFeedback`, `deliveryFeedback`).
|
- O painel `/store/reviews` segue funcional com os campos legados (`rate`, `message`, `itemFeedback`, `improvementFeedback`, `deliveryFeedback`).
|
||||||
- Campos novos coexistem para evolução gradual sem quebrar o fluxo atual.
|
- Campos novos coexistem para evolução gradual sem quebrar o fluxo atual.
|
||||||
|
|
||||||
|
Autor: Daniel Arantes Loverde
|
||||||
|
|||||||
@@ -638,3 +638,5 @@ Assina o contrato draft atual da loja.
|
|||||||
### 14. Visualizar PDF do Contrato
|
### 14. Visualizar PDF do Contrato
|
||||||
**GET** `/api/store/contract/:contractId/pdf`
|
**GET** `/api/store/contract/:contractId/pdf`
|
||||||
Retorna o stream do arquivo PDF do contrato (draft ou assinado).
|
Retorna o stream do arquivo PDF do contrato (draft ou assinado).
|
||||||
|
|
||||||
|
Autor: Daniel Arantes Loverde
|
||||||
|
|||||||
@@ -98,3 +98,5 @@ FEATURE_CONTROL_MODULE_TOKEN="550e8400-e29b-41d4-a716-44665544000b" npm start
|
|||||||
cd feature-control-bff
|
cd feature-control-bff
|
||||||
npm test
|
npm test
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Autor: Daniel Arantes Loverde
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 82 KiB |
@@ -1,116 +1,44 @@
|
|||||||
{
|
{
|
||||||
"images": [
|
"images" : [
|
||||||
{
|
{ "filename" : "icon_iphone_20pt@2x.png", "idiom" : "iphone", "scale" : "2x", "size" : "20x20" },
|
||||||
"idiom": "iphone",
|
{ "appearances" : [ { "appearance" : "luminosity", "value" : "dark" } ], "filename" : "icon_iphone_20pt@2x_dark.png", "idiom" : "iphone", "scale" : "2x", "size" : "20x20" },
|
||||||
"size": "20x20",
|
{ "filename" : "icon_iphone_20pt@3x.png", "idiom" : "iphone", "scale" : "3x", "size" : "20x20" },
|
||||||
"scale": "2x",
|
{ "appearances" : [ { "appearance" : "luminosity", "value" : "dark" } ], "filename" : "icon_iphone_20pt@3x_dark.png", "idiom" : "iphone", "scale" : "3x", "size" : "20x20" },
|
||||||
"filename": "icon_iphone_20pt@2x.png"
|
{ "filename" : "icon_iphone_29pt@2x.png", "idiom" : "iphone", "scale" : "2x", "size" : "29x29" },
|
||||||
},
|
{ "appearances" : [ { "appearance" : "luminosity", "value" : "dark" } ], "filename" : "icon_iphone_29pt@2x_dark.png", "idiom" : "iphone", "scale" : "2x", "size" : "29x29" },
|
||||||
{
|
{ "filename" : "icon_iphone_29pt@3x.png", "idiom" : "iphone", "scale" : "3x", "size" : "29x29" },
|
||||||
"idiom": "iphone",
|
{ "appearances" : [ { "appearance" : "luminosity", "value" : "dark" } ], "filename" : "icon_iphone_29pt@3x_dark.png", "idiom" : "iphone", "scale" : "3x", "size" : "29x29" },
|
||||||
"size": "20x20",
|
{ "filename" : "icon_iphone_40pt@2x.png", "idiom" : "iphone", "scale" : "2x", "size" : "40x40" },
|
||||||
"scale": "3x",
|
{ "appearances" : [ { "appearance" : "luminosity", "value" : "dark" } ], "filename" : "icon_iphone_40pt@2x_dark.png", "idiom" : "iphone", "scale" : "2x", "size" : "40x40" },
|
||||||
"filename": "icon_iphone_20pt@3x.png"
|
{ "filename" : "icon_iphone_40pt@3x.png", "idiom" : "iphone", "scale" : "3x", "size" : "40x40" },
|
||||||
},
|
{ "appearances" : [ { "appearance" : "luminosity", "value" : "dark" } ], "filename" : "icon_iphone_40pt@3x_dark.png", "idiom" : "iphone", "scale" : "3x", "size" : "40x40" },
|
||||||
{
|
{ "filename" : "icon_iphone_60pt@2x.png", "idiom" : "iphone", "scale" : "2x", "size" : "60x60" },
|
||||||
"idiom": "iphone",
|
{ "appearances" : [ { "appearance" : "luminosity", "value" : "dark" } ], "filename" : "icon_iphone_60pt@2x_dark.png", "idiom" : "iphone", "scale" : "2x", "size" : "60x60" },
|
||||||
"size": "29x29",
|
{ "filename" : "icon_iphone_60pt@3x.png", "idiom" : "iphone", "scale" : "3x", "size" : "60x60" },
|
||||||
"scale": "2x",
|
{ "appearances" : [ { "appearance" : "luminosity", "value" : "dark" } ], "filename" : "icon_iphone_60pt@3x_dark.png", "idiom" : "iphone", "scale" : "3x", "size" : "60x60" },
|
||||||
"filename": "icon_iphone_29pt@2x.png"
|
{ "filename" : "icon_ipad_20pt@1x.png", "idiom" : "ipad", "scale" : "1x", "size" : "20x20" },
|
||||||
},
|
{ "appearances" : [ { "appearance" : "luminosity", "value" : "dark" } ], "filename" : "icon_ipad_20pt@1x_dark.png", "idiom" : "ipad", "scale" : "1x", "size" : "20x20" },
|
||||||
{
|
{ "filename" : "icon_ipad_20pt@2x.png", "idiom" : "ipad", "scale" : "2x", "size" : "20x20" },
|
||||||
"idiom": "iphone",
|
{ "appearances" : [ { "appearance" : "luminosity", "value" : "dark" } ], "filename" : "icon_ipad_20pt@2x_dark.png", "idiom" : "ipad", "scale" : "2x", "size" : "20x20" },
|
||||||
"size": "29x29",
|
{ "filename" : "icon_ipad_29pt@1x.png", "idiom" : "ipad", "scale" : "1x", "size" : "29x29" },
|
||||||
"scale": "3x",
|
{ "appearances" : [ { "appearance" : "luminosity", "value" : "dark" } ], "filename" : "icon_ipad_29pt@1x_dark.png", "idiom" : "ipad", "scale" : "1x", "size" : "29x29" },
|
||||||
"filename": "icon_iphone_29pt@3x.png"
|
{ "filename" : "icon_ipad_29pt@2x.png", "idiom" : "ipad", "scale" : "2x", "size" : "29x29" },
|
||||||
},
|
{ "appearances" : [ { "appearance" : "luminosity", "value" : "dark" } ], "filename" : "icon_ipad_29pt@2x_dark.png", "idiom" : "ipad", "scale" : "2x", "size" : "29x29" },
|
||||||
{
|
{ "filename" : "icon_ipad_40pt@1x.png", "idiom" : "ipad", "scale" : "1x", "size" : "40x40" },
|
||||||
"idiom": "iphone",
|
{ "appearances" : [ { "appearance" : "luminosity", "value" : "dark" } ], "filename" : "icon_ipad_40pt@1x_dark.png", "idiom" : "ipad", "scale" : "1x", "size" : "40x40" },
|
||||||
"size": "40x40",
|
{ "filename" : "icon_ipad_40pt@2x.png", "idiom" : "ipad", "scale" : "2x", "size" : "40x40" },
|
||||||
"scale": "2x",
|
{ "appearances" : [ { "appearance" : "luminosity", "value" : "dark" } ], "filename" : "icon_ipad_40pt@2x_dark.png", "idiom" : "ipad", "scale" : "2x", "size" : "40x40" },
|
||||||
"filename": "icon_iphone_40pt@2x.png"
|
{ "filename" : "icon_ipad_76pt@1x.png", "idiom" : "ipad", "scale" : "1x", "size" : "76x76" },
|
||||||
},
|
{ "appearances" : [ { "appearance" : "luminosity", "value" : "dark" } ], "filename" : "icon_ipad_76pt@1x_dark.png", "idiom" : "ipad", "scale" : "1x", "size" : "76x76" },
|
||||||
{
|
{ "filename" : "icon_ipad_76pt@2x.png", "idiom" : "ipad", "scale" : "2x", "size" : "76x76" },
|
||||||
"idiom": "iphone",
|
{ "appearances" : [ { "appearance" : "luminosity", "value" : "dark" } ], "filename" : "icon_ipad_76pt@2x_dark.png", "idiom" : "ipad", "scale" : "2x", "size" : "76x76" },
|
||||||
"size": "40x40",
|
{ "filename" : "icon_ipad_83.5pt@2x.png", "idiom" : "ipad", "scale" : "2x", "size" : "83.5x83.5" },
|
||||||
"scale": "3x",
|
{ "appearances" : [ { "appearance" : "luminosity", "value" : "dark" } ], "filename" : "icon_ipad_83.5pt@2x_dark.png", "idiom" : "ipad", "scale" : "2x", "size" : "83.5x83.5" },
|
||||||
"filename": "icon_iphone_40pt@3x.png"
|
{ "filename" : "icon_ios-marketing_1024pt@1x.png", "idiom" : "ios-marketing", "scale" : "1x", "size" : "1024x1024" },
|
||||||
},
|
{ "appearances" : [ { "appearance" : "luminosity", "value" : "dark" } ], "filename" : "icon_ios-marketing_1024pt@1x_dark.png", "idiom" : "ios-marketing", "scale" : "1x", "size" : "1024x1024" }
|
||||||
{
|
|
||||||
"idiom": "iphone",
|
|
||||||
"size": "60x60",
|
|
||||||
"scale": "2x",
|
|
||||||
"filename": "icon_iphone_60pt@2x.png"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom": "iphone",
|
|
||||||
"size": "60x60",
|
|
||||||
"scale": "3x",
|
|
||||||
"filename": "icon_iphone_60pt@3x.png"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom": "ipad",
|
|
||||||
"size": "20x20",
|
|
||||||
"scale": "1x",
|
|
||||||
"filename": "icon_ipad_20pt@1x.png"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom": "ipad",
|
|
||||||
"size": "20x20",
|
|
||||||
"scale": "2x",
|
|
||||||
"filename": "icon_ipad_20pt@2x.png"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom": "ipad",
|
|
||||||
"size": "29x29",
|
|
||||||
"scale": "1x",
|
|
||||||
"filename": "icon_ipad_29pt@1x.png"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom": "ipad",
|
|
||||||
"size": "29x29",
|
|
||||||
"scale": "2x",
|
|
||||||
"filename": "icon_ipad_29pt@2x.png"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom": "ipad",
|
|
||||||
"size": "40x40",
|
|
||||||
"scale": "1x",
|
|
||||||
"filename": "icon_ipad_40pt@1x.png"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom": "ipad",
|
|
||||||
"size": "40x40",
|
|
||||||
"scale": "2x",
|
|
||||||
"filename": "icon_ipad_40pt@2x.png"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom": "ipad",
|
|
||||||
"size": "76x76",
|
|
||||||
"scale": "1x",
|
|
||||||
"filename": "icon_ipad_76pt@1x.png"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom": "ipad",
|
|
||||||
"size": "76x76",
|
|
||||||
"scale": "2x",
|
|
||||||
"filename": "icon_ipad_76pt@2x.png"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom": "ipad",
|
|
||||||
"size": "83.5x83.5",
|
|
||||||
"scale": "2x",
|
|
||||||
"filename": "icon_ipad_83.5pt@2x.png"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom": "ios-marketing",
|
|
||||||
"size": "1024x1024",
|
|
||||||
"scale": "1x",
|
|
||||||
"filename": "icon_ios-marketing_1024pt@1x.png"
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
"info": {
|
"info" : {
|
||||||
"version": 1,
|
"author" : "xcode",
|
||||||
"author": "xcode"
|
"version" : 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 82 KiB |
@@ -1,4 +1,4 @@
|
|||||||
# Plano - Tela de Perfil
|
e# Plano - Tela de Perfil
|
||||||
|
|
||||||
Legenda:
|
Legenda:
|
||||||
- 🟢 Concluído
|
- 🟢 Concluído
|
||||||
@@ -28,3 +28,4 @@ Legenda:
|
|||||||
- Configurações/Ajuda (confirmar nomenclatura final)
|
- Configurações/Ajuda (confirmar nomenclatura final)
|
||||||
- 🔴 Corrigir build global do projeto (dependência `LCEssentials` ausente em `StoreDetailView.swift`)
|
- 🔴 Corrigir build global do projeto (dependência `LCEssentials` ausente em `StoreDetailView.swift`)
|
||||||
|
|
||||||
|
Autor: Daniel Arantes Loverde
|
||||||
|
|||||||
@@ -49,3 +49,4 @@ Implicação:
|
|||||||
1. Mudança de splash para iOS pode ser feita sem tocar Android.
|
1. Mudança de splash para iOS pode ser feita sem tocar Android.
|
||||||
2. Quando Android for tratado, deve entrar em camada própria (tema/recursos Android), sem impactar o fluxo iOS.
|
2. Quando Android for tratado, deve entrar em camada própria (tema/recursos Android), sem impactar o fluxo iOS.
|
||||||
|
|
||||||
|
Autor: Daniel Arantes Loverde
|
||||||
|
|||||||
@@ -58,3 +58,5 @@ Kotlin JUnit tests in the Robolectric Android simulation environment.
|
|||||||
|
|
||||||
Parity testing can be performed with `skip test`,
|
Parity testing can be performed with `skip test`,
|
||||||
which will output a table of the test results for both platforms.
|
which will output a table of the test results for both platforms.
|
||||||
|
|
||||||
|
Autor: Daniel Arantes Loverde
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ struct SecondaryButton: View {
|
|||||||
image
|
image
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.foregroundStyle(AppColors.textInverse)
|
.foregroundStyle(AppColors.textPrimary)
|
||||||
.frame(maxWidth: fullWidth ? .infinity : nil)
|
.frame(maxWidth: fullWidth ? .infinity : nil)
|
||||||
.frame(height: 56)
|
.frame(height: 56)
|
||||||
.background(AppColors.secondary)
|
.background(AppColors.secondary)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ struct SearchField: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(spacing: 12) {
|
HStack(spacing: 12) {
|
||||||
Image(systemName: "magnifyingglass")
|
Image(systemName: "magnifyingglass")
|
||||||
.foregroundStyle(AppColors.secondary)
|
.foregroundStyle(AppColors.primary)
|
||||||
TextField(placeholder, text: $text)
|
TextField(placeholder, text: $text)
|
||||||
.appNoAutoCap()
|
.appNoAutoCap()
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,7 @@ struct SearchField: View {
|
|||||||
.clipShape(RoundedRectangle(cornerRadius: AppLayout.radiusLG, style: .continuous))
|
.clipShape(RoundedRectangle(cornerRadius: AppLayout.radiusLG, style: .continuous))
|
||||||
.overlay(
|
.overlay(
|
||||||
RoundedRectangle(cornerRadius: AppLayout.radiusLG, style: .continuous)
|
RoundedRectangle(cornerRadius: AppLayout.radiusLG, style: .continuous)
|
||||||
.stroke(AppColors.secondary.opacity(0.15), lineWidth: 1)
|
.stroke(AppColors.primary.opacity(0.15), lineWidth: 1)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -30,14 +30,14 @@ struct PillButton: View {
|
|||||||
Text(title)
|
Text(title)
|
||||||
.font(AppTypography.caption)
|
.font(AppTypography.caption)
|
||||||
.tracking(AppTypography.captionLetterSpacing)
|
.tracking(AppTypography.captionLetterSpacing)
|
||||||
.foregroundStyle(isActive ? AppColors.textInverse : AppColors.secondary)
|
.foregroundStyle(isActive ? AppColors.textInverse : AppColors.primary)
|
||||||
.padding(.horizontal, 14)
|
.padding(.horizontal, 14)
|
||||||
.padding(.vertical, 8)
|
.padding(.vertical, 8)
|
||||||
.background(isActive ? AppColors.primary : AppColors.backgroundLight)
|
.background(isActive ? AppColors.primary : AppColors.backgroundLight)
|
||||||
.clipShape(Capsule())
|
.clipShape(Capsule())
|
||||||
.overlay(
|
.overlay(
|
||||||
Capsule()
|
Capsule()
|
||||||
.stroke(AppColors.secondary.opacity(0.15), lineWidth: isActive ? 0 : 1)
|
.stroke(AppColors.primary.opacity(0.15), lineWidth: isActive ? 0 : 1)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,36 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
#if canImport(UIKit)
|
||||||
|
import UIKit
|
||||||
|
#elseif canImport(AppKit)
|
||||||
|
import AppKit
|
||||||
|
#endif
|
||||||
|
|
||||||
// MARK: - Colors
|
// MARK: - Colors
|
||||||
|
|
||||||
enum AppColors {
|
enum AppColors {
|
||||||
static let primary = Color(hex: "#1E6B43")
|
// Brandbook 2026 (Pedi Foods)
|
||||||
static let secondary = Color(hex: "#2F7C4B")
|
// Primary now follows the "FOODS" dark green tone from the logo.
|
||||||
static let tertiary = Color(hex: "#8CFF2E")
|
static let primary = Color(hex: "#345D54")
|
||||||
|
// Secondary keeps the vivid lime from the symbol/logo body.
|
||||||
|
static let secondary = Color(hex: "#D5D841")
|
||||||
|
static let tertiary = Color(hex: "#A7BF42")
|
||||||
|
|
||||||
static let brandDark = Color(hex: "#1B5C3A")
|
static let brandDark = Color(hex: "#1F2D40")
|
||||||
static let brandSoft = Color(hex: "#E8F2EC")
|
static let brandSoft = Color(hex: "#F2F5E3")
|
||||||
|
|
||||||
static let backgroundLight = Color(hex: "#F3F5F7")
|
static let backgroundLight = Color(hex: "#F3F5F7")
|
||||||
static let backgroundDark = Color(hex: "#18230F")
|
static let backgroundDark = Color(hex: "#1F2D40")
|
||||||
static let surface = Color(hex: "#FFFFFF")
|
static let surface = Color(hex: "#FFFFFF")
|
||||||
static let textPrimary = Color(hex: "#1C1F23")
|
static let textPrimary = Color(hex: "#000000")
|
||||||
static let textInverse = Color(hex: "#FFFFFF")
|
static let textInverse = Color(hex: "#FFFFFF")
|
||||||
static let textMuted = Color(hex: "#7B8794")
|
static let textMuted = Color(hex: "#667085")
|
||||||
}
|
}
|
||||||
|
|
||||||
enum AppDarkColors {
|
enum AppDarkColors {
|
||||||
static let background = Color(hex: "#18230F")
|
static let background = Color(hex: "#1F2D40")
|
||||||
static let surface = Color(hex: "#FFFFFF", alpha: 0.05)
|
static let surface = Color(hex: "#FFFFFF", alpha: 0.08)
|
||||||
static let textPrimary = Color(hex: "#FFFFFF")
|
static let textPrimary = Color(hex: "#FFFFFF")
|
||||||
static let textSecondary = Color(hex: "#A3A3A3")
|
static let textSecondary = Color(hex: "#D0D5DD")
|
||||||
static let primary = AppColors.primary
|
static let primary = AppColors.primary
|
||||||
static let secondary = AppColors.secondary
|
static let secondary = AppColors.secondary
|
||||||
static let tertiary = AppColors.tertiary
|
static let tertiary = AppColors.tertiary
|
||||||
@@ -31,22 +39,38 @@ enum AppDarkColors {
|
|||||||
// MARK: - Typography
|
// MARK: - Typography
|
||||||
|
|
||||||
enum AppTypography {
|
enum AppTypography {
|
||||||
static let fontFamily = "Plus Jakarta Sans"
|
// Brandbook typography: Nexa (fallback: system font)
|
||||||
|
static let fontFamily = "Nexa-Regular"
|
||||||
|
|
||||||
// Avoid applying dynamic weight on custom font descriptors to prevent
|
static let heading1 = resolvedFont(size: 28, fallbackWeight: .bold)
|
||||||
// SwiftUI runtime warnings on some platforms/toolchains.
|
static let heading25 = resolvedFont(size: 25, fallbackWeight: .bold)
|
||||||
static let heading1 = Font.custom(fontFamily, size: 28)
|
static let heading2 = resolvedFont(size: 20, fallbackWeight: .semibold)
|
||||||
static let heading25 = Font.custom(fontFamily, size: 25)
|
static let heading3 = resolvedFont(size: 16, fallbackWeight: .semibold)
|
||||||
static let heading2 = Font.custom(fontFamily, size: 20)
|
static let body = resolvedFont(size: 16, fallbackWeight: .regular)
|
||||||
static let heading3 = Font.custom(fontFamily, size: 16)
|
static let button = resolvedFont(size: 14, fallbackWeight: .semibold)
|
||||||
static let body = Font.custom(fontFamily, size: 16)
|
static let caption = resolvedFont(size: 10, fallbackWeight: .regular)
|
||||||
static let button = Font.custom(fontFamily, size: 14)
|
static let overline = resolvedFont(size: 11, fallbackWeight: .regular)
|
||||||
static let caption = Font.custom(fontFamily, size: 10)
|
|
||||||
static let overline = Font.custom(fontFamily, size: 11)
|
|
||||||
|
|
||||||
static let bodyLineHeight: CGFloat = 1.6
|
static let bodyLineHeight: CGFloat = 1.6
|
||||||
static let buttonLetterSpacing: CGFloat = 0.08
|
static let buttonLetterSpacing: CGFloat = 0.08
|
||||||
static let captionLetterSpacing: CGFloat = 0.12
|
static let captionLetterSpacing: CGFloat = 0.12
|
||||||
|
|
||||||
|
private static func resolvedFont(size: CGFloat, fallbackWeight: Font.Weight) -> Font {
|
||||||
|
if isBrandFontAvailable {
|
||||||
|
return Font.custom(fontFamily, size: size)
|
||||||
|
}
|
||||||
|
return .system(size: size, weight: fallbackWeight, design: .default)
|
||||||
|
}
|
||||||
|
|
||||||
|
private static var isBrandFontAvailable: Bool {
|
||||||
|
#if canImport(UIKit)
|
||||||
|
return UIFont(name: fontFamily, size: 16) != nil
|
||||||
|
#elseif canImport(AppKit)
|
||||||
|
return NSFont(name: fontFamily, size: 16) != nil
|
||||||
|
#else
|
||||||
|
return false
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Layout
|
// MARK: - Layout
|
||||||
|
|||||||
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 120 KiB |
@@ -14,8 +14,83 @@
|
|||||||
],
|
],
|
||||||
"groups" : [
|
"groups" : [
|
||||||
{
|
{
|
||||||
|
"hidden" : false,
|
||||||
"layers" : [
|
"layers" : [
|
||||||
|
{
|
||||||
|
"glass-specializations" : [
|
||||||
|
{
|
||||||
|
"appearance" : "dark",
|
||||||
|
"value" : true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"hidden" : false,
|
||||||
|
"image-name" : "Screenshot 2026-04-25 at 16.22.36.png",
|
||||||
|
"name" : "Screenshot 2026-04-25 at 16.22.36",
|
||||||
|
"opacity-specializations" : [
|
||||||
|
{
|
||||||
|
"value" : 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearance" : "dark",
|
||||||
|
"value" : 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"position-specializations" : [
|
||||||
|
{
|
||||||
|
"idiom" : "iOS",
|
||||||
|
"value" : {
|
||||||
|
"scale" : 1.24,
|
||||||
|
"translation-in-points" : [
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "watchOS",
|
||||||
|
"value" : {
|
||||||
|
"scale" : 1.54,
|
||||||
|
"translation-in-points" : [
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hidden" : false,
|
||||||
|
"image-name" : "Screenshot 2026-04-25 at 16.22.59.png",
|
||||||
|
"name" : "Screenshot 2026-04-25 at 16.22.59",
|
||||||
|
"position-specializations" : [
|
||||||
|
{
|
||||||
|
"idiom" : "iOS",
|
||||||
|
"value" : {
|
||||||
|
"scale" : 1.24,
|
||||||
|
"translation-in-points" : [
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "watchOS",
|
||||||
|
"value" : {
|
||||||
|
"scale" : 1.54,
|
||||||
|
"translation-in-points" : [
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"opacity-specializations" : [
|
||||||
|
{
|
||||||
|
"appearance" : "dark",
|
||||||
|
"value" : 1
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"shadow" : {
|
"shadow" : {
|
||||||
"kind" : "neutral",
|
"kind" : "neutral",
|
||||||
@@ -27,54 +102,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"layers" : [
|
"blend-mode" : "normal",
|
||||||
|
"hidden-specializations" : [
|
||||||
{
|
{
|
||||||
"blend-mode-specializations" : [
|
"value" : false
|
||||||
{
|
},
|
||||||
"value" : "normal"
|
{
|
||||||
},
|
"idiom" : "iOS",
|
||||||
{
|
"value" : false
|
||||||
"appearance" : "dark",
|
|
||||||
"value" : "normal"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"fill-specializations" : [
|
|
||||||
{
|
|
||||||
"value" : "none"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"appearance" : "dark",
|
|
||||||
"value" : {
|
|
||||||
"solid" : "srgb:0.00000,0.50000,0.04260,1.00000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"glass" : false,
|
|
||||||
"hidden" : false,
|
|
||||||
"image-name" : "pedifoods_big.png",
|
|
||||||
"name" : "pedifoods_big",
|
|
||||||
"position-specializations" : [
|
|
||||||
{
|
|
||||||
"value" : {
|
|
||||||
"scale" : 1,
|
|
||||||
"translation-in-points" : [
|
|
||||||
137.390625,
|
|
||||||
11.984375
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "square",
|
|
||||||
"value" : {
|
|
||||||
"scale" : 0.35,
|
|
||||||
"translation-in-points" : [
|
|
||||||
8,
|
|
||||||
0
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"layers" : [
|
||||||
|
|
||||||
],
|
],
|
||||||
"shadow" : {
|
"shadow" : {
|
||||||
"kind" : "neutral",
|
"kind" : "neutral",
|
||||||
@@ -87,6 +126,9 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"supported-platforms" : {
|
"supported-platforms" : {
|
||||||
|
"circles" : [
|
||||||
|
"watchOS"
|
||||||
|
],
|
||||||
"squares" : [
|
"squares" : [
|
||||||
"iOS"
|
"iOS"
|
||||||
]
|
]
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 82 KiB |
@@ -258,12 +258,12 @@ final class FeatureControlService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func featureKeys() -> [String] {
|
private func featureKeys() -> [String] {
|
||||||
let raw = ProcessInfo.processInfo.environment["FEATURE_CONTROL_KEYS"] ?? "fc.promo,fc.promo-codes,fc.android,fc.city-aguai,fc.ios"
|
let raw = ProcessInfo.processInfo.environment["FEATURE_CONTROL_KEYS"] ?? "at.city.aguai,at.promo,at.ios.only,at.android.only"
|
||||||
let items = raw
|
let items = raw
|
||||||
.split(separator: ",")
|
.split(separator: ",")
|
||||||
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
|
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
|
||||||
.filter { $0.isEmpty == false }
|
.filter { $0.isEmpty == false }
|
||||||
return items.isEmpty ? ["fc.ios"] : items
|
return items.isEmpty ? ["at.ios.only"] : items
|
||||||
}
|
}
|
||||||
|
|
||||||
private func platformName() -> String {
|
private func platformName() -> String {
|
||||||
|
|||||||
@@ -62,6 +62,16 @@ struct FeatureFlagsState: Codable, Equatable {
|
|||||||
var source: String = "default"
|
var source: String = "default"
|
||||||
var values: [String: FeatureFlagValue] = [:]
|
var values: [String: FeatureFlagValue] = [:]
|
||||||
var raw: [String: FeatureControlRawFlag] = [:]
|
var raw: [String: FeatureControlRawFlag] = [:]
|
||||||
|
|
||||||
|
func isEnabled(_ key: String, default defaultValue: Bool = false) -> Bool {
|
||||||
|
if let rawValue = raw[key] {
|
||||||
|
return rawValue.enabled || rawValue.variant.lowercased() == "on"
|
||||||
|
}
|
||||||
|
if let mapped = values[key] {
|
||||||
|
return mapped.boolValue
|
||||||
|
}
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum AppModal: String, Identifiable {
|
enum AppModal: String, Identifiable {
|
||||||
|
|||||||
@@ -67,7 +67,9 @@ extension View {
|
|||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
self
|
self
|
||||||
#else
|
#else
|
||||||
self.navigationBarTitleDisplayMode(.inline)
|
self
|
||||||
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
|
.modifier(AppRoundedBackButtonModifier())
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,3 +141,28 @@ extension View {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !os(macOS)
|
||||||
|
private struct AppRoundedBackButtonModifier: ViewModifier {
|
||||||
|
@Environment(\.dismiss) private var dismiss
|
||||||
|
|
||||||
|
func body(content: Content) -> some View {
|
||||||
|
content
|
||||||
|
.navigationBarBackButtonHidden(true)
|
||||||
|
.toolbar {
|
||||||
|
ToolbarItem(placement: .topBarLeading) {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -47,6 +47,13 @@ struct AddAddressFormView: View {
|
|||||||
|
|
||||||
ScrollView {
|
ScrollView {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
|
screenHeader(
|
||||||
|
title: existingAddress == nil ? "Novo endereço" : "Editar endereço",
|
||||||
|
onBack: { dismiss() }
|
||||||
|
)
|
||||||
|
.padding(.horizontal, 24)
|
||||||
|
.padding(.bottom, 12)
|
||||||
|
|
||||||
logoImage
|
logoImage
|
||||||
.scaledToFit()
|
.scaledToFit()
|
||||||
.frame(width: 120, height: 120)
|
.frame(width: 120, height: 120)
|
||||||
@@ -134,6 +141,28 @@ struct AddAddressFormView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func screenHeader(title: String, onBack: @escaping () -> Void) -> some View {
|
||||||
|
ZStack {
|
||||||
|
Text(title)
|
||||||
|
.font(AppTypography.heading2)
|
||||||
|
.foregroundStyle(colorScheme == .dark ? Color.white : AppColors.textPrimary)
|
||||||
|
|
||||||
|
HStack {
|
||||||
|
Button(action: onBack) {
|
||||||
|
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 saveAddress() {
|
private func saveAddress() {
|
||||||
guard !isLoading else { return }
|
guard !isLoading else { return }
|
||||||
let latLong: [Double]? = {
|
let latLong: [Double]? = {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ struct AddressesView: View {
|
|||||||
|
|
||||||
ScrollView(showsIndicators: false) {
|
ScrollView(showsIndicators: false) {
|
||||||
VStack(spacing: 20) {
|
VStack(spacing: 20) {
|
||||||
header
|
screenHeader(title: "Meus Endereços", onBack: { dismiss() })
|
||||||
|
|
||||||
if let message {
|
if let message {
|
||||||
Text(message)
|
Text(message)
|
||||||
@@ -131,28 +131,6 @@ struct AddressesView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var header: some View {
|
|
||||||
ZStack {
|
|
||||||
Text("Meus Endereços")
|
|
||||||
.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)
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var bottomOverlay: some View {
|
var bottomOverlay: some View {
|
||||||
ZStack(alignment: .bottom) {
|
ZStack(alignment: .bottom) {
|
||||||
Rectangle()
|
Rectangle()
|
||||||
@@ -181,6 +159,28 @@ struct AddressesView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func screenHeader(title: String, onBack: @escaping () -> Void) -> some View {
|
||||||
|
ZStack {
|
||||||
|
Text(title)
|
||||||
|
.font(AppTypography.heading2)
|
||||||
|
.foregroundStyle(AppColors.textPrimary)
|
||||||
|
|
||||||
|
HStack {
|
||||||
|
Button(action: onBack) {
|
||||||
|
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 selectAddress(_ address: CustomerAddress) {
|
private func selectAddress(_ address: CustomerAddress) {
|
||||||
appState.address.selectedId = address.id
|
appState.address.selectedId = address.id
|
||||||
let label = (address.label ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
|
let label = (address.label ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
|
|||||||
@@ -121,15 +121,17 @@ struct HomeView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
section(title: "#PediPromo") {
|
if appState.featureFlags.isEnabled("at.promo") {
|
||||||
ScrollView(.horizontal, showsIndicators: false) {
|
section(title: "#PediPromo") {
|
||||||
HStack(spacing: 16) {
|
ScrollView(.horizontal, showsIndicators: false) {
|
||||||
ForEach(specials) { item in
|
HStack(spacing: 16) {
|
||||||
SpecialOfferCard(model: item)
|
ForEach(specials) { item in
|
||||||
.frame(width: 260, height: 120)
|
SpecialOfferCard(model: item)
|
||||||
|
.frame(width: 260, height: 120)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
.padding(.horizontal, 20)
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 20)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,7 +206,7 @@ struct HomeView: View {
|
|||||||
|
|
||||||
return ZStack(alignment: .top) {
|
return ZStack(alignment: .top) {
|
||||||
RoundedRectangle(cornerRadius: 32, style: .continuous)
|
RoundedRectangle(cornerRadius: 32, style: .continuous)
|
||||||
.fill(AppColors.brandDark)
|
.fill(AppColors.primary)
|
||||||
.frame(height: height)
|
.frame(height: height)
|
||||||
.overlay(headerRings.opacity(1 - collapseProgress), alignment: .topTrailing)
|
.overlay(headerRings.opacity(1 - collapseProgress), alignment: .topTrailing)
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ struct CategoryChip: View {
|
|||||||
.foregroundStyle(isActive ? AppColors.textInverse : AppColors.textPrimary)
|
.foregroundStyle(isActive ? AppColors.textInverse : AppColors.textPrimary)
|
||||||
.padding(.horizontal, 16)
|
.padding(.horizontal, 16)
|
||||||
.padding(.vertical, 10)
|
.padding(.vertical, 10)
|
||||||
.background(isActive ? AppColors.brandDark : AppColors.surface)
|
.background(isActive ? AppColors.primary : AppColors.surface)
|
||||||
.clipShape(Capsule())
|
.clipShape(Capsule())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,12 +72,12 @@ struct MainTabView: View {
|
|||||||
.font(AppTypography.heading3)
|
.font(AppTypography.heading3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.foregroundStyle(isActive ? AppColors.primary : AppColors.textPrimary)
|
.foregroundStyle(isActive ? AppColors.textInverse : AppColors.textPrimary)
|
||||||
.padding(.horizontal, 18)
|
.padding(.horizontal, 18)
|
||||||
.padding(.vertical, 10)
|
.padding(.vertical, 10)
|
||||||
.background(
|
.background(
|
||||||
Capsule()
|
Capsule()
|
||||||
.fill(isActive ? AppColors.brandSoft : Color.clear)
|
.fill(isActive ? AppColors.primary : Color.clear)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct OrdersView: View {
|
struct OrdersView: View {
|
||||||
|
@Environment(\.dismiss) var dismiss
|
||||||
@State var isLoading = false
|
@State var isLoading = false
|
||||||
@State var errorMessage: String? = nil
|
@State var errorMessage: String? = nil
|
||||||
@State var orders: [AppOrderSummary] = []
|
@State var orders: [AppOrderSummary] = []
|
||||||
@@ -12,6 +13,8 @@ struct OrdersView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
ScrollView(showsIndicators: false) {
|
ScrollView(showsIndicators: false) {
|
||||||
VStack(alignment: .leading, spacing: 14) {
|
VStack(alignment: .leading, spacing: 14) {
|
||||||
|
screenHeader(title: "Meus Pedidos", onBack: { dismiss() })
|
||||||
|
|
||||||
if isLoading {
|
if isLoading {
|
||||||
ProgressView()
|
ProgressView()
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
@@ -35,11 +38,12 @@ struct OrdersView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 20)
|
.padding(.horizontal, 20)
|
||||||
|
.padding(.top, 18)
|
||||||
.padding(.bottom, UIDevice.bottomNotch + 18)
|
.padding(.bottom, UIDevice.bottomNotch + 18)
|
||||||
}
|
}
|
||||||
.background(AppColors.backgroundLight)
|
.background(AppColors.backgroundLight)
|
||||||
.navigationTitle("Meus Pedidos")
|
.navigationBarBackButtonHidden(true)
|
||||||
.appInlineNavigationTitle()
|
.appHiddenNavigationBar()
|
||||||
.task {
|
.task {
|
||||||
await loadOrdersIfNeeded()
|
await loadOrdersIfNeeded()
|
||||||
await refreshStoreRatings()
|
await refreshStoreRatings()
|
||||||
@@ -59,6 +63,28 @@ struct OrdersView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func screenHeader(title: String, onBack: @escaping () -> Void) -> some View {
|
||||||
|
ZStack {
|
||||||
|
Text(title)
|
||||||
|
.font(AppTypography.heading2)
|
||||||
|
.foregroundStyle(AppColors.textPrimary)
|
||||||
|
|
||||||
|
HStack {
|
||||||
|
Button(action: onBack) {
|
||||||
|
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 orderCard(_ order: AppOrderSummary) -> some View {
|
private func orderCard(_ order: AppOrderSummary) -> some View {
|
||||||
let status = orderVisualStatus(for: order)
|
let status = orderVisualStatus(for: order)
|
||||||
let detailsRoute = OrderRouteContext(
|
let detailsRoute = OrderRouteContext(
|
||||||
@@ -81,7 +107,6 @@ struct OrdersView: View {
|
|||||||
AsyncStoreImage(imageURL: resolvedMediaURL(order.storeLogoURL))
|
AsyncStoreImage(imageURL: resolvedMediaURL(order.storeLogoURL))
|
||||||
.frame(width: 80, height: 80)
|
.frame(width: 80, height: 80)
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 20, style: .continuous))
|
.clipShape(RoundedRectangle(cornerRadius: 20, style: .continuous))
|
||||||
.background(AppColors.brandSoft, in: RoundedRectangle(cornerRadius: 20, style: .continuous))
|
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 5) {
|
VStack(alignment: .leading, spacing: 5) {
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ struct StoreDetailView: View {
|
|||||||
.refreshable {
|
.refreshable {
|
||||||
await loadStoreData(forceRefresh: true)
|
await loadStoreData(forceRefresh: true)
|
||||||
}
|
}
|
||||||
.appNamedCoordinateSpace(StoreDetailScrollCoordinateSpace.name)
|
.coordinateSpace(name: StoreDetailScrollCoordinateSpace.name)
|
||||||
.ignoresSafeArea(edges: .top)
|
.ignoresSafeArea(edges: .top)
|
||||||
}
|
}
|
||||||
.ignoresSafeArea(edges: .top)
|
.ignoresSafeArea(edges: .top)
|
||||||
@@ -286,7 +286,7 @@ struct StoreDetailView: View {
|
|||||||
HStack(spacing: 0) {
|
HStack(spacing: 0) {
|
||||||
statItem(title: "DISTÂNCIA", value: distanceValueLabel)
|
statItem(title: "DISTÂNCIA", value: distanceValueLabel)
|
||||||
Divider().frame(height: 34)
|
Divider().frame(height: 34)
|
||||||
statItem(title: "TEMPO", value: info?.deliveryTime ?? "25-35 min")
|
statItem(title: "TEMPO", value: info?.deliveryTime ?? "--")
|
||||||
Divider().frame(height: 34)
|
Divider().frame(height: 34)
|
||||||
statItem(title: "ENTREGA", value: deliveryValueLabel)
|
statItem(title: "ENTREGA", value: deliveryValueLabel)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,3 +131,5 @@
|
|||||||
3. `[🟥]` Implementar carrinho real (itens, subtotal, edicao) para destravar checkout.
|
3. `[🟥]` Implementar carrinho real (itens, subtotal, edicao) para destravar checkout.
|
||||||
4. `[🟥]` Implementar mapa e tracking de pedidos.
|
4. `[🟥]` Implementar mapa e tracking de pedidos.
|
||||||
5. `[🟥]` Corrigir bloqueio de build por dependencia (`LCEssentials`) para fechar validacao iOS/Android ponta a ponta.
|
5. `[🟥]` Corrigir bloqueio de build por dependencia (`LCEssentials`) para fechar validacao iOS/Android ponta a ponta.
|
||||||
|
|
||||||
|
Autor: Daniel Arantes Loverde
|
||||||
|
|||||||
@@ -179,3 +179,5 @@ Icon {
|
|||||||
active?: boolean
|
active?: boolean
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Autor: Daniel Arantes Loverde
|
||||||
|
|||||||
@@ -359,3 +359,5 @@ Legenda:
|
|||||||
- Build Swift/Kotlin finalizado.
|
- Build Swift/Kotlin finalizado.
|
||||||
- Etapa de conexão Android falhou com `adb devices` vazio no ambiente atual.
|
- Etapa de conexão Android falhou com `adb devices` vazio no ambiente atual.
|
||||||
- Próximo passo para concluir Task 6: conectar device físico (USB) ou iniciar AVD válido.
|
- Próximo passo para concluir Task 6: conectar device físico (USB) ou iniciar AVD válido.
|
||||||
|
|
||||||
|
Autor: Daniel Arantes Loverde
|
||||||
|
|||||||
@@ -742,3 +742,5 @@ Implementar assim:
|
|||||||
- nova alteração somente após 90 dias
|
- nova alteração somente após 90 dias
|
||||||
- aviso visual claro antes de salvar
|
- aviso visual claro antes de salvar
|
||||||
- registro do slug antigo para redirect temporário
|
- registro do slug antigo para redirect temporário
|
||||||
|
|
||||||
|
Autor: Daniel Arantes Loverde
|
||||||
|
|||||||