A Persian-first Flutter e-commerce app for browsing, searching and buying luxury watches.
Clean Bloc architecture, RTL layout, and a polished shopping experience — from catalog to checkout.
Visual Tour • Features • Tech Stack • Run Locally • Architecture
These are actual Flutter renders from the running app — not mockups or Figma exports. Light, RTL-optimized, and production-feeling.
Left: Home catalog with hero carousel & categories (ساعت مردانه / اسپورت / زنانه / دیجیتال) • Center: Product detail with specs & CTA • Right: Basket with stepper & pricing (تومان)
📸 See more (how it's built)
- Home (
home.jpg): Search (جستجوی محصولات) + Watch Store branding, hero carousel (3 dots), horizontal category chips with gradient cards, product grid with discount badges (۲٪) and price in Toman, bottom nav (خانه / سبد خرید / پروفایل). - Detail (
detail.jpg): Full-widthG-SHOCK GA-2000SU-1ADRimage, breadcrumb, tabs (خصوصیات / نقد و بررسی / نظرات), spec chips (جنس بدنه: تیتانیوم,جنس بند: چرم), sticky price + primary CTAافزودن به سبد خرید. - Basket (
basket.jpg):سبد خریدheader, delivery banner, two items (SRPG23J1 سیکو×5 andMG07G11I سیتیزن×9) with original vs. discounted price,+ / −stepper, delete icon, sticky footer with totalsمجموع با تخفیف ۷۵,۶۵۷,۲۰۰ تومانand red CTAادامه فرآیند خرید.
- Catalog Home — Hero carousel (
carousel_slider) + auto-scroll, category filter chips,پربازدیدترین هاhottest section with grid - Product Detail — Gallery, specs, reviews tabs, price with discount,
افزودن به سبد خریدCTA - Basket / Cart —
BasketBlocwithBasketCountProductEvent, quantity stepper, item removal, discount calculation, persisted total - Search —
SearchBloc+productRepository+ Dio, debounced, empty/error states handled - Auth —
AuthenticationCubitwith phone-entry flow,SharedPreferencesManager,LoggedinState→MainScreenelseEnterPhoneScreen - Navigation — Bottom nav (
خانه / سبد خرید با Badge 2 / پروفایل),route/routes.dartdeclarative routing - Persian UX —
Locale('fa'), RTL mirroring, Persian numerals & currency (تومان),google_fonts, proper vertical rhythm
| Area | Stack |
|---|---|
| Core | Flutter 3.3+ / Dart 3.3+ |
| State | flutter_bloc 8.1.4 + bloc 8.1.3 (BasketBloc, SearchBloc, AuthenticationCubit) |
| Networking | dio 5.4.1 + equatable models |
| Persistence | shared_preferences + SharedPreferencesManager |
| UI | google_fonts 6.2.1, flutter_svg 2.0.10, carousel_slider 4.2.1, dropdown_button2 2.3.9 |
| Services | image_picker 1.1.0, image_cropper 5.0.1, flutter_osm_plugin 0.70.4, url_launcher 6.3.0 |
| Architecture | Repository pattern (data/repository → product_repository.dart, cart_repository.dart) + feature-based folders |
lib/
├── data/
│ └── repository/
│ ├── cart_repository.dart
│ └── product_repository.dart
├── models/
├── screens/
│ ├── authentication/
│ │ ├── cubit/authentication_cubit.dart
│ │ └── enter_phone_screen.dart
│ ├── basket_screen/bloc/basket_bloc.dart
│ ├── search_screen/bloc/search_bloc.dart
│ └── main_screen/main_screen.dart
├── widgets/ # reusable UI (product card, stepper, chip)
├── route/routes.dart
├── style/app_theme.dart # lightThemeData()
├── utils/shared_preferences_manager.dart
├── constant/
├── gen/
└── main.dart # MultiBlocProvider + Locale('fa')
State flow is unidirectional: UI → Bloc Event → Repository (Dio) → State → UI. Cart count is derived via BasketCountProductEvent on app start.
# 1. Clone
git clone https://github.com/Muhammad1831/Watch-Store.git
cd Watch-Store
# 2. Install
flutter pub get
# 3. Run (pick a device)
flutter run -d chrome # Web — fastest to verify RTL
flutter run -d android # Android emulator
flutter run -d ios # iOS simulator (macOS)
# 4. Build release
flutter build apk --release
flutter build web --releaseTested on: Flutter 3.3.2. No env vars or API keys required — mock data layer works offline. When backend is ready, set Dio baseUrl in data/repository/.
- Typography: Persian-first with
google_fonts, line-height tuned for Arabic script - Color: Dark watch imagery on light cream/cyan cards, red discount badges, solid primary CTA
- Empty/Loading/Error: Every async view has a dedicated state — no blank screens
- RTL: All paddings, icons and carousels mirrored;
carousel_sliderrespects RTL
- Favorites / Wishlist with local persistence
- Payment gateway & order tracking
- Push notifications for price drops (Firebase Messaging)
- Unit tests for
BasketBloc+ widget tests for cart stepper - Dark mode (already in
app_theme.dartfoundation)
PRs welcome — please keep Persian UX and Bloc conventions. Run flutter analyze before pushing.
Built with Flutter 💙 by Muhammad Saleh · Persian-first, Bloc-clean, shipment-ready
Actual implementation captures from the running app — no Figma mockups. Prices in Toman are demo data.


