Feat: add features print ticket boarding pass
This commit is contained in:
parent
0a38f3f788
commit
c0d27d6fdf
|
@ -7,6 +7,12 @@
|
|||
"packageUri": "lib/",
|
||||
"languageVersion": "3.2"
|
||||
},
|
||||
{
|
||||
"name": "archive",
|
||||
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/archive-4.0.7",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.0"
|
||||
},
|
||||
{
|
||||
"name": "args",
|
||||
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/args-2.7.0",
|
||||
|
@ -31,6 +37,12 @@
|
|||
"packageUri": "lib/",
|
||||
"languageVersion": "2.12"
|
||||
},
|
||||
{
|
||||
"name": "bidi",
|
||||
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/bidi-2.0.13",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "2.12"
|
||||
},
|
||||
{
|
||||
"name": "boolean_selector",
|
||||
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/boolean_selector-2.1.1",
|
||||
|
@ -295,6 +307,12 @@
|
|||
"packageUri": "lib/",
|
||||
"languageVersion": "2.12"
|
||||
},
|
||||
{
|
||||
"name": "image",
|
||||
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/image-4.5.4",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.0"
|
||||
},
|
||||
{
|
||||
"name": "intl",
|
||||
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/intl-0.20.2",
|
||||
|
@ -397,6 +415,18 @@
|
|||
"packageUri": "lib/",
|
||||
"languageVersion": "3.2"
|
||||
},
|
||||
{
|
||||
"name": "pdf",
|
||||
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/pdf-3.11.3",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "2.19"
|
||||
},
|
||||
{
|
||||
"name": "pdf_widget_wrapper",
|
||||
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/pdf_widget_wrapper-1.0.4",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "2.18"
|
||||
},
|
||||
{
|
||||
"name": "permission_handler",
|
||||
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/permission_handler-11.4.0",
|
||||
|
@ -451,6 +481,18 @@
|
|||
"packageUri": "lib/",
|
||||
"languageVersion": "3.0"
|
||||
},
|
||||
{
|
||||
"name": "posix",
|
||||
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/posix-6.0.2",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.0"
|
||||
},
|
||||
{
|
||||
"name": "printing",
|
||||
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/printing-5.14.2",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "3.3"
|
||||
},
|
||||
{
|
||||
"name": "qr",
|
||||
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/qr-3.0.2",
|
||||
|
@ -638,7 +680,7 @@
|
|||
"languageVersion": "3.4"
|
||||
}
|
||||
],
|
||||
"generated": "2025-05-05T05:14:47.271498Z",
|
||||
"generated": "2025-05-07T08:39:04.087158Z",
|
||||
"generator": "pub",
|
||||
"generatorVersion": "3.5.0",
|
||||
"flutterRoot": "file:///D:/Flutter/flutter_sdk/flutter_3.24.0",
|
||||
|
|
|
@ -2,6 +2,10 @@ _flutterfire_internals
|
|||
3.2
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/_flutterfire_internals-1.3.54/
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/_flutterfire_internals-1.3.54/lib/
|
||||
archive
|
||||
3.0
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/archive-4.0.7/
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/archive-4.0.7/lib/
|
||||
args
|
||||
3.3
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/args-2.7.0/
|
||||
|
@ -18,6 +22,10 @@ barcode_widget
|
|||
2.12
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/barcode_widget-2.0.4/
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/barcode_widget-2.0.4/lib/
|
||||
bidi
|
||||
2.12
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/bidi-2.0.13/
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/bidi-2.0.13/lib/
|
||||
boolean_selector
|
||||
2.17
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/boolean_selector-2.1.1/
|
||||
|
@ -182,6 +190,10 @@ http_parser
|
|||
2.12
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/http_parser-4.0.2/
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/http_parser-4.0.2/lib/
|
||||
image
|
||||
3.0
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/image-4.5.4/
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/image-4.5.4/lib/
|
||||
intl
|
||||
3.3
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/intl-0.20.2/
|
||||
|
@ -250,6 +262,14 @@ path_provider_windows
|
|||
3.2
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/path_provider_windows-2.3.0/
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/path_provider_windows-2.3.0/lib/
|
||||
pdf
|
||||
2.19
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/pdf-3.11.3/
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/pdf-3.11.3/lib/
|
||||
pdf_widget_wrapper
|
||||
2.18
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/pdf_widget_wrapper-1.0.4/
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/pdf_widget_wrapper-1.0.4/lib/
|
||||
permission_handler
|
||||
3.5
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/permission_handler-11.4.0/
|
||||
|
@ -286,6 +306,14 @@ plugin_platform_interface
|
|||
3.0
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/plugin_platform_interface-2.1.8/
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/plugin_platform_interface-2.1.8/lib/
|
||||
posix
|
||||
3.0
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/posix-6.0.2/
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/posix-6.0.2/lib/
|
||||
printing
|
||||
3.3
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/printing-5.14.2/
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/printing-5.14.2/lib/
|
||||
qr
|
||||
3.4
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/qr-3.0.2/
|
||||
|
|
|
@ -73,11 +73,7 @@ class FlightModel {
|
|||
|
||||
factory FlightModel.fromDocument(DocumentSnapshot doc) {
|
||||
final data = doc.data() as Map<String, dynamic>;
|
||||
|
||||
// Ambil field seat (Map) dari Firestore
|
||||
final seatData = data['seat'] as Map<String, dynamic>? ?? {};
|
||||
|
||||
// Konversi setiap entry di seatData menjadi SeatInfo
|
||||
final seatMap = seatData.map<String, SeatInfo>((key, value) {
|
||||
return MapEntry(
|
||||
key,
|
||||
|
@ -85,8 +81,6 @@ class FlightModel {
|
|||
);
|
||||
});
|
||||
|
||||
// print("FlightModel.fromDocument - Doc ID: ${doc.id}, data: $data");
|
||||
|
||||
return FlightModel(
|
||||
id: doc.id,
|
||||
airLines: data['airlines'] ?? '',
|
||||
|
@ -103,7 +97,7 @@ class FlightModel {
|
|||
stop: data['stop'] ?? '',
|
||||
price: data['price'] ?? 0,
|
||||
airlineLogo: data['airlineLogo'] ?? '',
|
||||
seat: seatMap, // masukkan Map<String, SeatInfo>
|
||||
seat: seatMap,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -288,8 +288,9 @@ class _BoardingPassScreenState extends State<BoardingPassScreen> with SingleTick
|
|||
'id_transaction': transaction.id,
|
||||
'id_ticket': transaction.ticketId,
|
||||
};
|
||||
log('ID Transaction: ${transaction.id}');
|
||||
log('ID Ticket: ${transaction.ticketId}');
|
||||
log('Arrival Time: $arrivalTime');
|
||||
log('Departure Time: $departureTime');
|
||||
|
||||
Get.toNamed(Routes.DETAILTICKET, arguments: argument);
|
||||
},
|
||||
),
|
||||
|
|
|
@ -4,6 +4,7 @@ import 'package:e_porter/_core/component/button/button_outline.dart';
|
|||
import 'package:e_porter/_core/component/dotted/dashed_line_component.dart';
|
||||
import 'package:e_porter/_core/constants/colors.dart';
|
||||
import 'package:e_porter/_core/constants/typography.dart';
|
||||
import 'package:e_porter/_core/utils/formatter/date_helper.dart';
|
||||
import 'package:e_porter/presentation/controllers/history_controller.dart';
|
||||
import 'package:e_porter/presentation/screens/boarding_pass/component/card_details_passenger.dart';
|
||||
import 'package:e_porter/presentation/screens/routes/app_rountes.dart';
|
||||
|
@ -84,7 +85,14 @@ class _DetailTicketScreenState extends State<DetailTicketScreen> {
|
|||
return Center(child: TypographyStyles.body('Data transaksi tidak ditemukan', color: GrayColors.gray400));
|
||||
}
|
||||
|
||||
log('ID Booking Detail Tiket: ${transaction.idBooking}');
|
||||
final departureTime = DateFormatterHelper.formatFlightTime(transaction.flightDetails['departureTime']);
|
||||
final arrivalTime = DateFormatterHelper.formatFlightTime(transaction.flightDetails['arrivalTime']);
|
||||
final departureDate = DateFormatterHelper.formatFlightDate(transaction.flightDetails['departureTime']);
|
||||
final arrivalDate = DateFormatterHelper.formatFlightDate(transaction.flightDetails['arrivalTime']);
|
||||
final duration = DateFormatterHelper.calculateFlightDuration(
|
||||
transaction.flightDetails['departureTime'],
|
||||
transaction.flightDetails['arrivalTime'],
|
||||
);
|
||||
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 20.h),
|
||||
|
@ -110,7 +118,7 @@ class _DetailTicketScreenState extends State<DetailTicketScreen> {
|
|||
color: GrayColors.gray800,
|
||||
),
|
||||
SizedBox(width: 10.w),
|
||||
SvgPicture.asset('assets/images/citilink.svg', width: 40.w, height: 10.h),
|
||||
Image.network(transaction.flightDetails['airlineLogo'], width: 40.w),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 4.h),
|
||||
|
@ -131,15 +139,14 @@ class _DetailTicketScreenState extends State<DetailTicketScreen> {
|
|||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
TypographyStyles.caption("12:20", color: GrayColors.gray800),
|
||||
TypographyStyles.small("Sen, 27 Jan",
|
||||
TypographyStyles.caption(departureTime, color: GrayColors.gray800),
|
||||
TypographyStyles.small(departureDate,
|
||||
color: GrayColors.gray600, fontWeight: FontWeight.w400),
|
||||
SizedBox(height: 20.h),
|
||||
TypographyStyles.small("5j 40m", color: GrayColors.gray600, fontWeight: FontWeight.w400),
|
||||
TypographyStyles.small(duration, color: GrayColors.gray600, fontWeight: FontWeight.w400),
|
||||
SizedBox(height: 20.h),
|
||||
TypographyStyles.caption("12:20", color: GrayColors.gray800),
|
||||
TypographyStyles.small("Sen, 27 Jan",
|
||||
color: GrayColors.gray600, fontWeight: FontWeight.w400),
|
||||
TypographyStyles.caption(arrivalTime, color: GrayColors.gray800),
|
||||
TypographyStyles.small(arrivalDate, color: GrayColors.gray600, fontWeight: FontWeight.w400),
|
||||
],
|
||||
),
|
||||
SizedBox(width: 20.w),
|
||||
|
@ -237,11 +244,7 @@ class _DetailTicketScreenState extends State<DetailTicketScreen> {
|
|||
onTap: () {
|
||||
Get.toNamed(
|
||||
Routes.UPLOADFILE,
|
||||
arguments: {
|
||||
'ticketId': transaction.ticketId,
|
||||
'transactionId': transaction.id,
|
||||
'mode': 'history'
|
||||
},
|
||||
arguments: {'ticketId': transaction.ticketId, 'transactionId': transaction.id, 'mode': 'history'},
|
||||
);
|
||||
},
|
||||
),
|
||||
|
|
|
@ -1,18 +1,104 @@
|
|||
import 'dart:developer';
|
||||
import 'dart:ui' as ui;
|
||||
import 'package:e_porter/_core/utils/snackbar/snackbar_helper.dart';
|
||||
import 'package:pdf/pdf.dart';
|
||||
import 'package:pdf/widgets.dart' as pw;
|
||||
import 'package:barcode_widget/barcode_widget.dart';
|
||||
import 'package:e_porter/_core/component/card/custome_shadow_cotainner.dart';
|
||||
import 'package:e_porter/_core/component/dotted/dashed_line_component.dart';
|
||||
import 'package:e_porter/_core/constants/colors.dart';
|
||||
import 'package:e_porter/_core/constants/typography.dart';
|
||||
import 'package:e_porter/_core/utils/formatter/date_helper.dart';
|
||||
import 'package:e_porter/presentation/controllers/history_controller.dart';
|
||||
import 'package:e_porter/presentation/screens/home/component/card_tickets.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:printing/printing.dart';
|
||||
|
||||
import '../../../../_core/component/appbar/appbar_component.dart';
|
||||
|
||||
class PrintBoardingPassScreen extends StatelessWidget {
|
||||
class PrintBoardingPassScreen extends StatefulWidget {
|
||||
const PrintBoardingPassScreen({super.key});
|
||||
|
||||
@override
|
||||
State<PrintBoardingPassScreen> createState() => _PrintBoardingPassScreenState();
|
||||
}
|
||||
|
||||
class _PrintBoardingPassScreenState extends State<PrintBoardingPassScreen> {
|
||||
final GlobalKey _printKey = GlobalKey();
|
||||
final historyController = Get.find<HistoryController>();
|
||||
|
||||
late final String transactionTicketId;
|
||||
late final String ticketId;
|
||||
late final int passenger;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final args = Get.arguments as Map<String, dynamic>;
|
||||
transactionTicketId = args['transactionId'];
|
||||
ticketId = args['ticketId'];
|
||||
passenger = args['passengerIndex'];
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_loadTransactionData();
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _loadTransactionData() async {
|
||||
try {
|
||||
await historyController.getTransactionFromFirestore(ticketId, transactionTicketId);
|
||||
} catch (e) {
|
||||
log('[Print Boarding Pass] Error getTransaction $e');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _printPass() async {
|
||||
Get.dialog(
|
||||
const Center(child: CircularProgressIndicator()),
|
||||
barrierDismissible: false,
|
||||
);
|
||||
|
||||
final pw.Document doc = pw.Document();
|
||||
final pageFormat = PdfPageFormat.a6.copyWith(
|
||||
marginLeft: 0,
|
||||
marginTop: 0,
|
||||
marginRight: 0,
|
||||
marginBottom: 0,
|
||||
);
|
||||
|
||||
try {
|
||||
final ctx = _printKey.currentContext;
|
||||
if (ctx == null) throw 'Boarding pass belum siap';
|
||||
|
||||
final boundary = ctx.findRenderObject() as RenderRepaintBoundary;
|
||||
final ui.Image image = await boundary.toImage(pixelRatio: 3.0);
|
||||
final byteData = await image.toByteData(format: ui.ImageByteFormat.png);
|
||||
final pngBytes = byteData!.buffer.asUint8List();
|
||||
|
||||
final pw.MemoryImage pwImage = pw.MemoryImage(pngBytes);
|
||||
doc.addPage(
|
||||
pw.Page(
|
||||
pageFormat: pageFormat,
|
||||
build: (c) => pw.Center(child: pw.Image(pwImage)),
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
if (Get.isDialogOpen ?? false) Get.back();
|
||||
SnackbarHelper.showError('Error', e.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (Get.isDialogOpen ?? false) Get.back();
|
||||
|
||||
await Printing.layoutPdf(
|
||||
onLayout: (PdfPageFormat format) async => doc.save(),
|
||||
format: pageFormat,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
|
@ -26,68 +112,117 @@ class PrintBoardingPassScreen extends StatelessWidget {
|
|||
},
|
||||
),
|
||||
body: SafeArea(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 20.h),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
CustomeShadowCotainner(
|
||||
child: RepaintBoundary(
|
||||
key: _printKey,
|
||||
child: Obx(
|
||||
() {
|
||||
if (historyController.isLoading.value) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
if (historyController.errorMessage.value.isNotEmpty) {
|
||||
return Center(
|
||||
child: TypographyStyles.body(
|
||||
historyController.errorMessage.value,
|
||||
color: GrayColors.gray400,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final transaction = historyController.selectedTransaction.value;
|
||||
if (transaction == null) {
|
||||
return Center(
|
||||
child: TypographyStyles.body(
|
||||
'Data transaksi tidak ditemukan',
|
||||
color: GrayColors.gray400,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final departureTime = DateFormatterHelper.formatFlightTime(transaction.flightDetails['departureTime']);
|
||||
final arrivalTime = DateFormatterHelper.formatFlightTime(transaction.flightDetails['arrivalTime']);
|
||||
final ticketDate = DateFormatterHelper.formatFlightDate(transaction.flightDetails['departureTime']);
|
||||
final duration = DateFormatterHelper.calculateFlightDuration(
|
||||
transaction.flightDetails['departureTime'],
|
||||
transaction.flightDetails['arrivalTime'],
|
||||
);
|
||||
|
||||
final seatNumber = transaction.numberSeat.length > passenger ? transaction.numberSeat[passenger] : '-';
|
||||
final passengerMap = (transaction.passengerDetails as List<dynamic>)[passenger] as Map<String, dynamic>;
|
||||
final idBarcode = passengerMap['idBarcode'] ?? '';
|
||||
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 20.h),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
TypographyStyles.caption(
|
||||
'Kode Booking Maskapai',
|
||||
color: GrayColors.gray500,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
TypographyStyles.h6('text', color: GrayColors.gray800),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 10),
|
||||
child: Divider(thickness: 1, color: GrayColors.gray200),
|
||||
),
|
||||
CardTickets(
|
||||
withContainer: false,
|
||||
showFooter: false,
|
||||
departureCity: 'departureCity',
|
||||
date: 'date',
|
||||
arrivalCity: 'arrivalCity',
|
||||
departureCode: 'YIA',
|
||||
arrivalCode: 'LOP',
|
||||
departureTime: 'departureTime',
|
||||
arrivalTime: 'arrivalTime',
|
||||
duration: 'duration',
|
||||
seatClass: 'seatClass',
|
||||
price: 'price',
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 10),
|
||||
child: Divider(thickness: 1, color: GrayColors.gray200),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
_buildColumnText(context, label: 'Layanan', value: 'value'),
|
||||
_buildColumnText(context, label: 'Class', value: 'value'),
|
||||
_buildColumnText(context, label: 'Gate', value: 'value'),
|
||||
_buildColumnText(context, label: 'Seat', value: 'value'),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 20.h),
|
||||
child: CustomDashedLine(),
|
||||
),
|
||||
_buildBarcode(context, barcodeData: 'PK230222BE143')
|
||||
CustomeShadowCotainner(
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
TypographyStyles.caption(
|
||||
'Kode Booking Maskapai',
|
||||
color: GrayColors.gray500,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
TypographyStyles.h6(transaction.idBooking, color: GrayColors.gray800),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 10),
|
||||
child: Divider(thickness: 1, color: GrayColors.gray200),
|
||||
),
|
||||
CardTickets(
|
||||
withContainer: false,
|
||||
showFooter: false,
|
||||
airlineLogo: transaction.flightDetails['airlineLogo'],
|
||||
departureCity: transaction.flightDetails['cityDeparture'],
|
||||
arrivalCity: transaction.flightDetails['cityArrival'],
|
||||
date: ticketDate,
|
||||
departureCode: transaction.flightDetails['codeDeparture'],
|
||||
arrivalCode: transaction.flightDetails['codeArrival'],
|
||||
departureTime: departureTime,
|
||||
arrivalTime: arrivalTime,
|
||||
duration: duration,
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 10),
|
||||
child: Divider(thickness: 1, color: GrayColors.gray200),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
_buildColumnText(context, label: 'Layanan', value: 'value'),
|
||||
_buildColumnText(context,
|
||||
label: 'Class', value: transaction.flightDetails['flightClass']),
|
||||
_buildColumnText(context, label: 'Gate', value: 'value'),
|
||||
_buildColumnText(context, label: 'Seat', value: seatNumber),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 20.h),
|
||||
child: CustomDashedLine(),
|
||||
),
|
||||
_buildBarcode(context, barcodeData: idBarcode)
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
)),
|
||||
floatingActionButton: FloatingActionButton.extended(
|
||||
icon: Icon(Icons.print_outlined, color: Colors.white, size: 24),
|
||||
label: TypographyStyles.caption('Cetak', color: Colors.white),
|
||||
onPressed: _printPass,
|
||||
backgroundColor: PrimaryColors.primary800,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
import 'package:e_porter/presentation/controllers/history_controller.dart';
|
||||
import 'package:e_porter/presentation/screens/boarding_pass/pages/print_boarding_pass_screen.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:mobile_scanner/mobile_scanner.dart';
|
||||
|
||||
class ScanBarcodeScreen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text('Scan Boarding Pass')),
|
||||
body: MobileScanner(
|
||||
// Versi baru onDetect hanya terima satu arg
|
||||
onDetect: (capture) {
|
||||
for (final bar in capture.barcodes) {
|
||||
final raw = bar.rawValue;
|
||||
if (raw != null && raw.startsWith('P-')) {
|
||||
// hentikan scanner
|
||||
MobileScannerController().stop();
|
||||
// ambil tx dari HistoryController
|
||||
final history = Get.find<HistoryController>();
|
||||
final tx = history.selectedTransaction.value;
|
||||
if (tx != null) {
|
||||
final idx = (tx.passengerDetails as List).indexWhere((p) => p['idBarcode'] == raw);
|
||||
if (idx >= 0) {
|
||||
// navigasi ke print screen
|
||||
Get.to(
|
||||
() => PrintBoardingPassScreen(),
|
||||
arguments: {
|
||||
'transactionId': tx.id,
|
||||
'ticketId': tx.ticketId,
|
||||
'passengerIndex': idx,
|
||||
},
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Get.snackbar('Error', 'Penumpang tidak ditemukan');
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -18,8 +18,8 @@ class CardTickets extends StatelessWidget {
|
|||
final String departureTime;
|
||||
final String arrivalTime;
|
||||
final String duration;
|
||||
final String seatClass;
|
||||
final String price;
|
||||
final String? seatClass;
|
||||
final String? price;
|
||||
final VoidCallback? onTap;
|
||||
final bool withContainer;
|
||||
final bool showFooter;
|
||||
|
@ -35,8 +35,8 @@ class CardTickets extends StatelessWidget {
|
|||
required this.departureTime,
|
||||
required this.arrivalTime,
|
||||
required this.duration,
|
||||
required this.seatClass,
|
||||
required this.price,
|
||||
this.seatClass,
|
||||
this.price,
|
||||
this.onTap,
|
||||
this.withContainer = true,
|
||||
this.showFooter = true,
|
||||
|
@ -115,12 +115,12 @@ class CardTickets extends StatelessWidget {
|
|||
children: [
|
||||
CustomeIcons.FlightSeatFilled(),
|
||||
SizedBox(width: 6.w),
|
||||
TypographyStyles.caption(seatClass, color: GrayColors.gray800),
|
||||
TypographyStyles.caption('$seatClass', color: GrayColors.gray800),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
TypographyStyles.body(price, color: PrimaryColors.primary800),
|
||||
TypographyStyles.body('$price', color: PrimaryColors.primary800),
|
||||
SizedBox(width: 2.w),
|
||||
TypographyStyles.small('/orang', color: GrayColors.gray600, fontWeight: FontWeight.w400),
|
||||
],
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <printing/printing_plugin.h>
|
||||
|
||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) printing_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "PrintingPlugin");
|
||||
printing_plugin_register_with_registrar(printing_registrar);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
printing
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|
|
|
@ -14,6 +14,7 @@ import firebase_database
|
|||
import firebase_storage
|
||||
import mobile_scanner
|
||||
import path_provider_foundation
|
||||
import printing
|
||||
import shared_preferences_foundation
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
|
@ -26,5 +27,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
|||
FLTFirebaseStoragePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseStoragePlugin"))
|
||||
MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
PrintingPlugin.register(with: registry.registrar(forPlugin: "PrintingPlugin"))
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
}
|
||||
|
|
56
pubspec.lock
56
pubspec.lock
|
@ -9,6 +9,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.54"
|
||||
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,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.4"
|
||||
bidi:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: bidi
|
||||
sha256: "77f475165e94b261745cf1032c751e2032b8ed92ccb2bf5716036db79320637d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.13"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -384,6 +400,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.2"
|
||||
image:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image
|
||||
sha256: "4e973fcf4caae1a4be2fa0a13157aa38a8f9cb049db6529aa00b4d71abc4d928"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.5.4"
|
||||
intl:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -520,6 +544,22 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
pdf:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: pdf
|
||||
sha256: "28eacad99bffcce2e05bba24e50153890ad0255294f4dd78a17075a2ba5c8416"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.11.3"
|
||||
pdf_widget_wrapper:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pdf_widget_wrapper
|
||||
sha256: c930860d987213a3d58c7ec3b7ecf8085c3897f773e8dc23da9cae60a5d6d0f5
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
permission_handler:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -592,6 +632,22 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.8"
|
||||
posix:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: posix
|
||||
sha256: f0d7856b6ca1887cfa6d1d394056a296ae33489db914e365e2044fdada449e62
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.2"
|
||||
printing:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: printing
|
||||
sha256: "482cd5a5196008f984bb43ed0e47cbfdca7373490b62f3b27b3299275bf22a93"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.14.2"
|
||||
qr:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -60,6 +60,8 @@ dependencies:
|
|||
permission_handler: ^11.4.0
|
||||
device_info_plus: ^11.3.0
|
||||
mobile_scanner: ^6.0.10
|
||||
pdf: ^3.11.3
|
||||
printing: ^5.14.2
|
||||
# workmanager: ^0.5.2
|
||||
|
||||
# pin_code_fields: ^8.0.1
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <firebase_core/firebase_core_plugin_c_api.h>
|
||||
#include <firebase_storage/firebase_storage_plugin_c_api.h>
|
||||
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
||||
#include <printing/printing_plugin.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
CloudFirestorePluginCApiRegisterWithRegistrar(
|
||||
|
@ -23,4 +24,6 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
|||
registry->GetRegistrarForPlugin("FirebaseStoragePluginCApi"));
|
||||
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
|
||||
PrintingPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("PrintingPlugin"));
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
|||
firebase_core
|
||||
firebase_storage
|
||||
permission_handler_windows
|
||||
printing
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|
|
Loading…
Reference in New Issue