Localization Changes #6

This commit is contained in:
2025-09-08 13:07:35 +05:30
parent 1204507375
commit d8d87e8da4
11 changed files with 317 additions and 20 deletions

View File

@@ -1,11 +1,17 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:material_symbols_icons/material_symbols_icons.dart';
import 'package:path_provider/path_provider.dart';
import 'package:shimmer/shimmer.dart';
import 'package:kmobile/data/models/transaction.dart';
import 'package:kmobile/data/repositories/transaction_repository.dart';
import 'package:kmobile/di/injection.dart';
import '../../../l10n/app_localizations.dart';
import 'transaction_details_screen.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:permission_handler/permission_handler.dart';
import 'package:device_info_plus/device_info_plus.dart';
class AccountStatementScreen extends StatefulWidget {
final String accountNo;
@@ -27,6 +33,7 @@ class _AccountStatementScreen extends State<AccountStatementScreen> {
List<Transaction> _transactions = [];
final _minAmountController = TextEditingController();
final _maxAmountController = TextEditingController();
Future<Map<String, dynamic>?>? accountStatementsFuture;
@override
void initState() {
@@ -308,9 +315,182 @@ class _AccountStatementScreen extends State<AccountStatementScreen> {
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
_exportToPdf();
},
child: const Icon(Icons.download),
),
);
}
Future<void> _exportToPdf() async {
if (accountStatementsFuture == null) return;
if (Platform.isAndroid) {
final androidInfo = await DeviceInfoPlugin().androidInfo;
if (androidInfo.version.sdkInt < 29) {
final status = await Permission.storage.status;
if (status.isDenied) {
final result = await Permission.storage.request();
if (result.isDenied) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Storage permission is required to save PDF'),
duration: Duration(seconds: 3),
),
);
}
return;
}
}
}
}
String logoSvg = await rootBundle.loadString('assets/logos/logo.svg');
var rubik = await rootBundle.load("assets/fonts/Rubik-Regular.ttf");
try {
final statements = await accountStatementsFuture;
if (statements == null) return;
final pdf = pw.Document();
pdf.addPage(pw.MultiPage(
margin: const pw.EdgeInsets.all(20),
build: (pw.Context context) {
return [
pw.Row(
mainAxisAlignment: pw.MainAxisAlignment.start,
crossAxisAlignment: pw.CrossAxisAlignment.center,
children: [
pw.SvgImage(svg: logoSvg, width: 50, height: 50),
pw.SizedBox(width: 20),
pw.Text(AppLocalizations.of(context as BuildContext).kccBankFull,
style: pw.TextStyle(
fontSize: 24, fontWeight: pw.FontWeight.bold)),
]),
pw.SizedBox(height: 20),
pw.Row(
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
children: [
pw.Text('Account Number: ${widget.accountNo}',
style: pw.TextStyle(
font: pw.Font.ttf(rubik), fontSize: 15)),
pw.Text('Account Type: selectedAccountType',
style: pw.TextStyle(
fontSize: 15,
font: pw.Font.ttf(rubik),
)),
]),
pw.SizedBox(height: 20),
pw.Table(border: pw.TableBorder.all(), columnWidths: {
0: const pw.FractionColumnWidth(0.2),
1: const pw.FractionColumnWidth(0.5),
2: const pw.FractionColumnWidth(0.15),
3: const pw.FractionColumnWidth(0.15),
}, children: [
pw.TableRow(
children: [
pw.Padding(
padding: const pw.EdgeInsets.all(4),
child: pw.Text('Date')),
pw.Padding(
padding: const pw.EdgeInsets.all(4),
child: pw.Text('Description', softWrap: true)),
pw.Padding(
padding: const pw.EdgeInsets.all(4),
child: pw.Text('Amount')),
pw.Padding(
padding: const pw.EdgeInsets.all(4),
child: pw.Text('Balance')),
],
),
...statements['accountStatement'].map<pw.TableRow>((statement) {
return pw.TableRow(children: [
pw.Padding(
padding: const pw.EdgeInsets.all(10),
child: pw.Text(
'${statement['postDate']} ${statement['postTime']}',
style: pw.TextStyle(
fontSize: 12,
font: pw.Font.ttf(rubik),
))),
pw.Padding(
padding: const pw.EdgeInsets.all(10),
child: pw.Text(statement['narration'],
style: pw.TextStyle(
fontSize: 12, font: pw.Font.ttf(rubik)))),
pw.Padding(
padding: const pw.EdgeInsets.all(10),
child: pw.Text("${statement['transactionAmount']}",
style: pw.TextStyle(
fontSize: 12,
font: pw.Font.ttf(rubik),
// color:
// statement['transactionAmount'].contains('-')
// ? const PdfColor.fromInt(0xFFB00020)
// : const PdfColor.fromInt(0xFF007B0D),
))),
pw.Padding(
padding: const pw.EdgeInsets.all(10),
child: pw.Text("${statement['endBalance']}",
style: pw.TextStyle(
fontSize: 12,
font: pw.Font.ttf(rubik),
))),
]);
}).toList(),
])
];
},
footer: (pw.Context context) {
return pw.Container(
alignment: pw.Alignment.centerRight,
margin: const pw.EdgeInsets.only(top: 10),
child: pw.Text(
'Kangra Central Co-Operative bank Pvt Ltd. ©. All rights reserved.',
style: pw.TextStyle(
font: pw.Font.ttf(rubik),
fontSize: 8,
),
),
);
}));
Directory? directory;
if (Platform.isAndroid) {
directory = Directory('/storage/emulated/0/Download');
} else {
directory = await getDownloadsDirectory();
}
if (directory == null) {
throw Exception('Could not access downloads directory');
}
final String timestamp = DateTime.now().millisecondsSinceEpoch.toString();
final file = File('${directory.path}/account_statement_$timestamp.pdf');
await file.writeAsBytes(await pdf.save());
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('PDF saved to: ${file.path}'),
duration: const Duration(seconds: 3),
),
);
}
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Error saving PDF: $e'),
duration: const Duration(seconds: 3),
),
);
}
}
}
Widget buildDateBox(String label, DateTime? date) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 16),

View File

@@ -1,21 +1,23 @@
import 'package:flutter/material.dart';
import '../../l10n/app_localizations.dart';
class LogoutDialog extends StatelessWidget {
const LogoutDialog({super.key});
@override
Widget build(BuildContext context) {
return AlertDialog(
title: const Text("Logout"),
content: const Text("Are you sure you want to logout?"),
title: Text(AppLocalizations.of(context).logout),
content: Text(AppLocalizations.of(context).logoutCheck),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false), // dismiss
child: const Text("No"),
child: Text(AppLocalizations.of(context).no),
),
TextButton(
onPressed: () => Navigator.pop(context, true), // confirm
child: const Text("Yes"),
child: Text(AppLocalizations.of(context).yes),
),
],
);

View File

@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:kmobile/data/repositories/auth_repository.dart';
import 'package:kmobile/features/profile/preferences/logout_dialog.dart';
import 'package:kmobile/features/profile/logout_dialog.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../di/injection.dart';
import '../../l10n/app_localizations.dart';
@@ -43,7 +43,7 @@ class ProfileScreen extends StatelessWidget {
// You can add more profile options here later
ListTile(
leading: const Icon(Icons.logout),
title: const Text("Logout"),
title: Text(AppLocalizations.of(context).logout),
onTap: () async {
final shouldLogout = await showDialog<bool>(
context: context,