From 990814fd89a4576baa106ec8916420b14a9ccb01 Mon Sep 17 00:00:00 2001 From: Erick Date: Tue, 7 Jan 2025 13:24:53 +0300 Subject: [PATCH] chore: added flavor config to the application --- lib/app.dart | 8 +- lib/configs/configs.dart | 73 +++++++++++++++++++ .../repository/user_remote_repository.dart | 4 +- lib/main_development.dart | 11 ++- lib/main_production.dart | 12 ++- lib/main_staging.dart | 12 ++- lib/utils/network/dio_client.dart | 28 ++++--- 7 files changed, 129 insertions(+), 19 deletions(-) create mode 100644 lib/configs/configs.dart diff --git a/lib/app.dart b/lib/app.dart index f270c3f..393c981 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -1,3 +1,4 @@ +import 'package:academia/configs/configs.dart'; import 'package:academia/database/database.dart'; import 'package:academia/features/features.dart'; import 'package:academia/utils/router/router.dart'; @@ -8,16 +9,15 @@ import 'package:get_it/get_it.dart'; import 'package:google_fonts/google_fonts.dart'; class Academia extends StatelessWidget { - final String flavor; const Academia({ super.key, - required this.flavor, }); @override Widget build(BuildContext context) { + final GetIt getIt = GetIt.instance; // Inject the application database - GetIt.instance.registerSingletonIfAbsent( + getIt.registerSingletonIfAbsent( () => AppDatabase(), instanceName: "cacheDB", ); @@ -29,7 +29,7 @@ class Academia extends StatelessWidget { ], child: DynamicColorBuilder( builder: (lightscheme, darkscheme) => MaterialApp.router( - title: flavor, + title: getIt().appName, routerConfig: AcademiaRouter.router, theme: ThemeData( colorScheme: lightscheme, diff --git a/lib/configs/configs.dart b/lib/configs/configs.dart new file mode 100644 index 0000000..73443a1 --- /dev/null +++ b/lib/configs/configs.dart @@ -0,0 +1,73 @@ +/// Enum to define available app flavors +/// +/// This is used to differentiate between different versions of the app, +/// such as development, staging, and production environments. +enum Flavor { dev, staging, production } + +/// Class to manage flavor configurations +/// +/// This class provides a structure for managing different app flavors, +/// allowing you to specify flavor-specific properties like the app name +/// and API base URL. It includes helpers to determine the current flavor. +class FlavorConfig { + /// The current app flavor + /// + /// Defines whether the app is running in development, staging, or production. + final Flavor flavor; + + /// The name of the application + /// + /// This can be used for display purposes to indicate the current flavor of the app. + final String appName; + + /// The base URL for API calls + /// + /// This allows you to configure different backend environments for each flavor. + final String apiBaseUrl; + + /// The human-readable name of the current flavor + /// + /// This is derived from the `Flavor` enum and is primarily used for logging or debugging. + final String flavorName; + + /// Constructor + /// + /// Creates an instance of `FlavorConfig` with the specified properties. + /// + /// * [flavor] - The app flavor (e.g., `Flavor.dev` for development). + /// * [appName] - The name of the app for the specified flavor. + /// * [apiBaseUrl] - The API base URL for the specified flavor. + FlavorConfig({ + required this.flavor, + required this.appName, + required this.apiBaseUrl, + }) : flavorName = flavor.name; + + /// Checks if the current flavor is development + /// + /// Returns `true` if the app is running in the development environment. + bool get isDevelopment => flavor == Flavor.dev; + + /// Checks if the current flavor is staging + /// + /// Returns `true` if the app is running in the staging environment. + bool get isStaging => flavor == Flavor.staging; + + /// Checks if the current flavor is production + /// + /// Returns `true` if the app is running in the production environment. + bool get isProduction => flavor == Flavor.production; +} + +/// Example of how to use this class with `get_it` for dependency injection: +/// +/// ```dart +/// final getIt = GetIt.instance; +/// getIt.registerSingleton( +/// FlavorConfig( +/// flavor: Flavor.dev, +/// appName: "My App Dev", +/// apiBaseUrl: "https://api.dev.myapp.com", +/// ), +/// ); +/// ``` diff --git a/lib/features/auth/repository/user_remote_repository.dart b/lib/features/auth/repository/user_remote_repository.dart index 59a6821..b3ef5c8 100644 --- a/lib/features/auth/repository/user_remote_repository.dart +++ b/lib/features/auth/repository/user_remote_repository.dart @@ -14,7 +14,7 @@ final class UserRemoteRepository with DioErrorHandler { ) async { try { final response = await _client.dio.post( - "/auth/authenticate", + "/verisafe/v2/auth/authenticate", data: credentials.toJson(), ); @@ -36,7 +36,7 @@ final class UserRemoteRepository with DioErrorHandler { /// went wrong Future> fetchUserProfile() async { try { - final response = await _client.dio.get("/users/profile"); + final response = await _client.dio.get("/verisafe/v2/users/profile"); if (response.statusCode == 200) { return right(UserProfileData.fromJson(response.data)); } diff --git a/lib/main_development.dart b/lib/main_development.dart index 06446a6..ef63380 100644 --- a/lib/main_development.dart +++ b/lib/main_development.dart @@ -1,7 +1,16 @@ import 'package:academia/app.dart'; import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; +import 'package:academia/configs/configs.dart'; // Development's entry point void main() { - runApp(const Academia(flavor: "development")); + GetIt.instance.registerSingleton( + FlavorConfig( + flavor: Flavor.dev, + appName: "Academia - Dev", + apiBaseUrl: "http://127.0.0.1:8000", + ), + ); + runApp(const Academia()); } diff --git a/lib/main_production.dart b/lib/main_production.dart index f3d64ac..15f2f3b 100644 --- a/lib/main_production.dart +++ b/lib/main_production.dart @@ -1,7 +1,17 @@ import 'package:academia/app.dart'; +import 'package:academia/configs/configs.dart'; import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; // Production's entry point void main() { - runApp(const Academia(flavor: "production")); + GetIt.instance.registerSingleton( + FlavorConfig( + flavor: Flavor.dev, + appName: "Academia", + apiBaseUrl: "http://127.0.0.1:8000", + ), + ); + + runApp(const Academia()); } diff --git a/lib/main_staging.dart b/lib/main_staging.dart index dc6220e..6fa79b6 100644 --- a/lib/main_staging.dart +++ b/lib/main_staging.dart @@ -1,7 +1,17 @@ import 'package:academia/app.dart'; +import 'package:academia/configs/configs.dart'; import 'package:flutter/material.dart'; +import 'package:get_it/get_it.dart'; // Staging's entry point void main(List args) { - runApp(const Academia(flavor: "staging")); + GetIt.instance.registerSingleton( + FlavorConfig( + flavor: Flavor.dev, + appName: "Academia - Staging", + apiBaseUrl: "http://127.0.0.1:8000", + ), + ); + + runApp(const Academia()); } diff --git a/lib/utils/network/dio_client.dart b/lib/utils/network/dio_client.dart index 1fb3318..fa2b982 100644 --- a/lib/utils/network/dio_client.dart +++ b/lib/utils/network/dio_client.dart @@ -1,13 +1,29 @@ +import 'package:academia/configs/configs.dart'; import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; +import 'package:get_it/get_it.dart'; import './auth_interceptor.dart'; import 'package:pretty_dio_logger/pretty_dio_logger.dart'; class DioClient { - static const String _baseUrl = "http://192.168.43.218:8000/v2"; - // static const String _baseUrl = "http://127.0.0.1:8000/v2"; + /// The DioClient + /// + /// Will be used to send requests to the server + late Dio dio; + /// Ensure that before instanciating a DioClient that + /// you must have injected the flavor DioClient() { + final GetIt getIt = GetIt.instance; + + dio = Dio( + BaseOptions( + baseUrl: getIt().apiBaseUrl, + preserveHeaderCase: true, + receiveDataWhenStatusError: true, + ), + ); + dio.interceptors.add( PrettyDioLogger( error: true, @@ -25,14 +41,6 @@ class DioClient { _addAuthInterceptor(); } - final Dio dio = Dio( - BaseOptions( - baseUrl: _baseUrl, - preserveHeaderCase: true, - receiveDataWhenStatusError: true, - ), - ); - void _addAuthInterceptor() { dio.interceptors.add( AuthInterceptor(