Download notification created and Profile added in quick links

This commit is contained in:
2025-12-02 17:06:49 +05:30
parent 992092052a
commit 5d307607fd
8 changed files with 211 additions and 67 deletions

View File

@@ -34,6 +34,7 @@ android {
ndkVersion "27.0.12077973"
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
@@ -80,4 +81,6 @@ flutter {
source '../..'
}
dependencies {}
dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

View File

@@ -13,6 +13,8 @@ import 'package:permission_handler/permission_handler.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:path_provider/path_provider.dart';
import 'package:share_plus/share_plus.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:open_filex/open_filex.dart';
import 'package:kmobile/data/models/user.dart';
@@ -38,13 +40,50 @@ class _AccountStatementScreen extends State<AccountStatementScreen> {
List<Transaction> _transactions = [];
final _minAmountController = TextEditingController();
final _maxAmountController = TextEditingController();
//Future<Map<String, dynamic>?>? accountStatementsFuture;
late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
@override
void initState() {
super.initState();
selectedUser = widget.users[widget.selectedIndex];
_loadTransactions();
_initializeNotifications();
}
void _initializeNotifications() async {
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('notification_icon');
const InitializationSettings initializationSettings =
InitializationSettings(android: initializationSettingsAndroid);
await flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onDidReceiveNotificationResponse: _onDidReceiveNotificationResponse,
);
_requestNotificationPermission();
}
void _onDidReceiveNotificationResponse(
NotificationResponse notificationResponse) async {
final String? payload = notificationResponse.payload;
if (payload != null && payload.isNotEmpty) {
await OpenFilex.open(payload);
}
}
void _requestNotificationPermission() async {
if (Platform.isAndroid) {
final AndroidFlutterLocalNotificationsPlugin? androidImplementation =
flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>();
if (androidImplementation != null) {
await androidImplementation.requestNotificationsPermission();
}
}
}
Future<void> _loadTransactions() async {
@@ -413,7 +452,6 @@ class _AccountStatementScreen extends State<AccountStatementScreen> {
}
Future<void> _exportToPdf() async {
// Step 1: Check if there are any transactions to export.
if (_transactions.isEmpty) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
@@ -425,6 +463,27 @@ class _AccountStatementScreen extends State<AccountStatementScreen> {
return;
}
// Show downloading notification
await flutterLocalNotificationsPlugin.show(
0,
'Downloading PDF',
'Your account statement is being downloaded...',
const NotificationDetails(
android: AndroidNotificationDetails(
'download_channel',
'Download Notifications',
channelDescription:
'Notifications for PDF downloads',
importance: Importance.low,
priority: Priority.low,
showProgress: true,
maxProgress: 0, // Indeterminate progress
ongoing: true,
icon: 'notification_icon',
),
),
);
var logo = await rootBundle.load('assets/images/logo.png');
var rubik = await rootBundle.load("assets/fonts/Rubik-Regular.ttf");
final pdf = pw.Document();
@@ -527,64 +586,81 @@ class _AccountStatementScreen extends State<AccountStatementScreen> {
);
}));
//Logic For all platforms
try {
final Uint8List pdfBytes = await pdf.save();
final String timestamp = DateTime.now().millisecondsSinceEpoch.toString();
final String fileName = 'account_statement_$timestamp.pdf';
// For Android
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'),
),
);
}
return;
}
}
}
String? filePath;
if (Platform.isAndroid) {
final directory = Directory('/storage/emulated/0/Download');
if (!await directory.exists()) {
await directory.create(recursive: true);
}
final file = File('${directory.path}/$fileName');
await file.writeAsBytes(pdfBytes);
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('PDF saved to: ${file.path}'),
),
);
}
}
// Add for IOS
else if (Platform.isIOS) {
// On iOS, we save to a temporary directory and then open the share sheet.
filePath = file.path;
} else if (Platform.isIOS) {
final tempDir = await getTemporaryDirectory();
final file = await File('${tempDir.path}/$fileName').create();
await file.writeAsBytes(pdfBytes);
filePath = file.path;
} else {
// For other platforms, we might just save to temporary directory
final tempDir = await getTemporaryDirectory();
final file = await File('${tempDir.path}/$fileName').create();
await file.writeAsBytes(pdfBytes);
filePath = file.path;
}
// Use share_plus to open the iOS share dialog
await Share.shareXFiles(
[XFile(file.path)],
);
}
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Error saving PDF: $e'),
// Update notification to download complete
await flutterLocalNotificationsPlugin.show(
0,
'PDF Download Complete',
'Your account statement has been saved.',
const NotificationDetails(
android: AndroidNotificationDetails(
'download_channel',
'Download Notifications',
channelDescription:
'Notifications for PDF downloads',
importance: Importance.high,
priority: Priority.high,
showProgress: false,
ongoing: false,
autoCancel: true,
icon: 'notification_icon',
actions: [
AndroidNotificationAction(
'open_pdf',
'Open PDF',
showsUserInterface: true,
)
],
),
);
}
),
payload: filePath,
);
} catch (e) {
await flutterLocalNotificationsPlugin.show(
0,
'PDF Download Failed',
'Error saving PDF: $e',
const NotificationDetails(
android: AndroidNotificationDetails(
'download_channel',
'Download Notifications',
channelDescription:
'Notifications for PDF downloads',
importance: Importance.high,
priority: Priority.high,
showProgress: false,
ongoing: false,
icon: 'notification_icon',
),
),
);
}
}

View File

@@ -388,6 +388,21 @@ class _DashboardScreenState extends State<DashboardScreen>
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final authState = context.read<AuthCubit>().state;
String mobileNumberToPass = '';
String customerNo = '';
String customerName = '';
if (authState is Authenticated) {
if (selectedAccountIndex >= 0 &&
selectedAccountIndex < authState.users.length) {
mobileNumberToPass =
authState.users[selectedAccountIndex].mobileNo ?? '';
customerNo =
authState.users[selectedAccountIndex].cifNumber ?? '';
customerName =
authState.users[selectedAccountIndex].name ?? '';
}
}
return BlocListener<AuthCubit, AuthState>(
listener: (context, state) async {
if (state is Authenticated && !_biometricPromptShown) {
@@ -429,21 +444,7 @@ class _DashboardScreenState extends State<DashboardScreen>
child: InkWell(
borderRadius: BorderRadius.circular(20),
onTap: () {
final authState = context.read<AuthCubit>().state;
String mobileNumberToPass = '';
String customerNo = '';
String customerName = '';
if (authState is Authenticated) {
if (selectedAccountIndex >= 0 &&
selectedAccountIndex < authState.users.length) {
mobileNumberToPass =
authState.users[selectedAccountIndex].mobileNo ?? '';
customerNo =
authState.users[selectedAccountIndex].cifNumber ?? '';
customerName =
authState.users[selectedAccountIndex].name ?? '';
}
}
Navigator.push(
context,
@@ -677,18 +678,21 @@ class _DashboardScreenState extends State<DashboardScreen>
const EnquiryScreen()));
}),
_buildQuickLink(
Symbols.checkbook,
AppLocalizations.of(context).chequeManagement,
Symbols.person,
AppLocalizations.of(context).profile,
() {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const ChequeManagementScreen(),
),
ProfileScreen(
mobileNumber: mobileNumberToPass,
customerNo: customerNo,
customerName: customerName),
),
);
},
disable: true,
disable: false,
),
],
),

View File

@@ -6,6 +6,7 @@ import FlutterMacOS
import Foundation
import device_info_plus
import flutter_local_notifications
import flutter_secure_storage_macos
import local_auth_darwin
import package_info_plus
@@ -16,6 +17,7 @@ import url_launcher_macos
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
FLALocalAuthPlugin.register(with: registry.registrar(forPlugin: "FLALocalAuthPlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))

View File

@@ -137,6 +137,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.8"
dbus:
dependency: transitive
description:
name: dbus
sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c"
url: "https://pub.dev"
source: hosted
version: "0.7.11"
device_info_plus:
dependency: "direct main"
description:
@@ -238,6 +246,38 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.2"
flutter_local_notifications:
dependency: "direct main"
description:
name: flutter_local_notifications
sha256: "19ffb0a8bb7407875555e5e98d7343a633bb73707bae6c6a5f37c90014077875"
url: "https://pub.dev"
source: hosted
version: "19.5.0"
flutter_local_notifications_linux:
dependency: transitive
description:
name: flutter_local_notifications_linux
sha256: e3c277b2daab8e36ac5a6820536668d07e83851aeeb79c446e525a70710770a5
url: "https://pub.dev"
source: hosted
version: "6.0.0"
flutter_local_notifications_platform_interface:
dependency: transitive
description:
name: flutter_local_notifications_platform_interface
sha256: "277d25d960c15674ce78ca97f57d0bae2ee401c844b6ac80fcd972a9c99d09fe"
url: "https://pub.dev"
source: hosted
version: "9.1.0"
flutter_local_notifications_windows:
dependency: transitive
description:
name: flutter_local_notifications_windows
sha256: "8d658f0d367c48bd420e7cf2d26655e2d1130147bca1eea917e576ca76668aaf"
url: "https://pub.dev"
source: hosted
version: "1.0.3"
flutter_localizations:
dependency: "direct main"
description: flutter
@@ -541,6 +581,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.0"
open_filex:
dependency: "direct main"
description:
name: open_filex
sha256: "9976da61b6a72302cf3b1efbce259200cd40232643a467aac7370addf94d6900"
url: "https://pub.dev"
source: hosted
version: "4.7.0"
package_info_plus:
dependency: "direct main"
description:
@@ -874,6 +922,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.7.6"
timezone:
dependency: transitive
description:
name: timezone
sha256: dd14a3b83cfd7cb19e7888f1cbc20f258b8d71b54c06f79ac585f14093a287d1
url: "https://pub.dev"
source: hosted
version: "0.10.1"
typed_data:
dependency: transitive
description:

View File

@@ -61,6 +61,8 @@ dependencies:
device_info_plus: ^11.3.0
showcaseview: ^2.0.3
package_info_plus: ^4.2.0
flutter_local_notifications: ^19.5.0
open_filex: ^4.7.0
# jailbreak_root_detection: "^1.1.6"

View File

@@ -11,6 +11,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST
flutter_local_notifications_windows
)
set(PLUGIN_BUNDLED_LIBRARIES)