diff --git a/lib/data/repositories/api_receipt_repository.dart b/lib/data/repositories/api_receipt_repository.dart index f2234b0..0bf8a86 100644 --- a/lib/data/repositories/api_receipt_repository.dart +++ b/lib/data/repositories/api_receipt_repository.dart @@ -24,7 +24,7 @@ class ApiReceiptRepository implements ReceiptRepository { required String copyFor, }) async { final uri = _normalizeLocalhostForAndroid( - Uri.parse('$baseUrl/transaction/pdf-html').replace( + Uri.parse('$baseUrl/transaction/pdf').replace( queryParameters: { 'transactionId': transactionId, 'copyFor': copyFor, @@ -70,7 +70,7 @@ class ApiReceiptRepository implements ReceiptRepository { required String copyFor, }) async { final uri = _normalizeLocalhostForAndroid( - Uri.parse('$baseUrl/transaction/pdf-html').replace( + Uri.parse('$baseUrl/transaction/pdf').replace( queryParameters: { 'transactionId': transactionId, 'copyFor': copyFor, diff --git a/lib/presentation/terminal/receipt_view_model.dart b/lib/presentation/terminal/receipt_view_model.dart index 3d958c1..e29893c 100644 --- a/lib/presentation/terminal/receipt_view_model.dart +++ b/lib/presentation/terminal/receipt_view_model.dart @@ -2,7 +2,6 @@ import 'dart:io'; import 'package:e_receipt_mobile/core/config/app_config.dart'; import 'package:e_receipt_mobile/data/repositories/api_receipt_repository.dart'; -import 'package:e_receipt_mobile/domain/entities/receipt_content.dart'; import 'package:e_receipt_mobile/domain/repositories/receipt_repository.dart'; import 'package:e_receipt_mobile/presentation/auth/session_controller.dart'; import 'package:e_receipt_mobile/presentation/login/login_view_model.dart'; @@ -39,12 +38,6 @@ class ReceiptPdfViewData extends ReceiptViewData { final File file; } -class ReceiptHtmlViewData extends ReceiptViewData { - const ReceiptHtmlViewData(this.html); - - final String html; -} - final receiptRepositoryProvider = Provider((ref) { return ApiReceiptRepository( baseUrl: AppConfig.apiBaseUrl, @@ -64,27 +57,20 @@ final transactionReceiptViewDataProvider = throw Exception('No active session'); } - final content = await ref + final bytes = await ref .watch(receiptRepositoryProvider) - .getTransactionReceipt( + .getTransactionReceiptPdfBytes( token: sessionUser.token, transactionId: query.transactionId, copyFor: query.copyFor, ); - switch (content) { - case ReceiptPdfContent(): - final dir = await Directory.systemTemp.createTemp( - 'e_receipt_mobile', - ); - final file = File( - '${dir.path}/receipt_${query.transactionId}_${query.copyFor}.pdf', - ); - await file.writeAsBytes(content.bytes, flush: true); - return ReceiptPdfViewData(file); - case ReceiptHtmlContent(): - return ReceiptHtmlViewData(content.html); - } + final dir = await Directory.systemTemp.createTemp('e_receipt_mobile'); + final file = File( + '${dir.path}/receipt_${query.transactionId}_${query.copyFor}.pdf', + ); + await file.writeAsBytes(bytes, flush: true); + return ReceiptPdfViewData(file); } catch (e, st) { debugPrint('[RECEIPT][ERROR] ${Error.safeToString(e)}\n$st'); throw Exception(Error.safeToString(e)); diff --git a/lib/presentation/terminal/terminal_next_screen.dart b/lib/presentation/terminal/terminal_next_screen.dart index 838b2df..04f1ccd 100644 --- a/lib/presentation/terminal/terminal_next_screen.dart +++ b/lib/presentation/terminal/terminal_next_screen.dart @@ -439,7 +439,7 @@ class _TerminalNextScreenState extends ConsumerState { _first(raw, const ['DE4']) ?? item.amount?.toString() ?? '-'; final currency = _first(raw, const ['DE49']) ?? 'MMK'; final status = _statusLabel( - _first(raw, const ['description', 'DE39', 'status']) ?? + _first(raw, const ['DE39']) ?? item.status, ); final type = _first(raw, const ['DE3']) ?? item.type ?? '-'; @@ -605,16 +605,15 @@ class _TerminalNextScreenState extends ConsumerState { } String _statusLabel(String? status) { - final normalized = (status ?? '').trim().toUpperCase(); - if (normalized == 'A' || - normalized == 'SUCCESS' || - normalized == 'PAY_SUCCESS') { + final normalized = status?.trim().toUpperCase(); + if (normalized == 'A') { return 'SUCCESS'; } - if (normalized == 'E' || normalized == 'FAILED') { + if (normalized == 'E' ) { return 'FAILED'; } - return normalized.isEmpty ? '-' : normalized; + return 'SUCCESS'; + } String? _sanitizeMultiline(String? value) { diff --git a/lib/presentation/terminal/transaction_receipt_screen.dart b/lib/presentation/terminal/transaction_receipt_screen.dart index a6cd2cf..d67fbd8 100644 --- a/lib/presentation/terminal/transaction_receipt_screen.dart +++ b/lib/presentation/terminal/transaction_receipt_screen.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'dart:io'; import 'dart:typed_data'; -import 'package:e_receipt_mobile/domain/entities/receipt_content.dart'; import 'package:e_receipt_mobile/domain/entities/terminal.dart'; import 'package:e_receipt_mobile/domain/entities/transaction_record.dart'; import 'package:e_receipt_mobile/presentation/auth/session_controller.dart'; @@ -13,7 +12,6 @@ import 'package:flutter_pdfview/flutter_pdfview.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:path_provider/path_provider.dart'; import 'package:printing/printing.dart'; -import 'package:webview_flutter/webview_flutter.dart'; class TransactionReceiptScreen extends ConsumerWidget { const TransactionReceiptScreen({ @@ -146,10 +144,6 @@ class TransactionReceiptScreen extends ConsumerWidget { }, ), ), - ReceiptHtmlViewData() => _ReceiptViewport( - padding: const EdgeInsets.fromLTRB(16, 16, 16, 12), - child: _ReceiptHtmlView(html: viewData.html), - ), }, ), SafeArea( @@ -356,22 +350,13 @@ Future _fetchReceiptPdfBytes({ throw Exception('No active session'); } - final content = await ref.read(receiptRepositoryProvider).getTransactionReceipt( + return ref + .read(receiptRepositoryProvider) + .getTransactionReceiptPdfBytes( token: sessionUser.token, transactionId: transactionId, copyFor: copyFor, ); - - switch (content) { - case ReceiptPdfContent(): - return content.bytes; - case ReceiptHtmlContent(): - try { - return await Printing.convertHtml(html: _wrapHtml(content.html)); - } catch (e) { - throw Exception('Server did not return PDF, and HTML→PDF failed: $e'); - } - } } Future _runWithProgress( @@ -416,146 +401,3 @@ Future _runWithProgress( } } } - -class _ReceiptHtmlWebView extends StatefulWidget { - const _ReceiptHtmlWebView({required this.html}); - - final String html; - - @override - State<_ReceiptHtmlWebView> createState() => _ReceiptHtmlWebViewState(); -} - -class _ReceiptHtmlWebViewState extends State<_ReceiptHtmlWebView> { - late final WebViewController _controller; - - @override - void initState() { - super.initState(); - - _controller = WebViewController() - ..setJavaScriptMode(JavaScriptMode.disabled) - ..setBackgroundColor(Colors.transparent) - ..setNavigationDelegate( - NavigationDelegate( - onNavigationRequest: (request) => NavigationDecision.prevent, - ), - ) - ..loadHtmlString(_wrapHtml(widget.html)); - } - - @override - Widget build(BuildContext context) { - return WebViewWidget(controller: _controller); - } -} - -class _ReceiptHtmlView extends StatelessWidget { - const _ReceiptHtmlView({required this.html}); - - final String html; - - @override - Widget build(BuildContext context) { - final platform = defaultTargetPlatform; - final supportsWebView = - platform == TargetPlatform.android || platform == TargetPlatform.iOS; - if (!supportsWebView) { - return _ReceiptHtmlFallbackText(html: html); - } - - return _ReceiptHtmlWebView(html: html); - } -} - -class _ReceiptHtmlFallbackText extends StatelessWidget { - const _ReceiptHtmlFallbackText({required this.html}); - - final String html; - - @override - Widget build(BuildContext context) { - final plainText = _htmlToPlainText(html); - return Padding( - padding: const EdgeInsets.all(16), - child: SelectionArea( - child: DefaultTextStyle( - style: - Theme.of(context).textTheme.bodyMedium?.copyWith( - fontFamily: 'monospace', - height: 1.35, - ) ?? - const TextStyle(fontFamily: 'monospace', height: 1.35), - child: Text(plainText), - ), - ), - ); - } -} - -String _wrapHtml(String html) { - // Keep backend HTML intact but ensure a sane viewport and remove default - // margins so it looks like the web "receipt iframe" container. - return ''' - - - - - - - - $html - -'''; -} - -String _htmlToPlainText(String html) { - var s = html; - - s = s.replaceAll( - RegExp( - r'<(script|style)[^>]*>.*?', - caseSensitive: false, - dotAll: true, - ), - '', - ); - s = s.replaceAll(RegExp(r'', caseSensitive: false), '\n'); - s = s.replaceAll( - RegExp( - r'', - caseSensitive: false, - ), - '\n', - ); - s = s.replaceAll(RegExp(r']*>', caseSensitive: false), '• '); - s = s.replaceAll(RegExp(r'', caseSensitive: false), '\n'); - - s = s.replaceAll(RegExp(r'<[^>]+>'), ''); - - s = s.replaceAll(' ', ' '); - s = s.replaceAll('&', '&'); - s = s.replaceAll('<', '<'); - s = s.replaceAll('>', '>'); - s = s.replaceAll('"', '"'); - s = s.replaceAll(''', "'"); - - s = s.replaceAllMapped(RegExp(r'&#(\d+);'), (m) { - final code = int.tryParse(m.group(1) ?? ''); - if (code == null) return ''; - return String.fromCharCode(code); - }); - s = s.replaceAllMapped(RegExp(r'&#x([0-9a-fA-F]+);'), (m) { - final code = int.tryParse(m.group(1) ?? '', radix: 16); - if (code == null) return ''; - return String.fromCharCode(code); - }); - - s = s.replaceAll(RegExp(r'[ \t]+\n'), '\n'); - s = s.replaceAll(RegExp(r'\n{3,}'), '\n\n'); - - return s.trim(); -} diff --git a/lib/presentation/terminal/widgets/terminal_list_view.dart b/lib/presentation/terminal/widgets/terminal_list_view.dart index 6070c89..b74fd55 100644 --- a/lib/presentation/terminal/widgets/terminal_list_view.dart +++ b/lib/presentation/terminal/widgets/terminal_list_view.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; +import 'dart:math'; import 'dart:ui'; import 'package:e_receipt_mobile/domain/entities/terminal.dart'; @@ -57,6 +59,7 @@ class TerminalListView extends StatelessWidget { separatorBuilder: (_, __) => const SizedBox(height: 10), itemBuilder: (context, index) { final terminal = terminals[index]; + print('this is terminal ${terminal.status}'); final enabled = terminal.tid != null || terminal.id != null; final title = (_sanitizeMultiline(terminal.name)?.isNotEmpty ?? false)