Download notification created and Profile added in quick links
This commit is contained in:
@@ -34,6 +34,7 @@ android {
|
|||||||
ndkVersion "27.0.12077973"
|
ndkVersion "27.0.12077973"
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
|
coreLibraryDesugaringEnabled true
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
}
|
}
|
||||||
@@ -80,4 +81,6 @@ flutter {
|
|||||||
source '../..'
|
source '../..'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {}
|
dependencies {
|
||||||
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
|
||||||
|
}
|
||||||
|
|||||||
BIN
android/app/src/main/res/drawable/notification_icon.png
Normal file
BIN
android/app/src/main/res/drawable/notification_icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 90 KiB |
@@ -13,6 +13,8 @@ import 'package:permission_handler/permission_handler.dart';
|
|||||||
import 'package:device_info_plus/device_info_plus.dart';
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:share_plus/share_plus.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';
|
import 'package:kmobile/data/models/user.dart';
|
||||||
|
|
||||||
@@ -38,13 +40,50 @@ class _AccountStatementScreen extends State<AccountStatementScreen> {
|
|||||||
List<Transaction> _transactions = [];
|
List<Transaction> _transactions = [];
|
||||||
final _minAmountController = TextEditingController();
|
final _minAmountController = TextEditingController();
|
||||||
final _maxAmountController = TextEditingController();
|
final _maxAmountController = TextEditingController();
|
||||||
//Future<Map<String, dynamic>?>? accountStatementsFuture;
|
late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
selectedUser = widget.users[widget.selectedIndex];
|
selectedUser = widget.users[widget.selectedIndex];
|
||||||
_loadTransactions();
|
_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 {
|
Future<void> _loadTransactions() async {
|
||||||
@@ -413,7 +452,6 @@ class _AccountStatementScreen extends State<AccountStatementScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _exportToPdf() async {
|
Future<void> _exportToPdf() async {
|
||||||
// Step 1: Check if there are any transactions to export.
|
|
||||||
if (_transactions.isEmpty) {
|
if (_transactions.isEmpty) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
@@ -425,6 +463,27 @@ class _AccountStatementScreen extends State<AccountStatementScreen> {
|
|||||||
return;
|
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 logo = await rootBundle.load('assets/images/logo.png');
|
||||||
var rubik = await rootBundle.load("assets/fonts/Rubik-Regular.ttf");
|
var rubik = await rootBundle.load("assets/fonts/Rubik-Regular.ttf");
|
||||||
final pdf = pw.Document();
|
final pdf = pw.Document();
|
||||||
@@ -527,64 +586,81 @@ class _AccountStatementScreen extends State<AccountStatementScreen> {
|
|||||||
);
|
);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
//Logic For all platforms
|
|
||||||
try {
|
try {
|
||||||
final Uint8List pdfBytes = await pdf.save();
|
final Uint8List pdfBytes = await pdf.save();
|
||||||
final String timestamp = DateTime.now().millisecondsSinceEpoch.toString();
|
final String timestamp = DateTime.now().millisecondsSinceEpoch.toString();
|
||||||
final String fileName = 'account_statement_$timestamp.pdf';
|
final String fileName = 'account_statement_$timestamp.pdf';
|
||||||
|
|
||||||
// For Android
|
String? filePath;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (Platform.isAndroid) {
|
||||||
final directory = Directory('/storage/emulated/0/Download');
|
final directory = Directory('/storage/emulated/0/Download');
|
||||||
|
if (!await directory.exists()) {
|
||||||
|
await directory.create(recursive: true);
|
||||||
|
}
|
||||||
final file = File('${directory.path}/$fileName');
|
final file = File('${directory.path}/$fileName');
|
||||||
await file.writeAsBytes(pdfBytes);
|
await file.writeAsBytes(pdfBytes);
|
||||||
|
filePath = file.path;
|
||||||
if (mounted) {
|
} else if (Platform.isIOS) {
|
||||||
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.
|
|
||||||
final tempDir = await getTemporaryDirectory();
|
final tempDir = await getTemporaryDirectory();
|
||||||
final file = await File('${tempDir.path}/$fileName').create();
|
final file = await File('${tempDir.path}/$fileName').create();
|
||||||
await file.writeAsBytes(pdfBytes);
|
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
|
// Update notification to download complete
|
||||||
await Share.shareXFiles(
|
await flutterLocalNotificationsPlugin.show(
|
||||||
[XFile(file.path)],
|
0,
|
||||||
);
|
'PDF Download Complete',
|
||||||
}
|
'Your account statement has been saved.',
|
||||||
} catch (e) {
|
const NotificationDetails(
|
||||||
if (mounted) {
|
android: AndroidNotificationDetails(
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
'download_channel',
|
||||||
SnackBar(
|
'Download Notifications',
|
||||||
content: Text('Error saving PDF: $e'),
|
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',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -388,6 +388,21 @@ class _DashboardScreenState extends State<DashboardScreen>
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(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>(
|
return BlocListener<AuthCubit, AuthState>(
|
||||||
listener: (context, state) async {
|
listener: (context, state) async {
|
||||||
if (state is Authenticated && !_biometricPromptShown) {
|
if (state is Authenticated && !_biometricPromptShown) {
|
||||||
@@ -429,21 +444,7 @@ class _DashboardScreenState extends State<DashboardScreen>
|
|||||||
child: InkWell(
|
child: InkWell(
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
onTap: () {
|
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(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
@@ -677,18 +678,21 @@ class _DashboardScreenState extends State<DashboardScreen>
|
|||||||
const EnquiryScreen()));
|
const EnquiryScreen()));
|
||||||
}),
|
}),
|
||||||
_buildQuickLink(
|
_buildQuickLink(
|
||||||
Symbols.checkbook,
|
Symbols.person,
|
||||||
AppLocalizations.of(context).chequeManagement,
|
AppLocalizations.of(context).profile,
|
||||||
() {
|
() {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) =>
|
builder: (context) =>
|
||||||
const ChequeManagementScreen(),
|
ProfileScreen(
|
||||||
),
|
mobileNumber: mobileNumberToPass,
|
||||||
|
customerNo: customerNo,
|
||||||
|
customerName: customerName),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
disable: true,
|
disable: false,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import FlutterMacOS
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
import device_info_plus
|
import device_info_plus
|
||||||
|
import flutter_local_notifications
|
||||||
import flutter_secure_storage_macos
|
import flutter_secure_storage_macos
|
||||||
import local_auth_darwin
|
import local_auth_darwin
|
||||||
import package_info_plus
|
import package_info_plus
|
||||||
@@ -16,6 +17,7 @@ import url_launcher_macos
|
|||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||||
|
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
|
||||||
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
||||||
FLALocalAuthPlugin.register(with: registry.registrar(forPlugin: "FLALocalAuthPlugin"))
|
FLALocalAuthPlugin.register(with: registry.registrar(forPlugin: "FLALocalAuthPlugin"))
|
||||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||||
|
|||||||
56
pubspec.lock
56
pubspec.lock
@@ -137,6 +137,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.8"
|
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:
|
device_info_plus:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -238,6 +246,38 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.2"
|
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:
|
flutter_localizations:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
@@ -541,6 +581,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
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:
|
package_info_plus:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -874,6 +922,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.6"
|
version: "0.7.6"
|
||||||
|
timezone:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: timezone
|
||||||
|
sha256: dd14a3b83cfd7cb19e7888f1cbc20f258b8d71b54c06f79ac585f14093a287d1
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.10.1"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -61,6 +61,8 @@ dependencies:
|
|||||||
device_info_plus: ^11.3.0
|
device_info_plus: ^11.3.0
|
||||||
showcaseview: ^2.0.3
|
showcaseview: ^2.0.3
|
||||||
package_info_plus: ^4.2.0
|
package_info_plus: ^4.2.0
|
||||||
|
flutter_local_notifications: ^19.5.0
|
||||||
|
open_filex: ^4.7.0
|
||||||
# jailbreak_root_detection: "^1.1.6"
|
# jailbreak_root_detection: "^1.1.6"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
|||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
flutter_local_notifications_windows
|
||||||
)
|
)
|
||||||
|
|
||||||
set(PLUGIN_BUNDLED_LIBRARIES)
|
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||||
|
|||||||
Reference in New Issue
Block a user