From be352aa2636dec115e34010bf1ce34c14f5f904a Mon Sep 17 00:00:00 2001 From: Patrick Alvin Alcala Date: Mon, 26 Jan 2026 19:02:10 +0800 Subject: [PATCH 1/4] Updated pages --- lib/pages/index_page.dart | 4 ++-- lib/pages/login_page.dart | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/pages/index_page.dart b/lib/pages/index_page.dart index 7a84d23..a3e9845 100644 --- a/lib/pages/index_page.dart +++ b/lib/pages/index_page.dart @@ -44,8 +44,8 @@ class IndexPage extends StatelessWidget { child: Column( children: [ const Gap(88), - const ImageWidget(imagePath: 'assets/logo.webp', size: 140, measureByHeight: false), - const Gap(24), + const ImageWidget(imagePath: 'assets/logo.webp', size: 160, measureByHeight: false), + const Gap(20), const TextWidget( text: "OCBO e-Sign", color: Color.fromARGB(255, 244, 243, 243), diff --git a/lib/pages/login_page.dart b/lib/pages/login_page.dart index dfa7526..0f58031 100644 --- a/lib/pages/login_page.dart +++ b/lib/pages/login_page.dart @@ -10,6 +10,7 @@ import 'package:ocbo_esign_mobile/widgets/box_widget.dart'; import 'package:ocbo_esign_mobile/widgets/button_widget.dart'; import 'package:ocbo_esign_mobile/widgets/image_widget.dart'; import 'package:ocbo_esign_mobile/widgets/input_widget.dart'; +import 'package:ocbo_esign_mobile/widgets/login_box_widget.dart'; import 'package:ocbo_esign_mobile/widgets/text_widget.dart'; class LoginPage extends StatefulWidget { @@ -121,7 +122,7 @@ class _LoginPageState extends State { const Gap(88), const ImageWidget(imagePath: 'assets/logo.webp', size: 100, measureByHeight: true), const Gap(58), - BoxWidget( + LoginBoxWidget( title: 'Login', content: Column( crossAxisAlignment: CrossAxisAlignment.start, From c5e0b439ad4c3fb84f32f20b8d4257761718586e Mon Sep 17 00:00:00 2001 From: Patrick Alvin Alcala Date: Mon, 26 Jan 2026 19:02:18 +0800 Subject: [PATCH 2/4] Updated validation --- lib/pages/validate_detail_page.dart | 78 ++++++++++++++++++++++++++++- lib/pages/validate_page.dart | 74 ++++++++++++++++----------- 2 files changed, 121 insertions(+), 31 deletions(-) diff --git a/lib/pages/validate_detail_page.dart b/lib/pages/validate_detail_page.dart index 2fddca8..feffb12 100644 --- a/lib/pages/validate_detail_page.dart +++ b/lib/pages/validate_detail_page.dart @@ -1,8 +1,43 @@ -import 'package:flutter/material.dart'; +import 'dart:developer'; -class ValidateDetailPage extends StatelessWidget { +import 'package:flutter/material.dart'; +import 'package:gap/gap.dart'; +import 'package:ocbo_esign_mobile/blocs/qr/functions/bloc_getqr.dart'; +import 'package:ocbo_esign_mobile/functions/get_api.dart'; +import 'package:ocbo_esign_mobile/widgets/box_widget.dart'; +import 'package:ocbo_esign_mobile/widgets/input_widget.dart'; +import 'package:ocbo_esign_mobile/widgets/text_widget.dart'; + +class ValidateDetailPage extends StatefulWidget { const ValidateDetailPage({super.key}); + @override + State createState() => _ValidateDetailPageState(); +} + +class _ValidateDetailPageState extends State { + final _searchController = TextEditingController(); + late double _total = 0; + + void _getTotalSigned() async { + final name = await blocGetQr(context); + final response = await getApi('get-transactions-count', name, null); + log(name.toString()); + log(response.toString()); + final total = response['result']; + + setState(() { + _total = double.parse(total); + }); + } + + @override + void initState() { + _getTotalSigned(); + + super.initState(); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -23,6 +58,45 @@ class ValidateDetailPage extends StatelessWidget { ], ), ), + child: SizedBox( + width: MediaQuery.of(context).size.width - 90, + child: Column( + children: [ + const Gap(88), + InputWidget(controller: _searchController, password: false, placeholder: 'Specify Application Number'), + const Gap(24), + BoxWidget( + circular: 16, + content: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Column( + children: [ + TextWidget(text: _total.toString(), size: 64, bold: true), + TextWidget(text: 'Total Signed Applications', size: 16), + ], + ), + ], + ), + ), + const Gap(16), + const BoxWidget( + circular: 16, + content: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Column( + children: [ + TextWidget(text: '23-000123', size: 24, bold: true), + TextWidget(text: 'Total Signed Applications', size: 20), + ], + ), + ], + ), + ), + ], + ), + ), ), ); } diff --git a/lib/pages/validate_page.dart b/lib/pages/validate_page.dart index 04942b6..d0ac073 100644 --- a/lib/pages/validate_page.dart +++ b/lib/pages/validate_page.dart @@ -1,7 +1,10 @@ +import 'dart:developer'; + import 'package:flutter/material.dart'; import 'package:gap/gap.dart'; import 'package:go_router/go_router.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; +import 'package:ocbo_esign_mobile/blocs/qr/functions/bloc_setqr.dart'; import 'package:ocbo_esign_mobile/functions/get_api.dart'; import 'package:ocbo_esign_mobile/widgets/button_widget.dart'; import 'package:ocbo_esign_mobile/widgets/text_widget.dart'; @@ -59,37 +62,50 @@ class _BarcodeScannerScreenState extends State { } } - // void tryQR() async { - // final value = "Use OCBO e-Sign Validator - scanid=0918d59e"; + void tryQR() async { + final value = "Use OCBO e-Sign Validator - scanid=0918d59e"; - // if (value.contains('OCBO e-Sign')) { - // final qr = value.substring(35); - // final response = await getApi('check-qr', qr, null); - // final result = response["result"].toString(); + if (value.contains('OCBO e-Sign')) { + final qr = value.substring(35); + final response = await getApi('check-qr', qr, null); + final result = response["result"]?.toString(); + log('result: $result'); - // if (result != '') { - // setState(() { - // qrResult = result; - // }); - // } else { - // setState(() { - // qrResult = 'result'; - // }); - // } - // } else { - // setState(() { - // qrResult = 'invalid'; - // }); + if (result != null) { + setState(() { + qrResult = result; + }); + } else { + setState(() { + qrResult = 'non-exist'; + }); - // Future.delayed(Duration(seconds: 3), () { - // setState(() { - // qrResult = ''; - // }); - // }); - // } - // } + Future.delayed(Duration(seconds: 3), () { + setState(() { + qrResult = ''; + }); + }); + } + } else { + setState(() { + qrResult = 'invalid'; + }); - void gotoDetails() { + Future.delayed(Duration(seconds: 3), () { + setState(() { + qrResult = ''; + }); + }); + } + } + + void updateBlockQr() async { + await blocSetQr(context, qrResult); + } + + void gotoDetails() async { + log('qr $qrResult'); + updateBlockQr(); context.push('/details'); } @@ -164,7 +180,7 @@ class _BarcodeScannerScreenState extends State { ), ), const Gap(24), - // ButtonWidget(text: 'Try API', disabled: false, onPressed: tryQR), + ButtonWidget(text: 'Try API', disabled: false, onPressed: tryQR), if (qrResult.isNotEmpty) Column( children: [ @@ -201,7 +217,7 @@ class _BarcodeScannerScreenState extends State { TextWidget(text: 'Not valid OCBO e-Sign QR', bold: true, size: 20, color: redColor), ], ) - else if (qrResult != 'non-exist') + else if (qrResult == 'non-exist') Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ From bb4cbcabe7eb74790d9bfee000218d666d93146f Mon Sep 17 00:00:00 2001 From: Patrick Alvin Alcala Date: Mon, 26 Jan 2026 19:02:29 +0800 Subject: [PATCH 3/4] Fixed widgets --- lib/widgets/box_widget.dart | 22 ++++------------- lib/widgets/login_box_widget.dart | 40 +++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 17 deletions(-) create mode 100644 lib/widgets/login_box_widget.dart diff --git a/lib/widgets/box_widget.dart b/lib/widgets/box_widget.dart index 94037a6..fa9eb85 100644 --- a/lib/widgets/box_widget.dart +++ b/lib/widgets/box_widget.dart @@ -3,37 +3,25 @@ import 'package:gap/gap.dart'; import 'package:ocbo_esign_mobile/widgets/text_widget.dart'; class BoxWidget extends StatelessWidget { - final String title; final Widget content; + final double? circular; + // final double? titleSize; - const BoxWidget({super.key, required this.title, required this.content}); + const BoxWidget({super.key, required this.content, this.circular = 8}); @override Widget build(BuildContext context) { return Container( padding: EdgeInsets.all(16), decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), + borderRadius: BorderRadius.circular(circular ?? 8), color: Color.fromRGBO(16, 22, 28, 0.584), 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: [ - 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), - ], + children: [Padding(padding: const EdgeInsets.all(16), child: content)], ), ); } diff --git a/lib/widgets/login_box_widget.dart b/lib/widgets/login_box_widget.dart new file mode 100644 index 0000000..a307bdc --- /dev/null +++ b/lib/widgets/login_box_widget.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:gap/gap.dart'; +import 'package:ocbo_esign_mobile/widgets/text_widget.dart'; + +class LoginBoxWidget extends StatelessWidget { + final String title; + final Widget content; + + const LoginBoxWidget({super.key, required this.title, required this.content}); + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.all(16), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Color.fromRGBO(16, 22, 28, 0.584), + 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: [ + 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), + ], + ), + ); + } +} From 89fdcce6139a1f5bb2c9c67196cb59df5f24ec9e Mon Sep 17 00:00:00 2001 From: Patrick Alvin Alcala Date: Mon, 26 Jan 2026 19:02:41 +0800 Subject: [PATCH 4/4] Added qr bloc --- lib/blocs/qr/functions/bloc_getqr.dart | 14 ++++++++++++++ lib/blocs/qr/functions/bloc_setqr.dart | 14 ++++++++++++++ lib/blocs/qr/qr_bloc.dart | 14 ++++++++++++++ lib/blocs/qr/qr_event.dart | 8 ++++++++ lib/blocs/qr/qr_state.dart | 5 +++++ lib/functions/get_api.dart | 1 + 6 files changed, 56 insertions(+) create mode 100644 lib/blocs/qr/functions/bloc_getqr.dart create mode 100644 lib/blocs/qr/functions/bloc_setqr.dart create mode 100644 lib/blocs/qr/qr_bloc.dart create mode 100644 lib/blocs/qr/qr_event.dart create mode 100644 lib/blocs/qr/qr_state.dart diff --git a/lib/blocs/qr/functions/bloc_getqr.dart b/lib/blocs/qr/functions/bloc_getqr.dart new file mode 100644 index 0000000..e70a36c --- /dev/null +++ b/lib/blocs/qr/functions/bloc_getqr.dart @@ -0,0 +1,14 @@ +import 'package:flutter/widgets.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:ocbo_esign_mobile/blocs/qr/qr_bloc.dart'; +import 'package:ocbo_esign_mobile/blocs/qr/qr_event.dart'; + +Future blocGetQr(BuildContext context) async { + try { + final qrBloc = context.read(); + qrBloc.add(QrGetValue()); + return qrBloc.state.value; + } catch (e) { + return ''; + } +} diff --git a/lib/blocs/qr/functions/bloc_setqr.dart b/lib/blocs/qr/functions/bloc_setqr.dart new file mode 100644 index 0000000..b7baf11 --- /dev/null +++ b/lib/blocs/qr/functions/bloc_setqr.dart @@ -0,0 +1,14 @@ +import 'package:flutter/widgets.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:ocbo_esign_mobile/blocs/qr/qr_bloc.dart'; +import 'package:ocbo_esign_mobile/blocs/qr/qr_event.dart'; + +Future blocSetQr(BuildContext context, String value) async { + try { + final qrBloc = context.read(); + qrBloc.add(QrSetValue(value)); + return true; + } catch (e) { + return false; + } +} diff --git a/lib/blocs/qr/qr_bloc.dart b/lib/blocs/qr/qr_bloc.dart new file mode 100644 index 0000000..a336e98 --- /dev/null +++ b/lib/blocs/qr/qr_bloc.dart @@ -0,0 +1,14 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:ocbo_esign_mobile/blocs/qr/qr_event.dart'; +import 'package:ocbo_esign_mobile/blocs/qr/qr_state.dart'; + +class QrBloc extends Bloc { + QrBloc() : super(QrState('')) { + on((event, emit) { + emit(QrState(event.value)); + }); + on((event, emit) { + emit(state); + }); + } +} diff --git a/lib/blocs/qr/qr_event.dart b/lib/blocs/qr/qr_event.dart new file mode 100644 index 0000000..4277819 --- /dev/null +++ b/lib/blocs/qr/qr_event.dart @@ -0,0 +1,8 @@ +abstract class QrEvent {} + +class QrSetValue extends QrEvent { + final String value; + QrSetValue(this.value); +} + +class QrGetValue extends QrEvent {} diff --git a/lib/blocs/qr/qr_state.dart b/lib/blocs/qr/qr_state.dart new file mode 100644 index 0000000..05016e6 --- /dev/null +++ b/lib/blocs/qr/qr_state.dart @@ -0,0 +1,5 @@ +class QrState { + final String value; + + QrState(this.value); +} diff --git a/lib/functions/get_api.dart b/lib/functions/get_api.dart index 139d47e..025b349 100644 --- a/lib/functions/get_api.dart +++ b/lib/functions/get_api.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:developer'; import 'package:dio/dio.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:dio_smart_retry/dio_smart_retry.dart';