34 KiB
34 KiB
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
- Create a new page in FlutterFlow
- Follow the widget tree top-down — add outermost widget first
- Indented items are children of the item above
- Properties in parentheses are the key values to set
- 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")