base project

This commit is contained in:
efrilm
2025-10-23 22:16:53 +07:00
parent 6612cef24f
commit 4fee7c4bb7
52 changed files with 3319 additions and 229 deletions
+238
View File
@@ -0,0 +1,238 @@
import 'package:awesome_dio_interceptor/awesome_dio_interceptor.dart';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:injectable/injectable.dart';
import '../../env.dart';
import 'api_failure.dart';
import 'errors/bad_network_error.dart';
import 'errors/bad_request_error.dart';
import 'errors/connection_timeout_error.dart';
import 'errors/internal_server_error.dart';
import 'errors/not_found_error.dart';
import 'errors/unauthorized_error.dart';
import 'interceptors/bad_network_interceptor.dart';
import 'interceptors/bad_request_interceptor.dart';
import 'interceptors/connection_timeout_interceptor.dart';
import 'interceptors/internal_server_interceptor.dart';
import 'interceptors/not_found_interceptor.dart';
import 'interceptors/unauthorized_interceptor.dart';
@lazySingleton
class ApiClient {
final Dio _dio;
final Env _env;
ApiClient(this._dio, this._env) {
_dio.options.baseUrl = _env.baseUrl;
_dio.options.connectTimeout = const Duration(seconds: 20);
_dio.interceptors.add(BadNetworkErrorInterceptor());
_dio.interceptors.add(BadRequestErrorInterceptor());
_dio.interceptors.add(InternalServerErrorInterceptor());
_dio.interceptors.add(NotFoundErrorInterceptor());
_dio.interceptors.add(UnauthorizedInterceptor());
_dio.interceptors.add(ConnectionTimeoutErrorInterceptor());
if (kDebugMode) {
_dio.interceptors.add(
AwesomeDioInterceptor(
logResponseHeaders: false,
logRequestTimeout: false,
logRequestHeaders: true,
),
);
}
}
Future<Response> post(
String path, {
dynamic data,
Map<String, dynamic>? headers,
Map<String, dynamic>? params,
bool followRedirects = true,
bool Function(int?)? validateStatus,
String? contentType,
}) async {
try {
return await _dio.post(
path,
data: data,
options: Options(
headers: headers,
followRedirects: followRedirects,
validateStatus: validateStatus,
contentType: contentType,
),
queryParameters: params,
);
} on UnauthorizedError catch (e) {
throw ApiFailure.unauthorized(e.messageError);
} on InternalServerError {
throw const ApiFailure.internalServerError();
} on BadNetworkError {
throw const ApiFailure.connectionError();
} on BadRequestError catch (e) {
throw ApiFailure.badRequest(e.messageError);
} on NotFoundError catch (e) {
throw ApiFailure.notFound(e.messageError);
} on ConnectionTimeoutError {
throw const ApiFailure.connectionTimeout();
} on DioException catch (e) {
var errorMessage =
e.response?.data['message'] ?? e.response?.statusMessage ?? e.error;
if (errorMessage.toString().contains('Connection reset')) {
errorMessage = 'Connection reset';
}
throw ApiFailure.serverError(
statusCode: e.response?.statusCode ?? 0,
errorMessage: errorMessage.toString(),
);
} catch (e, s) {
throw ApiFailure.unexpectedError(errorMessage: e, stackTrace: s);
}
}
Future<Response> get(
String path, {
Map<String, dynamic>? headers,
Map<String, dynamic>? params,
bool followRedirects = true,
bool Function(int?)? validateStatus,
String? contentType,
}) async {
try {
return await _dio.get(
path,
options: Options(
headers: headers,
followRedirects: followRedirects,
validateStatus: validateStatus,
contentType: contentType,
),
queryParameters: params,
);
} on UnauthorizedError catch (e) {
throw ApiFailure.unauthorized(e.messageError);
} on InternalServerError {
throw const ApiFailure.internalServerError();
} on BadNetworkError {
throw const ApiFailure.connectionError();
} on BadRequestError catch (e) {
throw ApiFailure.badRequest(e.messageError);
} on NotFoundError catch (e) {
throw ApiFailure.notFound(e.messageError);
} on ConnectionTimeoutError {
throw const ApiFailure.connectionTimeout();
} on DioException catch (e) {
var errorMessage =
e.response?.data['message'] ?? e.response?.statusMessage ?? e.error;
if (errorMessage.toString().contains('Connection reset')) {
errorMessage = 'Connection reset';
}
throw ApiFailure.serverError(
statusCode: e.response?.statusCode ?? 0,
errorMessage: errorMessage.toString(),
);
} catch (e, s) {
throw ApiFailure.unexpectedError(errorMessage: e, stackTrace: s);
}
}
Future<Response> put(
String path, {
dynamic data,
Map<String, dynamic>? headers,
Map<String, dynamic>? params,
bool followRedirects = true,
bool Function(int?)? validateStatus,
String? contentType,
void Function(int count, int total)? onSendProgress,
}) async {
try {
return await _dio.put(
path,
data: data,
options: Options(
headers: headers,
followRedirects: followRedirects,
validateStatus: validateStatus,
contentType: contentType,
),
queryParameters: params,
onSendProgress: onSendProgress,
);
} on UnauthorizedError catch (e) {
throw ApiFailure.unauthorized(e.messageError);
} on InternalServerError {
throw const ApiFailure.internalServerError();
} on BadNetworkError {
throw const ApiFailure.connectionError();
} on BadRequestError catch (e) {
throw ApiFailure.badRequest(e.messageError);
} on NotFoundError catch (e) {
throw ApiFailure.notFound(e.messageError);
} on ConnectionTimeoutError {
throw const ApiFailure.connectionTimeout();
} on DioException catch (e) {
var errorMessage =
e.response?.data['message'] ?? e.response?.statusMessage ?? e.error;
if (errorMessage.toString().contains('Connection reset')) {
errorMessage = 'Connection reset';
}
throw ApiFailure.serverError(
statusCode: e.response?.statusCode ?? 0,
errorMessage: errorMessage.toString(),
);
} catch (e, s) {
throw ApiFailure.unexpectedError(errorMessage: e, stackTrace: s);
}
}
Future<Response> delete(
String path, {
dynamic data,
Map<String, dynamic>? headers,
Map<String, dynamic>? params,
bool followRedirects = true,
bool Function(int?)? validateStatus,
String? contentType,
}) async {
try {
return await _dio.delete(
path,
data: data,
options: Options(
headers: headers,
followRedirects: followRedirects,
validateStatus: validateStatus,
contentType: contentType,
),
queryParameters: params,
);
} on UnauthorizedError catch (e) {
throw ApiFailure.unauthorized(e.messageError);
} on InternalServerError {
throw const ApiFailure.internalServerError();
} on BadNetworkError {
throw const ApiFailure.connectionError();
} on BadRequestError catch (e) {
throw ApiFailure.badRequest(e.messageError);
} on NotFoundError catch (e) {
throw ApiFailure.notFound(e.messageError);
} on DioException catch (e) {
throw ApiFailure.serverError(
statusCode: e.response?.statusCode ?? 0,
errorMessage:
e.response?.data['message'] ?? e.response?.statusMessage ?? e.error,
);
} catch (e, s) {
throw ApiFailure.unexpectedError(errorMessage: e, stackTrace: s);
}
}
}
+58
View File
@@ -0,0 +1,58 @@
import 'package:flutter/material.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'api_failure.freezed.dart';
@freezed
sealed class ApiFailure with _$ApiFailure {
const ApiFailure._();
const factory ApiFailure.serverError({
required int statusCode,
required Object errorMessage,
}) = _ServerError;
const factory ApiFailure.unexpectedError({
required Object errorMessage,
required StackTrace stackTrace,
}) = _UnexpectedError;
const factory ApiFailure.connectionError() = _ConnectionError;
const factory ApiFailure.internalServerError() = _InternalServerError;
const factory ApiFailure.unauthorized(String? message) = _Unauthorized;
const factory ApiFailure.badRequest(String? message) = _BadRequest;
const factory ApiFailure.notFound(String? message) = _NotFound;
const factory ApiFailure.connectionTimeout() = _ConnectionTimeout;
String toStringFormatted(
BuildContext context, {
String? unauthorizedMessage,
}) {
return switch (this) {
_ServerError(:final statusCode, :final errorMessage) =>
'There is a problem with the server. Status code: $statusCode Error: $errorMessage',
_UnexpectedError() => 'An error occurred. Please try again later.',
_ConnectionError() => 'No Internet',
_InternalServerError() =>
'The server is experiencing problems. Please try again later.',
_Unauthorized(:final message) =>
message ?? unauthorizedMessage ?? 'Session has expired.',
_BadRequest(:final message) =>
message ?? 'There is an incorrect entry. Please check again',
_NotFound(:final message) => message ?? 'Not Found',
_ConnectionTimeout() => 'Connection Timeout',
};
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,15 @@
import 'package:dio/dio.dart';
class BadNetworkError extends DioException {
final DioException dioError;
BadNetworkError(this.dioError)
: super(
requestOptions: dioError.requestOptions,
error: dioError.error,
response: dioError.response,
type: dioError.type,
message: dioError.message,
stackTrace: dioError.stackTrace,
);
}
@@ -0,0 +1,16 @@
import 'package:dio/dio.dart';
class BadRequestError extends DioException {
final DioException dioError;
final String? messageError;
BadRequestError(this.dioError, this.messageError)
: super(
error: dioError.error,
requestOptions: dioError.requestOptions,
response: dioError.response,
type: dioError.type,
message: dioError.message,
stackTrace: dioError.stackTrace,
);
}
@@ -0,0 +1,15 @@
import 'package:dio/dio.dart';
class ConnectionTimeoutError extends DioException {
final DioException dioError;
ConnectionTimeoutError(this.dioError)
: super(
error: dioError.error,
requestOptions: dioError.requestOptions,
response: dioError.response,
type: dioError.type,
message: dioError.message,
stackTrace: dioError.stackTrace,
);
}
@@ -0,0 +1,15 @@
import 'package:dio/dio.dart';
class InternalServerError extends DioException {
final DioException dioError;
InternalServerError(this.dioError)
: super(
requestOptions: dioError.requestOptions,
error: dioError.error,
response: dioError.response,
type: dioError.type,
message: dioError.message,
stackTrace: dioError.stackTrace,
);
}
@@ -0,0 +1,16 @@
import 'package:dio/dio.dart';
class NotFoundError extends DioException {
final DioException dioError;
final String? messageError;
NotFoundError(this.dioError, this.messageError)
: super(
error: dioError.error,
requestOptions: dioError.requestOptions,
response: dioError.response,
type: dioError.type,
message: dioError.message,
stackTrace: dioError.stackTrace,
);
}
@@ -0,0 +1,16 @@
import 'package:dio/dio.dart';
class UnauthorizedError extends DioException {
final DioException dioError;
final String? messageError;
UnauthorizedError(this.dioError, this.messageError)
: super(
requestOptions: dioError.requestOptions,
error: dioError.error,
response: dioError.response,
type: dioError.type,
message: dioError.message,
stackTrace: dioError.stackTrace,
);
}
@@ -0,0 +1,22 @@
import 'package:dio/dio.dart';
import '../../../injection.dart';
import '../../network/network_client.dart';
import '../errors/bad_network_error.dart';
class BadNetworkErrorInterceptor extends Interceptor {
final _networkClient = getIt<NetworkClient>();
@override
void onError(DioException err, ErrorInterceptorHandler handler) async {
final isConnected = await _networkClient.isConnected;
if (err.type == DioExceptionType.connectionTimeout ||
!isConnected ||
err.type == DioExceptionType.receiveTimeout ||
err.type == DioExceptionType.connectionError) {
return super.onError(BadNetworkError(err), handler);
}
super.onError(err, handler);
}
}
@@ -0,0 +1,15 @@
import 'package:dio/dio.dart';
import '../errors/bad_request_error.dart';
class BadRequestErrorInterceptor extends Interceptor {
@override
void onError(DioException err, ErrorInterceptorHandler handler) {
if (err.response?.statusCode == 422 ||
err.response?.statusCode == 400 ||
err.response?.statusCode == 405) {
return super.onError(BadRequestError(err, null), handler);
}
super.onError(err, handler);
}
}
@@ -0,0 +1,13 @@
import 'package:dio/dio.dart';
import '../errors/connection_timeout_error.dart';
class ConnectionTimeoutErrorInterceptor extends Interceptor {
@override
void onError(DioException err, ErrorInterceptorHandler handler) {
if (err.type == DioExceptionType.connectionTimeout) {
return super.onError(ConnectionTimeoutError(err), handler);
}
super.onError(err, handler);
}
}
@@ -0,0 +1,18 @@
import 'package:dio/dio.dart';
import '../errors/internal_server_error.dart';
class InternalServerErrorInterceptor extends Interceptor {
@override
void onError(DioException err, ErrorInterceptorHandler handler) {
if (err.response != null) {
if (err.response?.statusCode != null &&
err.response!.statusCode! >= 500 &&
err.response!.statusCode! < 600) {
return super.onError(InternalServerError(err), handler);
}
}
super.onError(err, handler);
}
}
@@ -0,0 +1,13 @@
import 'package:dio/dio.dart';
import '../errors/not_found_error.dart';
class NotFoundErrorInterceptor extends Interceptor {
@override
void onError(DioException err, ErrorInterceptorHandler handler) {
if (err.response?.statusCode == 404) {
return super.onError(NotFoundError(err, null), handler);
}
super.onError(err, handler);
}
}
@@ -0,0 +1,15 @@
import 'package:dio/dio.dart';
import '../errors/unauthorized_error.dart';
class UnauthorizedInterceptor extends Interceptor {
@override
void onError(DioException err, ErrorInterceptorHandler handler) {
if (err.response?.statusCode == 401 ||
err.response?.statusCode == 403 ||
err.response?.statusCode == 419) {
return super.onError(UnauthorizedError(err, null), handler);
}
super.onError(err, handler);
}
}
+1
View File
@@ -0,0 +1 @@
// TODO: define your code
+3
View File
@@ -0,0 +1,3 @@
class AppConstant {
static const String appName = "";
}
+9
View File
@@ -0,0 +1,9 @@
import 'package:injectable/injectable.dart';
import '../../presentation/router/app_router.dart';
@module
abstract class AutoRouteDi {
@lazySingleton
AppRouter get appRouter => AppRouter();
}
+8
View File
@@ -0,0 +1,8 @@
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:injectable/injectable.dart';
@module
abstract class ConnectivityDi {
@lazySingleton
Connectivity get connectivity => Connectivity();
}
+8
View File
@@ -0,0 +1,8 @@
import 'package:dio/dio.dart';
import 'package:injectable/injectable.dart';
@module
abstract class DioDi {
@lazySingleton
Dio get dio => Dio();
}
+8
View File
@@ -0,0 +1,8 @@
import 'package:injectable/injectable.dart';
import 'package:shared_preferences/shared_preferences.dart';
@module
abstract class SharedPreferencesDi {
@preResolve
Future<SharedPreferences> get prefs => SharedPreferences.getInstance();
}
+1
View File
@@ -0,0 +1 @@
// TODO: define your code
+8
View File
@@ -0,0 +1,8 @@
import 'package:flutter/material.dart';
void dismissKeyboard(BuildContext context) {
final currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus && currentFocus.focusedChild != null) {
FocusManager.instance.primaryFocus?.unfocus();
}
}
+19
View File
@@ -0,0 +1,19 @@
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:injectable/injectable.dart';
@lazySingleton
class NetworkClient extends NetworkInfoBase {
final Connectivity connectivity;
NetworkClient(this.connectivity);
@override
Future<bool> get isConnected async {
final result = await connectivity.checkConnectivity();
return result.first != ConnectivityResult.none;
}
}
abstract class NetworkInfoBase {
Future<bool> get isConnected;
}
+5
View File
@@ -0,0 +1,5 @@
part of 'theme.dart';
class AppColor {
// TODO: define color
}
+5
View File
@@ -0,0 +1,5 @@
part of 'theme.dart';
class AppStyle {
// TODO: define style
}
+5
View File
@@ -0,0 +1,5 @@
part of 'theme.dart';
class AppValue {
// TODO: define value
}
+11
View File
@@ -0,0 +1,11 @@
import 'package:flutter/material.dart';
part 'app_color.dart';
part 'app_style.dart';
part 'app_value.dart';
class ThemeApp {
static ThemeData get theme => ThemeData(
useMaterial3: true,
);
}
+20
View File
@@ -0,0 +1,20 @@
import 'package:injectable/injectable.dart';
abstract class Env {
String get baseUrl;
// add getter here...
}
@Injectable(as: Env)
@dev
class DevEnv implements Env {
@override
String get baseUrl => ''; // example value
}
@Injectable(as: Env)
@prod
class ProdEnv implements Env {
@override
String get baseUrl => '';
}
+68
View File
@@ -0,0 +1,68 @@
// dart format width=80
// GENERATED CODE - DO NOT MODIFY BY HAND
// **************************************************************************
// InjectableConfigGenerator
// **************************************************************************
// ignore_for_file: type=lint
// coverage:ignore-file
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:apskel_pos_flutter_v2/common/api/api_client.dart' as _i457;
import 'package:apskel_pos_flutter_v2/common/di/di_auto_route.dart' as _i729;
import 'package:apskel_pos_flutter_v2/common/di/di_connectivity.dart' as _i807;
import 'package:apskel_pos_flutter_v2/common/di/di_dio.dart' as _i86;
import 'package:apskel_pos_flutter_v2/common/di/di_shared_preferences.dart'
as _i135;
import 'package:apskel_pos_flutter_v2/common/network/network_client.dart'
as _i171;
import 'package:apskel_pos_flutter_v2/env.dart' as _i923;
import 'package:apskel_pos_flutter_v2/presentation/router/app_router.dart'
as _i800;
import 'package:connectivity_plus/connectivity_plus.dart' as _i895;
import 'package:dio/dio.dart' as _i361;
import 'package:get_it/get_it.dart' as _i174;
import 'package:injectable/injectable.dart' as _i526;
import 'package:shared_preferences/shared_preferences.dart' as _i460;
const String _dev = 'dev';
const String _prod = 'prod';
extension GetItInjectableX on _i174.GetIt {
// initializes the registration of main-scope dependencies inside of GetIt
Future<_i174.GetIt> init({
String? environment,
_i526.EnvironmentFilter? environmentFilter,
}) async {
final gh = _i526.GetItHelper(this, environment, environmentFilter);
final sharedPreferencesDi = _$SharedPreferencesDi();
final dioDi = _$DioDi();
final autoRouteDi = _$AutoRouteDi();
final connectivityDi = _$ConnectivityDi();
await gh.factoryAsync<_i460.SharedPreferences>(
() => sharedPreferencesDi.prefs,
preResolve: true,
);
gh.lazySingleton<_i361.Dio>(() => dioDi.dio);
gh.lazySingleton<_i800.AppRouter>(() => autoRouteDi.appRouter);
gh.lazySingleton<_i895.Connectivity>(() => connectivityDi.connectivity);
gh.lazySingleton<_i171.NetworkClient>(
() => _i171.NetworkClient(gh<_i895.Connectivity>()),
);
gh.factory<_i923.Env>(() => _i923.DevEnv(), registerFor: {_dev});
gh.lazySingleton<_i457.ApiClient>(
() => _i457.ApiClient(gh<_i361.Dio>(), gh<_i923.Env>()),
);
gh.factory<_i923.Env>(() => _i923.ProdEnv(), registerFor: {_prod});
return this;
}
}
class _$SharedPreferencesDi extends _i135.SharedPreferencesDi {}
class _$DioDi extends _i86.DioDi {}
class _$AutoRouteDi extends _i729.AutoRouteDi {}
class _$ConnectivityDi extends _i807.ConnectivityDi {}
+9
View File
@@ -0,0 +1,9 @@
import 'package:get_it/get_it.dart';
import 'package:injectable/injectable.dart';
import 'injection.config.dart';
final getIt = GetIt.instance;
@InjectableInit()
Future<void> configureDependencies(String env) => getIt.init(environment: env);
+20 -114
View File
@@ -1,122 +1,28 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:injectable/injectable.dart';
void main() {
runApp(const MyApp());
}
import 'injection.dart';
import 'presentation/app_widget.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key});
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// TRY THIS: Try running your application with "flutter run". You'll see
// the application has a purple toolbar. Then, without quitting the app,
// try changing the seedColor in the colorScheme below to Colors.green
// and then invoke "hot reload" (save your changes or press the "hot
// reload" button in a Flutter-supported IDE, or press "r" if you used
// the command line to start the app).
//
// Notice that the counter didn't reset back to zero; the application
// state is not lost during the reload. To reset the state, use hot
// restart instead.
//
// This works for code too, not just values: Most code changes can be
// tested with just a hot reload.
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.dark,
),
);
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
if (kReleaseMode) {
debugPrint = (message, {wrapWidth}) => '';
}
@override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// TRY THIS: Try changing the color here to a specific color (to
// Colors.amber, perhaps?) and trigger a hot reload to see the AppBar
// change color while the other colors stay the same.
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
// Column is also a layout widget. It takes a list of children and
// arranges them vertically. By default, it sizes itself to fit its
// children horizontally, and tries to be as tall as its parent.
//
// Column has various properties to control how it sizes itself and
// how it positions its children. Here we use mainAxisAlignment to
// center the children vertically; the main axis here is the vertical
// axis because Columns are vertical (the cross axis would be
// horizontal).
//
// TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint"
// action in the IDE, or press "p" in the console), to see the
// wireframe for each widget.
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('You have pushed the button this many times:'),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
await configureDependencies(
kReleaseMode ? Environment.prod : Environment.dev,
);
runApp(const AppWidget());
}
+30
View File
@@ -0,0 +1,30 @@
import 'package:flutter/material.dart';
import '../common/theme/theme.dart';
import '../common/constant/app_constant.dart';
import '../injection.dart';
import 'router/app_router.dart';
import 'router/app_router_observer.dart';
class AppWidget extends StatefulWidget {
const AppWidget({super.key});
@override
State<AppWidget> createState() => _AppWidgetState();
}
class _AppWidgetState extends State<AppWidget> {
final _appRouter = getIt<AppRouter>();
@override
Widget build(BuildContext context) {
return MaterialApp.router(
debugShowCheckedModeBanner: false,
title: AppConstant.appName,
theme: ThemeApp.theme,
routerConfig: _appRouter.config(
navigatorObservers: () => <NavigatorObserver>[AppRouteObserver()],
),
);
}
}
@@ -0,0 +1,14 @@
// dart format width=80
/// GENERATED CODE - DO NOT MODIFY BY HAND
/// *****************************************************
/// FlutterGen
/// *****************************************************
// coverage:ignore-file
// ignore_for_file: type=lint
// ignore_for_file: deprecated_member_use,directives_ordering,implicit_dynamic_list_literal,unnecessary_import
class Assets {
const Assets._();
}
@@ -0,0 +1,17 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
@RoutePage()
class SplashPage extends StatefulWidget {
const SplashPage({super.key});
@override
State<SplashPage> createState() => _SplashPageState();
}
class _SplashPageState extends State<SplashPage> {
@override
Widget build(BuildContext context) {
return Scaffold(body: Center(child: Text("Splash Page")));
}
}
+11
View File
@@ -0,0 +1,11 @@
import 'package:auto_route/auto_route.dart';
import 'app_router.gr.dart';
@AutoRouterConfig()
class AppRouter extends RootStackRouter {
@override
List<AutoRoute> get routes => [
// Splash
AutoRoute(page: SplashRoute.page, initial: true),
];
}
@@ -0,0 +1,30 @@
// dart format width=80
// GENERATED CODE - DO NOT MODIFY BY HAND
// **************************************************************************
// AutoRouterGenerator
// **************************************************************************
// ignore_for_file: type=lint
// coverage:ignore-file
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:apskel_pos_flutter_v2/presentation/pages/splash/splash_page.dart'
as _i1;
import 'package:auto_route/auto_route.dart' as _i2;
/// generated route for
/// [_i1.SplashPage]
class SplashRoute extends _i2.PageRouteInfo<void> {
const SplashRoute({List<_i2.PageRouteInfo>? children})
: super(SplashRoute.name, initialChildren: children);
static const String name = 'SplashRoute';
static _i2.PageInfo page = _i2.PageInfo(
name,
builder: (data) {
return const _i1.SplashPage();
},
);
}
@@ -0,0 +1,21 @@
import 'dart:developer';
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
class AppRouteObserver extends AutoRouterObserver {
@override
void didPush(Route route, Route? previousRoute) {
log('New route pushed: ${route.settings.name}');
}
@override
void didInitTabRoute(TabPageRoute route, TabPageRoute? previousRoute) {
log('Tab route visited: ${route.name}');
}
@override
void didChangeTabRoute(TabPageRoute route, TabPageRoute previousRoute) {
log('Tab route re-visited: ${route.name}');
}
}