diff --git a/assets/icon/icon.png b/assets/icon/icon.png new file mode 100644 index 0000000..8b1c2c0 Binary files /dev/null and b/assets/icon/icon.png differ diff --git a/devtools_options.yaml b/devtools_options.yaml new file mode 100644 index 0000000..fa0b357 --- /dev/null +++ b/devtools_options.yaml @@ -0,0 +1,3 @@ +description: This file stores settings for Dart & Flutter DevTools. +documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states +extensions: diff --git a/lib/main.dart b/lib/main.dart index c93245d..12d9574 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -18,9 +18,38 @@ final _router = GoRouter( initialLocation: '/', routes: [ GoRoute(name: 'index', path: '/', builder: (context, state) => const IndexPage()), - GoRoute(name: 'login', path: '/login', builder: (context, state) => const LoginPage()), + GoRoute( + name: 'login', + path: '/login', + builder: (context, state) => const LoginPage(), + pageBuilder: (BuildContext context, GoRouterState state) => CustomTransitionPage( + key: state.pageKey, + child: const LoginPage(), + transitionsBuilder: (context, animation, secondaryAnimation, child) { + return SlideTransition( + position: Tween(begin: Offset(-1.0, 0.0), end: Offset.zero).animate(animation), + child: child, + ); + }, + ), + ), GoRoute(name: 'approval', path: '/approval', builder: (context, state) => const ApprovalPage()), - GoRoute(name: 'validate', path: '/validate', builder: (context, state) => const ValidatePage()), + GoRoute( + name: 'validate', + path: '/validate', + builder: (context, state) => const ValidatePage(), + pageBuilder: (BuildContext context, GoRouterState state) => CustomTransitionPage( + key: state.pageKey, + child: const ValidatePage(), + transitionsBuilder: (context, animation, secondaryAnimation, child) { + return SlideTransition( + position: Tween(begin: Offset(1.0, 0.0), end: Offset.zero).animate(animation), + child: child, + ); + }, + ), + ), + // GoRoute(name: 'validate', path: '/validate', builder: (context, state) => const ValidatePage()), GoRoute(name: 'result', path: '/result', builder: (context, state) => const ValidationResultPage()), ], ); diff --git a/lib/pages/index_page.dart b/lib/pages/index_page.dart index 44c35ac..4458874 100644 --- a/lib/pages/index_page.dart +++ b/lib/pages/index_page.dart @@ -53,14 +53,14 @@ class IndexPage extends StatelessWidget { ), Padding( padding: EdgeInsets.only(right: (screenWidth / 2) - 100), - child: Row( + child: const Row( mainAxisAlignment: MainAxisAlignment.end, children: [ TextWidget(text: "Mobile", color: Color.fromARGB(255, 244, 243, 243), bold: false, size: 16), ], ), ), - Gap(200), + const MaxGap(200), Row( mainAxisAlignment: MainAxisAlignment.center, spacing: 32, diff --git a/lib/pages/validate_page.dart b/lib/pages/validate_page.dart index 469a866..a769922 100644 --- a/lib/pages/validate_page.dart +++ b/lib/pages/validate_page.dart @@ -1,7 +1,10 @@ import 'package:flutter/material.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:gap/gap.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; +import 'package:ocbo_esign_validator/widgets/box_widget.dart'; import 'package:ocbo_esign_validator/widgets/text_widget.dart'; +import 'package:vibration/vibration.dart'; class ValidatePage extends StatelessWidget { const ValidatePage({super.key}); @@ -43,53 +46,114 @@ class _BarcodeScannerScreenState extends State { ), child: Center( child: Padding( - padding: const EdgeInsets.only(top: 88, left: 16, right: 16), + padding: const EdgeInsets.only(top: 70, left: 16, right: 16), child: Column( children: [ Container( padding: EdgeInsets.only(top: 8, bottom: 8, left: 20, right: 20), decoration: BoxDecoration( - color: Color.fromARGB(149, 16, 22, 28), - borderRadius: BorderRadius.circular(8), + color: const Color.fromRGBO(9, 13, 16, 0.623), + borderRadius: BorderRadius.circular(32), ), - child: TextWidget(text: 'Scan OCBO e-Sign QR Code', size: 14, bold: true), + child: const TextWidget(text: 'Scan OCBO e-Sign QR Code', size: 14, bold: true), ), - const Gap(50), - SizedBox( - height: 350, + const Gap(24), + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(24), + boxShadow: [ + const BoxShadow( + color: Color.fromRGBO(5, 5, 8, 0.341), + blurRadius: 8.0, + offset: Offset(4, 4), // left and up + ), + const BoxShadow( + color: Color.fromRGBO(92, 71, 97, 0.373), + blurRadius: 8.0, + offset: Offset(-4, -4), // right and down + ), + ], + ), + height: 330, + width: 340, child: ClipRRect( - borderRadius: BorderRadius.circular(20), // Adjust the radius as needed + borderRadius: BorderRadius.circular(24), // Adjust the radius as needed child: MobileScanner( fit: BoxFit.cover, - onDetect: (BarcodeCapture capture) { + onDetect: (BarcodeCapture capture) async { final List barcodes = capture.barcodes; if (barcodes.isNotEmpty && barcodes.first.rawValue != null) { setState(() { qrResult = barcodes.first.rawValue!; }); + + if (await Vibration.hasVibrator()) { + Vibration.vibrate(duration: 100); + } } }, ), ), ), const Gap(40), - Container( - padding: EdgeInsets.all(0), - width: 120, - height: 120, - decoration: BoxDecoration( - border: Border.all( - color: Color.fromRGBO(59, 169, 62, 1), - width: 2, - ), // Background color of the container - borderRadius: BorderRadius.circular(99), // Optional: rounded corners + if (qrResult.isNotEmpty) + Padding( + padding: const EdgeInsets.only(left: 16, right: 16), + child: Column( + children: [ + Row( + children: [ + Container( + padding: EdgeInsets.all(0), + width: 90, + height: 90, + decoration: BoxDecoration( + color: const Color.fromRGBO(69, 191, 73, 0.1), + border: Border.all(color: Color.fromRGBO(69, 191, 73, 1), width: 2), + borderRadius: BorderRadius.circular(99), // Optional: rounded corners + ), + child: Icon(Icons.thumb_up, color: const Color.fromRGBO(69, 191, 73, 1), size: 48), + ), + const Gap(32), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const TextWidget( + text: 'Verified', + bold: true, + size: 22, + color: Color.fromRGBO(69, 191, 73, 1), + ), + const Gap(16), + const TextWidget( + text: 'QR is a valid OCBO e-Sign', + bold: false, + size: 16, + color: Color.fromRGBO(69, 191, 73, 1), + ), + ], + ), + ], + ), + const Gap(32), + BoxWidget( + title: '', + content: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextWidget(text: 'Name', bold: true, size: 14), + const Gap(8), + TextWidget(text: dotenv.env['HEAD']!, bold: false, size: 14), + const Gap(16), + TextWidget(text: 'Role:', bold: true, size: 14), + const Gap(8), + TextWidget(text: 'APPROVER', bold: false, size: 14), + ], + ), + ), + ], + ), ), - child: Icon(Icons.thumb_up, color: const Color.fromRGBO(59, 169, 62, 1), size: 80), - ), - const Gap(16), - const TextWidget(text: 'Verified', size: 20, bold: true, color: Color.fromRGBO(59, 169, 62, 1)), - const Gap(16), - TextWidget(text: qrResult, size: 20, bold: true), ], ), ), diff --git a/lib/widgets/box_widget.dart b/lib/widgets/box_widget.dart index d992392..498b5a6 100644 --- a/lib/widgets/box_widget.dart +++ b/lib/widgets/box_widget.dart @@ -15,18 +15,23 @@ class BoxWidget extends StatelessWidget { decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), color: Color.fromRGBO(16, 22, 28, 0.584), - border: Border.all(color: const Color.fromRGBO(32, 47, 61, 1)), + border: Border.all(color: const Color.fromRGBO(41, 60, 78, 0.914)), ), width: MediaQuery.of(context).size.width - 30, // height: MediaQuery.of(context).size.height / 2.2, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [TextWidget(text: title, bold: true, size: 24)], - ), - const Gap(16), + if (title.isNotEmpty) + Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [TextWidget(text: title, bold: true, size: 24)], + ), + const Gap(16), + ], + ), Padding(padding: const EdgeInsets.all(16), child: content), ], ), diff --git a/lib/widgets/menu_widget.dart b/lib/widgets/menu_widget.dart index b342438..275661a 100644 --- a/lib/widgets/menu_widget.dart +++ b/lib/widgets/menu_widget.dart @@ -16,9 +16,9 @@ class MenuWidget extends StatelessWidget { child: Container( padding: EdgeInsets.all(16), decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), + borderRadius: BorderRadius.circular(24), color: Color.fromARGB(149, 16, 22, 28), - border: Border.all(color: const Color.fromRGBO(32, 47, 61, 1)), + border: Border.all(color: const Color.fromRGBO(41, 60, 78, 0.914)), ), width: 120, height: 120, diff --git a/pubspec.lock b/pubspec.lock index b0f3ddb..41159df 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,14 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + archive: + dependency: transitive + description: + name: archive + sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" + url: "https://pub.dev" + source: hosted + version: "4.0.7" args: dependency: transitive description: @@ -41,6 +49,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" + url: "https://pub.dev" + source: hosted + version: "2.0.4" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c + url: "https://pub.dev" + source: hosted + version: "0.4.2" clock: dependency: transitive description: @@ -89,6 +113,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.11" + device_info_plus: + dependency: transitive + description: + name: device_info_plus + sha256: "4df8babf73058181227e18b08e6ea3520cf5fc5d796888d33b7cb0f33f984b7c" + url: "https://pub.dev" + source: hosted + version: "12.3.0" + device_info_plus_platform_interface: + dependency: transitive + description: + name: device_info_plus_platform_interface + sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f + url: "https://pub.dev" + source: hosted + version: "7.0.3" dio: dependency: "direct main" description: @@ -137,6 +177,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" flutter: dependency: "direct main" description: flutter @@ -158,6 +206,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.0.0" + flutter_launcher_icons: + dependency: "direct dev" + description: + name: flutter_launcher_icons + sha256: "10f13781741a2e3972126fae08393d3c4e01fa4cd7473326b94b72cf594195e7" + url: "https://pub.dev" + source: hosted + version: "0.14.4" flutter_lints: dependency: "direct dev" description: @@ -232,6 +288,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.2" + image: + dependency: transitive + description: + name: image + sha256: "51555e36056541237b15b57afc31a0f53d4f9aefd9bd00873a6dc0090e54e332" + url: "https://pub.dev" + source: hosted + version: "4.6.0" internet_connection_checker: dependency: "direct main" description: @@ -240,6 +304,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" leak_tracker: dependency: transitive description: @@ -416,6 +488,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + posix: + dependency: transitive + description: + name: posix + sha256: "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61" + url: "https://pub.dev" + source: hosted + version: "6.0.3" provider: dependency: transitive description: @@ -493,6 +573,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.0" + vibration: + dependency: "direct main" + description: + name: vibration + sha256: "1fd51cb0f91c6d512734ca0e282dd87fbc7f389b6da5f03c77709ba2cf8fa901" + url: "https://pub.dev" + source: hosted + version: "3.1.4" + vibration_platform_interface: + dependency: transitive + description: + name: vibration_platform_interface + sha256: "4134fbfcd427b59a7a91f8733292e4e9b29a7f1e8224ff0d80f5745fbf0743c6" + url: "https://pub.dev" + source: hosted + version: "0.1.1" vm_service: dependency: transitive description: @@ -509,6 +605,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + win32: + dependency: transitive + description: + name: win32 + sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e + url: "https://pub.dev" + source: hosted + version: "5.15.0" + win32_registry: + dependency: transitive + description: + name: win32_registry + sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae" + url: "https://pub.dev" + source: hosted + version: "2.1.0" xdg_directories: dependency: transitive description: @@ -525,6 +637,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.6.1" + yaml: + dependency: transitive + description: + name: yaml + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + url: "https://pub.dev" + source: hosted + version: "3.1.3" sdks: dart: ">=3.9.2 <4.0.0" flutter: ">=3.35.0" diff --git a/pubspec.yaml b/pubspec.yaml index 958ee4a..33252f6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -21,12 +21,21 @@ dependencies: dio_smart_retry: ^7.0.1 hashlib: ^2.2.0 flutter_bloc: ^9.1.1 + vibration: ^3.1.4 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^6.0.0 + flutter_launcher_icons: ^0.14.3 + +flutter_icons: + android: true + ios: true + image_path: "assets/icon/icon.png" + remove_alpha_ios: true + min_sdk_android: 21 flutter: uses-material-design: true