Feat: fix boarding pass after scan QR

This commit is contained in:
orangdeso 2025-05-19 10:38:59 +07:00
parent 00083b6e75
commit 2e38c7da39
10 changed files with 297 additions and 238 deletions

View File

@ -680,7 +680,7 @@
"languageVersion": "3.4"
}
],
"generated": "2025-05-16T07:28:56.076101Z",
"generated": "2025-05-18T15:09:53.002617Z",
"generator": "pub",
"generatorVersion": "3.5.0",
"flutterRoot": "file:///D:/Flutter/flutter_sdk/flutter_3.24.0",

View File

@ -132,7 +132,6 @@ class HistoryRepositoryImpl implements HistoryRepository {
data['id'] = transactionId;
data['ticketId'] = ticketId;
// Konversi ke model TransactionModel
final transaction = TransactionModel.fromJson(data);
log('HistoryRepositoryImpl: berhasil mengambil transaksi dari Firestore');
return transaction;
@ -141,4 +140,53 @@ class HistoryRepositoryImpl implements HistoryRepository {
return null;
}
}
@override
Future<bool> checkIfTicketHasPorter(String ticketId, String transactionId) async {
try {
log('HistoryRepositoryImpl: checking if ticket has porter, ticketId: $ticketId, transactionId: $transactionId');
final querySnapshot = await _firestore
.collection('porterTransactions')
.where('ticketId', isEqualTo: ticketId)
.where('transactionId', isEqualTo: transactionId)
.limit(1)
.get();
final hasPorter = querySnapshot.docs.isNotEmpty;
log('HistoryRepositoryImpl: ticket has porter: $hasPorter');
return hasPorter;
} catch (e) {
log('HistoryRepositoryImpl: error checking if ticket has porter: $e');
return false;
}
}
@override
Future<String?> getPorterTransactionId(String ticketId, String transactionId) async {
try {
log('HistoryRepositoryImpl: getting porter transaction ID, ticketId: $ticketId, transactionId: $transactionId');
final querySnapshot = await _firestore
.collection('porterTransactions')
.where('ticketId', isEqualTo: ticketId)
.where('transactionId', isEqualTo: transactionId)
.limit(1)
.get();
if (querySnapshot.docs.isEmpty) {
log('HistoryRepositoryImpl: no porter transaction found');
return null;
}
final porterTransactionId = querySnapshot.docs.first.id;
log('HistoryRepositoryImpl: found porter transaction ID: $porterTransactionId');
return porterTransactionId;
} catch (e) {
log('HistoryRepositoryImpl: error getting porter transaction ID: $e');
return null;
}
}
}

View File

@ -1,4 +1,4 @@
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:e_porter/domain/repositories/statistic_repository.dart';
class StatisticRepositoryImpl implements StatisticRepository {

View File

@ -4,4 +4,6 @@ abstract class HistoryRepository {
Stream<List<TransactionModel>> getTransactionsStream(String userId, String status);
Stream<List<TransactionModel>> getHistoryTransactionsStream(String userId);
Future<TransactionModel?> getTransactionFromFirestore(String ticketId, String transactionId);
Future<bool> checkIfTicketHasPorter(String ticketId, String transactionId);
Future<String?> getPorterTransactionId(String ticketId, String transactionId);
}

View File

@ -22,4 +22,12 @@ class HistoryUseCase {
Future<TransactionModel?> getTransactionFromFirestore(String ticketId, String transactionId) {
return _repository.getTransactionFromFirestore(ticketId, transactionId);
}
Future<bool> checkIfTicketHasPorter(String ticketId, String transactionId) {
return _repository.checkIfTicketHasPorter(ticketId, transactionId);
}
Future<String?> getPorterTransactionId(String ticketId, String transactionId) {
return _repository.getPorterTransactionId(ticketId, transactionId);
}
}

View File

@ -15,6 +15,7 @@ class HistoryController extends GetxController {
final RxBool isLoading = true.obs;
final RxBool isCheckingExpiry = false.obs;
final RxBool hasAssignedPorter = false.obs;
final RxString errorMessage = ''.obs;
StreamSubscription? _pendingSubscription;
@ -22,6 +23,7 @@ class HistoryController extends GetxController {
StreamSubscription? _historySubscription;
String _currentUserId = '';
String? currentPorterTransactionId;
HistoryController(this._historyUseCase);
@ -44,18 +46,6 @@ class HistoryController extends GetxController {
isLoading.value = false;
});
// _activeSubscription = _historyUseCase.getActiveTransactionsStream(userId).listen((transactions) {
// log('HistoryController: active transactions updated, count: ${transactions.length}');
// final sortedTransactions = _sortTransactionsByCreatedAt(transactions);
// activeTransactions.value = sortedTransactions;
// isLoading.value = false;
// }, onError: (error) {
// log('HistoryController: Error mendapatkan transaksi active: $error');
// isLoading.value = false;
// });
_activeSubscription = _historyUseCase.getActiveTransactionsStream(userId).map((list) {
final todayStart = DateTime(
DateTime.now().year,
@ -126,6 +116,12 @@ class HistoryController extends GetxController {
if (transaction != null) {
selectedTransaction.value = transaction;
hasAssignedPorter.value = await _historyUseCase.checkIfTicketHasPorter(ticketId, transactionId);
if (hasAssignedPorter.value) {
currentPorterTransactionId = await _historyUseCase.getPorterTransactionId(ticketId, transactionId);
}
} else {
errorMessage.value = 'Transaksi tidak ditemukan';
}
@ -140,6 +136,26 @@ class HistoryController extends GetxController {
}
}
Future<bool> checkIfTicketHasPorter(String ticketId, String transactionId) async {
try {
hasAssignedPorter.value = await _historyUseCase.checkIfTicketHasPorter(ticketId, transactionId);
return hasAssignedPorter.value;
} catch (e) {
log('HistoryController: error checking if ticket has porter: $e');
return false;
}
}
Future<String?> getPorterTransactionId(String ticketId, String transactionId) async {
try {
currentPorterTransactionId = await _historyUseCase.getPorterTransactionId(ticketId, transactionId);
return currentPorterTransactionId;
} catch (e) {
log('HistoryController: error getting porter transaction ID: $e');
return null;
}
}
Future<void> refreshTransactions(String userId) async {
log('HistoryController: Memperbarui data transaksi untuk userId: $userId');

View File

@ -1,5 +1,4 @@
import 'dart:developer';
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';
@ -14,7 +13,6 @@ import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:zoom_tap_animation/zoom_tap_animation.dart';
import '../../../../_core/component/appbar/appbar_component.dart';
import '../../../../_core/component/button/button_fill.dart';
import '../../../../_core/component/card/custome_shadow_cotainner.dart';
@ -41,7 +39,6 @@ class _DetailTicketScreenState extends State<DetailTicketScreen> {
final args = Get.arguments as Map<String, dynamic>;
id_transaction = args['id_transaction'];
id_ticket = args['id_ticket'];
WidgetsBinding.instance.addPostFrameCallback((_) {
_loadTransactionData();
});
@ -100,13 +97,17 @@ class _DetailTicketScreenState extends State<DetailTicketScreen> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TypographyStyles.caption(
"Kode Booking Maskapai",
color: GrayColors.gray500,
fontWeight: FontWeight.w500,
_buildUIHeader(
value: "${transaction.idBooking}",
onTap: () {
Get.toNamed(
Routes.PROCESSING,
arguments: {
'transactionPorterId': historyController.currentPorterTransactionId,
},
);
},
),
SizedBox(height: 6.h),
TypographyStyles.body("${transaction.idBooking}", color: GrayColors.gray800),
Padding(
padding: EdgeInsets.symmetric(vertical: 20.h),
child: CustomDashedLine(),
@ -123,15 +124,7 @@ class _DetailTicketScreenState extends State<DetailTicketScreen> {
),
SizedBox(height: 4.h),
Row(
children: [
TypographyStyles.small("Fast Track (FT)",
color: GrayColors.gray600, fontWeight: FontWeight.w400),
SizedBox(width: 10.w),
CircleAvatar(radius: 2.r, backgroundColor: Color(0xFFD9D9D9)),
SizedBox(width: 10.w),
TypographyStyles.small("${transaction.flightDetails['flightClass']}",
color: GrayColors.gray600, fontWeight: FontWeight.w400),
],
children: _buildServiceInfoItems(transaction),
),
SizedBox(height: 16.h),
Row(
@ -250,30 +243,36 @@ class _DetailTicketScreenState extends State<DetailTicketScreen> {
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ButtonOutline(
text: 'Scan QR Code Porter',
textColor: PrimaryColors.primary800,
onTap: () async {
await Permission.camera.status;
if (!historyController.hasAssignedPorter.value)
ButtonOutline(
text: 'Scan QR Code Porter',
textColor: PrimaryColors.primary800,
onTap: () async {
await Permission.camera.status;
final result = await Get.toNamed(
Routes.SCANQR,
arguments: {
'ticketId': transaction.ticketId,
'transactionId': transaction.id,
},
);
if (result == 'PORTER_BUSY') {
SnackbarHelper.showError(
'Porter Tidak Tersedia',
'Tidak ada porter yang tersedia atau semua porter sedang sibuk, coba nanti.',
final result = await Get.toNamed(
Routes.SCANQR,
arguments: {
'ticketId': transaction.ticketId,
'transactionId': transaction.id,
},
);
return;
}
},
),
SizedBox(height: 12.h),
if (result == 'PORTER_BUSY') {
SnackbarHelper.showError(
'Porter Tidak Tersedia',
'Tidak ada porter yang tersedia atau semua porter sedang sibuk, coba nanti.',
);
return;
}
if (result == 'SUCCESS') {
historyController.hasAssignedPorter.value = true;
_loadTransactionData();
}
},
),
if (!historyController.hasAssignedPorter.value) SizedBox(height: 12.h),
ButtonFill(
text: 'Cetak Boarding Pass',
textColor: Colors.white,
@ -297,6 +296,45 @@ class _DetailTicketScreenState extends State<DetailTicketScreen> {
);
}
Widget _buildUIHeader({required String value, required VoidCallback? onTap}) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TypographyStyles.caption(
"Kode Booking Maskapai",
color: GrayColors.gray500,
fontWeight: FontWeight.w500,
),
SizedBox(height: 6.h),
TypographyStyles.body(value, color: GrayColors.gray800),
],
),
Obx(() {
if (historyController.hasAssignedPorter.value) {
return ZoomTapAnimation(
child: GestureDetector(
onTap: onTap,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 14.w, vertical: 8.h),
decoration: BoxDecoration(
color: Colors.orange.shade400,
borderRadius: BorderRadius.circular(20.r),
),
child: TypographyStyles.small("Lihat Status Porter", color: Colors.white),
),
),
);
} else {
return SizedBox();
}
}),
],
);
}
Widget _buildDataBandara({
required String titleDeparture,
required String planeDeparture,
@ -342,6 +380,48 @@ class _DetailTicketScreenState extends State<DetailTicketScreen> {
);
}
List<Widget> _buildServiceInfoItems(TransactionModel transaction) {
List<Widget> items = [];
if (transaction.porterServiceDetails != null &&
(transaction.porterServiceDetails as Map<String, dynamic>).isNotEmpty) {
if ((transaction.porterServiceDetails as Map<String, dynamic>).containsKey('departure') &&
(transaction.porterServiceDetails as Map<String, dynamic>)['departure'] != null) {
final departureName =
(transaction.porterServiceDetails as Map<String, dynamic>)['departure']['name'] as String? ?? "Fast Track";
items.add(TypographyStyles.small(
departureName,
color: GrayColors.gray600,
fontWeight: FontWeight.w400,
));
items.add(SizedBox(width: 10.w));
items.add(CircleAvatar(radius: 2.r, backgroundColor: Color(0xFFD9D9D9)));
items.add(SizedBox(width: 10.w));
}
if ((transaction.porterServiceDetails as Map<String, dynamic>).containsKey('transit') &&
(transaction.porterServiceDetails as Map<String, dynamic>)['transit'] != null) {
final transitName =
(transaction.porterServiceDetails as Map<String, dynamic>)['transit']['name'] as String? ?? "Transit";
items.add(TypographyStyles.small(
transitName,
color: GrayColors.gray600,
fontWeight: FontWeight.w400,
));
items.add(SizedBox(width: 10.w));
items.add(CircleAvatar(radius: 2.r, backgroundColor: Color(0xFFD9D9D9)));
items.add(SizedBox(width: 10.w));
}
}
items.add(TypographyStyles.small(
"${transaction.flightDetails['flightClass']}",
color: GrayColors.gray600,
fontWeight: FontWeight.w400,
));
return items;
}
void _showCetakBoardingPassBottomSheet(TransactionModel transaction) {
Get.bottomSheet(
backgroundColor: Colors.white,

View File

@ -28,6 +28,7 @@ class _ScanQRScreenState extends State<ScanQRScreen> {
torchEnabled: false,
returnImage: true,
);
bool isProcessing = false;
bool _isTorchOn = false;
@ -220,7 +221,7 @@ class _ScanQRScreenState extends State<ScanQRScreen> {
transactionId: transactionId,
location: rawLocation,
);
await Future.delayed(Duration(seconds: 3));
// await Future.delayed(Duration(seconds: 3));
log('[ScanQRScreen] requestPorter succeeded: $result');
@ -245,7 +246,6 @@ class _ScanQRScreenState extends State<ScanQRScreen> {
} on Exception catch (e) {
final msg = e.toString();
if (msg.contains('Porter tidak tersedia')) {
// Porter sibuk langsung pop dengan result
Get.back(result: 'PORTER_BUSY');
return;
}

View File

@ -34,12 +34,6 @@ class _ProcessingPorterScreenState extends State<ProcessingPorterScreen> {
@override
void initState() {
super.initState();
// final args = Get.arguments as Map<String, dynamic>;
// final location = args['location'] ?? '';
// final ticketId = args['ticketId'] ?? '';
// final transactionId = args['transactionId'];
// final porterOnlineId = args['porterOnlineId'];
// final transactionPorterId = args['transactionPorterId'] ?? '';
_initializeData();
}
@ -59,7 +53,6 @@ class _ProcessingPorterScreenState extends State<ProcessingPorterScreen> {
log('Memulai pemantauan transaksi porter: $transactionPorterId');
// Dapatkan detail transaksi dan mulai memantau perubahan
_porterController.getTransactionById(transactionPorterId).then((transaction) {
if (transaction == null) {
log('Transaksi tidak ditemukan: $transactionPorterId');
@ -70,7 +63,6 @@ class _ProcessingPorterScreenState extends State<ProcessingPorterScreen> {
log('Error mendapatkan transaksi: $e');
});
// Mulai memantau transaksi secara real-time
_porterController.watchTransaction(transactionPorterId);
}
@ -86,80 +78,48 @@ class _ProcessingPorterScreenState extends State<ProcessingPorterScreen> {
Get.back();
},
),
body: SafeArea(child: Obx(
() {
final transaction = _porterController.currentTransaction.value;
final isLoading = _porterController.isLoading.value;
final error = _porterController.error.value;
body: SafeArea(
child: Obx(
() {
final transaction = _porterController.currentTransaction.value;
final isLoading = _porterController.isLoading.value;
final error = _porterController.error.value;
if (isLoading) {
return const Center(child: CircularProgressIndicator());
}
if (error.isNotEmpty) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.error_outline, size: 48.h, color: Colors.red),
SizedBox(height: 16.h),
TypographyStyles.body(
'Terjadi Kesalahan',
color: Colors.red,
),
SizedBox(height: 8.h),
Padding(
padding: EdgeInsets.symmetric(horizontal: 32.w),
child: TypographyStyles.caption(
error,
color: GrayColors.gray600,
textAlign: TextAlign.center,
),
),
SizedBox(height: 16.h),
ButtonFill(
text: 'Kembali',
textColor: Colors.white,
onTap: () => Get.back(),
),
],
if (isLoading) {
return const Center(child: CircularProgressIndicator());
}
if (error.isNotEmpty) {
return Center(child: TypographyStyles.body('Data transaksi tidak ditemukan', color: GrayColors.gray400));
}
if (transaction == null) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.search_off, size: 48.h, color: GrayColors.gray400),
SizedBox(height: 16.h),
TypographyStyles.body('Transaksi tidak ditemukan', color: GrayColors.gray600),
],
),
);
}
return Padding(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 20.h),
child: SingleChildScrollView(
child: Column(
children: [
_buildPorterStatusCard(transaction.status),
SizedBox(height: 20.h),
_buildInfoPorterCard(kodePorter: transaction.kodePorter, namePorter: transaction.porterUserId),
SizedBox(height: 20.h),
_buildPorterDetailsCard(transaction),
],
),
),
);
}
if (transaction == null) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.search_off, size: 48.h, color: GrayColors.gray400),
SizedBox(height: 16.h),
TypographyStyles.body(
'Transaksi tidak ditemukan',
color: GrayColors.gray600,
),
SizedBox(height: 16.h),
ButtonFill(
text: 'Kembali',
textColor: Colors.white,
onTap: () => Get.back(),
),
],
),
);
}
return Padding(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 20.h),
child: SingleChildScrollView(
child: Column(
children: [
_buildPorterStatusCard(transaction.status),
SizedBox(height: 20.h),
_buildPorterDetailsCard(transaction),
],
),
),
);
},
)),
},
),
),
bottomNavigationBar: CustomeShadowCotainner(
child: ButtonFill(
text: 'Kembali ke menu',
@ -170,59 +130,6 @@ class _ProcessingPorterScreenState extends State<ProcessingPorterScreen> {
);
}
Widget _buildDesignOld() {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 20.h),
child: SingleChildScrollView(
child: Column(
children: [
TypographyStyles.h1('Ilustrasi'),
SizedBox(height: 32.h),
CustomeShadowCotainner(
child: Column(
children: [
TypographyStyles.h6('Tunggu Portermu', color: GrayColors.gray800),
SizedBox(height: 4.h),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TypographyStyles.caption(
'Tunngu dari pihak Porter merespon',
color: GrayColors.gray500,
fontWeight: FontWeight.w400,
),
SizedBox(width: 4.w),
Icon(Icons.timelapse_outlined)
],
),
],
),
),
SizedBox(height: 20.h),
CustomeShadowCotainner(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TypographyStyles.body('Ahmad Choirul Umam', color: GrayColors.gray800),
SizedBox(height: 10.h),
Divider(thickness: 1, color: GrayColors.gray200),
SizedBox(height: 10.h),
TypographyStyles.body('Lokasi', color: GrayColors.gray800),
SizedBox(height: 10.h),
// _buildRowLocation(location: 'Gate Penerbangan', desc: 'Lokasi Anda'),
SizedBox(height: 10.h),
// _buildRowLocation(location: 'Guyangan', desc: 'Lokasi Porter Anda'),
SizedBox(height: 10.h),
// _buildRowLocation(location: 'Porter menuju ke lokasi anda', desc: 'Porter bergerak'),
],
),
),
],
),
),
);
}
Widget _buildPorterStatusCard(String status) {
String statusText = '';
Widget statusIcon = const SizedBox.shrink();
@ -280,6 +187,39 @@ class _ProcessingPorterScreenState extends State<ProcessingPorterScreen> {
}
}
Widget _buildInfoPorterCard({required String kodePorter, required String namePorter}) {
return CustomeShadowCotainner(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TypographyStyles.h6('Informasi Porter', color: GrayColors.gray800),
SizedBox(height: 10.h),
Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TypographyStyles.body('Kode Porter', color: GrayColors.gray600, fontWeight: FontWeight.w400),
TypographyStyles.body('Nama Porter', color: GrayColors.gray600, fontWeight: FontWeight.w400),
],
),
SizedBox(width: 20.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TypographyStyles.body(kodePorter, color: GrayColors.gray800, maxlines: 1),
TypographyStyles.body(namePorter, color: GrayColors.gray800, maxlines: 1),
],
),
)
],
),
],
),
);
}
Widget _buildPorterDetailsCard(dynamic transaction) {
final now = DateTime.now();
@ -287,11 +227,7 @@ class _ProcessingPorterScreenState extends State<ProcessingPorterScreen> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TypographyStyles.body('Informasi Porter', color: GrayColors.gray800),
SizedBox(height: 10.h),
Divider(thickness: 1, color: GrayColors.gray200),
SizedBox(height: 10.h),
TypographyStyles.body('Lokasi', color: GrayColors.gray800),
TypographyStyles.h6('Lokasi', color: GrayColors.gray800),
SizedBox(height: 10.h),
_buildRowLocation(
location: location.isNotEmpty ? location : transaction.locationPassenger,
@ -310,20 +246,6 @@ class _ProcessingPorterScreenState extends State<ProcessingPorterScreen> {
desc: 'Status Porter',
timestamp: now,
),
SizedBox(height: 10.h),
TypographyStyles.body('Kode Porter', color: GrayColors.gray800),
SizedBox(height: 4.h),
Container(
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h),
decoration: BoxDecoration(
color: PrimaryColors.primary100,
borderRadius: BorderRadius.circular(4.r),
),
child: TypographyStyles.h6(
transaction.kodePorter,
color: PrimaryColors.primary800,
),
),
],
),
);
@ -353,12 +275,12 @@ class _ProcessingPorterScreenState extends State<ProcessingPorterScreen> {
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
TypographyStyles.caption(
TypographyStyles.body(
_dateFormat.format(timestamp),
color: GrayColors.gray600,
fontWeight: FontWeight.w400,
),
TypographyStyles.caption(
TypographyStyles.body(
_timeFormat.format(timestamp),
color: GrayColors.gray600,
fontWeight: FontWeight.w400,
@ -370,16 +292,8 @@ class _ProcessingPorterScreenState extends State<ProcessingPorterScreen> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TypographyStyles.caption(
location,
color: GrayColors.gray800,
fontWeight: FontWeight.w600,
),
TypographyStyles.small(
desc,
color: GrayColors.gray600,
fontWeight: FontWeight.w400,
)
TypographyStyles.body(location, color: GrayColors.gray800),
TypographyStyles.caption(desc, color: GrayColors.gray600, fontWeight: FontWeight.w400)
],
),
),

View File

@ -409,7 +409,7 @@ class _HomeScreenState extends State<HomeScreen> {
icon: Icon(Icons.calendar_today, size: 20.r, color: PrimaryColors.primary800)),
SizedBox(width: 8.w),
DateSetting(
onTap: () => _statisticController.previousMonth(),
onTap: () => _statisticController.nextMonth(),
icon: Icon(Icons.chevron_right, size: 20.r, color: GrayColors.gray800),
),
],
@ -489,9 +489,7 @@ class _HomeScreenState extends State<HomeScreen> {
final hasPorter = _porterQueueController.currentPorter.value != null;
return ZoomTapAnimation(
child: GestureDetector(
onTap: hasPorter
? _handleStopPorterQueue // sekarang benar-benar terpilih saat Obx rebuild
: _handlePorterQueueCreation,
onTap: hasPorter ? _handleStopPorterQueue : _handlePorterQueueCreation,
child: Column(
children: [
Container(
@ -538,6 +536,7 @@ class _HomeScreenState extends State<HomeScreen> {
Future<bool> _showStopConfirmationDialog() async {
return await Get.dialog<bool>(
Dialog(
backgroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.r),
),
@ -551,13 +550,12 @@ class _HomeScreenState extends State<HomeScreen> {
color: GrayColors.gray800,
),
SizedBox(height: 16.h),
Text(
TypographyStyles.caption(
'Apakah Anda yakin ingin menghentikan layanan porter?',
fontWeight: FontWeight.w400,
color: GrayColors.gray500,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14.sp,
color: GrayColors.gray600,
),
maxlines: 3,
),
SizedBox(height: 24.h),
Row(
@ -569,7 +567,7 @@ class _HomeScreenState extends State<HomeScreen> {
style: TextButton.styleFrom(
foregroundColor: GrayColors.gray600,
),
child: Text('Batal'),
child: TypographyStyles.body('Batal', color: GrayColors.gray600),
),
),
SizedBox(width: 8.w),
@ -580,7 +578,7 @@ class _HomeScreenState extends State<HomeScreen> {
backgroundColor: RedColors.red500,
foregroundColor: Colors.white,
),
child: Text('Berhenti'),
child: TypographyStyles.body('Berhenti', color: Colors.white),
),
),
],
@ -681,7 +679,6 @@ class _HomeScreenState extends State<HomeScreen> {
required String nameAvatar,
required String nameUser,
required String subTitle,
// VoidCallback? onTap,
}) {
return CustomeShadowCotainner(
sizeRadius: 0.r,
@ -703,12 +700,6 @@ class _HomeScreenState extends State<HomeScreen> {
],
),
),
// ZoomTapAnimation(
// child: IconButton(
// onPressed: onTap,
// icon: CustomeIcons.NotificationOutline(),
// ),
// )
],
),
);