687 lines
34 KiB
Markdown
687 lines
34 KiB
Markdown
# ZIVVO Screen Blueprints
|
||
|
||
Screen-by-screen widget trees and build guides for all 4 roles. Each blueprint shows the exact widget hierarchy and key properties to configure in FlutterFlow.
|
||
|
||
## How to Use These Blueprints
|
||
|
||
1. Create a new page in FlutterFlow
|
||
2. Follow the widget tree top-down — add outermost widget first
|
||
3. Indented items are children of the item above
|
||
4. Properties in parentheses are the key values to set
|
||
5. After building, preview on target device size (390x844 for mobile)
|
||
|
||
---
|
||
|
||
## Shared Screens (All Roles)
|
||
|
||
### Splash Screen
|
||
|
||
**Page settings:** No AppBar, no bottom nav, full screen, no scroll.
|
||
|
||
```
|
||
Scaffold (backgroundColor: Background #FAFAF7)
|
||
└── Stack
|
||
├── Container (width: Expand, height: Expand)
|
||
│ └── Gradient background: Sunrise (Primary Light 8% → transparent)
|
||
├── Center
|
||
│ └── Column (mainAxisAlignment: Center, crossAxisSize: Min)
|
||
│ ├── Image (src: ZIVVO logo asset, width: 120, height: 120)
|
||
│ ├── SizedBox (height: 16)
|
||
│ └── Text ("ZIVVO", style: displayLarge, color: Primary #D4A012)
|
||
└── Positioned (bottom: 48, left: 0, right: 0)
|
||
└── Center
|
||
└── CircularProgressIndicator (color: Secondary #0D8B7D, strokeWidth: 3)
|
||
```
|
||
|
||
**Build steps:**
|
||
```
|
||
1. Create page "SplashScreen" → set as home page
|
||
2. Disable AppBar and bottom nav in page settings
|
||
3. Add Stack as root widget
|
||
4. Inside Stack: add Container → set Expand width/height → add gradient
|
||
5. Inside Stack: add Center → Column → Image + SizedBox + Text
|
||
6. Inside Stack: add Align (bottom center) → CircularProgressIndicator
|
||
7. Actions → On Load: wait 2s then navigate to OnboardingPage
|
||
```
|
||
|
||
### Onboarding (3 Pages)
|
||
|
||
**Page settings:** No AppBar, no bottom nav, full screen.
|
||
|
||
```
|
||
Scaffold
|
||
└── Column (mainAxisAlignment: SpaceBetween)
|
||
├── Expanded
|
||
│ └── PageView (controller: pageController, pageSnapping: true)
|
||
│ ├── Page 1: "Move Freely"
|
||
│ │ └── Column (mainAxisAlignment: Center, padding: 32)
|
||
│ │ ├── Image (src: city illustration, width: 280, height: 280, fit: Contain)
|
||
│ │ ├── SizedBox (height: 32)
|
||
│ │ ├── Text ("Move Freely", style: headlineLarge, textAlign: Center)
|
||
│ │ ├── SizedBox (height: 12)
|
||
│ │ └── Text ("Rides, rentals, and deliveries — all in one app.",
|
||
│ │ style: bodyLarge, color: TextSecondary, textAlign: Center)
|
||
│ ├── Page 2: "Works Everywhere"
|
||
│ │ └── Column (same structure)
|
||
│ │ ├── Image (signal bars illustration)
|
||
│ │ ├── Text ("Works Everywhere")
|
||
│ │ └── Text ("Offline maps, low-bandwidth tracking, 2G-ready.")
|
||
│ └── Page 3: "You're in Control"
|
||
│ └── Column (same structure)
|
||
│ ├── Image (tracking screen illustration)
|
||
│ ├── Text ("You're in Control")
|
||
│ └── Text ("Real-time tracking, transparent pricing, SOS safety.")
|
||
├── Container (padding: horizontal 24, vertical 16)
|
||
│ └── Column
|
||
│ ├── Row (mainAxisAlignment: Center, spacing: 8)
|
||
│ │ ├── Container (w: 8, h: 8, radius: 4, color: conditional on page index)
|
||
│ │ ├── Container (same — dot indicator)
|
||
│ │ └── Container (same — dot indicator)
|
||
│ ├── SizedBox (height: 24)
|
||
│ └── Row (mainAxisAlignment: SpaceBetween)
|
||
│ ├── ZivvoButtonGhost (text: "Skip", onTap: navigate to PhoneEntry)
|
||
│ └── ZivvoButtonPrimary (text: conditional "Next"/"Get Started",
|
||
│ width: 160, onTap: next page or navigate to PhoneEntry)
|
||
```
|
||
|
||
### Phone Entry Screen
|
||
|
||
```
|
||
Scaffold (AppBar: back button only, transparent, no title)
|
||
└── Column (padding: horizontal 24)
|
||
├── SizedBox (height: 32)
|
||
├── Text ("Enter your phone number", style: headlineLarge)
|
||
├── SizedBox (height: 8)
|
||
├── Text ("We'll send you a verification code",
|
||
│ style: bodyMedium, color: TextSecondary)
|
||
├── SizedBox (height: 32)
|
||
├── Row (spacing: 12)
|
||
│ ├── Container (width: 88, height: 52, radius: 12, border: 1.5px #E8E4DC)
|
||
│ │ └── Center
|
||
│ │ └── Row (mainAxisAlignment: Center, spacing: 4)
|
||
│ │ ├── Text ("🇨🇲", style: bodyLarge)
|
||
│ │ └── Text ("+237", style: bodyLarge, weight: 600)
|
||
│ └── Expanded
|
||
│ └── ZivvoInput (hintText: "6XX XXX XXX", keyboardType: Phone,
|
||
│ maxLength: 9, autofocus: true)
|
||
├── Spacer
|
||
└── Container (padding: bottom 32)
|
||
└── ZivvoButtonPrimary (text: "Continue", width: Expand,
|
||
enabled: phoneField.length == 9,
|
||
onTap: send OTP → navigate to OTPVerification)
|
||
```
|
||
|
||
### OTP Verification Screen
|
||
|
||
```
|
||
Scaffold (AppBar: back button, transparent)
|
||
└── Column (padding: horizontal 24)
|
||
├── SizedBox (height: 32)
|
||
├── Text ("Verify your number", style: headlineLarge)
|
||
├── SizedBox (height: 8)
|
||
├── RichText
|
||
│ ├── TextSpan ("We sent a code to ", style: bodyMedium, color: TextSecondary)
|
||
│ └── TextSpan ("+237 6XX XXX XXX", style: bodyMedium, weight: 600)
|
||
├── SizedBox (height: 40)
|
||
├── PinCode (length: 6, autoFocus: true, keyboardType: Number,
|
||
│ fieldWidth: 48, fieldHeight: 56, borderRadius: 12,
|
||
│ activeBorderColor: Primary, selectedBorderColor: Secondary)
|
||
├── SizedBox (height: 24)
|
||
├── Row (mainAxisAlignment: Center)
|
||
│ ├── Text ("Didn't receive code? ", style: bodySmall, color: TextSecondary)
|
||
│ └── TextButton ("Resend", style: labelLarge, color: Secondary,
|
||
│ enabled: resendTimer == 0, onTap: resend OTP)
|
||
├── Spacer
|
||
└── Container (padding: bottom 32)
|
||
└── ZivvoButtonPrimary (text: "Verify", width: Expand,
|
||
enabled: pinCode.length == 6,
|
||
onTap: verify OTP → navigate based on registration state)
|
||
```
|
||
|
||
### Settings Screen
|
||
|
||
```
|
||
Scaffold (AppBar: title "Settings", back button)
|
||
└── ListView (padding: vertical 8)
|
||
├── ListTile (leading: CircleImage(user photo), title: user name,
|
||
│ subtitle: phone number, trailing: chevron, onTap: Profile)
|
||
├── Divider (indent: 16, endIndent: 16)
|
||
├── SectionHeader ("Preferences")
|
||
├── ListTile (leading: Icon(language), title: "Language",
|
||
│ trailing: Text(current lang), onTap: LanguagePicker)
|
||
├── ListTile (leading: Icon(dark_mode), title: "Dark Mode",
|
||
│ trailing: Switch(value: isDarkMode))
|
||
├── ListTile (leading: Icon(notifications), title: "Notifications",
|
||
│ trailing: chevron, onTap: NotificationSettings)
|
||
├── Divider
|
||
├── SectionHeader ("Account")
|
||
├── ListTile (leading: Icon(payment), title: "Payment Methods",
|
||
│ trailing: chevron, onTap: PaymentMethods)
|
||
├── ListTile (leading: Icon(history), title: "Ride History",
|
||
│ trailing: chevron, onTap: RideHistory)
|
||
├── ListTile (leading: Icon(help), title: "Help & Support",
|
||
│ trailing: chevron, onTap: HelpSupport)
|
||
├── ListTile (leading: Icon(info), title: "About ZIVVO",
|
||
│ trailing: chevron, onTap: About)
|
||
├── Divider
|
||
└── ListTile (leading: Icon(logout, color: Error), title: "Sign Out",
|
||
titleColor: Error, onTap: confirm → sign out)
|
||
```
|
||
|
||
---
|
||
|
||
## Customer Role Screens
|
||
|
||
### Customer Home (Map + Where To)
|
||
|
||
```
|
||
Scaffold (extendBody: true, no AppBar)
|
||
└── Stack
|
||
├── FlutterMap (width: Expand, height: Expand)
|
||
│ ├── TileLayer (urlTemplate: vector tile URL)
|
||
│ ├── MarkerLayer — user location
|
||
│ │ └── Marker (point: userLatLng)
|
||
│ │ └── Container (w: 20, h: 20, radius: 10, color: Secondary,
|
||
│ │ border: 3px white, shadow: teal glow)
|
||
│ └── MarkerLayer — nearby drivers
|
||
│ └── [Dynamic markers from driver positions]
|
||
│ └── Image (src: car_icon, width: 32, height: 32, rotation: heading)
|
||
├── Positioned (top: safeAreaTop + 8, left: 16, right: 16)
|
||
│ └── Row (mainAxisAlignment: SpaceBetween)
|
||
│ ├── Container (w: 44, h: 44, radius: 22, color: white, shadow: sm)
|
||
│ │ └── IconButton (icon: menu, onTap: open drawer)
|
||
│ └── Container (w: 44, h: 44, radius: 22, color: white, shadow: sm)
|
||
│ └── Stack
|
||
│ ├── IconButton (icon: notifications_outlined, onTap: Notifications)
|
||
│ └── Positioned (top: 0, right: 0)
|
||
│ └── Badge (count: unreadCount, color: Error)
|
||
├── DraggableScrollableSheet (initialChildSize: 0.25, minChildSize: 0.15,
|
||
│ maxChildSize: 0.85)
|
||
│ └── Container (radius: topLeft 20, topRight 20, color: Surface, shadow: xl)
|
||
│ └── Column
|
||
│ ├── Center
|
||
│ │ └── Container (w: 40, h: 4, radius: 2, color: Divider, margin: top 8)
|
||
│ ├── SizedBox (height: 16)
|
||
│ ├── Container (margin: horizontal 16, padding: 0)
|
||
│ │ └── Row
|
||
│ │ ├── Container (w: 3, h: 48, radius: 1.5, color: Primary)
|
||
│ │ └── Expanded
|
||
│ │ └── ZivvoInput (hintText: "Where to?",
|
||
│ │ prefixIcon: search, readOnly: true,
|
||
│ │ onTap: navigate to DestinationSearch)
|
||
│ ├── SizedBox (height: 16)
|
||
│ ├── Container (height: 40, padding: horizontal 16)
|
||
│ │ └── ListView (direction: Horizontal, spacing: 8)
|
||
│ │ ├── ZivvoChip (icon: home, text: "Home", onTap: set destination)
|
||
│ │ ├── ZivvoChip (icon: work, text: "Work", onTap: set destination)
|
||
│ │ └── ZivvoChip (icon: bookmark, text: "Saved", onTap: SavedPlaces)
|
||
│ └── SizedBox (height: 16)
|
||
```
|
||
|
||
### Destination Search Screen
|
||
|
||
```
|
||
Scaffold (AppBar: none)
|
||
└── Column
|
||
├── Container (padding: 16, color: Surface)
|
||
│ └── Column (spacing: 12)
|
||
│ ├── Row
|
||
│ │ ├── IconButton (icon: arrow_back, onTap: pop)
|
||
│ │ └── Expanded
|
||
│ │ └── Text ("Plan your trip", style: headingMedium)
|
||
│ ├── Row (spacing: 12)
|
||
│ │ ├── Column (width: 24, spacing: 4)
|
||
│ │ │ ├── Container (w: 10, h: 10, radius: 5, color: Primary)
|
||
│ │ │ ├── Container (w: 2, h: 24, color: Divider)
|
||
│ │ │ └── Container (w: 10, h: 10, radius: 2, color: Error)
|
||
│ │ └── Expanded
|
||
│ │ └── Column (spacing: 8)
|
||
│ │ ├── ZivvoInput (hintText: "Pickup location", value: currentAddress)
|
||
│ │ └── ZivvoInput (hintText: "Where to?", autofocus: true)
|
||
├── Expanded
|
||
│ └── ListView
|
||
│ ├── SectionHeader ("Recent")
|
||
│ ├── [RecentPlaceRow] × N
|
||
│ │ └── ListTile (leading: Icon(history), title: place name,
|
||
│ │ subtitle: address, onTap: select destination)
|
||
│ ├── SectionHeader ("Saved Places")
|
||
│ └── [SavedPlaceRow] × N
|
||
│ └── ListTile (leading: Icon(star), title: place name,
|
||
│ subtitle: address, onTap: select destination)
|
||
```
|
||
|
||
### Vehicle Selection & Fare Estimate
|
||
|
||
```
|
||
Scaffold (AppBar: back button, "Choose a ride")
|
||
└── Column
|
||
├── Container (height: 200)
|
||
│ └── FlutterMap (showing route polyline, pickup/dropoff markers)
|
||
├── Expanded
|
||
│ └── ListView (padding: 16, spacing: 8)
|
||
│ ├── VehicleOption (selected state)
|
||
│ │ └── ZivvoCard (border: 2px Primary when selected)
|
||
│ │ └── Row (spacing: 12)
|
||
│ │ ├── Image (src: economy_car, width: 64, height: 40, fit: Contain)
|
||
│ │ ├── Expanded
|
||
│ │ │ └── Column (crossAxisAlignment: Start)
|
||
│ │ │ ├── Row
|
||
│ │ │ │ ├── Text ("Economy", style: titleLarge)
|
||
│ │ │ │ └── Badge ("Popular", color: Primary Wash)
|
||
│ │ │ └── Text ("4 min away • 4 seats", style: bodySmall, color: TextSecondary)
|
||
│ │ └── Column (crossAxisAlignment: End)
|
||
│ │ ├── Text ("2,500 XAF", style: titleLarge, weight: 700)
|
||
│ │ └── Text ("~15 min", style: bodySmall, color: TextSecondary)
|
||
│ ├── VehicleOption (Comfort)
|
||
│ │ └── ... (same structure, different image/price/time)
|
||
│ ├── VehicleOption (Premium)
|
||
│ │ └── ... (same structure)
|
||
│ └── VehicleOption (Moto)
|
||
│ └── ... (same structure, motorcycle image, 1 seat)
|
||
├── Container (padding: 16, color: Surface, shadow: xl)
|
||
│ └── Column (spacing: 12)
|
||
│ ├── Row (mainAxisAlignment: SpaceBetween)
|
||
│ │ ├── Row (spacing: 8)
|
||
│ │ │ ├── Icon (payment, color: Primary)
|
||
│ │ │ └── Text ("MTN MoMo", style: bodyMedium)
|
||
│ │ └── TextButton ("Change", color: Secondary)
|
||
│ └── ZivvoButtonPrimary (text: "Book Economy • 2,500 XAF",
|
||
│ width: Expand, onTap: request ride)
|
||
```
|
||
|
||
### Active Ride Tracking
|
||
|
||
```
|
||
Scaffold (extendBody: true, no AppBar)
|
||
└── Stack
|
||
├── FlutterMap (width: Expand, height: Expand)
|
||
│ ├── TileLayer
|
||
│ ├── PolylineLayer
|
||
│ │ └── Polyline (points: routeCoords, color: Secondary, strokeWidth: 5)
|
||
│ ├── MarkerLayer
|
||
│ │ ├── Marker (pickup: gold pin icon)
|
||
│ │ └── Marker (dropoff: red pin icon)
|
||
│ └── MarkerLayer (animated)
|
||
│ └── Marker (driver: car icon, rotated to heading, animated position)
|
||
├── Positioned (top: safeAreaTop + 8, left: 16, right: 16)
|
||
│ └── ZivvoCard
|
||
│ └── Row (mainAxisAlignment: SpaceBetween)
|
||
│ ├── Column (crossAxisAlignment: Start)
|
||
│ │ ├── Text ("Arriving in", style: bodySmall, color: TextSecondary)
|
||
│ │ └── Text ("4 min", style: headingLarge, color: Secondary)
|
||
│ └── Column (crossAxisAlignment: End)
|
||
│ ├── Text ("Distance", style: bodySmall, color: TextSecondary)
|
||
│ └── Text ("1.2 km", style: headingMedium)
|
||
├── DraggableScrollableSheet (initialChildSize: 0.3, minChildSize: 0.15)
|
||
│ └── Container (radius: top 20, color: Surface, shadow: xl)
|
||
│ └── Column
|
||
│ ├── Handle bar (same as home screen)
|
||
│ ├── Container (padding: 16)
|
||
│ │ └── Row (spacing: 12)
|
||
│ │ ├── ZivvoAvatar (src: driverPhoto, size: 48)
|
||
│ │ ├── Expanded
|
||
│ │ │ └── Column (crossAxisAlignment: Start)
|
||
│ │ │ ├── Text (driverName, style: titleLarge)
|
||
│ │ │ └── Row (spacing: 4)
|
||
│ │ │ ├── Icon (star, color: Primary, size: 16)
|
||
│ │ │ └── Text ("4.8", style: bodySmall)
|
||
│ │ └── Column
|
||
│ │ ├── Text (vehicleMake, style: bodySmall, color: TextSecondary)
|
||
│ │ └── Text (licensePlate, style: labelLarge)
|
||
│ ├── Divider
|
||
│ ├── Container (padding: horizontal 16, vertical 8)
|
||
│ │ └── Row (mainAxisAlignment: SpaceEvenly)
|
||
│ │ ├── IconButton (icon: phone, label: "Call", onTap: call driver)
|
||
│ │ ├── IconButton (icon: message, label: "Chat", onTap: open chat)
|
||
│ │ └── IconButton (icon: share, label: "Share", onTap: share tracking link)
|
||
│ ├── Divider
|
||
│ ├── Container (padding: 16)
|
||
│ │ └── Text ("Driver is on the way to pick you up",
|
||
│ │ style: bodyMedium, color: TextSecondary, textAlign: Center)
|
||
│ └── Container (padding: 16)
|
||
│ └── ZivvoButtonDanger (text: "SOS Emergency",
|
||
│ width: Expand, icon: warning,
|
||
│ onTap: hold 3s → trigger SOS)
|
||
```
|
||
|
||
### Ride Complete & Rating
|
||
|
||
```
|
||
Scaffold (AppBar: none)
|
||
└── Column (padding: 24)
|
||
├── SizedBox (height: 48)
|
||
├── Icon (check_circle, color: Success, size: 64)
|
||
├── SizedBox (height: 16)
|
||
├── Text ("Trip Complete!", style: headlineLarge, textAlign: Center)
|
||
├── SizedBox (height: 32)
|
||
├── ZivvoCard
|
||
│ └── Column (spacing: 12)
|
||
│ ├── Row (mainAxisAlignment: SpaceBetween)
|
||
│ │ ├── Text ("Total Fare", style: bodyMedium, color: TextSecondary)
|
||
│ │ └── Text ("2,500 XAF", style: headingMedium, weight: 700)
|
||
│ ├── Divider
|
||
│ ├── Row (mainAxisAlignment: SpaceBetween)
|
||
│ │ ├── Text ("Distance", style: bodySmall, color: TextSecondary)
|
||
│ │ └── Text ("4.2 km", style: bodyMedium)
|
||
│ ├── Row (mainAxisAlignment: SpaceBetween)
|
||
│ │ ├── Text ("Duration", style: bodySmall, color: TextSecondary)
|
||
│ │ └── Text ("15 min", style: bodyMedium)
|
||
│ └── Row (mainAxisAlignment: SpaceBetween)
|
||
│ ├── Text ("Payment", style: bodySmall, color: TextSecondary)
|
||
│ └── Text ("MTN MoMo", style: bodyMedium)
|
||
├── SizedBox (height: 32)
|
||
├── Text ("Rate your driver", style: headingMedium, textAlign: Center)
|
||
├── SizedBox (height: 16)
|
||
├── Row (mainAxisAlignment: Center, spacing: 8)
|
||
│ ├── ZivvoAvatar (src: driverPhoto, size: 56)
|
||
│ └── Text (driverName, style: titleLarge)
|
||
├── SizedBox (height: 12)
|
||
├── RatingBar (initialRating: 5, itemCount: 5, itemSize: 40,
|
||
│ activeColor: Primary, inactiveColor: Divider)
|
||
├── SizedBox (height: 16)
|
||
├── ZivvoInput (hintText: "Add a comment (optional)", maxLines: 3)
|
||
├── Spacer
|
||
└── ZivvoButtonPrimary (text: "Done", width: Expand, onTap: submit → navigate home)
|
||
```
|
||
|
||
---
|
||
|
||
## Driver Role Screens
|
||
|
||
### Driver Home
|
||
|
||
```
|
||
Scaffold (extendBody: true, no AppBar)
|
||
└── Stack
|
||
├── FlutterMap (width: Expand, height: Expand)
|
||
│ └── TileLayer + optional demand heatmap overlay
|
||
├── Positioned (top: safeAreaTop + 8, left: 16, right: 16)
|
||
│ └── ZivvoCard
|
||
│ └── Row (mainAxisAlignment: SpaceBetween)
|
||
│ ├── Row (spacing: 12)
|
||
│ │ ├── ZivvoAvatar (src: driverSelfie, size: 40)
|
||
│ │ └── Column (crossAxisAlignment: Start)
|
||
│ │ ├── Text (driverName, style: titleLarge)
|
||
│ │ └── Row (spacing: 4)
|
||
│ │ ├── Icon (star, color: Primary, size: 14)
|
||
│ │ ├── Text ("4.8", style: bodySmall)
|
||
│ │ └── Badge ("Gold", color: Primary Wash, textColor: Primary)
|
||
│ └── Switch (value: isOnline, activeColor: Primary,
|
||
│ onChanged: toggle availability)
|
||
├── Positioned (bottom: 16, left: 16, right: 16)
|
||
│ └── ZivvoCard
|
||
│ └── Column (spacing: 8)
|
||
│ ├── Row (mainAxisAlignment: SpaceEvenly)
|
||
│ │ ├── Column (crossAxisAlignment: Center)
|
||
│ │ │ ├── Text ("12,500 XAF", style: headingMedium, color: Primary)
|
||
│ │ │ └── Text ("Today's earnings", style: bodySmall, color: TextSecondary)
|
||
│ │ ├── Container (w: 1, h: 40, color: Divider)
|
||
│ │ └── Column (crossAxisAlignment: Center)
|
||
│ │ ├── Text ("7", style: headingMedium)
|
||
│ │ └── Text ("Trips", style: bodySmall, color: TextSecondary)
|
||
│ └── Text (isOnline ? "You're online" : "You're offline",
|
||
│ style: bodyMedium, color: isOnline ? Secondary : TextSecondary,
|
||
│ textAlign: Center)
|
||
```
|
||
|
||
### Ride Request Card (Incoming)
|
||
|
||
```
|
||
AnimatedContainer (slide up from bottom, duration: 500ms)
|
||
└── ZivvoCardElevated (margin: 16)
|
||
└── Column (spacing: 12)
|
||
├── Row (spacing: 12)
|
||
│ ├── ZivvoAvatar (src: customerPhoto, size: 48)
|
||
│ ├── Expanded
|
||
│ │ └── Column (crossAxisAlignment: Start)
|
||
│ │ ├── Text (customerName, style: titleLarge)
|
||
│ │ └── Row (spacing: 4)
|
||
│ │ ├── Icon (star, color: Primary, size: 14)
|
||
│ │ └── Text ("4.6 • 23 rides", style: bodySmall, color: TextSecondary)
|
||
│ └── Text ("2,500 XAF", style: headingMedium, weight: 700, color: Primary)
|
||
├── Divider
|
||
├── Row (spacing: 8)
|
||
│ ├── Icon (circle, color: Primary, size: 12)
|
||
│ ├── Expanded
|
||
│ │ └── Text (pickupAddress, style: bodyMedium, maxLines: 1, overflow: Ellipsis)
|
||
│ └── Text ("1.2 km", style: bodySmall, color: TextSecondary)
|
||
├── Row (spacing: 8)
|
||
│ ├── Icon (location_on, color: Error, size: 12)
|
||
│ └── Expanded
|
||
│ └── Text (dropoffAddress, style: bodyMedium, maxLines: 1, overflow: Ellipsis)
|
||
├── SizedBox (height: 4)
|
||
├── Center
|
||
│ └── Stack
|
||
│ ├── CircularProgressIndicator (value: countdown/30, color: Secondary,
|
||
│ │ strokeWidth: 4, size: 56)
|
||
│ └── Text (countdownSeconds, style: headingMedium)
|
||
├── SizedBox (height: 4)
|
||
└── Row (spacing: 12)
|
||
├── Expanded
|
||
│ └── ZivvoButtonGhost (text: "Decline", onTap: decline request)
|
||
└── Expanded
|
||
└── ZivvoButtonPrimary (text: "Accept", onTap: accept request)
|
||
```
|
||
|
||
### Driver Navigation (Active Trip)
|
||
|
||
```
|
||
Scaffold (extendBody: true, no AppBar)
|
||
└── Stack
|
||
├── FlutterMap (full screen)
|
||
│ ├── PolylineLayer (route to pickup/dropoff, color: Secondary, width: 5)
|
||
│ ├── MarkerLayer (pickup pin, dropoff pin)
|
||
│ └── MarkerLayer (driver position, animated)
|
||
├── Positioned (top: safeAreaTop, left: 0, right: 0)
|
||
│ └── Container (color: Secondary, padding: 16)
|
||
│ └── Column
|
||
│ ├── Text ("Head to pickup", style: bodyMedium, color: white)
|
||
│ ├── Text ("Turn right on Rue de la Joie", style: headingMedium, color: white)
|
||
│ └── Row (spacing: 16)
|
||
│ ├── Text ("1.2 km", style: headingLarge, color: white)
|
||
│ └── Text ("4 min", style: headingLarge, color: white)
|
||
├── Positioned (bottom: 0, left: 0, right: 0)
|
||
│ └── ZivvoCard (radiusTopOnly: 20)
|
||
│ └── Column (padding: 16, spacing: 12)
|
||
│ ├── Row (spacing: 12)
|
||
│ │ ├── ZivvoAvatar (src: customerPhoto, size: 40)
|
||
│ │ ├── Expanded → Column
|
||
│ │ │ ├── Text (customerName, style: titleLarge)
|
||
│ │ │ └── Text (pickupAddress, style: bodySmall, color: TextSecondary)
|
||
│ │ ├── IconButton (icon: phone, onTap: call customer)
|
||
│ │ └── IconButton (icon: message, onTap: open chat)
|
||
│ └── ZivvoButtonPrimary (text: "Arrived at Pickup",
|
||
│ width: Expand, onTap: update trip status)
|
||
```
|
||
|
||
---
|
||
|
||
## Dealer Role Screens
|
||
|
||
### Dealer Dashboard
|
||
|
||
```
|
||
Scaffold (AppBar: title "Dashboard", actions: [notifications, settings])
|
||
└── ListView (padding: 16, spacing: 16)
|
||
├── ZivvoCard (gradient: Sunrise 5%)
|
||
│ └── Column (spacing: 8)
|
||
│ ├── Text ("Welcome back, Jean", style: headingMedium)
|
||
│ ├── Text ("Here's your fleet overview", style: bodyMedium, color: TextSecondary)
|
||
│ └── Row (mainAxisAlignment: SpaceEvenly, spacing: 12)
|
||
│ ├── StatColumn (value: "24", label: "Vehicles", icon: directions_car)
|
||
│ ├── StatColumn (value: "18", label: "Active", icon: check_circle, color: Success)
|
||
│ ├── StatColumn (value: "3", label: "Rented", icon: key, color: Secondary)
|
||
│ └── StatColumn (value: "3", label: "Idle", icon: pause_circle, color: Warning)
|
||
├── ZivvoCard
|
||
│ └── Column (spacing: 12)
|
||
│ ├── Row (mainAxisAlignment: SpaceBetween)
|
||
│ │ ├── Text ("Revenue", style: titleLarge)
|
||
│ │ └── DropDown (options: ["This Week", "This Month", "This Year"])
|
||
│ ├── Text ("485,000 XAF", style: displayMedium, color: Primary)
|
||
│ ├── Row (spacing: 4)
|
||
│ │ ├── Icon (trending_up, color: Success, size: 16)
|
||
│ │ └── Text ("+12% vs last week", style: bodySmall, color: Success)
|
||
│ └── Chart (type: Line, height: 150, color: Primary)
|
||
├── Row (mainAxisAlignment: SpaceBetween)
|
||
│ ├── Text ("Pending Requests", style: titleLarge)
|
||
│ └── TextButton ("View All", color: Secondary)
|
||
├── [RentalRequestCard] × 2-3
|
||
│ └── ZivvoCard
|
||
│ └── Row (spacing: 12)
|
||
│ ├── CircleImage (customer photo)
|
||
│ ├── Expanded → Column
|
||
│ │ ├── Text (customerName, style: titleLarge)
|
||
│ │ └── Text ("Toyota Corolla • 3 days", style: bodySmall)
|
||
│ └── Column
|
||
│ ├── ZivvoButtonPrimary (text: "Accept", height: 36)
|
||
│ └── ZivvoButtonGhost (text: "Decline", height: 36)
|
||
└── SizedBox (height: 80) // bottom nav clearance
|
||
```
|
||
|
||
### Vehicle Management (Fleet List)
|
||
|
||
```
|
||
Scaffold (AppBar: title "My Fleet", actions: [filter, sort])
|
||
├── FloatingActionButton (icon: add, onTap: AddVehicle)
|
||
└── ListView (padding: 16, spacing: 12)
|
||
└── [VehicleCard] × N
|
||
└── ZivvoCard
|
||
└── Row (spacing: 12)
|
||
├── Container (width: 100, height: 80, radius: 12)
|
||
│ └── Image (src: vehiclePhoto, fit: Cover)
|
||
├── Expanded
|
||
│ └── Column (crossAxisAlignment: Start, spacing: 4)
|
||
│ ├── Text ("Toyota Corolla 2021", style: titleLarge)
|
||
│ ├── Text ("LT 1234 AB", style: bodySmall, color: TextSecondary)
|
||
│ ├── Row (spacing: 4)
|
||
│ │ └── Badge (status: "Active", color: conditional)
|
||
│ └── Text ("15,000 XAF/day", style: labelLarge, color: Primary)
|
||
└── IconButton (icon: more_vert, onTap: vehicle options menu)
|
||
```
|
||
|
||
---
|
||
|
||
## Admin Role Screens
|
||
|
||
### Admin Dashboard
|
||
|
||
```
|
||
Scaffold (AppBar: title "Admin", actions: [notifications])
|
||
└── ListView (padding: 16, spacing: 16)
|
||
├── Row (spacing: 12)
|
||
│ ├── Expanded → ZivvoCard
|
||
│ │ └── Column
|
||
│ │ ├── Icon (people, color: Secondary, size: 32)
|
||
│ │ ├── Text ("12,450", style: headingLarge)
|
||
│ │ └── Text ("Total Users", style: bodySmall, color: TextSecondary)
|
||
│ └── Expanded → ZivvoCard
|
||
│ └── Column
|
||
│ ├── Icon (directions_car, color: Primary, size: 32)
|
||
│ ├── Text ("342", style: headingLarge)
|
||
│ └── Text ("Active Rides", style: bodySmall, color: TextSecondary)
|
||
├── Row (spacing: 12)
|
||
│ ├── Expanded → ZivvoCard
|
||
│ │ └── Column
|
||
│ │ ├── Icon (verified, color: Success, size: 32)
|
||
│ │ ├── Text ("89", style: headingLarge)
|
||
│ │ └── Text ("KYC Pending", style: bodySmall, color: Warning)
|
||
│ └── Expanded → ZivvoCard
|
||
│ └── Column
|
||
│ ├── Icon (warning, color: Error, size: 32)
|
||
│ ├── Text ("3", style: headingLarge)
|
||
│ └── Text ("Active SOS", style: bodySmall, color: Error)
|
||
├── ZivvoCard
|
||
│ └── Column (spacing: 12)
|
||
│ ├── Text ("Revenue Today", style: titleLarge)
|
||
│ ├── Text ("1,250,000 XAF", style: displayMedium, color: Primary)
|
||
│ └── Chart (type: Bar, height: 150)
|
||
└── ZivvoCard
|
||
└── Column (spacing: 8)
|
||
├── Text ("Recent Activity", style: titleLarge)
|
||
└── [ActivityRow] × 5
|
||
└── ListTile (leading: avatar, title: action, subtitle: timestamp)
|
||
```
|
||
|
||
### KYC Review Screen
|
||
|
||
```
|
||
Scaffold (AppBar: title "KYC Review", back button)
|
||
└── ListView (padding: 16, spacing: 16)
|
||
├── ZivvoCard
|
||
│ └── Column (spacing: 12)
|
||
│ ├── Row (spacing: 12)
|
||
│ │ ├── ZivvoAvatar (src: applicantPhoto, size: 64)
|
||
│ │ └── Column (crossAxisAlignment: Start)
|
||
│ │ ├── Text (applicantName, style: headingMedium)
|
||
│ │ ├── Text ("Driver Application", style: bodyMedium, color: TextSecondary)
|
||
│ │ └── Text ("Submitted 2h ago", style: bodySmall, color: TextSecondary)
|
||
│ ├── Divider
|
||
│ ├── Text ("Identity Document", style: titleLarge)
|
||
│ ├── Image (src: idFrontPhoto, width: Expand, height: 200, fit: Contain, radius: 12)
|
||
│ ├── Image (src: idBackPhoto, width: Expand, height: 200, fit: Contain, radius: 12)
|
||
│ ├── Divider
|
||
│ ├── Text ("Driver's License", style: titleLarge)
|
||
│ ├── Image (src: licensePhoto, width: Expand, height: 200, fit: Contain, radius: 12)
|
||
│ ├── Divider
|
||
│ ├── Text ("Vehicle Registration", style: titleLarge)
|
||
│ ├── Image (src: registrationPhoto, width: Expand, height: 200, fit: Contain, radius: 12)
|
||
│ ├── Divider
|
||
│ ├── Text ("Selfie Verification", style: titleLarge)
|
||
│ ├── Row (spacing: 12)
|
||
│ │ ├── Image (src: selfiePhoto, width: 150, height: 150, fit: Cover, radius: 12)
|
||
│ │ └── Column
|
||
│ │ ├── Row → Icon(check) + Text("Face match: 94%")
|
||
│ │ └── Row → Icon(check) + Text("Liveness: Passed")
|
||
├── ZivvoInput (hintText: "Rejection reason (if applicable)", maxLines: 3)
|
||
├── Row (spacing: 12)
|
||
│ ├── Expanded
|
||
│ │ └── ZivvoButtonDanger (text: "Reject", onTap: reject with reason)
|
||
│ └── Expanded
|
||
│ └── ZivvoButtonPrimary (text: "Approve", onTap: approve KYC)
|
||
```
|
||
|
||
---
|
||
|
||
## Bottom Navigation Bars
|
||
|
||
### Customer Bottom Nav
|
||
|
||
```
|
||
BottomNavigationBar (type: Fixed, backgroundColor: Surface, elevation: 8)
|
||
├── Item (icon: home, label: "Home", activeColor: Primary)
|
||
├── Item (icon: history, label: "Rides", activeColor: Primary)
|
||
├── Item (icon: directions_car, label: "Rentals", activeColor: Primary)
|
||
└── Item (icon: person, label: "Account", activeColor: Primary)
|
||
```
|
||
|
||
### Driver Bottom Nav
|
||
|
||
```
|
||
BottomNavigationBar
|
||
├── Item (icon: map, label: "Home")
|
||
├── Item (icon: list, label: "Trips")
|
||
├── Item (icon: account_balance_wallet, label: "Earnings")
|
||
└── Item (icon: person, label: "Account")
|
||
```
|
||
|
||
### Dealer Bottom Nav
|
||
|
||
```
|
||
BottomNavigationBar
|
||
├── Item (icon: dashboard, label: "Dashboard")
|
||
├── Item (icon: directions_car, label: "Fleet")
|
||
├── Item (icon: assignment, label: "Requests")
|
||
└── Item (icon: person, label: "Account")
|
||
```
|
||
|
||
### Admin Bottom Nav
|
||
|
||
```
|
||
BottomNavigationBar
|
||
├── Item (icon: dashboard, label: "Dashboard")
|
||
├── Item (icon: people, label: "Users")
|
||
├── Item (icon: verified_user, label: "KYC")
|
||
├── Item (icon: report, label: "Disputes")
|
||
└── Item (icon: settings, label: "Settings")
|
||
```
|