2026-02-06 17:27:21 +07:00
2025-08-06 12:01:00 +07:00
2025-10-02 16:56:00 +07:00
2026-02-06 17:27:21 +07:00
2025-10-02 16:56:00 +07:00
2025-09-16 17:55:45 +07:00
2026-02-06 17:27:21 +07:00
2025-08-06 12:01:00 +07:00
2025-09-15 17:51:39 +07:00
2025-08-06 12:01:00 +07:00
2025-08-06 12:01:00 +07:00
2025-09-15 17:51:39 +07:00
2025-08-06 12:01:00 +07:00
2025-10-07 11:50:37 +07:00
2025-08-06 12:01:00 +07:00
2026-02-06 17:27:21 +07:00
2025-08-06 12:01:00 +07:00
2025-08-06 12:01:00 +07:00
2025-11-01 13:20:46 +07:00
2025-11-01 13:20:46 +07:00
2025-11-01 13:20:46 +07:00
2025-08-06 12:01:00 +07:00
2025-10-02 16:56:00 +07:00
2025-08-06 12:01:00 +07:00
2025-08-06 12:01:00 +07:00
2025-11-13 22:37:23 -05:00
2025-11-01 13:20:46 +07:00
2025-09-11 10:15:21 +07:00
2025-11-01 13:20:46 +07:00

BRL IOT App

Ứng dụng di động IOT được phát triển bằng Flutter, dựa trên thiết kế từ Figma.

Cấu trúc dự án

lib/
  ├── constants/     # Các hằng số và cấu hình
  ├── models/        # Các model dữ liệu
  ├── screens/       # Các màn hình
  │   └── home_screen.dart
  ├── theme/         # Theme và style
  │   └── app_theme.dart
  ├── utils/         # Các tiện ích
  ├── widgets/       # Các widget tái sử dụng
  │   ├── custom_header.dart
  │   ├── custom_bottom_navigation.dart
  │   └── home_content.dart
  └── main.dart      # Entry point

Layout chính

Ứng dụng được chia thành 3 phần chính:

  1. Header: Hiển thị thông tin chào mừng và avatar người dùng
  2. Body: Nội dung chính của ứng dụng, bao gồm:
    • Thông báo đăng nhập
    • Danh sách thiết bị
    • Phần thêm thiết bị mới
    • Khuyến mãi
    • Khám phá IOT
    • Dịch vụ và hỗ trợ
  3. Bottom Navigation: Thanh điều hướng với 4 tab và nút quét ở giữa
    • Thiết bị
    • Thông báo
    • Tin tức
    • Tài khoản

Yêu cầu

  • Flutter SDK: >=3
  • .2.6 <4.0.0
  • Các font SF Pro Display (Regular, Medium, Semibold)
  • Các hình ảnh cần thiết trong thư mục assets/images/ và assets/icons/

Cài đặt

  1. Clone repository
  2. Chạy flutter pub get để cài đặt các dependencies
  3. Chạy flutter run để khởi động ứng dụng

Lưu ý

  • Cần thêm các font SF Pro Display vào thư mục assets/fonts/
  • Cần thêm các hình ảnh cần thiết vào thư mục assets/images/ và assets/icons/

BRL Flutter App - Notification System Documentation

📋 Tổng quan dự án

BRL Flutter App là ứng dụng IoT với hệ thống thông báo hoàn chỉnh, sử dụng kiến trúc Clean Architecture và BLoC pattern để quản lý state.

🏗️ Kiến trúc hệ thống

Cấu trúc thư mục

lib/
├── core/                           # Lớp cốt lõi
│   ├── constants/
│   │   └── api_constants.dart      # Các hằng số API
│   ├── network/
│   │   └── dio_client.dart         # HTTP Client với Dio
│   ├── errors/
│   │   └── api_exception.dart      # Xử lý lỗi API
│   └── storage/
│       └── storage_service.dart    # Lưu trữ local với SharedPreferences
├── data/                           # Lớp dữ liệu
│   ├── models/
│   │   ├── notification_model.dart # Model thông báo
│   │   └── api_models.dart        # Model request/response API
│   ├── services/
│   │   └── notification_service.dart # Service gọi API
│   └── repositories/
│       └── notification_repository.dart # Repository pattern
├── presentation/                   # Lớp giao diện
│   └── blocs/notification/
│       ├── notification_bloc.dart  # BLoC chính
│       ├── notification_event.dart # Các events
│       └── notification_state.dart # Các states
└── screens/
    ├── notification_screen.dart    # Màn hình danh sách thông báo
    └── notification_detail_screen.dart # Màn hình chi tiết thông báo

🔄 Luồng hoạt động hiện tại

1. Khởi tạo ứng dụng

App Start → StorageService.init() → Load User Data → Initialize BLoC

2. Luồng tải thông báo

UI (NotificationScreen) 
    ↓ 
BLoC (LoadNotifications event)
    ↓
Repository (getNotifications)
    ↓
Service (getNotifications)
    ↓
DioClient (POST request)
    ↓
API Server (/notifications/filter)
    ↓
Response → Models → BLoC → UI Update

3. Luồng chi tiết từng bước

Bước 1: UI khởi tạo

// notification_screen.dart
@override
void initState() {
  super.initState();
  _notificationBloc = NotificationBloc(repository: NotificationRepository());
  _notificationBloc.add(const LoadNotifications(refresh: true));
}

Bước 2: BLoC xử lý event

// notification_bloc.dart
Future<void> _onLoadNotifications(
  LoadNotifications event,
  Emitter<NotificationState> emit,
) async {
  // Emit loading state
  emit(NotificationLoading());
  
  // Gọi repository
  final response = await _repository.getNotifications(...);
  
  // Xử lý response và emit state mới
  if (response.success) {
    emit(NotificationLoaded(...));
  } else {
    emit(NotificationError(...));
  }
}

Bước 3: Repository gọi Service

// notification_repository.dart
Future<ApiResponse<List<NotificationModel>>> getNotifications(...) async {
  return await _notificationService.getNotifications(...);
}

Bước 4: Service thực hiện API call

// notification_service.dart
Future<ApiResponse<List<NotificationModel>>> getNotifications(...) async {
  // Lấy userId từ storage
  final userId = StorageService.getUserId() ?? "007";
  
  // Tạo request filter
  final request = NotificationFilterRequest.forUser(userId: userId, ...);
  
  // Gọi API
  final response = await _dioClient.post(
    ApiConstants.notificationFilter,
    data: request.toJson(),
  );
  
  // Parse response và return
  return ApiResponse.success(data: notifications);
}

Bước 5: DioClient xử lý HTTP request

// dio_client.dart
Future<Response<T>> post<T>(...) async {
  try {
    // Tự động thêm token vào header
    // Log request/response
    return await _dio.post<T>(...);
  } on DioException catch (e) {
    throw ApiException.fromDioError(e);
  }
}

📊 Các tính năng chính đã triển khai

1. Quản lý thông báo

  • Tải danh sách thông báo theo userId
  • Phân trang (pagination)
  • Làm mới (refresh)
  • Đánh dấu đã đọc/chưa đọc
  • Xóa thông báo
  • Lọc theo loại, trạng thái, độ ưu tiên
  • Tìm kiếm thông báo
  • Sắp xếp theo thời gian

2. State Management với BLoC

// Các Events có sẵn
- LoadNotifications          // Tải thông báo
- LoadNotificationById       // Tải chi tiết thông báo
- MarkNotificationAsRead     // Đánh dấu đã đọc
- MarkAllNotificationsAsRead // Đánh dấu tất cả đã đọc
- DeleteNotification         // Xóa thông báo
- FilterNotifications        // Lọc thông báo
- SearchNotifications        // Tìm kiếm
- RefreshNotifications       // Làm mới
- LoadMoreNotifications      // Tải thêm

// Các States có sẵn
- NotificationInitial        // Trạng thái ban đầu
- NotificationLoading        // Đang tải
- NotificationLoaded         // Đã tải xong
- NotificationError          // Lỗi
- NotificationDetailLoaded   // Chi tiết đã tải
- NotificationOperationSuccess // Thao tác thành công

3. Xử lý lỗi toàn diện

// api_exception.dart
- Connection timeout
- Network errors  
- HTTP status codes (400, 401, 403, 404, 500)
- Custom error messages trong tiếng Việt
- Retry mechanisms

4. Local Storage

// storage_service.dart
- User ID  User Name
- Access Token  Refresh Token  
- Generic storage methods
- Automatic initialization

🎯 Cách sử dụng trong UI

1. Khởi tạo BLoC trong Widget

class NotificationScreen extends StatefulWidget {
  @override
  void initState() {
    super.initState();
    _notificationBloc = NotificationBloc(repository: NotificationRepository());
    _notificationBloc.add(const LoadNotifications(refresh: true));
  }
}

2. Lắng nghe state changes

BlocConsumer<NotificationBloc, NotificationState>(
  listener: (context, state) {
    // Xử lý side effects (hiển thị snackbar, navigation...)
    if (state is NotificationError) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text(state.message))
      );
    }
  },
  builder: (context, state) {
    // Xây dựng UI dựa trên state
    if (state is NotificationLoading) {
      return CircularProgressIndicator();
    } else if (state is NotificationLoaded) {
      return _buildNotificationList(state.filteredNotifications);
    }
    return Container();
  },
)

3. Thực hiện các thao tác

// Đánh dấu đã đọc
context.read<NotificationBloc>().add(
  MarkNotificationAsRead(notificationId)
);

// Lọc thông báo
context.read<NotificationBloc>().add(
  const FilterNotifications(showOnlyUnread: true)
);

// Tìm kiếm
context.read<NotificationBloc>().add(
  SearchNotifications('từ khóa')
);

🔧 Configuration

1. API Constants

// lib/core/constants/api_constants.dart
class ApiConstants {
  static const String baseUrl = 'https://your-api-domain.com/api';
  static const String notificationFilter = '/notifications/filter';
  
  // Timeouts
  static const int connectTimeout = 30000;
  static const int receiveTimeout = 30000;
  
  // Storage keys
  static const String userIdKey = 'user_id';
  static const String accessTokenKey = 'access_token';
}

2. Dependencies trong pubspec.yaml

dependencies:
  # State Management
  flutter_bloc: ^8.1.3
  equatable: ^2.0.5
  
  # API & Network
  dio: ^5.4.0
  
  # Storage
  shared_preferences: ^2.2.2
  
  # Utilities
  logger: ^2.0.2

🌐 API Integration

Request Format

POST /notifications/filter
{
  "metadata": { "type": "" },
  "filter": [
    {
      "property": "userId",
      "type": "string", 
      "condition": "equals",
      "value": "007"
    }
  ],
  "sort": [
    {
      "orderBy": "createTime",
      "orderDesc": true
    }
  ],
  "paging": {
    "indexPage": 0,
    "numberOfPage": 100
  }
}

Response Format

{
  "success": true,
  "message": "Success",
  "data": {
    "data": [
      {
        "from": { "id": "system", "type": "system" },
        "to": { "userId": "007", "userName": "User Name" },
        "header": {
          "metadata": {
            "priority": 1,
            "type": "alert",
            "status": "unread",
            "channel": "mobile",
            "createTime": "2025-01-20T10:30:00Z"
          }
        },
        "body": {
          "title": "Notification Title",
          "content": "Notification content"
        }
      }
    ],
    "totalCount": 100
  }
}

🎨 UI Features

1. Notification List

  • Nhóm theo ngày tháng
  • Hiển thị trạng thái đã đọc/chưa đọc
  • Badge cho thông báo khẩn cấp
  • Pull-to-refresh
  • Infinite scroll (load more)

2. Visual Indicators

  • 🔵 Chấm xanh: Thông báo chưa đọc
  • 🟠 Badge cam: Thông báo khẩn cấp
  • Màu mờ: Thông báo đã đọc

3. Interactions

  • 👆 Tap: Xem chi tiết và đánh dấu đã đọc
  • 🔄 Pull down: Refresh danh sách
  • ⚙️ More button: Menu tùy chọn

🚀 Cách mở rộng

1. Thêm loại thông báo mới

// Thêm vào FilterCondition
FilterCondition(
  property: 'type',
  type: 'string',
  condition: 'equals', 
  value: 'new_type',
)

2. Thêm API endpoint mới

// api_constants.dart
static const String newEndpoint = '/notifications/new-endpoint';

// notification_service.dart  
Future<ApiResponse<T>> newApiCall() async {
  final response = await _dioClient.get(ApiConstants.newEndpoint);
  // Process response...
}

3. Thêm state và event mới

// notification_event.dart
class NewNotificationEvent extends NotificationEvent {
  // Implementation...
}

// notification_state.dart
class NewNotificationState extends NotificationState {
  // Implementation...  
}

// notification_bloc.dart
on<NewNotificationEvent>(_onNewNotificationEvent);

🐛 Debugging Tips

1. Enable Logging

// dio_client.dart sẽ tự động log requests/responses trong debug mode
// Kiểm tra console để xem:
// - REQUEST[POST] => PATH: /notifications/filter
// - RESPONSE[200] => PATH: /notifications/filter  
// - ERROR[400] => PATH: /notifications/filter

2. BLoC Inspector

// Sử dụng flutter inspector để theo dõi state changes
// Hoặc thêm prints trong BLoC:
print('Current state: $state');
print('Processing event: $event');

3. Common Issues

  • Token expired: Kiểm tra StorageService.getAccessToken()
  • Network error: Kiểm tra kết nối internet
  • Parsing error: Kiểm tra format JSON response
  • State not updating: Kiểm tra BlocProvider scope

📝 Notes

  • User ID hiện tại: Hardcode "007" trong NotificationService (dòng 16)
  • Base URL: Cần thay đổi trong ApiConstants (dòng 3)
  • Token management: Tự động thêm vào header trong DioClient
  • Error messages: Đã dịch sang tiếng Việt trong ApiException
  • Pagination: Mặc định 20 items/page, có thể thay đổi trong NotificationBloc

🔄 Next Steps

  1. Cập nhật Base URL trong api_constants.dart
  2. Implement token refresh logic trong DioClient
  3. Thêm push notifications integration
  4. Optimize performance với caching
  5. Add unit tests cho các components
  6. Implement offline support với local database

Tài liệu này được cập nhật lần cuối: $(date)

Description
No description provided
Readme 1.9 GiB
Languages
Dart 60.9%
Makefile 31.4%
JavaScript 2.4%
PureBasic 1.1%
C++ 1.1%
Other 2.9%