The class is responsible for managing HTTP requests, including setting headers, building URLs, and handling responses and this class is a good example of how to manage HTTP requests in a Flutter application
api_service.dart -> ApiService: User Authentication Management and many more API Services
apis.dart -> Apis: All the end-points Url resource should be adding here as constant variables
http_manager. dart
class CustomHttpManager extends HttpManager {/// Init class constructor CustomHttpManager() {}/// Use override function from based class HttpManager /// buildOptions function for add/customize httpHeaders@override Options buildOptions(String method, CachePolicy? policy) { httpHeaders['x-language'] = CoreConfig.LANG;///Returns an Options object containing the headers and HTTP method. return Options(headers: httpHeaders, method: method); }/// This method returns the base URL for the API by calling Apis.resolveHost(), /// which likely determines the correct host based on the environment or configuration.@override String buildBaseUrl() => Apis.resolveHost();///This method retrieves the authentication token /// from the application instance.@override String?getToken() => Application.instance.getToken();/// Returning Parameters: /// It returns a map containing all the constructed query parameters.@override Map<String, dynamic> buildQueryParameters( Map<String, dynamic>? queryParameters, String? url, {String? method}) {var params =<String, dynamic>{}; params['os'] = deviceType; params['oss'] = _deviceId; params['t'] = t.toString(); params['device_id'] = _deviceId;if (!TextUtil.isEmpty(getToken())) { params['token'] =getToken(); }return map; }///Purpose: This method intercepts the result data returned from an HTTP request. /// It allows you to handle specific response codes or /// modify the response before it is returned to the caller. /// Handling Unauthorized Access (401):@override ResultData interceptResultData(ResultData data) {/// If the response code is 401 (Unauthorized), /// it indicates that the user is not authenticated or the token has expired.return data; }}
Analysis
The class named BaseAnalysis that is responsible for managing and logging various user-related events and actions within the application, using the Firebase Analytics and Smartlook services
FirebaseAnalytics Instance: The class has a private _analytics property that holds an instance of the FirebaseAnalytics class
event(String name, [Map<String, Object?>? parameters]): This method is responsible for logging an event with the provided name and optional parameters.
_convertSafeMap(Map<String, Object?> values): This private method is responsible for converting the provided parameters map to a safe format
logAppOpen(): This method is responsible for logging the "app_open" event. It calls the logAppOpen() method of the _analytics instance, the trackEvent() method of the Smartlook.instance.trackEvent() instance, and sets the user ID and user properties in the _analytics instance if the user is logged in.
setAnalyticsUserId(String userId): This method is responsible for setting the user ID in the _analytics instance.
trackNavigationEnter(String name): This method is responsible for logging the screen view event. It calls the logScreenView() method of the _analytics instance and the trackNavigationEnter() method of the SmartLookManager.instance instance.
trackNavigationExit(String name): This method is responsible for logging the screen exit event when the user exits a screen.
logOut(): This method is responsible for logging the "log_out" event when the user logs out. It retrieves the user information from the Application.instance.userInfo object, calls the event() method to log the event, and calls the openNew().
login(): This method is responsible for logging the "login" event when the user logs in. It retrieves the user information from the Application.instance.userInfo object, calls the setUser() method of the SmartLookManager.instance instance, and calls the event() method to log the event.
The Dart class named AnalysisManager that extends the BaseAnalysis class. This class is responsible for managing various user-related events and actions within an application.
Singleton Pattern: The class uses the Singleton pattern to ensure that there is only one instance of AnalysisManager available throughout the application. The _instance variable is used to store the single instance, and the _getInstance() method is used to retrieve it.
Factory Constructor: The factory AnalysisManager() constructor is used to create a new instance of AnalysisManager.
editProfile(): This method is responsible for handling the "edit_profile" event.
clickBottomTab(int index): This method is responsible for handling the "click_[tab_name]" event when the user clicks on a bottom tab. It calls the event() method with the appropriate event name based on the tab index.
registerUser(Map<String, Object?>? parameters): This method is responsible for handling the "register_user" event. It calls the trackEvent() method of the SmartLookManager instance.
continueToBookingClicked(Map<String, Object?>? parameters): This method is responsible for handling the "continue_to_booking" event. It calls the trackEvent() method of the SmartLookManager instance.
createOrder(Map<String, Object?>? parameters): This method is responsible for handling the "create_order" event. It calls the trackEvent() method of the SmartLookManager instance to log the event.
checkout(Map<String, Object?>? parameters): This method is responsible for handling the "checkout" event.
Configuration
The Dart class named AppImageConfig that implements the ImageLoaderConfigInterface interface from the infinity_core package
getErrorBuilder(double? width, double? height, double? border, Color? borderColor, double? radius): This method returns a LoadingErrorWidgetBuilder function that is used to display an error widget.
getPlaceBuilder(double? width, double? height, double? border, Color? borderColor, double? radius): This method returns a PlaceholderWidgetBuilder function that is used to display a placeholder widget.
getCircleErrorBuilder(double? radius, double? border, Color? borderColor): This method returns a LoadingErrorWidgetBuilder function that is used to display an error widget when a circular image fails to load.
getCirclePlaceBuilder(double? radius, double? border, Color? borderColor): This method returns a PlaceholderWidgetBuilder function that is used to display a placeholder widget for a circular image while it is loading.
The Dart class named AppUiConfig that extends the AppUI class from the infinity_core package
refreshHeader(...): This method returns a Widget that represents the header for the pull-to-refresh functionality.
loadMoreFooter(...): This method returns a Widget that represents the footer for the load-more functionality. It creates a CustomFooter widget that contains a RefreshFooter widget.
loadingPage(): This method returns a Widget that represents the loading page. It returns a CircularProgressIndicatorWidget that displays a circular progress indicator.
emptyPage(VoidCallback refreshCallback, String? tip): This method returns a Widget that represents the empty page.
errorPage(VoidCallback refreshCallback, String? msg): This method returns a Widget that represents the error page.
Middleware
The Dart class named LoginMiddleware that extends the GetMiddleware class from the infinity_core package.
MiddleWareRedirectArgs: This is a data class that holds the information needed for the redirection, including the route name and any arguments.
LoginMiddleware: This is the main class that extends GetMiddleware.
redirect(String? route): This is the main method that is called by the GetMiddleware class to determine if a route should be redirected.
Inside the method, it first checks if the user is not logged in (!Application.instance.isLogin).
If the user is not logged in, it retrieves the previous route name (previousRouteName) and any arguments (args) that were passed with the route.
It then returns a new RouteSettings object with the LoginPage.routeName as the route name and the MiddleWareRedirectArgs object as the arguments.
If the user is logged in, it returns null, which means that the route should not be redirected.
Local storage
The Application class is a central point of access for managing the application's state and data, providing a consistent and organized way to interact with the application's data throughout the codebase.
Singleton Pattern: The class uses the Singleton pattern to ensure that there is only one instance of Application available throughout the application.
User Management: The class provides methods for managing the user's information, such as saveUser(), getUser(), and getUid(). It also checks the user's login status using the isLogin getter.
Currency Management: The class provides methods for managing the application's currency, such as saveCurrency(), getCurrency(), saveExchangeRate(), and getExchangeRate().
Country Management: The class provides methods for managing the user's country, such as getCountryCode(), saveCountryCode(), getCountryId(), and saveCountryId()
Clearing Data: The clear() method is responsible for clearing the user's data, such as the userInfo, exchangeRate, and currency.
Routes
The AppPages class is responsible for defining the application's navigation structure and the configuration of each route. It uses the GetX package to manage the navigation and routing, which provides a flexible way to handle navigation in Flutter.
The _page() method is a helper function that simplifies the creation of GetPage objects with common configuration options, such as the system UI overlay style, transparent routes, and logging.
initial: This constant defines the initial route of the application, which is set to SplashPage.routeName.
routes: This is a list of GetPage objects that define the application's routes. Each GetPage object represents a single route and contains the following properties:
name: The name of the route.
page: A function that returns the widget to be displayed for the route.
binding: A Bindings object that defines the dependencies to be injected into the route's controllers.
transition: The transition animation to be used when navigating to the route.
_page(): This is a private method that creates a GetPage object with the provided configuration. It handles the following cases:
If transparentRoute is true, it creates a TransparentRoute object instead of a GetPage object.
If the platform is Android, it sets the system UI overlay style to a custom dark theme with a black system navigation bar color.
It sets the opaque property of the GetPage object based on the provided value.
It sets the fullscreenDialog property of the GetPage object based on the provided value.
It sets the binding, customTransition, transition, and middlewares properties of the GetPage object based on the provided values.
It calls the Monitor.instance.putPage() method to log the page name and transition.
Resources
Colours
Define color name and hex code
Tailwind Style
To generate Tailwind CSS .g file follow instruction below
Generate Tailwind extension file
Dart code, which appears to be a custom extension library for styling and sizing elements using a Tailwind-like approach and similar to Tailwind CSS's utility-first.
Font Family Extension:
Font Size Extensions:
Text Style Extensions:
Shadow Extension:
Decoration Extensions:
The code provides a flexible, chainable way to apply styles and sizes in Flutter
This code relies on custom extensions and libraries (like infinity_core) that are not standard Flutter, so the exact behavior would depend on those specific implementations.
Icon
This is a utility class typically used for organizing and centralizing resource paths in a Flutter/Dart application. The 'R' likely stands for 'Resources'
Add asset resrouce in the Assets Folder then generate the code
Usage
Translation
GetX localization configuration in Flutter:
Global Initialization Method:
Calls a global initialization method
Takes an asynchronous callback function and a list of supported languages
Directly runs the main app without additional setup (unlike the previous example)
Language Configuration:
Each Languages entry contains three parameters:
Display name of the language
Language code
Country/region code
Supported Languages:
Traditional Chinese (Hong Kong)
English (United States)
Khmer (Cambodia)
Simplified Chinese (China)
This setup provides a straightforward way to:
Initialize the app
Configure multilingual support
Set up language options for user selection
Supported Locales:
Defines the languages and specific regional variants that the app supports
Each Locale has two parameters:
First parameter: language code (zh = Chinese, en = English, km = Khmer)
Second parameter: country/region code (CH = China, US = United States, KH = Cambodia)
Localization Delegates:
Provides localization support for different parts of the app
GlobalMaterialLocalizations.delegate: Adds localization for Material Design widgets
GlobalWidgetsLocalizations.delegate: Provides localization for basic widgets
GlobalCupertinoLocalizations.delegate: Adds localization for Cupertino (iOS-style) widgets
Locale Setting:
Dynamically sets the app's current language
Uses a LanguageUtil helper to get the current language
Converts the language to a Locale object
Translations:
Uses a custom TranslationService() for managing translations
Likely implements the GetX Translations interface to provide translation maps for different languages
Overall, this configuration sets up a multilingual app with support for Chinese, English, and Khmer, using GetX for internationalization. It allows the app to:
Support multiple languages
Dynamically change the app's language
Provide localized strings and widget translations
Handle different regional variants of languages
This approach provides a flexible and comprehensive way to internationalize a Flutter application.
Let me break down this code for fetching and managing languages:
getLanguages() Method:
ApiService Class:
Key Functionality:
Fetches available languages from an API
Clears and repopulates the global languages list
Adds translations for each non-English language
Uses GetX for state management and translations
Dynamically loads translations based on language code
Workflow:
Clear existing languages
Fetch languages from API
For each language:
Add to global languages list
Set current language if matched
Fetch translations
Update UI
Handle any errors
The code is designed to:
Dynamically update app languages
Fetch translations from a backend service
Provide a flexible multilingual approach
Handle different language variants (zh-HK, zh-Hans, km, etc.)
class Colours {
static const Color secondaryColor = Color(0xFF8D8D8D);
}
// Allows easy setting of height, width, and size using method chaining
extension SizeExt on T {
T get h200 => this..height = 200.h;
T get w200 => this..width = 200.w;
T get s200 => this..size = 200.r;
}
// Quickly set font family to Nunito
extension TextFeatureExt on T {
T get fontNunito => this..fontFamily = 'Nunito';
}
// Provides quick methods to set font sizes
extension TextFontSizeFeatureExt on T {
T get f21 => this..font(21);
T get f31 => this..font(31);
T get f25 => this..font(25);
T get f45 => this..font(45);
}
// Defines multiple text styles
extension TextStyleExt on T {
T get styleMain => this..style = ts.redAccent.f16.bold.underline.mk;
T get styleAccent => this..style = ts.greenAccent.f20.bold.underline.mk;
T get styleTradition => this
..style = TextStyle(
color: Colors.greenAccent,
fontSize: 20.sp,
fontWeight: FontWeight.bold,
decoration: TextDecoration.underline,
);
}
// Provides a predefined box shadow with specific properties
extension ShadowExt on T {
T get customShadow => this
..boxShadow = const [
BoxShadow(
color: Color(0x78000000),
offset: Offset(0, 4),
blurRadius: 4.0,
spreadRadius: 0.0,
)
];
}
// Defines box decorations using both Tailwind-like and traditional Flutter approaches
extension DecorationExt on T {
T get decorMain => this..decoration = bd.greenAccent.circle.borderBrown.rounded8.customShadow.border5.mk;
T get decorTradition => this
..decoration = BoxDecoration(
color: Colors.greenAccent,
border: Border.all(color: Colors.brown, width: 5.r),
borderRadius: BorderRadius.circular(8.r),
boxShadow: const [
BoxShadow(
color: Color(0x78000000),
offset: Offset(0, 4),
blurRadius: 4.0,
spreadRadius: 0.0,
),
]
);
}
getLanguages() async {
LoadingUtil.show();
Global.languages.clear(); // Clear existing languages
// Fetch languages from API
final repository = await ApiService().getLanguages();
if (repository.isSuccess()) {
LoadingUtil.dismiss();
repository.data.forEach((v) {
Global.languages.add(LanguageModel(v['name'], v['code'], ''));
// Check if this language matches current language
if (v['code'] == LanguageUtil.getCurrentLanguage().languageCode) {
LanguageUtil.setLocalModel(context: context, model: LanguageModel(v['name'], v['code'], ''));
}
// Get translation for each language
String locale = v['code'];
debugPrint('_i18nLanguages: $locale');
ApiService.of.getTranslation(locale);
});
setState(() {});
LoadingUtil.dismiss();
} else {
showToast('${repository.msg}');
}
LoadingUtil.dismiss();
}
class ApiService extends BaseRepository {
// Singleton-like access to ApiService
static ApiService get of => getx.Get.find<ApiService>();
final dio.Dio _dio = dio.Dio();
/// Translation request method
Future<void> getTranslation(String lang) async {
// Only fetch translations for non-English languages
if (lang != 'en') {
// Construct URL with environment variables
final url = Env.translatesProds;
final appId = Env.appId;
final version = Env.version;
final name = Env.appName;
try {
final response = await _dio.get('$url?lang=$lang&appId=$appId&version=$version&name=$name');
if (response.statusCode == 200) {
final data = Map<String, String>.from(response.data);
// Add translations to GetX translation service
getx.Get.addTranslations({lang: data});
} else {
log('Error fetching data: ${response.statusCode}');
}
} on dio.DioException catch (e) {
log('DioError: $e URL --> $url');
}
}
}
}