Skip to main content

Swopix — Technical Documentation

Last updated: May 5, 2026


Table of Contents

  1. Project Overview
  2. Tech Stack
  3. Project Structure
  4. Architecture
  5. Dependencies
  6. Theme System
  7. Routing
  8. Screens & Components
  9. Shared Widgets
  10. Platform Considerations
  11. Known Issues Summary
  12. Environment & Configuration

1. Project Overview

Swopix is a Flutter-based college campus marketplace application. It enables verified students to buy, sell, and rent items within their local college community. The app enforces identity verification (student ID capture) and uses a trust score system to build community confidence.

Target Platforms: Android, iOS, Web (Chrome)
Package Name: com.swopix.app
Flutter SDK Requirement: ^3.6.0 (Dart SDK ^3.6.0)


2. Tech Stack

LayerTechnology
UI FrameworkFlutter 3.x (Material 3)
LanguageDart 3.x
Responsive Layoutsizer ^2.0.15
TypographyGoogle Fonts (plus_jakarta_sans, inter, jetbrains_mono)
NavigationFlutter Named Routes (MaterialApp.routes)
State ManagementsetState (local, no global state manager)
BackendFirebase (Auth, Firestore, Storage)
PaymentsRazorpay
Networkingdio ^5.4.0 (declared, not yet integrated)
Local Storageshared_preferences ^2.2.2
Image Loadingcached_network_image ^3.3.1
SVG Renderingflutter_svg ^2.0.9
Cameracamera ^0.10.5+5
Image Pickerimage_picker ^1.0.4
Permissionspermission_handler ^11.1.0
Phone Inputintl_phone_number_input ^0.7.5
OTP Inputpinput ^6.0.0
Apple Sign Insign_in_with_apple ^7.0.1
Connectivityconnectivity_plus ^6.1.4
Sharingshare_plus ^12.0.1
Toastsfluttertoast ^8.2.4
Chartsfl_chart ^0.65.0
Page Indicatorssmooth_page_indicator ^1.2.1
Swipeable List Itemsflutter_slidable ^4.0.3
Dropdown Searchdropdown_search ^6.0.2
Build TargetAndroid (minSdk 21), iOS 12+, Web

3. Project Structure

lib/
├── main.dart # App entry point, Firebase init, error handler, orientation lock
├── firebase_options.dart # Generated by FlutterFire CLI
├── app/
│ ├── routes.dart # All named route definitions and route map
│ └── theme.dart # Light & dark ThemeData, color constants, text styles
├── core/
│ ├── app_export.dart # Barrel export: connectivity, google_fonts, routes, widgets, theme
│ ├── currency_service.dart # Multi-currency formatting (default: INR)
│ ├── listings_notifier.dart # ChangeNotifier for global listings state (not yet wired)
│ └── theme_service.dart # Theme persistence via SharedPreferences
├── models/
│ └── user_model.dart # UserModel with Firestore serialization
├── services/
│ ├── auth_service.dart # Firebase Auth wrapper (email, Google, Apple, phone OTP)
│ ├── firestore_service.dart # All Firestore reads/writes
│ ├── storage_service.dart # Firebase Storage + Cloudinary uploads
│ ├── payment_service.dart # Razorpay checkout wrapper
│ ├── order_service.dart # Order + payment recording in Firestore
│ ├── ocr_service.dart # ML Kit OCR fallback for ID verification
│ ├── gemini_ocr_service.dart # Gemini Vision API OCR (primary ID extraction)
│ ├── gemini_id_verification_service.dart # Gemini authenticity check (unused — see RED-02)
│ ├── content_moderation_service.dart # Keyword-based listing moderation (not yet called)
│ ├── trust_score_service.dart # Trust score calculation (not yet called)
│ ├── college_service.dart # OpenStreetMap college lookup
│ └── env_loader.dart # Reads env.json for API keys
├── widgets/ # Shared reusable widgets
│ ├── custom_app_bar.dart # AppBar variants (standard, search, transparent, minimal)
│ ├── custom_error_widget.dart # Global error fallback widget
│ ├── custom_icon_widget.dart # Icon name → IconData mapper (large icon map)
│ ├── custom_image_widget.dart # Multi-source image widget (network, file, SVG, asset)
│ └── main_shell.dart # Main navigation shell with bottom bar + FAB
└── screens/
├── splash/
│ └── splash_screen.dart
├── onboarding/
│ └── onboarding_screen.dart
├── auth/
│ └── auth_screen.dart
├── college_selection/
│ ├── college_selection_screen.dart
│ └── widgets/
│ ├── college_dropdown_field.dart
│ ├── location_permission_card.dart
│ └── progress_indicator_widget.dart
├── id_verification/
│ ├── id_verification_screen.dart
│ └── widgets/
│ ├── camera_preview_overlay.dart
│ ├── id_capture_card.dart
│ ├── verification_instructions.dart
│ └── verification_step_indicator.dart
├── admin_panel/
│ └── admin_panel_screen.dart # Full admin dashboard (fully implemented)
├── home/
│ ├── home_screen.dart
│ └── widgets/
│ ├── empty_state_widget.dart
│ ├── filter_bottom_sheet_widget.dart
│ ├── filter_chip_widget.dart
│ ├── listing_card_widget.dart
│ └── search_bar_widget.dart
├── listing_details/
│ ├── listing_details_screen.dart
│ └── widgets/
│ ├── image_carousel_widget.dart
│ ├── purchase_bottom_sheet.dart
│ ├── rental_duration_bottom_sheet.dart
│ ├── rental_info_card_widget.dart
│ └── seller_info_card_widget.dart
├── create_listing/
│ ├── create_listing_screen.dart
│ └── widgets/
│ ├── category_selector_widget.dart
│ ├── condition_selector_widget.dart
│ ├── photo_gallery_widget.dart
│ └── pricing_section_widget.dart
├── chat/
│ ├── chat_screen.dart # Inbox / conversation list (mock data — GAP-02)
│ ├── individual_chat_screen.dart # Single conversation view (mock data — GAP-03)
│ └── widgets/
│ ├── chat_input_widget.dart
│ ├── listing_context_card_widget.dart
│ ├── message_bubble_widget.dart
│ ├── quick_action_chip_widget.dart
│ └── typing_indicator_widget.dart
├── rentals/
│ ├── rentals_screen.dart
│ └── widgets/
│ ├── empty_state_widget.dart
│ ├── rental_card_widget.dart
│ └── rental_history_card_widget.dart
├── profile/
│ ├── profile_screen.dart
│ └── widgets/
│ ├── menu_item_widget.dart
│ ├── profile_header_widget.dart
│ ├── stats_section_widget.dart
│ ├── trust_score_widget.dart
│ └── verification_status_widget.dart
├── settings/
│ └── settings_screen.dart
├── support/
│ └── support_screen.dart
└── legal/
├── privacy_policy_screen.dart
└── terms_conditions_screen.dart

assets/
├── images/
│ ├── img_app_logo.svg
│ ├── no-image.jpg # Fallback image for CustomImageWidget
│ └── sad_face.svg # Used in CustomErrorWidget

4. Architecture

Pattern

The app currently uses a simple stateful widget pattern with setState for all local state. There is no global state management layer. Each screen is self-contained with its own mock data.

Entry Point (main.dart)

  • Calls WidgetsFlutterBinding.ensureInitialized()
  • Installs a custom ErrorWidget.builder that shows CustomErrorWidget on Flutter render errors (with a 5-second debounce to avoid repeated error widgets)
  • Locks device orientation to portrait via SystemChrome.setPreferredOrientations
  • Runs MyApp which wraps everything in Sizer for responsive sizing

MyApp

  • Uses MaterialApp with named routes
  • Applies AppTheme.lightTheme (dark theme defined but themeMode is hard-coded to ThemeMode.light)
  • Wraps child in MediaQuery override to lock textScaler to 1.0 (prevents system font size from breaking layouts)
  • Sets initialRoute to AppRoutes.initial which maps to SplashScreen
  • All navigation uses Navigator.pushNamed / Navigator.pushReplacementNamed / Navigator.pushNamedAndRemoveUntil
  • Route arguments are passed via arguments parameter but not yet consumed by destination screens (see BUG-16)
  • No deep linking or dynamic link handling is implemented

5. Dependencies

Core (Do Not Remove)

PackageVersionPurpose
flutterSDKFramework
sizer^2.0.15Responsive sizing (w, h, sp units)
flutter_svg^2.0.9SVG rendering for logo and error assets
google_fonts^6.1.0PlusJakartaSans, Inter, JetBrainsMono
shared_preferences^2.2.2Local key-value storage
web^1.1.1Web platform interop

Feature Dependencies

PackageVersionPurpose
cached_network_image^3.3.1Network image caching
connectivity_plus^6.1.4Network connectivity detection
dio^5.4.0HTTP client (not yet used)
fluttertoast^8.2.4Toast notifications
fl_chart^0.65.0Charts (not yet used in screens)
smooth_page_indicator^1.2.1Onboarding page dots
intl_phone_number_input^0.7.5International phone number input
pinput^6.0.0OTP/PIN input field
sign_in_with_apple^7.0.1Apple Sign In (iOS only)
permission_handler^11.1.0Camera, location permissions
dropdown_search^6.0.2Searchable dropdown (college selection)
camera^0.10.5+5Camera access for ID capture
image_picker^1.0.4Gallery/camera image selection
share_plus^12.0.1Native share sheet
flutter_slidable^4.0.3Swipeable list items (rental management)

6. Theme System

Color Palette

The app defines two visual themes. Note: As of the current codebase state, only 7 light-theme colors are declared as static const. The dark theme and many screens reference ~25 additional color constants that are not yet declared (see BUG-01 in errors.md).

Declared Light Theme Colors:

ConstantHexUsage
primaryIndigo#4F46E5Primary brand color
secondaryEmerald#10B981Secondary accent
accentAmber#F59E0BTertiary accent
surfaceWhite#FAFAFAScaffold background
textDark#111827Primary text
textLight#6B7280Secondary text
softBorder#E5E7EBBorder color

Required But Undeclared Colors (must be added): primarySkyBlue, primarySkyBlueDark, accentLimeGreen, accentLimeGreenDark, backgroundDark, surfaceDark, cardDark, borderDark, borderLight, neutralCharcoal, mediumGrey, lightGrey, pureWhite, shadowDark, errorRed, successGreen, warningOrange, trustGold, textHighEmphasisLight, textHighEmphasisDark, textMediumEmphasisLight, textMediumEmphasisDark, textDisabledLight, textDisabledDark

Typography

  • Light theme: PlusJakartaSans (Google Fonts)
  • Dark theme: Inter (Google Fonts)
  • Data display (prices, codes): JetBrainsMono (via AppTheme.dataTextStyle())
  • Text scaling is locked to 1.0 globally via MediaQuery override in MyApp

Responsive Sizing

All sizing uses sizer package units:

  • x.w — percentage of screen width
  • x.h — percentage of screen height
  • x.sp — scalable font size

7. Routing

All routes are defined in lib/routes/app_routes.dart.

Route ConstantPathScreen
AppRoutes.initial/SplashScreen
AppRoutes.splash/splash-screenSplashScreen
AppRoutes.onboarding/onboarding-screenOnboardingScreen
AppRoutes.authentication/authentication-screenAuthenticationScreen
AppRoutes.collegeSelection/college-selection-screenCollegeSelectionScreen
AppRoutes.idVerification/id-verification-screenIdVerificationScreen
AppRoutes.homeMarketplace/home-marketplace-screenHomeMarketplaceScreen
AppRoutes.listingDetails/listing-details-screenListingDetailsScreen
AppRoutes.createListing/create-listing-screenCreateListingScreen
AppRoutes.chat/chat-screenChatScreen
AppRoutes.individualChat/individual-chat-screenIndividualChatScreen
AppRoutes.rentalManagement/rental-management-screenRentalManagementScreen
AppRoutes.profile/profile-screenProfileScreen
SplashScreen
├── (new user) → OnboardingScreen → AuthenticationScreen
├── (authenticated, unverified) → IdVerificationScreen
└── (authenticated, verified) → HomeMarketplaceScreen

8. Screens & Components

SplashScreen

  • Purpose: App launch screen with animated logo, initialization status messages, and navigation routing
  • Key Logic: _initializeApp() simulates service initialization with staged delays. _navigateToNextScreen() determines where to go based on auth/verification state (currently hard-coded to always go to onboarding)
  • Animations: Scale + fade animation on logo using AnimationController with SingleTickerProviderStateMixin
  • Error Handling: Shows retry dialog on initialization failure

OnboardingScreen

  • Purpose: 3-slide feature introduction for new users
  • Key Logic: PageController with SmoothPageIndicator. Slide content is data-driven from _slides list. Last slide shows "Get Started" button instead of "Next Step"
  • Navigation: Skip button → AuthenticationScreen. Last slide "Get Started" → AuthenticationScreen

AuthenticationScreen

  • Purpose: Multi-method authentication (Phone OTP, Google, Apple, Email)
  • Key Logic: AuthMethod enum tracks selected method. Phone flow shows InternationalPhoneNumberInput then transitions to Pinput OTP entry. Apple Sign In is conditionally shown only on non-web iOS (!kIsWeb && defaultTargetPlatform == TargetPlatform.iOS)
  • OTP Timer: Future.doWhile countdown from 60 seconds. Resend button appears when timer reaches 0
  • Navigation: All auth methods → CollegeSelectionScreen on success

CollegeSelectionScreen

  • Purpose: Step 2 of 4 in verification. User selects their college from GPS-detected nearby institutions
  • Key Logic: WidgetsBindingObserver detects app resume to re-check location permission. Permission.location request flow with permanent denial dialog. Mock college data filtered by detected town
  • Widgets: CollegeDropdownField (uses dropdown_search), LocationPermissionCard, ProgressIndicatorWidget
  • Navigation: Continue → IdVerificationScreen

IdVerificationScreen

  • Purpose: Step 3 of 4. Captures front and back of student ID using device camera
  • Key Logic: availableCameras() initialization. Platform-specific camera settings (focus mode, flash). CameraPreviewOverlay pushed as a full-screen route for capture. Web uses front camera; native uses back camera
  • Widgets: IdCaptureCard, VerificationInstructions, VerificationStepIndicator, CameraPreviewOverlay
  • Navigation: Submit → HomeMarketplaceScreen (after success dialog)

HomeMarketplaceScreen

  • Purpose: Main browsing hub. Grid of listings with search, filter, and category quick-links
  • Key Logic: Debounced search (300ms Timer). ScrollController listener for infinite scroll trigger. FilterBottomSheetWidget for multi-criteria filtering. Long-press on listing card shows quick actions bottom sheet
  • Widgets: SearchBarWidget, FilterChipWidget, ListingCardWidget, EmptyStateWidget, FilterBottomSheetWidget
  • Navigation: Listing tap → ListingDetailsScreen (with listing as argument). FAB/bottom bar → CreateListingScreen

ListingDetailsScreen

  • Purpose: Full listing view with images, description, seller info, and rental/purchase actions
  • Key Logic: ImageCarouselWidget for photo gallery. Collapsible description (5-line limit with "Read More"). RentalDurationBottomSheet for rental initiation. Share.share() for native sharing
  • Widgets: ImageCarouselWidget, SellerInfoCardWidget, RentalInfoCardWidget, RentalDurationBottomSheet
  • Note: Currently ignores route arguments and always shows mock MacBook Pro data (BUG-16)

CreateListingScreen

  • Purpose: Form to create a new marketplace listing with photos, details, and pricing
  • Key Logic: ImagePicker for camera/gallery photo selection (max 8 photos). Form validation with per-field error state. Pricing type toggle (sell / rent / both) shows/hides relevant price fields. Draft auto-save hooks (not yet implemented)
  • Widgets: PhotoGalleryWidget, CategorySelectorWidget, ConditionSelectorWidget, PricingSectionWidget
  • Navigation: Post success → HomeMarketplaceScreen

ChatScreen (Inbox)

  • Purpose: List of all active conversations
  • Key Logic: Mock conversation list with unread count badges, online status indicators, and listing context tags. Pull-to-refresh. Filter tabs (All/Unread/Archived) are rendered but non-functional
  • Navigation: Conversation tap → IndividualChatScreen

IndividualChatScreen

  • Purpose: Real-time messaging interface between buyer and seller
  • Key Logic: Message list with ListView.builder. Typing indicator simulation via Future.delayed. ChatInputWidget with image attachment support. Long-press on message shows copy/delete/report options. Quick action chips for common messages
  • Widgets: ListingContextCardWidget, QuickActionChipWidget, MessageBubbleWidget, TypingIndicatorWidget, ChatInputWidget

RentalManagementScreen

  • Purpose: Tracks active rentals and rental history with countdown timers
  • Key Logic: TabController for Active/History tabs. Slidable list items with Contact/Details/Report swipe actions. Overdue rentals visually distinguished. Rating dialog for completed rentals. Timer updates via recursive Future.delayed (see BUG-19)
  • Widgets: RentalCardWidget, RentalHistoryCardWidget, EmptyStateWidget

ProfileScreen

  • Purpose: User profile, verification status, trust score, stats, and account management
  • Key Logic: Verification status drives conditional UI (pending/rejected shows VerificationStatusWidget, approved shows TrustScoreWidget). Trust score breakdown bottom sheet. Logout with confirmation dialog
  • Widgets: ProfileHeaderWidget, VerificationStatusWidget, TrustScoreWidget, StatsSectionWidget, MenuItemWidget

9. Shared Widgets

CustomAppBar

Implements PreferredSizeWidget. Four variants:

  • standard — title + optional actions
  • search — embedded search TextField
  • transparent — for image backgrounds
  • minimal — back button only, no title

Additional variants: CustomAppBarWithTrustScore, CustomAppBarWithTimer

CustomBottomBar

Floating pill-shaped bottom navigation with 4 items (Browse, Messages, Rentals, Profile) and a central + FAB for creating listings. Note: Has compile errors (BUG-02, BUG-03).

CustomErrorWidget

Global error fallback. Displays sad_face.svg, error message, and a back/home button. Installed as ErrorWidget.builder in main.dart.

CustomIconWidget

Maps string icon names to IconData. Contains a comprehensive icon map covering the full Material Icons set. Used throughout the app to allow icon names to be passed as strings (e.g., from data models).

CustomImageWidget

Multi-source image widget supporting:

  • Network URLs → CachedNetworkImage
  • Local file paths → Image.file (native) / Image.network (web)
  • SVG assets → SvgPicture.asset
  • Asset paths → Image.asset
  • Falls back to assets/images/no-image.jpg on error

10. Platform Considerations

Web

  • Platform.isIOS / Platform.isAndroid must not be used — use kIsWeb and defaultTargetPlatform from package:flutter/foundation.dart
  • Apple Sign In button is hidden on web (!kIsWeb && defaultTargetPlatform == TargetPlatform.iOS)
  • Camera uses front-facing lens on web
  • File images use Image.network instead of Image.file on web

Android

  • AndroidManifest.xml declares INTERNET, CAMERA, READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE, ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION permissions (verify current manifest)
  • minSdkVersion should be 21+ for camera package compatibility

iOS

  • Info.plist requires NSCameraUsageDescription, NSLocationWhenInUseUsageDescription, NSPhotoLibraryUsageDescription
  • Apple Sign In requires Sign In with Apple capability in Xcode

11. Known Issues Summary

See errors.md for the full tracker and phased fix plan. Critical open items:

IDIssueSeverityPhase
GAP-14Listing not marked sold after purchase🔴 HIGHB
GAP-18Trust score service never called after transactions🟠 MEDIUMC
GAP-20Phone OTP auth has no UI🟠 MEDIUMD

12. Environment & Configuration

env.json

Located at project root. Contains environment-specific configuration (Gemini API key, Razorpay keys, Cloudinary credentials, etc.). This file should not be committed to version control. Add to .gitignore immediately and rotate any exposed keys.

Active keys used by the app:

  • geminiApiKey — used by GeminiOcrService and GeminiIdVerificationService
  • razorpayKeyId / razorpayKeySecret — used by PaymentService (secret must move to Cloud Function)
  • cloudinaryCloudName / cloudinaryApiKey / cloudinaryApiSecret — used by CloudinaryService

Dead keys (defined but never used — safe to remove):

  • supabaseUrl, supabaseAnonKey — app uses Firebase, not Supabase
  • openaiApiKey, anthropicApiKey, perplexityApiKey — no AI provider other than Gemini is used

Firebase

The project uses Firebase for Auth, Firestore, and Storage. Configuration is in firebase_options.dart (generated by FlutterFire CLI) and GoogleService-Info.plist (iOS) / google-services.json (Android).

# Reconfigure Firebase (regenerates firebase_options.dart)
flutterfire configure --project=swopix-cbf7c

⚠️ Firebase Security Rules for Firestore and Storage must be configured before production launch to prevent unauthorized reads/writes.

Flutter SDK

The project requires Flutter SDK ^3.6.0. Ensure flutter is in your system PATH. Run flutter doctor to verify setup.

Running the App

# Install dependencies
flutter pub get

# Run on Android
flutter run -d android

# Run on iOS
flutter run -d ios

# Run on Chrome (web)
flutter run -d chrome

Build

# Android APK
flutter build apk --release

# iOS
flutter build ios --release

# Web
flutter build web --release