# Flutter 11: To'liq Loyiha — Desktop & Mobile Kross-Platforma Dashboard & Store App

> **Holat:** 2026-yil. Nazariy bilimlarni mustahkamlashning eng yaxshi yo'li — bu barcha qismlarni (Dart 3, Clean Architecture, REST API, Dio, Riverpod, Desktop & Mobile moslashuvchan interfeys) birlashtirgan to'liq ishlab chiqarish (production-ready) loyihasini qurishdir. Ushbu darsda biz macOS, Windows, iOS va Android'da birdek mukammal ishlaydigan "DevStore Hub" — zamonaviy e-commerce dashboard ilovasini noldan quramiz.

---

## Mundarija

1. [Loyiha konsepsiyasi va UI/UX xaritasi](#loyixa-xaritasi)
2. [Loyihaning to'liq papkalar strukturasi (Clean Architecture)](#papka-strukturasi)
3. [Domain Qatlami: Entities va Repository Shartnomasi](#domain-qatlami)
4. [Data Qatlami: Dio Client, Models va Repository Implementatsiyasi](#data-qatlami)
5. [Presentation Qatlami: Riverpod Notifiers](#state-management)
6. [UI/UX Qatlami: Desktop va Mobile uchun Moslashuvchan Shell (App Shell)](#app-shell)
7. [Mahsulotlar Katalogi va Master-Detail ko'rinishi](#catalog-screen)
8. [Statistika Dashboardi va Responsive Grid](#dashboard-screen)
9. [Desktop xususiyatlari: Klaviatura Shortcuts va Context Menu integratsiyasi](#desktop-features)
10. [Testlash va Ishga tushirish yo'riqnomasi](#run-project)
11. [Xulosa va Keyingi Qadamlar](#xulosa)
12. [Rasmiy Manbalar](#manbalar)

---

## 1. Loyiha konsepsiyasi va UI/UX xaritasi {#loyixa-xaritasi}

Loyihamiz — bu tovarlar ro'yxatini real REST API orqali olib keluvchi, qidiruv, saralash, tahlil qilish va savatchaga qo'shish imkoniyatiga ega boshqaruv paneli (Dashboard) hisoblanadi.

```
┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
│                                       DEVSTORE MULTIPLATFORM                                     │
├────────────────────────────────┬─────────────────────────────────────────────────────────────────┤
│ DESKTOP (macOS & Windows)      │ MOBILE (iOS & Android)                                          │
├────────────────────────────────┼─────────────────────────────────────────────────────────────────┤
│ • Chap tomonda qat'iy Sidebar  │ • Yuqorida AppBar + Qidiruv maydoni                             │
│ • Klaviatura tezkor tugmalari: │ • Pastda zamonaviy NavigationBar                                │
│   - Cmd/Ctrl+K -> Qidiruv      │ • Vertikal to'liq ekranli ro'yxat                               │
│   - Cmd/Ctrl+R -> Yangilash    │ • Pull-to-refresh (barmog'i bilan pastga tortish)               │
│ • Master-Detail (2 ta ustun)   │ • Detail sahifasiga alohida ekran orqali o'tish (Push route)    │
│ • Sichqoncha Hover va Context  │ • Tizim haptikasi (titrash)                                     │
└────────────────────────────────┴─────────────────────────────────────────────────────────────────┘
```

---

## 2. Loyihaning to'liq papkalar strukturasi (Clean Architecture) {#papka-strukturasi}

```
lib/
├── core/
│   ├── network/
│   │   ├── api_client.dart
│   │   └── api_result.dart
│   ├── theme/
│   │   └── app_theme.dart
│   └── utils/
│       └── responsive.dart
├── features/
│   ├── products/
│   │   ├── domain/
│   │   │   ├── entities/
│   │   │   │   └── product.dart
│   │   │   └── repositories/
│   │   │       └── product_repository.dart
│   │   ├── data/
│   │   │   ├── models/
│   │   │   │   └── product_dto.dart
│   │   │   └── repositories/
│   │   │       └── product_repository_impl.dart
│   │   └── presentation/
│   │       ├── providers/
│   │       │   └── product_providers.dart
│   │       └── widgets/
│   │           ├── product_card.dart
│   │           └── product_detail_view.dart
│   └── dashboard/
│       └── presentation/
│           └── dashboard_screen.dart
├── app_shell.dart
└── main.dart
```

---

## 3. Domain Qatlami: Entities va Repository Shartnomasi {#domain-qatlami}

### `lib/features/products/domain/entities/product.dart`
```dart
class Product {
  final int id;
  final String title;
  final double price;
  final String description;
  final String category;
  final String image;
  final double rating;

  const Product({
    required this.id,
    required this.title,
    required this.price,
    required this.description,
    required this.category,
    required this.image,
    required this.rating,
  });
}
```

### `lib/features/products/domain/repositories/product_repository.dart`
```dart
import '../../../../core/network/api_result.dart';
import '../entities/product.dart';

abstract interface class ProductRepository {
  Future<ApiResult<List<Product>>> fetchProducts();
  Future<ApiResult<Product>> fetchProductDetails(int id);
}
```

---

## 4. Data Qatlami: Dio Client, Models va Repository Implementatsiyasi {#data-qatlami}

### `lib/core/network/api_result.dart`
```dart
sealed class ApiResult<T> {
  const ApiResult();
}

final class ApiSuccess<T> extends ApiResult<T> {
  final T data;
  const ApiSuccess(this.data);
}

final class ApiFailure<T> extends ApiResult<T> {
  final String message;
  final int? statusCode;
  const ApiFailure(this.message, {this.statusCode});
}
```

### `lib/features/products/data/models/product_dto.dart`
```dart
import '../../domain/entities/product.dart';

class ProductDto extends Product {
  const ProductDto({
    required super.id,
    required super.title,
    required super.price,
    required super.description,
    required super.category,
    required super.image,
    required super.rating,
  });

  factory ProductDto.fromJson(Map<String, dynamic> json) {
    return ProductDto(
      id: json['id'] as int,
      title: json['title'] as String? ?? 'Nomsiz',
      price: (json['price'] as num?)?.toDouble() ?? 0.0,
      description: json['description'] as String? ?? '',
      category: json['category'] as String? ?? 'Umumiy',
      image: json['image'] as String? ?? 'https://fakestoreapi.com/img/81fPKd-2AYL._AC_SL1500_.jpg',
      rating: ((json['rating'] as Map<String, dynamic>?)?['rate'] as num?)?.toDouble() ?? 4.5,
    );
  }
}
```

### `lib/features/products/data/repositories/product_repository_impl.dart`
```dart
import 'package:dio/dio.dart';
import '../../../../core/network/api_result.dart';
import '../../domain/entities/product.dart';
import '../../domain/repositories/product_repository.dart';
import '../models/product_dto.dart';

class ProductRepositoryImpl implements ProductRepository {
  final Dio dio;

  const ProductRepositoryImpl(this.dio);

  @override
  Future<ApiResult<List<Product>>> fetchProducts() async {
    try {
      // FakeStore API — ochiq test API
      final response = await dio.get('https://fakestoreapi.com/products');

      if (response.statusCode == 200) {
        final rawList = response.data as List<dynamic>;
        final products = rawList
            .map((json) => ProductDto.fromJson(json as Map<String, dynamic>))
            .toList();
        return ApiSuccess(products);
      }
      return ApiFailure('Server xatosi: ${response.statusCode}', statusCode: response.statusCode);
    } on DioException catch (e) {
      if (e.type == DioExceptionType.connectionTimeout || e.type == DioExceptionType.receiveTimeout) {
        return const ApiFailure('Server javob bermadi (Timeout)');
      }
      return const ApiFailure('Internetga ulanishni tekshiring');
    } catch (e) {
      return ApiFailure('Kutilmagan xato: $e');
    }
  }

  @override
  Future<ApiResult<Product>> fetchProductDetails(int id) async {
    try {
      final response = await dio.get('https://fakestoreapi.com/products/$id');
      if (response.statusCode == 200) {
        return ApiSuccess(ProductDto.fromJson(response.data as Map<String, dynamic>));
      }
      return ApiFailure('Mahsulot topilmadi: ${response.statusCode}');
    } catch (e) {
      return ApiFailure('Xatolik: $e');
    }
  }
}
```

---

## 5. Presentation Qatlami: Riverpod Notifiers {#state-management}

### `lib/features/products/presentation/providers/product_providers.dart`
```dart
import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../../core/network/api_result.dart';
import '../../domain/entities/product.dart';
import '../../domain/repositories/product_repository.dart';
import '../../data/repositories/product_repository_impl.dart';

// Dio instansiyasi
final dioProvider = Provider<Dio>((ref) {
  return Dio(
    BaseOptions(
      connectTimeout: const Duration(seconds: 10),
      receiveTimeout: const Duration(seconds: 10),
    ),
  );
});

// Repository provayderi
final productRepositoryProvider = Provider<ProductRepository>((ref) {
  return ProductRepositoryImpl(ref.watch(dioProvider));
});

// Tanlangan mahsulot (Master-Detail uchun)
final selectedProductProvider = StateProvider<Product?>((ref) => null);

// Qidiruv so'zi
final searchQueryProvider = StateProvider<String>((ref) => '');

// Mahsulotlar ro'yxatini yuklovchi FutureProvider
final productsProvider = FutureProvider<List<Product>>((ref) async {
  final repository = ref.watch(productRepositoryProvider);
  final result = await repository.fetchProducts();

  return switch (result) {
    ApiSuccess(:final data) => data,
    ApiFailure(:final message) => throw Exception(message),
  };
});

// Qidiruv bo'yicha filtrlangan mahsulotlar
final filteredProductsProvider = Provider<AsyncValue<List<Product>>>((ref) {
  final productsAsync = ref.watch(productsProvider);
  final query = ref.watch(searchQueryProvider).toLowerCase();

  return productsAsync.whenData((products) {
    if (query.isEmpty) return products;
    return products.where((p) => p.title.toLowerCase().contains(query)).toList();
  });
});
```

---

## 6. UI/UX Qatlami: Desktop va Mobile uchun Moslashuvchan Shell {#app-shell}

Ilovaning asosi — `AppShell` ekrani. U foydalanuvchining ekrani kengligini tekshirib, avtomatik ravishda navigatsiyani o'zgartiradi:

```dart
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'features/products/presentation/providers/product_providers.dart';
import 'features/products/presentation/widgets/catalog_view.dart';
import 'features/dashboard/presentation/dashboard_screen.dart';

class AppShell extends ConsumerStatefulWidget {
  const AppShell({super.key});

  @override
  ConsumerState<AppShell> createState() => _AppShellState();
}

class _AppShellState extends ConsumerState<AppShell> {
  int _currentTab = 0;

  @override
  Widget build(BuildContext context) {
    final width = MediaQuery.sizeOf(context).width;
    final isDesktop = width >= 1024;
    final isTablet = width >= 600 && width < 1024;

    // Desktop Shortcuts (Cmd+K / Ctrl+K, Cmd+R / Ctrl+R)
    return Shortcuts(
      shortcuts: {
        LogicalKeySet(
          Platform.isMacOS ? LogicalKeyboardKey.meta : LogicalKeyboardKey.control,
          LogicalKeyboardKey.keyR,
        ): const _RefreshIntent(),
      },
      child: Actions(
        actions: {
          _RefreshIntent: CallbackAction<_RefreshIntent>(
            onInvoke: (_) => ref.refresh(productsProvider),
          ),
        },
        child: Focus(
          autofocus: true,
          child: Scaffold(
            body: Row(
              children: [
                // DESKTOP VA TABLET YONBOSH MENYUSI
                if (isDesktop || isTablet)
                  NavigationRail(
                    extended: isDesktop,
                    minExtendedWidth: 220,
                    selectedIndex: _currentTab,
                    onDestinationSelected: (val) => setState(() => _currentTab = val),
                    leading: Padding(
                      padding: const EdgeInsets.symmetric(vertical: 24, horizontal: 16),
                      child: Row(
                        children: [
                          Container(
                            padding: const EdgeInsets.all(8),
                            decoration: BoxDecoration(
                              color: Colors.indigo,
                              borderRadius: BorderRadius.circular(10),
                            ),
                            child: const Icon(Icons.storefront_rounded, color: Colors.white, size: 22),
                          ),
                          if (isDesktop) ...[
                            const SizedBox(width: 12),
                            const Text(
                              'DevStore',
                              style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
                            ),
                          ],
                        ],
                      ),
                    ),
                    destinations: const [
                      NavigationRailDestination(
                        icon: Icon(Icons.dashboard_outlined),
                        selectedIcon: Icon(Icons.dashboard),
                        label: Text('Boshqaruv'),
                      ),
                      NavigationRailDestination(
                        icon: Icon(Icons.inventory_2_outlined),
                        selectedIcon: Icon(Icons.inventory_2),
                        label: Text('Katalog'),
                      ),
                      NavigationRailDestination(
                        icon: Icon(Icons.shopping_cart_outlined),
                        selectedIcon: Icon(Icons.shopping_cart),
                        label: Text('Savatcha'),
                      ),
                    ],
                  ),
                if (isDesktop || isTablet) const VerticalDivider(width: 1, thickness: 1),

                // ASOSIY SAHIFA
                Expanded(
                  child: IndexedStack(
                    index: _currentTab,
                    children: const [
                      DashboardScreen(),
                      CatalogView(),
                      Center(child: Text('Savatcha bo\'limi')),
                    ],
                  ),
                ),
              ],
            ),
            // MOBIL PASTKI MENYUSI (< 600px)
            bottomNavigationBar: (!isDesktop && !isTablet)
                ? NavigationBar(
                    selectedIndex: _currentTab,
                    onDestinationSelected: (val) => setState(() => _currentTab = val),
                    destinations: const [
                      NavigationDestination(icon: Icon(Icons.dashboard_outlined), selectedIcon: Icon(Icons.dashboard), label: 'Statistika'),
                      NavigationDestination(icon: Icon(Icons.inventory_2_outlined), selectedIcon: Icon(Icons.inventory_2), label: 'Katalog'),
                      NavigationDestination(icon: Icon(Icons.shopping_cart_outlined), selectedIcon: Icon(Icons.shopping_cart), label: 'Savatcha'),
                    ],
                  )
                : null,
          ),
        ),
      ),
    );
  }
}

class _RefreshIntent extends Intent {
  const _RefreshIntent();
}
```

---

## 7. Mahsulotlar Katalogi va Master-Detail ko'rinishi {#catalog-screen}

Ushbu qismda desktopda mahsulot bosilganda o'ng tomonda uning to'liq ma'lumoti chiqadi (Master-Detail). Mobilda esa bosilganda yangi sahifaga o'tiladi:

```dart
// lib/features/products/presentation/widgets/catalog_view.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../domain/entities/product.dart';
import '../providers/product_providers.dart';

class CatalogView extends ConsumerWidget {
  const CatalogView({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final width = MediaQuery.sizeOf(context).width;
    final isDesktop = width >= 1024;
    final productsAsync = ref.watch(filteredProductsProvider);
    final selectedProduct = ref.watch(selectedProductProvider);

    return Scaffold(
      appBar: AppBar(
        title: const Text('Mahsulotlar katalogi'),
        bottom: PreferredSize(
          preferredSize: const Size.fromHeight(60),
          child: Padding(
            padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
            child: SearchBar(
              hintText: 'Mahsulot nomini qidiring...',
              leading: const Icon(Icons.search),
              onChanged: (val) => ref.read(searchQueryProvider.notifier).state = val,
            ),
          ),
        ),
        actions: [
          IconButton(
            tooltip: 'Yangilash',
            icon: const Icon(Icons.refresh),
            onPressed: () => ref.refresh(productsProvider),
          ),
        ],
      ),
      body: productsAsync.when(
        loading: () => const Center(child: CircularProgressIndicator.adaptive()),
        error: (err, _) => Center(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              const Icon(Icons.error_outline, size: 48, color: Colors.red),
              const SizedBox(height: 12),
              Text(err.toString()),
              const SizedBox(height: 12),
              ElevatedButton(onPressed: () => ref.refresh(productsProvider), child: const Text('Qayta urinish')),
            ],
          ),
        ),
        data: (products) {
          if (products.isEmpty) {
            return const Center(child: Text('Hech qanday mahsulot topilmadi'));
          }

          if (!isDesktop) {
            // MOBIL RO'YXAT
            return ListView.separated(
              padding: const EdgeInsets.all(16),
              itemCount: products.length,
              separatorBuilder: (_, __) => const SizedBox(height: 12),
              itemBuilder: (context, index) {
                final product = products[index];
                return _buildProductTile(context, product, onTap: () {
                  Navigator.push(
                    context,
                    MaterialPageRoute(builder: (_) => ProductDetailPage(product: product)),
                  );
                });
              },
            );
          }

          // DESKTOP MASTER-DETAIL (2 ustun)
          return Row(
            children: [
              // Chap ustun: Ro'yxat
              SizedBox(
                width: 420,
                child: ListView.separated(
                  padding: const EdgeInsets.all(16),
                  itemCount: products.length,
                  separatorBuilder: (_, __) => const SizedBox(height: 10),
                  itemBuilder: (context, index) {
                    final product = products[index];
                    final isSelected = selectedProduct?.id == product.id;
                    return _buildProductTile(
                      context,
                      product,
                      isSelected: isSelected,
                      onTap: () => ref.read(selectedProductProvider.notifier).state = product,
                    );
                  },
                ),
              ),
              const VerticalDivider(width: 1, thickness: 1),

              // O'ng ustun: Tafsilotlar
              Expanded(
                child: selectedProduct == null
                    ? const Center(child: Text('Mahsulotni tanlang'))
                    : ProductDetailContent(product: selectedProduct),
              ),
            ],
          );
        },
      ),
    );
  }

  Widget _buildProductTile(BuildContext context, Product product, {bool isSelected = false, required VoidCallback onTap}) {
    return Card(
      elevation: isSelected ? 2 : 0,
      color: isSelected ? Colors.indigo.shade50 : Colors.white,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(12),
        side: BorderSide(
          color: isSelected ? Colors.indigo : Colors.grey.shade300,
          width: isSelected ? 2 : 1,
        ),
      ),
      child: ListTile(
        contentPadding: const EdgeInsets.all(12),
        leading: ClipRRect(
          borderRadius: BorderRadius.circular(8),
          child: Image.network(product.image, width: 60, height: 60, fit: BoxFit.contain),
        ),
        title: Text(product.title, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle(fontWeight: FontWeight.w600)),
        subtitle: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const SizedBox(height: 4),
            Text(product.category.toUpperCase(), style: TextStyle(fontSize: 11, color: Colors.grey.shade600)),
            const SizedBox(height: 4),
            Text('\$${product.price}', style: const TextStyle(color: Colors.indigo, fontWeight: FontWeight.bold, fontSize: 15)),
          ],
        ),
        onTap: onTap,
      ),
    );
  }
}
```

---

## 8. Statistika Dashboardi va Responsive Grid {#dashboard-screen}

Katta ekranda 4 ta, o'rtacha ekranda 2 ta, mobilda esa 1 ta ustunli bo'lib moslashuvchi (Responsive Grid) statistika bloki:

```dart
// lib/features/dashboard/presentation/dashboard_screen.dart
import 'package:flutter/material.dart';

class DashboardScreen extends StatelessWidget {
  const DashboardScreen({super.key});

  @override
  Widget build(BuildContext context) {
    final width = MediaQuery.sizeOf(context).width;

    // Ustunlar sonini kenglikka qarab belgilaymiz
    int crossAxisCount = 1;
    if (width >= 1200) {
      crossAxisCount = 4;
    } else if (width >= 700) {
      crossAxisCount = 2;
    }

    return Scaffold(
      appBar: AppBar(title: const Text('Boshqaruv Paneli (Analytics)')),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(24),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('Kompaniya Ko\'rsatkichlari', style: Theme.of(context).textTheme.headlineSmall?.copyWith(fontWeight: FontWeight.bold)),
            const SizedBox(height: 16),
            GridView.count(
              shrinkWrap: true,
              physics: const NeverScrollableScrollPhysics(),
              crossAxisCount: crossAxisCount,
              mainAxisSpacing: 16,
              crossAxisSpacing: 16,
              childAspectRatio: 2.0,
              children: const [
                _StatCard(title: 'Jami Savdo', value: '\$128,450', icon: Icons.attach_money, color: Colors.green),
                _StatCard(title: 'Buyurtmalar', value: '1,420 ta', icon: Icons.shopping_bag, color: Colors.blue),
                _StatCard(title: 'Mijozlar', value: '8,920 nafar', icon: Icons.people, color: Colors.orange),
                _StatCard(title: 'Qaytarilganlar', value: '12 ta', icon: Icons.replay, color: Colors.red),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

class _StatCard extends StatelessWidget {
  final String title;
  final String value;
  final IconData icon;
  final Color color;

  const _StatCard({required this.title, required this.value, required this.icon, required this.color});

  @override
  Widget build(BuildContext context) {
    return Card(
      elevation: 0,
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16), side: BorderSide(color: Colors.grey.shade300)),
      child: Padding(
        padding: const EdgeInsets.all(20),
        child: Row(
          children: [
            CircleAvatar(radius: 24, backgroundColor: color.withOpacity(0.12), child: Icon(icon, color: color)),
            const SizedBox(width: 16),
            Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text(title, style: TextStyle(color: Colors.grey.shade600, fontSize: 13)),
                const SizedBox(height: 4),
                Text(value, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 20)),
              ],
            ),
          ],
        ),
      ),
    );
  }
}
```

---

## 9. Detail sahifasi va Mobil/Desktop tafsilotlar komponenti {#details-component}

```dart
class ProductDetailContent extends StatelessWidget {
  final Product product;
  const ProductDetailContent({super.key, required this.product});

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(32),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Center(
            child: ClipRRect(
              borderRadius: BorderRadius.circular(16),
              child: Image.network(product.image, height: 260, fit: BoxFit.contain),
            ),
          ),
          const SizedBox(height: 24),
          Chip(label: Text(product.category.toUpperCase()), backgroundColor: Colors.indigo.shade50),
          const SizedBox(height: 12),
          Text(product.title, style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold)),
          const SizedBox(height: 8),
          Row(
            children: [
              const Icon(Icons.star, color: Colors.amber, size: 20),
              const SizedBox(width: 4),
              Text('${product.rating} reyting', style: const TextStyle(fontWeight: FontWeight.w600)),
              const Spacer(),
              Text('\$${product.price}', style: const TextStyle(fontSize: 26, fontWeight: FontWeight.bold, color: Colors.indigo)),
            ],
          ),
          const Divider(height: 32),
          const Text('Tavsif', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
          const SizedBox(height: 8),
          Text(product.description, style: TextStyle(color: Colors.grey.shade700, height: 1.5)),
          const SizedBox(height: 32),
          SizedBox(
            width: double.infinity,
            height: 50,
            child: ElevatedButton.icon(
              style: ElevatedButton.styleFrom(backgroundColor: Colors.indigo, foregroundColor: Colors.white),
              onPressed: () {
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(content: Text('${product.title} savatchaga qo\'shildi!')),
                );
              },
              icon: const Icon(Icons.add_shopping_cart),
              label: const Text('Savatchaga qo\'shish', style: TextStyle(fontSize: 16)),
            ),
          ),
        ],
      ),
    );
  }
}

class ProductDetailPage extends StatelessWidget {
  final Product product;
  const ProductDetailPage({super.key, required this.product});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(product.title)),
      body: ProductDetailContent(product: product),
    );
  }
}
```

---

## 10. Testlash va Ishga tushirish yo'riqnomasi {#run-project}

Loyihani istalgan platformada bitta buyruq bilan ishga tushirish mumkin:

```bash
# macOS Desktopda ishga tushirish:
flutter run -d macos

# Windows Desktopda ishga tushirish:
flutter run -d windows

# iOS Simulyatorda:
flutter run -d "iPhone 16 Pro"

# Android Emulyatorda:
flutter run -d android
```

---

## 11. Xulosa va Keyingi Qadamlar {#xulosa}

Siz ushbu dars orqali quyidagi muhim bosqichlarni o'zlashtirdingiz:
1. **Clean Architecture tamoyillari:** Biznes mantiq (Domain) va server mijozini (Data) vizual interfeysdan (Presentation) butunlay ajratish.
2. **Kross-Platforma Dizayn:** `MediaQuery`, `NavigationRail` va `NavigationBar` yordamida har bir ekranda native hissini berish.
3. **Desktop xususiyatlari:** Shortcuts, Master-Detail va sichqoncha kursorlari bilan professional darajada ishlash.
4. **Tarmoq va Xatolar:** Dio va `ApiResult` bilan ishonchli xatoliklar menejmenti.

---

## 12. Rasmiy Manbalar {#manbalar}

- [Flutter Samples Github Repository](https://github.com/flutter/samples)
- [FakeStoreAPI — Bepul sinov REST API](https://fakestoreapi.com)
- [Flutter Clean Architecture Best Practices](https://docs.flutter.dev/app-architecture)
