├── .gitignore
├── .idea
├── .gitignore
├── caches
│ └── deviceStreaming.xml
├── git_toolbox_blame.xml
├── git_toolbox_prj.xml
├── libraries
│ └── Dart_SDK.xml
├── mason_bricks.iml
├── material_theme_project_new.xml
├── misc.xml
├── modules.xml
└── vcs.xml
├── README.md
├── bricks
├── base
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── __brick__
│ │ ├── assets
│ │ │ └── HandCoding-bro.svg
│ │ ├── l10n.yaml
│ │ ├── lib
│ │ │ ├── core
│ │ │ │ ├── constants
│ │ │ │ │ └── constants.dart
│ │ │ │ ├── data
│ │ │ │ │ ├── dio_config.dart
│ │ │ │ │ ├── interceptors
│ │ │ │ │ │ ├── auth_interceptor.dart
│ │ │ │ │ │ └── logging_interceptor.dart
│ │ │ │ │ ├── network
│ │ │ │ │ │ ├── api_provider.dart
│ │ │ │ │ │ └── network_info.dart
│ │ │ │ │ └── token_manager.dart
│ │ │ │ ├── error
│ │ │ │ │ ├── error_handler.dart
│ │ │ │ │ ├── exceptions.dart
│ │ │ │ │ ├── failures.dart
│ │ │ │ │ └── response_error.dart
│ │ │ │ ├── firebase
│ │ │ │ │ ├── firebase_config.dart
│ │ │ │ │ └── notification_controller.dart
│ │ │ │ ├── global_app_setup
│ │ │ │ │ ├── app_config.dart
│ │ │ │ │ └── global_app_setup.dart
│ │ │ │ ├── language
│ │ │ │ │ ├── language_bloc.dart
│ │ │ │ │ ├── language_event.dart
│ │ │ │ │ └── language_state.dart
│ │ │ │ ├── logger
│ │ │ │ │ └── app_logger.dart
│ │ │ │ ├── navigation
│ │ │ │ │ └── app_navigation.dart
│ │ │ │ ├── params
│ │ │ │ │ └── no_params.dart
│ │ │ │ ├── secure_storage
│ │ │ │ │ ├── flutter_secure_storage_const.dart
│ │ │ │ │ ├── secure_storage.dart
│ │ │ │ │ └── secure_storage_interface.dart
│ │ │ │ ├── service_locator.dart
│ │ │ │ ├── success_response
│ │ │ │ │ └── success_response.dart
│ │ │ │ ├── theme
│ │ │ │ │ ├── app_theme.dart
│ │ │ │ │ ├── bloc
│ │ │ │ │ │ ├── theme_bloc.dart
│ │ │ │ │ │ ├── theme_event.dart
│ │ │ │ │ │ └── theme_state.dart
│ │ │ │ │ ├── color_themes.dart
│ │ │ │ │ ├── text_themes.dart
│ │ │ │ │ └── theme_extensions.dart
│ │ │ │ ├── use_case
│ │ │ │ │ └── base_usecase.dart
│ │ │ │ └── utils
│ │ │ │ │ └── extensions
│ │ │ │ │ ├── context_extensions.dart
│ │ │ │ │ ├── date_extentions.dart
│ │ │ │ │ ├── file_extension.dart
│ │ │ │ │ └── string_extensions.dart
│ │ │ ├── features
│ │ │ │ └── splash_feature
│ │ │ │ │ ├── data
│ │ │ │ │ ├── data_sources
│ │ │ │ │ │ └── .gitkeep
│ │ │ │ │ ├── models
│ │ │ │ │ │ └── .gitkeep
│ │ │ │ │ └── repositories
│ │ │ │ │ │ └── .gitkeep
│ │ │ │ │ ├── domain
│ │ │ │ │ ├── entities
│ │ │ │ │ │ └── .gitkeep
│ │ │ │ │ ├── repositories
│ │ │ │ │ │ └── .gitkeep
│ │ │ │ │ └── use_cases
│ │ │ │ │ │ └── .gitkeep
│ │ │ │ │ └── presentation
│ │ │ │ │ ├── manager
│ │ │ │ │ └── .gitkeep
│ │ │ │ │ ├── pages
│ │ │ │ │ └── splash_page.dart
│ │ │ │ │ └── widgets
│ │ │ │ │ └── .gitkeep
│ │ │ ├── l10n
│ │ │ │ ├── intl_en.arb
│ │ │ │ └── intl_fa.arb
│ │ │ ├── library.dart
│ │ │ ├── main_dev.dart
│ │ │ ├── main_local.dart
│ │ │ ├── main_prod.dart
│ │ │ └── my_app.dart
│ │ └── pubspec.yaml
│ └── brick.yaml
├── feature
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── __brick__
│ │ └── lib
│ │ │ └── features
│ │ │ └── {{name}}_feature
│ │ │ ├── data
│ │ │ ├── data_sources
│ │ │ │ └── {{name}}_api_provider.dart
│ │ │ ├── models
│ │ │ │ └── .gitkeep
│ │ │ └── repositories
│ │ │ │ └── {{name}}_repository_impl.dart
│ │ │ ├── domain
│ │ │ ├── entities
│ │ │ │ └── .gitkeep
│ │ │ ├── repositories
│ │ │ │ └── {{name}}_repository.dart
│ │ │ └── use_cases
│ │ │ │ └── {{useCase}}_use_case.dart
│ │ │ └── presentation
│ │ │ ├── manager
│ │ │ ├── status
│ │ │ │ └── {{useCase}}_status.dart
│ │ │ ├── {{name}}_bloc.dart
│ │ │ ├── {{name}}_event.dart
│ │ │ └── {{name}}_state.dart
│ │ │ ├── pages
│ │ │ └── {{name}}_page.dart
│ │ │ └── widgets
│ │ │ └── .gitkeep
│ └── brick.yaml
└── status
│ ├── CHANGELOG.md
│ ├── LICENSE
│ ├── README.md
│ ├── __brick__
│ └── lib
│ │ └── features
│ │ ├── dealership_panel
│ │ └── {{blocName}}_bloc
│ │ │ ├── status
│ │ │ └── {{event}}_status.dart
│ │ │ └── {{blocName}}_state.dart
│ │ └── {{name}}_feature
│ │ └── presentation
│ │ └── manager
│ │ ├── status
│ │ ├── {{event}}_status.dart
│ │ └── {{useCase}}_status.dart
│ │ ├── {{name}}_bloc.dart
│ │ ├── {{name}}_event.dart
│ │ └── {{name}}_state.dart
│ └── brick.yaml
└── example
├── .gitignore
├── .mason
└── bricks.json
├── .metadata
├── analysis_options.yaml
├── android
├── .gitignore
├── app
│ ├── build.gradle
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── example
│ │ │ │ └── MainActivity.kt
│ │ └── res
│ │ │ ├── drawable-v21
│ │ │ └── launch_background.xml
│ │ │ ├── drawable
│ │ │ └── launch_background.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── values-night
│ │ │ └── styles.xml
│ │ │ └── values
│ │ │ └── styles.xml
│ │ └── profile
│ │ └── AndroidManifest.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle
├── assets
└── HandCoding-bro.svg
├── ios
├── .gitignore
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
├── Runner
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ └── Icon-App-83.5x83.5@2x.png
│ │ └── LaunchImage.imageset
│ │ │ ├── Contents.json
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ └── README.md
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── Info.plist
│ └── Runner-Bridging-Header.h
└── RunnerTests
│ └── RunnerTests.swift
├── l10n.yaml
├── lib
├── core
│ ├── constants
│ │ └── constants.dart
│ ├── data
│ │ └── network
│ │ │ ├── api_intercepror.dart
│ │ │ ├── api_interface.dart
│ │ │ └── api_provider.dart
│ ├── error
│ │ ├── error_handling.dart
│ │ └── response_error.dart
│ ├── extensions
│ │ ├── date_extentions.dart
│ │ ├── file_extension.dart
│ │ └── theme_extension.dart
│ ├── firebase
│ │ ├── firebase_config.dart
│ │ └── notification_controller.dart
│ ├── global_app_setup
│ │ ├── app_config.dart
│ │ └── global_app_setup.dart
│ ├── language
│ │ ├── language_bloc.dart
│ │ ├── language_event.dart
│ │ └── language_state.dart
│ ├── logger
│ │ └── app_logger.dart
│ ├── navigation
│ │ └── app_navigation.dart
│ ├── params
│ │ └── no_params.dart
│ ├── secure_storage
│ │ ├── flutter_secure_storage_const.dart
│ │ ├── secure_storage.dart
│ │ └── secure_storage_interface.dart
│ ├── service_locator.dart
│ ├── success_response
│ │ └── success_response.dart
│ ├── theme
│ │ ├── app_theme.dart
│ │ ├── bloc
│ │ │ ├── theme_bloc.dart
│ │ │ ├── theme_event.dart
│ │ │ └── theme_state.dart
│ │ ├── color_themes.dart
│ │ ├── text_themes.dart
│ │ └── theme_extensions.dart
│ └── use_case
│ │ └── base_usecase.dart
├── features
│ ├── splash_feature
│ │ ├── data
│ │ │ ├── data_sources
│ │ │ │ └── .gitkeep
│ │ │ ├── models
│ │ │ │ └── .gitkeep
│ │ │ └── repositories
│ │ │ │ └── .gitkeep
│ │ ├── domain
│ │ │ ├── entities
│ │ │ │ └── .gitkeep
│ │ │ ├── repositories
│ │ │ │ └── .gitkeep
│ │ │ └── use_cases
│ │ │ │ └── .gitkeep
│ │ └── presentation
│ │ │ ├── manager
│ │ │ └── .gitkeep
│ │ │ ├── pages
│ │ │ └── splash_page.dart
│ │ │ └── widgets
│ │ │ └── .gitkeep
│ └── user_feature
│ │ ├── data
│ │ ├── data_sources
│ │ │ └── user_api_provider.dart
│ │ ├── models
│ │ │ └── .gitkeep
│ │ └── repositories
│ │ │ └── user_repository_impl.dart
│ │ ├── domain
│ │ ├── entities
│ │ │ └── .gitkeep
│ │ ├── repositories
│ │ │ └── user_repository.dart
│ │ └── use_cases
│ │ │ └── get_users_use_case.dart
│ │ └── presentation
│ │ ├── manager
│ │ ├── status
│ │ │ └── get_users_status.dart
│ │ ├── user_bloc.dart
│ │ ├── user_event.dart
│ │ └── user_state.dart
│ │ ├── pages
│ │ └── user_page.dart
│ │ └── widgets
│ │ └── .gitkeep
├── l10n
│ ├── intl_en.arb
│ └── intl_fa.arb
├── library.dart
├── main_dev.dart
├── main_local.dart
├── main_prod.dart
└── my_app.dart
├── mason-lock.json
├── mason.yaml
├── pubspec.lock
└── pubspec.yaml
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore everything in this directory
2 | #*
3 | ## Except this file
4 | #!.gitignore
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/git_toolbox_blame.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/git_toolbox_prj.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.idea/libraries/Dart_SDK.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/.idea/mason_bricks.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/material_theme_project_new.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/bricks/base/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # 0.1.0+1
2 |
3 | - TODO: Describe initial release.
4 |
--------------------------------------------------------------------------------
/bricks/base/LICENSE:
--------------------------------------------------------------------------------
1 | TODO: Add your license here.
2 |
--------------------------------------------------------------------------------
/bricks/base/README.md:
--------------------------------------------------------------------------------
1 | # base template
2 |
3 | [](https://github.com/felangel/mason)
4 |
5 | A new brick created with the Mason CLI.
6 |
7 | _Generated by [mason][1] 🧱_
8 |
9 | ## Getting Started 🚀
10 |
11 | This is a starting point for a new brick.
12 | A few resources to get you started if this is your first brick template:
13 |
14 | - [Official Mason Documentation][2]
15 | - [Code generation with Mason Blog][3]
16 | - [Very Good Livestream: Felix Angelov Demos Mason][4]
17 | - [Flutter Package of the Week: Mason][5]
18 | - [Observable Flutter: Building a Mason brick][6]
19 | - [Meet Mason: Flutter Vikings 2022][7]
20 |
21 | [1]: https://github.com/felangel/mason
22 | [2]: https://docs.brickhub.dev
23 | [3]: https://verygood.ventures/blog/code-generation-with-mason
24 | [4]: https://youtu.be/G4PTjA6tpTU
25 | [5]: https://youtu.be/qjA0JFiPMnQ
26 | [6]: https://youtu.be/o8B1EfcUisw
27 | [7]: https://youtu.be/LXhgiF5HiQg
28 |
--------------------------------------------------------------------------------
/bricks/base/__brick__/l10n.yaml:
--------------------------------------------------------------------------------
1 | arb-dir: lib/l10n
2 | template-arb-file: intl_en.arb
3 | output-localization-file: app_localizations.dart
--------------------------------------------------------------------------------
/bricks/base/__brick__/lib/core/constants/constants.dart:
--------------------------------------------------------------------------------
1 | class Constants {
2 | static String? accessToken = "";
3 | static String? firebaseToken = "";
4 | }
--------------------------------------------------------------------------------
/bricks/base/__brick__/lib/core/data/dio_config.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 | import 'package:flutter/foundation.dart';
3 | import '../global_app_setup/app_config.dart';
4 | import 'interceptors/auth_interceptor.dart';
5 | import 'interceptors/logging_interceptor.dart';
6 | import 'package:pretty_dio_logger/pretty_dio_logger.dart';
7 |
8 | class DioConfig {
9 | static Dio createDio({
10 | String? baseUrl,
11 | Duration? connectTimeout,
12 | Duration? receiveTimeout,
13 | Duration? sendTimeout,
14 | }) {
15 | final dio = Dio(
16 | BaseOptions(
17 | baseUrl: baseUrl ?? AppConfig.baseUrl,
18 | connectTimeout: connectTimeout ?? const Duration(seconds: 30),
19 | receiveTimeout: receiveTimeout ?? const Duration(seconds: 30),
20 | sendTimeout: sendTimeout ?? const Duration(seconds: 30),
21 | headers: {
22 | 'Content-Type': 'application/json',
23 | 'Accept': 'application/json',
24 | },
25 | ),
26 | );
27 |
28 | dio.interceptors.addAll([
29 | AuthInterceptor(),
30 | LoggingInterceptor(),
31 | PrettyDioLogger(
32 | requestHeader: true,
33 | requestBody: true,
34 | responseBody: true,
35 | responseHeader: false,
36 | error: true,
37 | compact: true,
38 | maxWidth: 90,
39 | enabled: kDebugMode,)
40 | ]);
41 |
42 | return dio;
43 | }
44 | }
--------------------------------------------------------------------------------
/bricks/base/__brick__/lib/core/data/interceptors/auth_interceptor.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 | import 'package:foveo/core/data/token_manager.dart';
3 |
4 |
5 | class AuthInterceptor extends Interceptor {
6 |
7 | @override
8 | Future onRequest(
9 | RequestOptions options,
10 | RequestInterceptorHandler handler,
11 | ) async {
12 | final tokens =await TokenManager.getAccessToken();
13 | if (tokens != null) {
14 | options.headers['Authorization'] = 'Bearer $tokens';
15 | }
16 | return handler.next(options);
17 | }
18 |
19 | @override
20 | Future onError(
21 | DioException err,
22 | ErrorInterceptorHandler handler,
23 | ) async {
24 | if (err.response?.statusCode == 401) {
25 | try {
26 | final refreshToken = await TokenManager.getRefreshToken();
27 | if (refreshToken != null) {
28 | // اینجا باید درخواست refresh token را به سرور ارسال کنید
29 | // و توکنهای جدید را دریافت کنید
30 | // مثال:
31 | // final response = await dio.post('/refresh-token', data: {'refresh_token': tokens.refreshToken});
32 | // await ref.read(tokenProvider.notifier).refreshAccessToken(response.data['access_token']);
33 |
34 | // تکرار درخواست اصلی
35 | final newTokens = await TokenManager.getAccessToken();
36 | err.requestOptions.headers['Authorization'] = 'Bearer $newTokens';
37 | final response = await Dio().fetch(err.requestOptions);
38 | return handler.resolve(response);
39 | }
40 | } catch (e) {
41 | // در صورت خطا در refresh token، کاربر را logout کنید
42 | await TokenManager.clearTokens();
43 | // TODO: Navigate to login screen
44 | }
45 | }
46 | return handler.next(err);
47 | }
48 | }
--------------------------------------------------------------------------------
/bricks/base/__brick__/lib/core/data/interceptors/logging_interceptor.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 | import 'package:logger/logger.dart';
3 |
4 | class LoggingInterceptor extends Interceptor {
5 | final Logger _logger = Logger(
6 | printer: PrettyPrinter(
7 | methodCount: 2,
8 | errorMethodCount: 8,
9 | lineLength: 120,
10 | colors: true,
11 | printEmojis: true,
12 | printTime: true,
13 | ),
14 | );
15 |
16 | @override
17 | void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
18 | _logger.i('REQUEST[${options.method}] => PATH: ${options.path}');
19 | _logger.d('Headers: ${options.headers}');
20 | _logger.d('Data: ${options.data}');
21 | handler.next(options);
22 | }
23 |
24 | @override
25 | void onResponse(Response response, ResponseInterceptorHandler handler) {
26 | _logger.i(
27 | 'RESPONSE[${response.statusCode}] => PATH: ${response.requestOptions.path}',
28 | );
29 | _logger.d('Response Data: ${response.data}');
30 | handler.next(response);
31 | }
32 |
33 | @override
34 | void onError(DioException err, ErrorInterceptorHandler handler) {
35 | _logger.e(
36 | 'ERROR[${err.response?.statusCode}] => PATH: ${err.requestOptions.path}',
37 | );
38 | _logger.e('Error Data: ${err.response?.data}');
39 | handler.next(err);
40 | }
41 | }
--------------------------------------------------------------------------------
/bricks/base/__brick__/lib/core/data/network/api_provider.dart:
--------------------------------------------------------------------------------
1 | import 'package:dio/dio.dart';
2 | import '../../error/exceptions.dart';
3 | import '../../error/failures.dart';
4 | import '../dio_config.dart';
5 | import 'network_info.dart';
6 | import 'package:internet_connection_checker/internet_connection_checker.dart';
7 | abstract class ApiProviderInterface {
8 | Future get(String path, {Map? queryParameters});
9 | Future post(String path, {dynamic data});
10 | Future put(String path, {dynamic data});
11 | Future delete(String path);
12 | Future patch(String path, {dynamic data});
13 | }
14 |
15 | class ApiProvider implements ApiProviderInterface {
16 | final Dio _dio;
17 | final NetworkInfo _networkInfo;
18 |
19 | ApiProvider._internal(this._dio, this._networkInfo);
20 |
21 | static ApiProvider? _instance;
22 | static ApiProvider get instance {
23 | _instance ??= ApiProvider._internal(
24 | DioConfig.createDio(),
25 | NetworkInfoImpl(InternetConnectionChecker.createInstance()),
26 | );
27 | return _instance!;
28 | }
29 |
30 | @override
31 | Future get(String path, {Map? queryParameters}) async {
32 | try {
33 | if (!await _networkInfo.isConnected) {
34 | throw NetworkFailure();
35 | }
36 | final response = await _dio.get(path, queryParameters: queryParameters);
37 | return _handleResponse(response);
38 | } on DioException catch (e) {
39 | throw _handleDioError(e);
40 | } catch (e) {
41 | throw ServerException();
42 | }
43 | }
44 |
45 | @override
46 | Future post(String path, {dynamic data}) async {
47 | try {
48 | if (!await _networkInfo.isConnected) {
49 | throw NetworkFailure();
50 | }
51 | final response = await _dio.post(path, data: data);
52 | return _handleResponse(response);
53 | } on DioException catch (e) {
54 | throw _handleDioError(e);
55 | } catch (e) {
56 | throw ServerException();
57 | }
58 | }
59 |
60 | @override
61 | Future put(String path, {dynamic data}) async {
62 | try {
63 | if (!await _networkInfo.isConnected) {
64 | throw NetworkFailure();
65 | }
66 | final response = await _dio.put(path, data: data);
67 | return _handleResponse(response);
68 | } on DioException catch (e) {
69 | throw _handleDioError(e);
70 | } catch (e) {
71 | throw ServerException();
72 | }
73 | }
74 |
75 | @override
76 | Future delete(String path) async {
77 | try {
78 | if (!await _networkInfo.isConnected) {
79 | throw NetworkFailure();
80 | }
81 | final response = await _dio.delete(path);
82 | return _handleResponse(response);
83 | } on DioException catch (e) {
84 | throw _handleDioError(e);
85 | } catch (e) {
86 | throw ServerException();
87 | }
88 | }
89 |
90 | @override
91 | Future patch(String path, {dynamic data}) async {
92 | try {
93 | if (!await _networkInfo.isConnected) {
94 | throw NetworkFailure();
95 | }
96 | final response = await _dio.patch(path, data: data);
97 | return _handleResponse(response);
98 | } on DioException catch (e) {
99 | throw _handleDioError(e);
100 | } catch (e) {
101 | throw ServerException();
102 | }
103 | }
104 |
105 | dynamic _handleResponse(Response response) {
106 | if (response.statusCode! >= 200 && response.statusCode! < 300) {
107 | return response.data;
108 | } else {
109 | throw ServerException();
110 | }
111 | }
112 |
113 | Exception _handleDioError(DioException error) {
114 | switch (error.type) {
115 | case DioExceptionType.connectionTimeout:
116 | case DioExceptionType.sendTimeout:
117 | case DioExceptionType.receiveTimeout:
118 | return TimeoutException();
119 | case DioExceptionType.badResponse:
120 | switch (error.response?.statusCode) {
121 | case 400:
122 | return BadRequestException();
123 | case 401:
124 | return UnauthorizedException();
125 | case 403:
126 | return ForbiddenException();
127 | case 404:
128 | return NotFoundException();
129 | case 500:
130 | return ServerException();
131 | default:
132 | return ServerException();
133 | }
134 | case DioExceptionType.cancel:
135 | return RequestCancelledException();
136 | default:
137 | return ServerException();
138 | }
139 | }
140 | }
--------------------------------------------------------------------------------
/bricks/base/__brick__/lib/core/data/network/network_info.dart:
--------------------------------------------------------------------------------
1 | import 'package:internet_connection_checker/internet_connection_checker.dart';
2 |
3 | abstract class NetworkInfo {
4 | Future get isConnected;
5 | }
6 |
7 | class NetworkInfoImpl implements NetworkInfo {
8 | final InternetConnectionChecker connectionChecker;
9 |
10 | NetworkInfoImpl(this.connectionChecker);
11 |
12 | @override
13 | Future get isConnected => connectionChecker.hasConnection;
14 | }
--------------------------------------------------------------------------------
/bricks/base/__brick__/lib/core/data/token_manager.dart:
--------------------------------------------------------------------------------
1 | import '../secure_storage/secure_storage.dart';
2 |
3 | class TokenManager {
4 | static final _storage = SecureStorage();
5 | static const _accessTokenKey = 'access_token';
6 | static const _refreshTokenKey = 'refresh_token';
7 |
8 | static Future setTokens({
9 | required String accessToken,
10 | required String refreshToken,
11 | }) async {
12 | await _storage.write(_accessTokenKey, accessToken);
13 | await _storage.write(_refreshTokenKey, refreshToken);
14 | }
15 |
16 | static Future getAccessToken() async {
17 | return await _storage.read(_accessTokenKey);
18 | }
19 |
20 | static Future getRefreshToken() async {
21 | return await _storage.read(_refreshTokenKey);
22 | }
23 |
24 | static Future clearTokens() async {
25 | await _storage.delete(_accessTokenKey);
26 | await _storage.delete(_refreshTokenKey);
27 | }
28 | }
--------------------------------------------------------------------------------
/bricks/base/__brick__/lib/core/error/error_handler.dart:
--------------------------------------------------------------------------------
1 | import 'exceptions.dart';
2 | import 'failures.dart';
3 |
4 | class ErrorHandler {
5 | static Failure handleError(dynamic error) {
6 | if (error is ServerException) {
7 | return const ServerFailure();
8 | } else if (error is CacheException) {
9 | return const CacheFailure();
10 | } else if (error is NetworkException) {
11 | return const NetworkFailure();
12 | } else if (error is ValidationException) {
13 | return ValidationFailure(error.message);
14 | } else if (error is AuthenticationException) {
15 | return AuthenticationFailure(error.message);
16 | } else if (error is UnknownException) {
17 | return UnknownFailure(error.message);
18 | } else {
19 | return UnknownFailure(error.toString());
20 | }
21 | }
22 |
23 | static String getErrorMessage(Failure failure) {
24 | switch (failure.runtimeType) {
25 | case ServerFailure:
26 | return 'خطا در ارتباط با سرور';
27 | case CacheFailure:
28 | return 'خطا در ذخیرهسازی اطلاعات';
29 | case NetworkFailure:
30 | return 'خطا در اتصال به اینترنت';
31 | case ValidationFailure:
32 | return (failure as ValidationFailure).message;
33 | case AuthenticationFailure:
34 | return (failure as AuthenticationFailure).message;
35 | case UnknownFailure:
36 | return (failure as UnknownFailure).message;
37 | default:
38 | return 'خطای ناشناخته';
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/bricks/base/__brick__/lib/core/error/exceptions.dart:
--------------------------------------------------------------------------------
1 | class ServerException implements Exception {}
2 |
3 | class CacheException implements Exception {}
4 |
5 | class NetworkException implements Exception {}
6 |
7 | class TimeoutException implements Exception {}
8 |
9 | class BadRequestException implements Exception {}
10 |
11 | class UnauthorizedException implements Exception {}
12 |
13 | class ForbiddenException implements Exception {}
14 |
15 | class NotFoundException implements Exception {}
16 |
17 | class RequestCancelledException implements Exception {}
18 |
19 | class ValidationException implements Exception {
20 | final String message;
21 | ValidationException(this.message);
22 | }
23 |
24 | class AuthenticationException implements Exception {
25 | final String message;
26 | AuthenticationException(this.message);
27 | }
28 |
29 | class UnknownException implements Exception {
30 | final String message;
31 | UnknownException(this.message);
32 | }
--------------------------------------------------------------------------------
/bricks/base/__brick__/lib/core/error/failures.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:equatable/equatable.dart';
3 |
4 | abstract class Failure extends Equatable {
5 | final List properties;
6 |
7 | const Failure([this.properties = const []]);
8 |
9 | @override
10 | List