Orkun Client
Environment Variable
Use envied from pub.dev
Add new enviroment variable in .env file
Run cmd
dart run build_runner buildAdd new field in
env.dart
@EnviedField()
static String requestHeaderApiKey = _Env.requestHeaderApiKey;REST Api
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
_analyticsproperty that holds an instance of theFirebaseAnalyticsclassevent(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_analyticsinstance, thetrackEvent()method of theSmartlook.instance.trackEvent()instance, and sets the user ID and user properties in the_analyticsinstance if the user is logged in.setAnalyticsUserId(String userId): This method is responsible for setting the user ID in the
_analyticsinstance.trackNavigationEnter(String name): This method is responsible for logging the screen view event. It calls the
logScreenView()method of the_analyticsinstance and thetrackNavigationEnter()method of theSmartLookManager.instanceinstance.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.userInfoobject, calls theevent()method to log the event, and calls theopenNew().login(): This method is responsible for logging the "login" event when the user logs in. It retrieves the user information from the
Application.instance.userInfoobject, calls thesetUser()method of theSmartLookManager.instanceinstance, and calls theevent()method to log the event.
import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:flutter_smartlook/flutter_smartlook.dart';
import 'package:orkun/common/analysis/smartlook_manager.dart';
import 'package:orkun/common/application.dart';
class BaseAnalysis {
final FirebaseAnalytics _analytics = FirebaseAnalytics.instance;
///Report Event
void event(String name, [Map<String, Object?>? parameters]) {
if (parameters != null) {
var map = Map<String, Object?>.from(parameters);
_convertSafeMap(map);
_analytics.logEvent(name: name, parameters: map);
} else {
_analytics.logEvent(name: name);
}
SmartLookManager.instance.trackEvent(name, parameters: parameters);
}
void _convertSafeMap(Map<String, Object?> values) {
var removeKeys = <String>[];
for (final key in values.keys) {
var value = values[key];
if (value == null) {
removeKeys.add(key);
continue;
}
if (value is String || value is num) {
continue;
}
values[key] = value.toString();
}
for (final element in removeKeys) {
values.remove(element);
}
}
void logAppOpen() {
_analytics.logAppOpen();
Smartlook.instance.trackEvent('app_open');
if (Application.instance.isLogin) {
var user = Application.instance.userInfo!;
_analytics.setUserId(id: '${user.userId}');
_analytics.setUserProperty(name: '${user.clientName}', value: '${user.userId}');
SmartLookManager.instance.setUser(user);
}
}
void setAnalyticsUserId(String userId) => _analytics.setUserId(id: userId);
void trackNavigationEnter(String name) {
_analytics.logScreenView(screenName: name);
SmartLookManager.instance.trackNavigationEnter(name);
}
void trackNavigationExit(String name) {
SmartLookManager.instance.trackNavigationExit(name);
}
void logOut() {
var user = Application.instance.userInfo!;
event('log_out', {
'name': '${user.clientName}',
'id': '${user.userId}',
'phone number': '+${user.phoneCountry} ${user.phoneCountry}',
});
Smartlook.instance.user.openNew();
}
void login() {
var user = Application.instance.userInfo!;
SmartLookManager.instance.setUser(user);
event('login', {
'login method': 'Phone Login',
'id': '${user.userId}',
'phone number': '${user.phoneCountry} ${user.phoneCountry}',
});
}
}
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
AnalysisManageravailable throughout the application. The_instancevariable 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 ofAnalysisManager.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 theSmartLookManagerinstance.continueToBookingClicked(Map<String, Object?>? parameters): This method is responsible for handling the "continue_to_booking" event. It calls the
trackEvent()method of theSmartLookManagerinstance.createOrder(Map<String, Object?>? parameters): This method is responsible for handling the "create_order" event. It calls the
trackEvent()method of theSmartLookManagerinstance to log the event.checkout(Map<String, Object?>? parameters): This method is responsible for handling the "checkout" event.
import 'package:orkun/common/analysis/base_analysis.dart';
import 'package:orkun/common/analysis/smartlook_manager.dart';
import 'package:orkun/common/application.dart';
List _tabs = ['home_tab', 'request_tab', 'favorite_tab', 'message_tab', 'profile_tab'];
class AnalysisManager extends BaseAnalysis {
static AnalysisManager? _instance;
factory AnalysisManager() => _getInstance();
static AnalysisManager get instance => _getInstance();
AnalysisManager._internal();
static AnalysisManager _getInstance() => _instance ??= AnalysisManager._internal();
void editProfile() {
var user = Application.instance.userInfo;
event('edit_profile', {'name': '${user?.clientName}', 'avatar': '${user?.clientImage}'});
SmartLookManager.instance.setUser(user!);
}
void clickBottomTab(int index) => event('click_${_tabs[index]}');
void registerUser({Map<String, Object?>? parameters}) {
const registerUser = 'register_user';
SmartLookManager.instance.trackEvent(registerUser, parameters: parameters);
event(registerUser, parameters);
}
void continueToBookingClicked({Map<String, Object?>? parameters}) {
const continueToBooking = 'continue_to_booking';
SmartLookManager.instance.trackEvent(continueToBooking, parameters: parameters);
event(continueToBooking, parameters);
}
void createOrder({Map<String, Object?>? parameters}) {
const createOrder = 'create_order';
SmartLookManager.instance.trackEvent(createOrder, parameters: parameters);
event(createOrder, parameters);
}
void checkout({Map<String, Object?>? parameters}) {
const checkout = 'checkout';
SmartLookManager.instance.trackEvent(checkout, parameters: parameters);
event(checkout, parameters);
}
}
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
LoadingErrorWidgetBuilderfunction that is used to display an error widget.getPlaceBuilder(double? width, double? height, double? border, Color? borderColor, double? radius): This method returns a
PlaceholderWidgetBuilderfunction that is used to display a placeholder widget.getCircleErrorBuilder(double? radius, double? border, Color? borderColor): This method returns a
LoadingErrorWidgetBuilderfunction 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
PlaceholderWidgetBuilderfunction that is used to display a placeholder widget for a circular image while it is loading.
import 'package:flutter/material.dart';
import 'package:infinity_core/core.dart';
import 'package:orkun/res/colours.dart';
import 'package:orkun/res/r.dart';
import 'package:shimmer/shimmer.dart';
class AppImageConfig extends ImageLoaderConfigInterface {
@override
LoadingErrorWidgetBuilder getErrorBuilder(
double? width,
double? height,
double? border,
Color? borderColor,
double? radius,
) {
return (BuildContext context, String url, _) {
return const SizedBox();
};
}
@override
PlaceholderWidgetBuilder getPlaceBuilder(
double? width,
double? height,
double? border,
Color? borderColor,
double? radius,
) {
return (BuildContext context, String url) {
return Shimmer.fromColors(
baseColor: Colors.grey.shade300,
highlightColor: Colors.grey.shade100,
child: Container(color: Colors.grey.shade300),
);
};
}
@override
LoadingErrorWidgetBuilder getCircleErrorBuilder(double? radius, double? border, Color? borderColor) {
return (BuildContext context, String url, _) {
return ClipOval(
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(color: borderColor ?? Colours.transparent, width: border!),
),
width: radius! * 2,
height: radius * 2,
alignment: Alignment.center,
child: Image.asset(R.avatarProfile, width: radius * 2, height: radius * 2, fit: BoxFit.fitWidth),
),
);
};
}
@override
PlaceholderWidgetBuilder getCirclePlaceBuilder(double? radius, double? border, Color? borderColor) {
return (BuildContext context, String url) {
return ClipOval(
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(color: borderColor ?? Colours.transparent, width: border ?? 0),
),
width: radius! * 2,
height: radius * 2,
alignment: Alignment.center,
child: Image.asset(R.avatarProfile, width: radius * 2, height: radius * 2, fit: BoxFit.fitWidth),
),
);
};
}
}
The Dart class named AppUiConfig that extends the AppUI class from the infinity_core package
refreshHeader(...): This method returns a
Widgetthat represents the header for the pull-to-refresh functionality.loadMoreFooter(...): This method returns a
Widgetthat represents the footer for the load-more functionality. It creates aCustomFooterwidget that contains aRefreshFooterwidget.loadingPage(): This method returns a
Widgetthat represents the loading page. It returns aCircularProgressIndicatorWidgetthat displays a circular progress indicator.emptyPage(VoidCallback refreshCallback, String? tip): This method returns a
Widgetthat represents the empty page.errorPage(VoidCallback refreshCallback, String? msg): This method returns a
Widgetthat represents the error page.
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:infinity_core/core.dart';
import 'package:infinity_core/widget/refresh/refresh_footer.dart';
import 'package:orkun/res/colours.dart';
import 'package:orkun/res/r.dart';
import 'package:orkun/res/strings.dart';
import 'package:orkun/res/tailwind_ext.dart' hide TextFontSizeFeatureExt;
import 'package:orkun/widgets/pin_mark_widget.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
class AppUiConfig extends AppUI {
@override
Widget refreshHeader({String? releaseText, String? refreshingText, String? completeText, TextStyle? style}) {
return const MaterialClassicHeader();
}
@override
Widget loadMoreFooter({
String? noDataText,
String? loadingText,
String? canLoadingText,
String? idleText,
TextStyle style = const TextStyle(color: Colors.grey),
}) {
return CustomFooter(
height: 100,
builder: (context, mode) {
return RefreshFooter(
status: mode,
loadFailHint: idleText ?? Ids.loadingCompleted.trn,
loadingHint: loadingText ?? Ids.dataIsLoading.trn,
loadMoreHint: loadingText ?? Ids.dataIsLoading.trn,
noDataHint: noDataText ?? '',
);
},
);
}
@override
Widget loadingPage() {
return const CircularProgressIndicatorWidget();
}
@override
Widget emptyPage(VoidCallback refreshCallback, String? tip) {
return Column();
}
@override
Widget errorPage(VoidCallback refreshCallback, String? msg) {
return const SizedBox();
}
}
class CircularProgressIndicatorWidget extends StatelessWidget {
const CircularProgressIndicatorWidget({super.key});
@override
Widget build(BuildContext context) {
return Center(
child: Platform.isIOS
? const CupertinoActivityIndicator(
color: Colours.primaryColor,
)
: const CircularProgressIndicator(
color: Colours.primaryColor,
),
);
}
}
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
GetMiddlewareclass 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
RouteSettingsobject with theLoginPage.routeNameas the route name and theMiddleWareRedirectArgsobject as the arguments.If the user is logged in, it returns
null, which means that the route should not be redirected.
import 'package:flutter/material.dart';
import 'package:infinity_core/core.dart';
import 'package:orkun/common/application.dart';
import 'package:orkun/ui/auth_v2/login_page_v2.dart';
class MiddleWareRedirectArgs {
String? routeName;
Object? arguments;
MiddleWareRedirectArgs({this.routeName, this.arguments});
}
class LoginMiddleware extends GetMiddleware {
@override
RouteSettings? redirect(String? route) {
// If user not login yet
if (!Application.instance.isLogin) {
var previousRouteName = route;
Object? args = Get.arguments;
return RouteSettings(
name: LoginPageV2.routeName,
arguments: MiddleWareRedirectArgs(arguments: args, routeName: previousRouteName),
);
}
return null;
}
}
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
Applicationavailable throughout the application.User Management: The class provides methods for managing the user's information, such as
saveUser(),getUser(), andgetUid(). It also checks the user's login status using theisLogingetter.Currency Management: The class provides methods for managing the application's currency, such as
saveCurrency(),getCurrency(),saveExchangeRate(), andgetExchangeRate().Country Management: The class provides methods for managing the user's country, such as
getCountryCode(),saveCountryCode(),getCountryId(), andsaveCountryId()Clearing Data: The
clear()method is responsible for clearing the user's data, such as theuserInfo,exchangeRate, andcurrency.
import 'package:infinity_core/core.dart';
import 'package:orkun/common/analysis/analysis_manager.dart';
import 'package:orkun/ui/auth/model/user_info.dart';
import 'package:orkun/ui/request/model/exchange_rate_model.dart';
import 'package:orkun/ui/splash/model/currencyModel.dart';
class Application {
factory Application() => _getInstance();
Application._internal() {
userInfo = SpUtil.getObj<UserInfo>(_userInfo, UserInfo.fromJson);
currency = SpUtil.getObj<CurrencyModel>(_currency, CurrencyModel.fromJson);
exchangeRate = SpUtil.getObj<ExchangeRate>(_exchangeRate, ExchangeRate.fromJson);
}
static Application? _instance;
static Application _getInstance() {
_instance ??= Application._internal();
return _instance!;
}
static const String _currency = 'currency';
static const String _exchangeRate = 'ExchangeRate';
static const String _userInfo = '_userInfo';
static Application get instance => _getInstance();
UserInfo? userInfo;
ExchangeRate? exchangeRate;
CurrencyModel? currency;
String? getUid() => userInfo?.uuid;
String? getUserId() => userInfo?.userId ?? '';
String? getToken() => "Bearer ${userInfo?.userToken ?? ""}";
bool get isLogin => userInfo?.userId?.isNotEmpty ?? false;
void saveUser(UserInfo user) {
if (userInfo == null) {
userInfo = user;
} else {
userInfo?.mergerUser(user);
}
if (userInfo != null) {
Monitor.instance.putsConsole(['UserToken:', userInfo?.userToken ?? '']);
SpUtil.putObject(_userInfo, userInfo!);
}
AnalysisManager.instance.setAnalyticsUserId('${user.userId}');
}
UserInfo getUser() {
var user = SpUtil.getObj(_userInfo, UserInfo.fromJson);
return user ?? UserInfo();
}
CurrencyModel? getCurrency() => currency = SpUtil.getObj(_currency, CurrencyModel.fromJson);
void saveCurrency(CurrencyModel currency) {
this.currency = currency;
SpUtil.putObject(_currency, currency);
}
ExchangeRate? getExchangeRate() {
return exchangeRate ??= SpUtil.getObj(_exchangeRate, ExchangeRate.fromJson);
}
void saveExchangeRate(ExchangeRate exchangeRate) {
this.exchangeRate = exchangeRate;
SpUtil.putObject(_exchangeRate, exchangeRate);
}
void clear() {
SpUtil.remove(_userInfo);
userInfo = null;
userInfo?.userToken = '';
exchangeRate = null;
currency = null;
}
}
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
GetPageobjects that define the application's routes. EachGetPageobject 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: ABindingsobject 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
GetPageobject with the provided configuration. It handles the following cases:If
transparentRouteis true, it creates aTransparentRouteobject instead of aGetPageobject.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
opaqueproperty of theGetPageobject based on the provided value.It sets the
fullscreenDialogproperty of theGetPageobject based on the provided value.It sets the
binding,customTransition,transition, andmiddlewaresproperties of theGetPageobject based on the provided values.It calls the
Monitor.instance.putPage()method to log the page name and transition.
class AppPages {
static const initial = SplashPage.routeName;
/// Define all routes here.
/// Binding the controller for specific Page
/// Inject all the dependencies when route to
static final List<GetPage> routes = [
_page(
name: '/',
page: SplashPage.new,
binding: BindingsBuilder(() {
Get.lazyPut(SplashPageController.new);
Get.lazyPut(HomeController.new);
Get.lazyPut(PageRequestController.new);
}),
transition: Transition.rightToLeft,
),
];
static GetPage _page({
required String name,
required GetPageBuilder page,
bool fullscreenDialog = false,
bool transparentRoute = false,
bool opaque = true,
Bindings? binding,
Transition? transition,
CustomTransition? customTransition,
List<GetMiddleware>? middlewares,
}) {
if (transparentRoute) {
return TransparentRoute(
name: name,
binding: binding,
transition: transition ?? Transition.downToUp,
middlewares: [PageMiddleware(), ...?middlewares],
page: () {
Monitor.instance.putPage(name);
return page();
},
);
}
var mySystemTheme = SystemUiOverlayStyle.dark.copyWith(systemNavigationBarColor: Colors.black);
SystemChrome.setSystemUIOverlayStyle(mySystemTheme);
return GetPage(
name: name,
opaque: opaque,
fullscreenDialog: fullscreenDialog,
binding: binding,
customTransition: customTransition,
transition: transition ?? Transition.rightToLeft,
page: () {
Monitor.instance.putPage('PageName: $name Transition: $transition');
return page();
},
middlewares: [PageMiddleware(), ...?middlewares],
);
}
}Resources
Colours
Define color name and hex code
class Colours {
static const Color secondaryColor = Color(0xFF8D8D8D);
}Tailwind Style
To generate Tailwind CSS .g file follow instruction below

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.
// 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;
}Font Family Extension:
// Quickly set font family to Nunito
extension TextFeatureExt on T {
T get fontNunito => this..fontFamily = 'Nunito';
}Font Size Extensions:
// 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);
}Text Style Extensions:
// 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,
);
}Shadow Extension:
// 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,
)
];
}Decoration Extensions:
// 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,
),
]
);
}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'
class R {
static const String _assets = 'assets';
///------------------------ assets ------------------------
static const String icEdit = '$_assets/ic_edit.svg';
static const String icPerm = '$_assets/ic_perm.svg';
static const String icWarn = '$_assets/ic_warn.svg';
static const String icLangu = '$_assets/ic_langu.svg';
static const String icSmart = '$_assets/ic_smart.png';
}Add asset resrouce in the Assets Folder then generate the code

Usage
Image.asset(R.icFacebook)Translation
GetX localization configuration in Flutter:
Global Initialization Method:
Global.init(
() async {
runApp(const MyApp()); // Initialize
},
languages: [ ... ]
);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:
languages: [
Languages('繁体中文', 'zh-HK', 'HK'), // Traditional Chinese (Hong Kong)
Languages('English', 'en', 'US'), // English (United States)
Languages('ខ្មែរ', 'km', 'KH'), // Khmer (Cambodia)
Languages('简体中文', 'zh-Hans', 'CH'), // Simplified Chinese (China)
]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:
supportedLocales: const [
Locale('zh', 'CH'), // Chinese (China)
Locale('en', 'US'), // English (United States)
Locale('km', 'KH'), // Khmer (Cambodia)
],Defines the languages and specific regional variants that the app supports
Each
Localehas 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:
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],Provides localization support for different parts of the app
GlobalMaterialLocalizations.delegate: Adds localization for Material Design widgetsGlobalWidgetsLocalizations.delegate: Provides localization for basic widgetsGlobalCupertinoLocalizations.delegate: Adds localization for Cupertino (iOS-style) widgets
Locale Setting:
locale: LanguageUtil.getCurrentLanguage().toLocale(),Dynamically sets the app's current language
Uses a
LanguageUtilhelper to get the current languageConverts the language to a
Localeobject
Translations:
translations: TranslationService(),Uses a custom
TranslationService()for managing translationsLikely implements the GetX
Translationsinterface 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:
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();
}ApiServiceClass:
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');
}
}
}
}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.)
Utils
Apns Manager
Crashlytics Manager
Location Permission
Message Services
Nofitifcation Manager
Pusher Manager
Widget
Last updated