policy validation

This commit is contained in:
Surendiran 2025-12-12 16:59:08 +05:30
parent 3477cd99f3
commit fd64c2ef6c
18 changed files with 1272 additions and 216 deletions

File diff suppressed because one or more lines are too long

View File

@ -36,6 +36,7 @@ import '../../presentation/screens/staff/Enquiry/enquiry_list.dart';
import '../../presentation/screens/staff/Enquiry/staff_policy.dart';
import '../../presentation/screens/staff/policy/policy.dart';
import '../../presentation/screens/staff/policy/policy_list.dart';
import '../../presentation/screens/staff/policy/policy_validation.dart';
import '../../presentation/screens/staff/quotations/quotation.dart';
final GoRouter appRouter = GoRouter(
@ -185,6 +186,39 @@ final GoRouter appRouter = GoRouter(
path: AppRoutes.policylist,
builder: (context, state) => const policylist(),
),
GoRoute(
path: AppRoutes.policyValidation,
name: "policyValidation",
pageBuilder: (context, state) {
final item = state.extra;
return CustomTransitionPage(
key: state.pageKey,
opaque: true, // required for open animation
barrierColor: Colors.black.withOpacity(0.3), // optional dim background
fullscreenDialog: true,
transitionDuration: const Duration(milliseconds: 1000),
child: policyValidation(item: item),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
final curved = CurvedAnimation(
parent: animation,
curve: Curves.easeOutCubic,
);
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(0, 1), // slide from bottom
end: Offset.zero,
).animate(curved),
child: child,
);
},
);
},
),
GoRoute(
path: AppRoutes.quotation,

View File

@ -21,6 +21,7 @@ class AppRoutes {
static const String claimlist = '/claimList';
static const String endosement = '/endosement';
static const String policylist = '/policylist';
static const String policyValidation = '/policyValidation';
static const String quotation = '/QuotationScreen';
static const String policy = '/PolicyScreen';
static const String policyStaffEnq = '/policyStaffEnq';

View File

@ -35,10 +35,8 @@ class ApiService {
context.go(AppRoutes.login);
}
Future<Map<String, dynamic>> _makeGetRequest(
Uri url,
Map<String, String> headers,
) async {
Future<Map<String, dynamic>> _makeGetRequest(Uri url,
Map<String, String> headers,) async {
final response = await http.get(url, headers: headers);
return _handleResponse(response);
}
@ -60,10 +58,8 @@ class ApiService {
// }
// }
Future<http.Response> _makeGethttpRequest(
Uri url,
Map<String, String> headers,
) async {
Future<http.Response> _makeGethttpRequest(Uri url,
Map<String, String> headers,) async {
final response = await http.get(url, headers: headers);
if (response.statusCode == 200) {
@ -77,11 +73,9 @@ class ApiService {
}
}
Future<Map<String, dynamic>> _makePostRequestJson(
Uri url,
Map<String, dynamic> body,
Map<String, String> headers,
) async {
Future<Map<String, dynamic>> _makePostRequestJson(Uri url,
Map<String, dynamic> body,
Map<String, String> headers,) async {
final response = await http.post(
url,
headers: headers,
@ -89,6 +83,7 @@ class ApiService {
);
return _handleResponse(response);
}
// --------------------------- COMMON FILES __________________________________________
Future<Map<String, dynamic>> createUserData(data, path) async {
@ -156,10 +151,8 @@ class ApiService {
}
}
Future<Map<String, dynamic>> CheckDuplicate(
BuildContext context,
String value,
) async {
Future<Map<String, dynamic>> CheckDuplicate(BuildContext context,
String value,) async {
if (_token == null) {
await _initializeToken();
}
@ -200,7 +193,8 @@ class ApiService {
return {};
} else {
throw Exception(
'Failed to load checkDuplicate data. Status code: ${response.statusCode}',
'Failed to load checkDuplicate data. Status code: ${response
.statusCode}',
);
}
}
@ -294,11 +288,9 @@ class ApiService {
return fallback;
}
Future<void> getPdfDownload(
// BuildContext context,
String path,
String id,
) async {
Future<void> getPdfDownload(// BuildContext context,
String path,
String id,) async {
print('getPdfDownload 1 - $path');
// if (path.isEmpty) {
@ -352,7 +344,9 @@ class ApiService {
final contentDisp = response.headers['content-disposition'];
print('getPdfDownloadcontentDisp $contentDisp');
String fileName = extractFileName(contentDisp, path.split('/').last);
String fileName = extractFileName(contentDisp, path
.split('/')
.last);
print('Resolved fileName: $fileName');
final anchor = html.AnchorElement(href: blobUrl)
..setAttribute('download', fileName)
@ -363,15 +357,16 @@ class ApiService {
} else if (response.statusCode == 404) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('File not found.'),
actions: [
TextButton(
child: const Text('OK'),
onPressed: () => Navigator.of(context).pop(),
builder: (context) =>
AlertDialog(
title: const Text('File not found.'),
actions: [
TextButton(
child: const Text('OK'),
onPressed: () => Navigator.of(context).pop(),
),
],
),
],
),
);
} else if (response.statusCode == 403) {
await clearLocalStorageAndRedirect();
@ -455,12 +450,10 @@ class ApiService {
return response;
}
Future<Map<String, dynamic>> updateStatusMasters(
id,
status,
masterName,
userId,
) async {
Future<Map<String, dynamic>> updateStatusMasters(id,
status,
masterName,
userId,) async {
print('updateStatusMaster $id $status $masterName $userId');
final Map<String, dynamic> data = {
"is_active": int.parse(status),
@ -506,7 +499,8 @@ class ApiService {
url = Uri.parse('${Env.apiUrl}dashboard/managerDashboard?manager_id=$id');
} else if (role == 'handler') {
url = Uri.parse(
'${Env.apiUrl}dashboard/handlerDashboard?manager_id=$id&handler_id=$userId',
'${Env
.apiUrl}dashboard/handlerDashboard?manager_id=$id&handler_id=$userId',
);
} else if (role == 'staff') {
url = Uri.parse('${Env.apiUrl}dashboard/staffDashboard?staff_id=$userId');
@ -724,12 +718,11 @@ class ApiService {
final response = await _makeGetRequest(url, headers);
return response;
}
// ------------------------------------ SALES EXECUTIVE -----------------------------------------------------
Future<Map<String, dynamic>> fetchSalesExecutiveList(
int managerId,
role,
) async {
Future<Map<String, dynamic>> fetchSalesExecutiveList(int managerId,
role,) async {
// print(_token);
print('rolemanagerId - $managerId');
@ -810,15 +803,14 @@ class ApiService {
return response;
}
Future<Map<String, dynamic>> fetchEnquiryList(
int managerid,
int id,
String role, {
String? fromDate,
String? toDate,
String? selectedStatus,
String? selectedStaffId,
}) async {
Future<Map<String, dynamic>> fetchEnquiryList(int managerid,
int id,
String role, {
String? fromDate,
String? toDate,
String? selectedStatus,
String? selectedStaffId,
}) async {
print("selectedStatusselectedStatus - $selectedStatus");
if (_token == null) {
await _initializeToken();
@ -846,12 +838,15 @@ class ApiService {
if (role == 'staff') {
url = Uri.parse(
'${Env.apiUrl}enquiry/enquiryList?$query&from_date=${fromDate ?? ''}&to_date=${toDate ?? ''}&enquiry_status=$selectedStatus',
'${Env.apiUrl}enquiry/enquiryList?$query&from_date=${fromDate ??
''}&to_date=${toDate ?? ''}&enquiry_status=$selectedStatus',
// '${Env.apiUrl}enquiry/enquiryList?$query&from_date=${fromDate ?? ''}&to_date=${toDate ?? ''}&status=$selectedStatus',
);
} else {
url = Uri.parse(
'${Env.apiUrl}enquiry/enquiryList?$query&from_date=${fromDate ?? ''}&to_date=${toDate ?? ''}&enquiry_status=$selectedStatus&staff_id=$selectedStaffId',
'${Env.apiUrl}enquiry/enquiryList?$query&from_date=${fromDate ??
''}&to_date=${toDate ??
''}&enquiry_status=$selectedStatus&staff_id=$selectedStaffId',
// '${Env.apiUrl}enquiry/enquiryList?$query&from_date=${fromDate ?? ''}&to_date=${toDate ?? ''}&status=$selectedStatus&staff_id=$selectedStaffId',
);
}
@ -880,7 +875,8 @@ class ApiService {
// }
final url = Uri.parse(
'${Env.apiUrl}staff/monthlyLoginCount?month=${month ?? ''}&manager_id=$mangerId',
'${Env.apiUrl}staff/monthlyLoginCount?month=${month ??
''}&manager_id=$mangerId',
);
final headers = {
@ -995,6 +991,7 @@ class ApiService {
final response = await _makeGetRequest(url, headers);
return response;
}
//------------------------------------ Quotation ------------------------------------------------
Future<Map<String, dynamic>> fetchQuickQuotationList(int managerId) async {
@ -1051,14 +1048,13 @@ class ApiService {
// ----------------------------------- POLICY -------------------------------------------------
Future<Map<String, dynamic>> fetchPolicyList(
int id,
role, {
String? fromDate,
String? toDate,
String? selectedStatus,
String? selectedStaffId,
}) async {
Future<Map<String, dynamic>> fetchPolicyList(int id,
role, {
String? fromDate,
String? toDate,
String? selectedStatus,
String? selectedStaffId,
}) async {
// print(_token);
if (_token == null) {
await _initializeToken();
@ -1082,11 +1078,14 @@ class ApiService {
if (role == 'staff') {
url = Uri.parse(
'${Env.apiUrl}enquiry/enquiryList?$query&from_date=${fromDate ?? ''}&to_date=${toDate ?? ''}&status=$selectedStatus',
'${Env.apiUrl}enquiry/enquiryList?$query&from_date=${fromDate ??
''}&to_date=${toDate ?? ''}&status=$selectedStatus',
);
} else {
url = Uri.parse(
'${Env.apiUrl}enquiry/enquiryList?$query&from_date=${fromDate ?? ''}&to_date=${toDate ?? ''}&status=$selectedStatus&staff_id=$selectedStaffId',
'${Env.apiUrl}enquiry/enquiryList?$query&from_date=${fromDate ??
''}&to_date=${toDate ??
''}&status=$selectedStatus&staff_id=$selectedStaffId',
);
}
@ -1109,13 +1108,12 @@ class ApiService {
return response;
}
Future<Map<String, dynamic>> fetchPolicyDataOnlyList(
dynamic id,
role, {
String? fromDate,
String? toDate,
String? selectedStaffId,
}) async {
Future<Map<String, dynamic>> fetchPolicyDataOnlyList(dynamic id,
role, {
String? fromDate,
String? toDate,
String? selectedStaffId,
}) async {
// print(_token);
if (_token == null) {
await _initializeToken();
@ -1136,7 +1134,9 @@ class ApiService {
}
final url = Uri.parse(
'${Env.apiUrl}enquiry/enquiryList?$query&only_policy_data=true&from_date=${fromDate ?? ''}&to_date=${toDate ?? ''}&staff_id=$selectedStaffId',
'${Env
.apiUrl}enquiry/enquiryList?$query&only_policy_data=true&from_date=${fromDate ??
''}&to_date=${toDate ?? ''}&staff_id=$selectedStaffId',
);
// if (role == 'manager') {
@ -1323,10 +1323,8 @@ class ApiService {
return response;
}
Future<Map<String, dynamic>> fetchStaffListForEnquiryAssignDropDown(
id,
role,
) async {
Future<Map<String, dynamic>> fetchStaffListForEnquiryAssignDropDown(id,
role,) async {
print('fetchHandlerNameDropDown');
if (_token == null) {
await _initializeToken();
@ -1422,10 +1420,8 @@ class ApiService {
}
// Update enquiry
static Future<EnquiryModel> updateEnquiry(
String id,
EnquiryModel enquiry,
) async {
static Future<EnquiryModel> updateEnquiry(String id,
EnquiryModel enquiry,) async {
try {
final response = await http.put(
Uri.parse('$_baseUrl/api/enquiries/$id'),
@ -1570,4 +1566,62 @@ class ApiService {
final response = await _makeGetRequest(url, headers);
return response;
}
Future<Map<String, dynamic>> findPolicyApi(ID) async {
// print(_token);
if (_token == null) {
await _initializeToken();
}
final url = Uri.parse('${Env.apiUrl}policy/findPolicy?id=$ID');
final headers = {
'Authorization': 'Bearer $_token' ?? '',
'app-signature': Env.App_Signature,
};
final response = await _makeGetRequest(url, headers);
return response;
}
Future<Map<String, dynamic>> policyFilePathApi(ID, file_type) async {
// print(_token);
if (_token == null) {
await _initializeToken();
}
final url = Uri.parse('${Env
.apiUrl}policy/PolicyFilePath?policy_id=$ID&file_type=$file_type');
final headers = {
'Authorization': 'Bearer $_token' ?? '',
'app-signature': Env.App_Signature,
};
final response = await _makeGetRequest(url, headers);
return response;
}
Future<Map<String, dynamic>> updatePolicyApi(data) async {
final url = Uri.parse('${Env.apiUrl}policy/updatePolicy');
// final token = await getToken(); // Fetch token
if (_token == null) {
throw Exception('Token not found. Please log in.');
}
print("data------- $data}");
final headers = {
'Authorization': 'Bearer $_token',
'Content-Type': 'application/json',
'app-signature': Env.App_Signature,
// 'app-signature': 'nhance-partner-2025-signature-35468846JRhH551HK',
};
final response = await _makePostRequestJson(url, data, headers);
return response;
}
}

View File

@ -257,7 +257,7 @@ class _AppHeaderState extends ConsumerState<AppHeader> {
Spacer(),
// Dashboard
if (roleId != 'staff' && role != 'admin') ...[
if (roleId != 'staff' && role != 'Accounts') ...[
_buildMenuItem(
icon: Icons.dashboard,
label: "Dashboard",
@ -274,7 +274,7 @@ class _AppHeaderState extends ConsumerState<AppHeader> {
],
// Enquiry
if (role != 'admin') ...[
if (role != 'Accounts') ...[
_buildMenuItem(
icon: Icons.list_alt_rounded,
label: "Enquiry",
@ -295,7 +295,7 @@ class _AppHeaderState extends ConsumerState<AppHeader> {
const SizedBox(width: 8),
// User (Manager Only) - with hover popup
if (roleId == 'manager' || role == 'admin') ...[
if (roleId == 'manager' || role == 'Accounts') ...[
_buildHoverMenuItem(
icon: Icons.person_add_alt,
label: "User",
@ -327,8 +327,8 @@ class _AppHeaderState extends ConsumerState<AppHeader> {
const SizedBox(width: 8),
],
// Pay Out button for admin
if (role == 'admin') ...[
// Pay Out button for Accounts
if (role == 'Accounts') ...[
_buildMenuItem(
isActive: _activeMenu == 'Pay Out',
icon: Icons.checklist_outlined,

View File

@ -140,7 +140,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
} else if (roleId.toString() == "3") {
role = "staff";
} else if (roleId.toString() == "4") {
role = "admin";
role = "Accounts";
} else {
role = "agent"; // fallback if unexpected value
}
@ -343,7 +343,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
if (userRole == 'staff') {
context.go(AppRoutes.enquiryForStaff);
} else if (userRole == 'admin') {
} else if (userRole == 'Accounts') {
context.go(AppRoutes.payout);
} else {
context.go(AppRoutes.dashboard);

View File

@ -44,88 +44,7 @@ class _PayOutScreenState extends ConsumerState<PayOutScreen> {
// --------------------------
// Sample Data (replace with API later)
// --------------------------
final List<Map<String, dynamic>> allPolicies = [
{
'id': 1,
'policyNo': 'POL456578798',
'customer': 'Ram',
'agentId': 1,
'brokerId': 1,
'premium': 1500,
'commission': 450,
'date': '2025-10-01',
},
{
'id': 2,
'policyNo': 'POL456578799',
'customer': 'Shyam',
'agentId': 1,
'brokerId': 1,
'premium': 2000,
'commission': 600,
'date': '2025-10-02',
},
{
'id': 3,
'policyNo': 'POL456578800',
'customer': 'Mohan',
'agentId': 1,
'brokerId': 2,
'premium': 3000,
'commission': 900,
'date': '2025-10-03',
},
{
'id': 4,
'policyNo': 'POL98765',
'customer': 'Kumar',
'agentId': 1,
'brokerId': 2,
'premium': 15000,
'commission': 3500,
'date': '2025-10-04',
},
{
'id': 5,
'policyNo': 'POL98766',
'customer': 'Vijay',
'agentId': 1,
'brokerId': 3,
'premium': 5000,
'commission': 1250,
'date': '2025-10-05',
},
{
'id': 6,
'policyNo': 'POL98767',
'customer': 'Ajay',
'agentId': 1,
'brokerId': 3,
'premium': 7500,
'commission': 1875,
'date': '2025-10-06',
},
{
'id': 7,
'policyNo': 'POL98768',
'customer': 'Ravi',
'agentId': 2,
'brokerId': 4,
'premium': 4000,
'commission': 1000,
'date': '2025-10-07',
},
{
'id': 8,
'policyNo': 'POL98769',
'customer': 'Prakash',
'agentId': 2,
'brokerId': 4,
'premium': 6000,
'commission': 1500,
'date': '2025-10-08',
},
];
final List<Map<String, dynamic>> allPolicies = [];
List<Map<String, dynamic>> filteredPolicies = [];
Set<int> selectedPolicies = {};

View File

@ -0,0 +1,7 @@
import 'dart:typed_data';
import 'package:http/http.dart' as http;
Future<Uint8List> loadNetworkPdfBytes(String url) async {
final response = await http.get(Uri.parse(url));
return response.bodyBytes;
}

View File

@ -218,43 +218,32 @@ class policylistState extends ConsumerState<policylist> {
void filterData(String query) {
print("FilterDAta - $query");
final lowerQuery = query.toLowerCase();
setState(() {
filteredData = getStaffData.where((item) {
// final isActiveStatus = item['is_active'] == "1" ? "active" : "inactive";
return (item['agent_name'] ?? '-').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['reg_no'] ?? '-').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['insurer_name'] ?? '-').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['insurer_short_name'] ?? '-').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['assigned_to_name'] ?? '-').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['insured_name'] ?? '-').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['premium_amount'] ?? '-').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['payment_mode_value'] ?? '-').toLowerCase().contains(
query.toLowerCase(),
) ||
(_formatDate(item['updated_on']) ?? '-').toLowerCase().contains(
query.toLowerCase(),
) ||
(item['policy_number'] ?? '-').toLowerCase().contains(
query.toLowerCase(),
)
// ||
// (item['status'] ?? '-').toLowerCase().contains(query.toLowerCase());
;
// Compute UI status text
final accuracyText =
item['is_data_accuracy_checked'] == '1'
? 'Verified'
: 'Click to Verify';
return
(item['agent_name'] ?? '-').toLowerCase().contains(lowerQuery) ||
(item['reg_no'] ?? '-').toLowerCase().contains(lowerQuery) ||
(item['insurer_name'] ?? '-').toLowerCase().contains(lowerQuery) ||
(item['insurer_short_name'] ?? '-').toLowerCase().contains(lowerQuery) ||
(item['assigned_to_name'] ?? '-').toLowerCase().contains(lowerQuery) ||
(item['insured_name'] ?? '-').toLowerCase().contains(lowerQuery) ||
(item['premium_amount'] ?? '-').toLowerCase().contains(lowerQuery) ||
(item['payment_mode_value'] ?? '-').toLowerCase().contains(lowerQuery) ||
(_formatDate(item['updated_on']) ?? '-').toLowerCase().contains(lowerQuery) ||
(item['policy_number'] ?? '-').toLowerCase().contains(lowerQuery) ||
// NEW CONDITIONS for search
accuracyText.toLowerCase().contains(lowerQuery);
}).toList();
});
}
@ -513,6 +502,10 @@ class policylistState extends ConsumerState<policylist> {
flex: 3,
child: Text('Policy Number', style: _headerStyle),
),
Expanded(
flex: 2,
child: Text('BDS Pushed', style: _headerStyle),
),
Expanded(flex: 2, child: Text('Action', style: _headerStyle)),
],
@ -684,6 +677,15 @@ class policylistState extends ConsumerState<policylist> {
maxLines: 3,
),
),
Expanded(
flex: 2,
child: Text(
item['is_bds_pushed'] == '1' ? 'Yes' : 'No',
style: _dataBold,
softWrap: true,
maxLines: 3,
),
),
Expanded(
flex: 2,
child: Row(
@ -729,6 +731,54 @@ class policylistState extends ConsumerState<policylist> {
],
),
),
if (roleId == 'Accounts') ...[
const SizedBox(width: 5),
Tooltip(
message: '',
child: InkWell(
onTap: () {
context.push(
AppRoutes.policyValidation,
extra: item,
);
},
child: Container(
width: 110, // FIXED WIDTH Equal in both states
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: item['is_data_accuracy_checked'] == '1'
? const Color(0xFF2E7D6E)
: Colors.redAccent,
borderRadius: BorderRadius.circular(5),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center, // Center content
children: [
Icon(
item['is_data_accuracy_checked'] == '1'
? Icons.check_circle
: Icons.error,
size: 12,
color: Colors.white,
),
const SizedBox(width: 4),
Text(
item['is_data_accuracy_checked'] == '1'
? 'Verified'
: 'Click to Verify',
style: const TextStyle(
color: Colors.white,
fontSize: 10,
fontWeight: FontWeight.w500,
),
),
],
),
),
),
),
]
],
),
),
@ -953,3 +1003,4 @@ class policylistState extends ConsumerState<policylist> {
fontSize: 12,
);
}

View File

@ -0,0 +1,852 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:http/http.dart' as http;
import 'package:pdf_render/pdf_render_widgets.dart';
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';
import '../../../../core/config/env.dart';
import '../../../../core/services/api_service.dart';
import '../../../../data/utils/toastNotification.dart';
import '../../../providers/manager_provider.dart';
import 'loadNetworkPdfBytes.dart';
import 'dart:typed_data';
// /// Represents Homepage for Navigation
// class policyValidation extends ConsumerStatefulWidget {
// final dynamic item;
// const policyValidation({Key? key, this.item}) : super(key: key);
//
// @override
// ConsumerState<policyValidation> createState() => _policyValidationState();
// }
//
// class _policyValidationState extends ConsumerState<policyValidation> {
// final GlobalKey<SfPdfViewerState> _pdfViewerKey = GlobalKey();
//
// @override
// void initState() {
// super.initState();
// }
//
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// appBar: AppBar(
// title: const Text('Syncfusion Flutter PDF Viewer'),
// actions: <Widget>[
// IconButton(
// icon: const Icon(
// Icons.bookmark,
// color: Colors.white,
// semanticLabel: 'Bookmark',
// ),
// onPressed: () {
// _pdfViewerKey.currentState?.openBookmarkView();
// },
// ),
// ],
// ),
// body: SfPdfViewer.asset(
// 'assets/pdfs/sample.pdf',
// key: _pdfViewerKey,
// )
// );
// }
// }
class policyValidation extends ConsumerStatefulWidget {
final dynamic item;
const policyValidation({Key? key, this.item}) : super(key: key);
@override
ConsumerState<policyValidation> createState() => _policyValidationState();
}
class _policyValidationState extends ConsumerState<policyValidation> {
// --- Api / state
late ApiService apiService;
bool isLoading = false;
dynamic managerId;
dynamic userId;
String? pdfUrl; // full file path from API
// --- Controllers (all editable fields)
late TextEditingController policyNumberController;
late TextEditingController insuredNameController;
late TextEditingController premiumController;
late TextEditingController remarksController;
late TextEditingController rcNoController;
late TextEditingController issuedDateController;
late TextEditingController startDateController;
late TextEditingController endDateController;
late TextEditingController tpController;
late TextEditingController odController;
late TextEditingController paController;
late TextEditingController cgstController;
late TextEditingController sgstController;
late TextEditingController igstController;
late TextEditingController rtoStateCodeController;
late TextEditingController rtoCityCodeController;
late TextEditingController weightController;
late TextEditingController fuelTypeController;
late TextEditingController registrationDateController;
late TextEditingController yomController;
late TextEditingController engineNoController;
late TextEditingController chassisNoController;
late TextEditingController makeController;
late TextEditingController modelController;
late TextEditingController cubicCapacityController;
late TextEditingController vehicleTypeController;
late TextEditingController brokerNameController;
late TextEditingController commissionAmountController;
final GlobalKey<SfPdfViewerState> _pdfViewerKey = GlobalKey();
@override
void initState() {
super.initState();
apiService = ApiService();
// instantiate controllers with defaults
policyNumberController = TextEditingController();
insuredNameController = TextEditingController();
premiumController = TextEditingController();
remarksController = TextEditingController();
rcNoController = TextEditingController();
issuedDateController = TextEditingController();
startDateController = TextEditingController();
endDateController = TextEditingController();
tpController = TextEditingController();
odController = TextEditingController();
paController = TextEditingController();
cgstController = TextEditingController();
sgstController = TextEditingController();
igstController = TextEditingController();
rtoStateCodeController = TextEditingController();
rtoCityCodeController = TextEditingController();
weightController = TextEditingController();
fuelTypeController = TextEditingController();
registrationDateController = TextEditingController();
yomController = TextEditingController();
engineNoController = TextEditingController();
chassisNoController = TextEditingController();
makeController = TextEditingController();
modelController = TextEditingController();
cubicCapacityController = TextEditingController();
vehicleTypeController = TextEditingController();
brokerNameController = TextEditingController();
commissionAmountController = TextEditingController();
// Pre-fill controllers from initial `widget.item` (if available)
final item = widget.item as Map<String, dynamic>? ?? {};
policyNumberController.text = item['policy_number']?.toString() ?? '';
insuredNameController.text = item['insured_name']?.toString() ?? '';
premiumController.text = item['premium_amount']?.toString() ?? '';
remarksController.text = item['remarks']?.toString() ?? '';
rcNoController.text = item['rc_no']?.toString() ?? '';
issuedDateController.text = item['issued_date']?.toString() ?? '';
startDateController.text = item['start_date']?.toString() ?? '';
endDateController.text = item['end_date']?.toString() ?? '';
tpController.text = item['tp']?.toString() ?? '';
odController.text = item['od']?.toString() ?? '';
paController.text = item['pa']?.toString() ?? '';
cgstController.text = item['cgst']?.toString() ?? '';
sgstController.text = item['sgst']?.toString() ?? '';
igstController.text = item['igst']?.toString() ?? '';
rtoStateCodeController.text = item['rto_state_code']?.toString() ?? '';
rtoCityCodeController.text = item['rto_city_code']?.toString() ?? '';
weightController.text = item['weight']?.toString() ?? '';
fuelTypeController.text = item['fuel_type']?.toString() ?? '';
registrationDateController.text = item['date_of_registration']?.toString() ?? '';
yomController.text = item['year_of_manufacture']?.toString() ?? '';
engineNoController.text = item['engine_no']?.toString() ?? '';
chassisNoController.text = item['chassis_no']?.toString() ?? '';
makeController.text = item['make']?.toString() ?? '';
modelController.text = item['model']?.toString() ?? '';
cubicCapacityController.text = item['cubic_capacity']?.toString() ?? '';
vehicleTypeController.text = item['vehicle_type']?.toString() ?? '';
brokerNameController.text = item['broker_name']?.toString() ?? '';
commissionAmountController.text = item['commission_amount']?.toString() ?? '';
// read providers + call APIs
Future.microtask(() {
try {
managerId = ref.read(managerIdProvider);
} catch (e) {
managerId = null;
}
try {
userId = ref.read(userIdProvider);
} catch (e) {
userId = null;
}
getFindPolicy();
getPolicyFilePath();
});
}
@override
void dispose() {
policyNumberController.dispose();
insuredNameController.dispose();
premiumController.dispose();
remarksController.dispose();
rcNoController.dispose();
issuedDateController.dispose();
startDateController.dispose();
endDateController.dispose();
tpController.dispose();
odController.dispose();
paController.dispose();
cgstController.dispose();
sgstController.dispose();
igstController.dispose();
rtoStateCodeController.dispose();
rtoCityCodeController.dispose();
weightController.dispose();
fuelTypeController.dispose();
registrationDateController.dispose();
yomController.dispose();
engineNoController.dispose();
chassisNoController.dispose();
makeController.dispose();
modelController.dispose();
cubicCapacityController.dispose();
vehicleTypeController.dispose();
brokerNameController.dispose();
commissionAmountController.dispose();
super.dispose();
}
Future<void> getPolicyFilePath() async {
_pdfViewerKey.currentState?.openBookmarkView();
// 🔥 Use DIRECT FIXED URL you asked for
// const directPdfUrl = "https://venbait.in/nhance/mypdf.pdf";
//
// setState(() {
// pdfUrl = directPdfUrl;
// });
//
// debugPrint("FINAL PDF URL -> $pdfUrl");
final policyId = widget.item?['policy_id'];
if (policyId == null) {
debugPrint('policyValidation: policy id is null, skipping API call');
return;
}
if (!mounted) return;
setState(() => isLoading = true);
try {
final url = Uri.parse('${Env
.apiUrl}policy/PolicyFilePath?policy_id=$policyId&file_type=policy_pdf');
setState(() {
pdfUrl = "$url";
});
final response = await apiService.policyFilePathApi(policyId, 'policy_pdf');
debugPrint('policyFilePathApi response: $response');
if (response != null && response['status'] == 'success') {
// final filePath = response['data']?.toString();
//
// // The API returns a server absolute path like:
// // /home3/.../uploads/policy/policy_pdf/yourfile.pdf
// // You must convert it to a usable URL for web/mobile.
//
// if (filePath != null && filePath.isNotEmpty) {
// // EXAMPLE:
// // Build full URL based on your domain
// // final baseUrl = filePath;
// final baseUrl = "https://venbait.in/nhance/mypdf.pdf";
//
// final fileName = filePath.split('/').last;
//
// setState(() {
// pdfUrl = "$baseUrl$fileName";
// });
//
// debugPrint("FINAL PDF URL -> $pdfUrl");
// }
} else {
debugPrint('policyFilePathApi returned error: ${response?['message'] ?? 'unknown'}');
}
} catch (e, st) {
debugPrint('Exception in getPolicyFilePath: $e\n$st');
} finally {
if (!mounted) return;
setState(() => isLoading = false);
}
}
Future<void> getFindPolicy() async {
final policyId = widget.item?['policy_id'];
if (policyId == null) {
debugPrint('policyValidation: policy id is null, skipping API call');
return;
}
if (!mounted) return;
setState(() => isLoading = true);
try {
final response = await apiService.findPolicyApi(policyId);
debugPrint('findPolicyApi response: $response');
if (response != null && response['status'] == 'success') {
final data = (response['data'] ?? {}) as Map<String, dynamic>;
if (!mounted) return;
setState(() {
// update controllers (overwrite with authoritative API values)
policyNumberController.text = data['policy_number']?.toString() ?? policyNumberController.text;
insuredNameController.text = data['insured_name']?.toString() ?? insuredNameController.text;
premiumController.text = data['premium_amount']?.toString() ?? premiumController.text;
remarksController.text = data['remarks']?.toString() ?? remarksController.text;
rcNoController.text = data['rc_no']?.toString() ?? rcNoController.text;
issuedDateController.text = data['issued_date']?.toString() ?? issuedDateController.text;
startDateController.text = data['start_date']?.toString() ?? startDateController.text;
endDateController.text = data['end_date']?.toString() ?? endDateController.text;
tpController.text = data['tp']?.toString() ?? tpController.text;
odController.text = data['od']?.toString() ?? odController.text;
paController.text = data['pa']?.toString() ?? paController.text;
cgstController.text = data['cgst']?.toString() ?? cgstController.text;
sgstController.text = data['sgst']?.toString() ?? sgstController.text;
igstController.text = data['igst']?.toString() ?? igstController.text;
rtoStateCodeController.text = data['rto_state_code']?.toString() ?? rtoStateCodeController.text;
rtoCityCodeController.text = data['rto_city_code']?.toString() ?? rtoCityCodeController.text;
weightController.text = data['weight']?.toString() ?? weightController.text;
fuelTypeController.text = data['fuel_type']?.toString() ?? fuelTypeController.text;
registrationDateController.text = data['date_of_registration']?.toString() ?? registrationDateController.text;
yomController.text = data['year_of_manufacture']?.toString() ?? yomController.text;
engineNoController.text = data['engine_no']?.toString() ?? engineNoController.text;
chassisNoController.text = data['chassis_no']?.toString() ?? chassisNoController.text;
makeController.text = data['make']?.toString() ?? makeController.text;
modelController.text = data['model']?.toString() ?? modelController.text;
cubicCapacityController.text = data['cubic_capacity']?.toString() ?? cubicCapacityController.text;
vehicleTypeController.text = data['vehicle_type']?.toString() ?? vehicleTypeController.text;
brokerNameController.text = data['broker_name']?.toString() ?? brokerNameController.text;
commissionAmountController.text = data['commission_amount']?.toString() ?? commissionAmountController.text;
});
} else {
debugPrint('findPolicyApi returned error: ${response?['message'] ?? 'unknown'}');
}
} catch (e, st) {
debugPrint('Exception in getFindPolicy: $e\n$st');
} finally {
if (!mounted) return;
setState(() => isLoading = false);
}
}
Future<void> _pickDate(TextEditingController controller, BuildContext context) async {
DateTime initial = DateTime.now();
try {
if (controller.text.isNotEmpty) {
// try parse dd-MM-yyyy
final parts = controller.text.split('-');
if (parts.length == 3) {
final d = int.tryParse(parts[0]) ?? initial.day;
final m = int.tryParse(parts[1]) ?? initial.month;
final y = int.tryParse(parts[2]) ?? initial.year;
initial = DateTime(y, m, d);
}
}
} catch (_) {}
final picked = await showDatePicker(
context: context,
initialDate: initial,
firstDate: DateTime(1900),
lastDate: DateTime(2100),
);
if (picked != null) {
controller.text = "${picked.day.toString().padLeft(2,'0')}-${picked.month.toString().padLeft(2,'0')}-${picked.year}";
}
}
Future<void> _save() async {
final policyId = widget.item?['policy_id'];
if (policyId == null) {
ToastHelper.showWarningToast(context, 'Missing policy id');
return;
}
final payload = {
"id": policyId,
"rc_no": rcNoController.text,
"insured_name": insuredNameController.text,
"issued_date": issuedDateController.text,
"start_date": startDateController.text,
"end_date": endDateController.text,
"premium_amount": premiumController.text,
"policy_number": policyNumberController.text,
"tp": tpController.text.isEmpty ? null : tpController.text,
"od": odController.text.isEmpty ? null : odController.text,
"pa": paController.text.isEmpty ? null : paController.text,
"cgst": cgstController.text.isEmpty ? null : cgstController.text,
"sgst": sgstController.text.isEmpty ? null : sgstController.text,
"igst": igstController.text.isEmpty ? null : igstController.text,
"rto_state_code": rtoStateCodeController.text.isEmpty ? null : rtoStateCodeController.text,
"rto_city_code": rtoCityCodeController.text.isEmpty ? null : rtoCityCodeController.text,
"weight": weightController.text.isEmpty ? null : weightController.text,
"fuel_type": fuelTypeController.text.isEmpty ? null : fuelTypeController.text,
"date_of_registration": registrationDateController.text.isEmpty ? null : registrationDateController.text,
"year_of_manufacture": yomController.text.isEmpty ? null : yomController.text,
"engine_no": engineNoController.text.isEmpty ? null : engineNoController.text,
"chassis_no": chassisNoController.text.isEmpty ? null : chassisNoController.text,
"make": makeController.text.isEmpty ? null : makeController.text,
"model": modelController.text.isEmpty ? null : modelController.text,
"cubic_capacity": cubicCapacityController.text.isEmpty ? null : cubicCapacityController.text,
"vehicle_type": vehicleTypeController.text.isEmpty ? null : vehicleTypeController.text,
"broker_name": brokerNameController.text.isEmpty ? null : brokerNameController.text,
"commission_amount": commissionAmountController.text.isEmpty ? null : commissionAmountController.text,
"updated_by": userId
};
if (!mounted) return;
setState(() => isLoading = true);
try {
debugPrint('FINAL SAVE PAYLOAD => $payload');
final result = await apiService.updatePolicyApi(payload);
debugPrint('updatePolicy result => $result');
if (result != null && result['status'] == 'success') {
if (!mounted) return;
setState(() => isLoading = false);
context.pop();
ToastHelper.showSuccessToast(context, "Policy updated successfully");
} else {
if (!mounted) return;
setState(() => isLoading = false);
ToastHelper.showErrorToast(context, result?['message']?.toString() ?? 'Error updating policy');
}
} catch (e, st) {
debugPrint('Exception in updatePolicy: $e\n$st');
if (!mounted) return;
setState(() => isLoading = false);
ToastHelper.showWarningToast(context, 'Exception: $e');
}
}
Widget _sectionHeader(String title, {IconData icon = Icons.info}) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 12),
decoration: BoxDecoration(
color: Color(0xFFE3F9F8),
borderRadius: BorderRadius.circular(6),
),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(6),
decoration: const BoxDecoration(
color: Color(0xFF2E7D6E),
shape: BoxShape.circle,
),
child: Icon(icon, size: 16, color: Colors.white),
),
const SizedBox(width: 10),
Text(
title,
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
),
],
),
);
}
Widget _buildInput(String label, TextEditingController controller, {TextInputType keyboardType = TextInputType.text, bool readOnly = false, VoidCallback? onTap}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: const TextStyle(fontWeight: FontWeight.w500)),
const SizedBox(height: 6),
TextField(
controller: controller,
keyboardType: keyboardType,
readOnly: readOnly,
onTap: onTap,
decoration: InputDecoration(
border: OutlineInputBorder(borderRadius: BorderRadius.circular(6)),
isDense: true,
contentPadding: const EdgeInsets.all(10),
),
),
const SizedBox(height: 12),
],
);
}
@override
Widget build(BuildContext context) {
// Ensure global AppHeader remains visible by pushing content down by 64px
return SafeArea(
child: Scaffold(
backgroundColor: Color(0xffD9EBE8),
// FIXED BUTTON FOOTER
bottomNavigationBar: Container(
padding: const EdgeInsets.all(16),
color: const Color(0xFFF7FBFA),
child: Row(
mainAxisAlignment: MainAxisAlignment.end, // 👉 move button to right
children: [
ElevatedButton(
onPressed: widget.item?['is_data_accuracy_checked'] == '1' ? null : _save,
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF2E7D6E),
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
vertical: 10,
horizontal: 20, // 👉 smaller width
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: const Text(
'Confirm Data Accuracy',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),
],
),
),
body: Container(
// margin: const EdgeInsets.only(top: 64), // <-- keeps popup under global AppHeader
width: double.infinity,
// height: MediaQuery.of(context).size.height - 64,
color: const Color(0xFFF7FBFA),
child: Column(
children: [
// In-body header
Container(
height: 56,
color: Color(0xFFE3F9F8),
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Row(
children: [
IconButton(icon: const Icon(Icons.file_open), onPressed: () => context.pop()),
const Expanded(child: Text('Insurance Policy Review', style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600))),
if (isLoading) const SizedBox(width: 12, height: 12, child: CircularProgressIndicator(strokeWidth: 2)),
const SizedBox(width: 8),
IconButton(icon: const Icon(Icons.close), onPressed: () => context.pop()),
],
),
),
// Body: left PDF preview + right grouped form
Expanded(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
// LEFT - PDF placeholder
Expanded(
flex: 1,
child: Container(
margin: const EdgeInsets.only(right: 12),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.grey.shade200),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(
'Orginal Policy Document',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
),
const SizedBox(height: 8),
Expanded(
child: FutureBuilder<Uint8List>(
future: loadNetworkPdfBytes(pdfUrl!),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(child: CircularProgressIndicator());
}
final pdfBytes = snapshot.data!;
return PdfDocumentLoader.openData(
pdfBytes,
documentBuilder: (context, pdfDocument, pageCount) {
return ListView.builder(
itemCount: pageCount,
itemBuilder: (context, index) {
return Container(
color: Colors.black12,
child: PdfPageView(
pdfDocument: pdfDocument,
pageNumber: index + 1,
),
);
},
);
},
);
},
),
)
// Expanded(
// child: PdfDocumentLoader.openAsset(
// 'assets/pdfs/sample.pdf',
// documentBuilder: (context, pdfDocument, pageCount) => LayoutBuilder(
// builder: (context, constraints) => ListView.builder(
// itemCount: pageCount,
// itemBuilder: (context, index) => Container(
// // margin: EdgeInsets.all(margin),
// // padding: EdgeInsets.all(padding),
// color: Colors.black12,
// child: PdfPageView(
// pdfDocument: pdfDocument,
// pageNumber: index + 1,
// )
// )
// )
// ),
// )
// )
],
),
),
),
// RIGHT - Grouped Form
Expanded(
flex: 1,
child: SingleChildScrollView(
child: Card(
elevation: 2,
color: Colors.white,
margin: EdgeInsets.zero, // flush with container
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Policy Details
Card(
elevation: 5,
color: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_sectionHeader('Policy Details', icon: Icons.policy),
SizedBox(height: 10),
Row(
children: [
Expanded(child: _buildInput('Policy Number', policyNumberController)),
const SizedBox(width: 8),
Expanded(child: _buildInput('Insured Name', insuredNameController)),
],
),
Row(
children: [
Expanded(child: _buildInput('Issued Date', issuedDateController, readOnly: true, onTap: () => _pickDate(issuedDateController, context))),
const SizedBox(width: 8),
Expanded(child: _buildInput('Start Date', startDateController, readOnly: true, onTap: () => _pickDate(startDateController, context))),
const SizedBox(width: 8),
Expanded(child: _buildInput('End Date', endDateController, readOnly: true, onTap: () => _pickDate(endDateController, context)),)
],
),
Row(
children: [
Expanded(child: _buildInput('Premium Amount', premiumController, keyboardType: TextInputType.number)),
const SizedBox(width: 8),
Expanded(child: _buildInput('Remarks', remarksController)),
],
),
],
),
),
),
const SizedBox(height: 12),
// Tax Details
Card(
elevation: 5,
color: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_sectionHeader('Tax / Cover Details', icon: Icons.attach_money),
SizedBox(height: 10),
Row(
children: [
Expanded(child: _buildInput('TP', tpController, keyboardType: TextInputType.number)),
const SizedBox(width: 8),
Expanded(child: _buildInput('OD', odController, keyboardType: TextInputType.number)),
const SizedBox(width: 8),
Expanded(child: _buildInput('PA', paController, keyboardType: TextInputType.number)),
],
),
Row(
children: [
Expanded(child: _buildInput('CGST', cgstController, keyboardType: TextInputType.number)),
const SizedBox(width: 8),
Expanded(child: _buildInput('SGST', sgstController, keyboardType: TextInputType.number)),
const SizedBox(width: 8),
Expanded(child: _buildInput('IGST', igstController, keyboardType: TextInputType.number)),
],
),
],
),
),
),
const SizedBox(height: 12),
// Vehicle Details
Card(
elevation: 5,
color: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_sectionHeader('Vehicle Details', icon: Icons.directions_car),
SizedBox(height: 10),
Row(
children: [
Expanded(child: _buildInput('RTO State Name', rtoStateCodeController)),
const SizedBox(width: 8),
Expanded(child: _buildInput('RTO City Code', rtoCityCodeController)),
const SizedBox(width: 8),
Expanded(child: _buildInput('Weight', weightController, keyboardType: TextInputType.number)),
],
),
Row(
children: [
Expanded(child: _buildInput('Fuel Type', fuelTypeController)),
const SizedBox(width: 8),
Expanded(child: _buildInput('Date of Registration', registrationDateController, readOnly: true, onTap: () => _pickDate(registrationDateController, context))),
const SizedBox(width: 8),
Expanded(child: _buildInput('Year of Manufacture', yomController, keyboardType: TextInputType.number)),
],
),
Row(
children: [
Expanded(child: _buildInput('Engine No', engineNoController)),
const SizedBox(width: 8),
Expanded(child: _buildInput('Chassis No', chassisNoController)),
const SizedBox(width: 8),
Expanded(child: Expanded(child: _buildInput('Make', makeController))),
],
),
Row(
children: [
Expanded(child: _buildInput('Model', modelController)),
const SizedBox(width: 8),
Expanded(child: _buildInput('Cubic Capacity', cubicCapacityController, keyboardType: TextInputType.number)),
const SizedBox(width: 8),
Expanded(child: _buildInput('Vehicle Type', vehicleTypeController)),
],
),
],
),
),
),
const SizedBox(height: 12),
// Broker Details
Card(
elevation: 5,
color: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_sectionHeader('Broker / Commission', icon: Icons.person),
SizedBox(height: 10),
Row(
children: [
Expanded(child: _buildInput('Broker Name', brokerNameController)),
const SizedBox(width: 8),
Expanded(child: _buildInput('Commission Amount', commissionAmountController, keyboardType: TextInputType.number)),
],
),
],
),
),
),
const SizedBox(height: 20),// spacing above fixed button
],
),
),
),
),
)
],
),
),
),
],
),
),
),
);
}
}

View File

@ -8,6 +8,7 @@
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
#include <open_file_linux/open_file_linux_plugin.h>
#include <syncfusion_pdfviewer_linux/syncfusion_pdfviewer_linux_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
@ -17,6 +18,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) open_file_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "OpenFileLinuxPlugin");
open_file_linux_plugin_register_with_registrar(open_file_linux_registrar);
g_autoptr(FlPluginRegistrar) syncfusion_pdfviewer_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "SyncfusionPdfviewerLinuxPlugin");
syncfusion_pdfviewer_linux_plugin_register_with_registrar(syncfusion_pdfviewer_linux_registrar);
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);

View File

@ -5,6 +5,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
flutter_secure_storage_linux
open_file_linux
syncfusion_pdfviewer_linux
url_launcher_linux
)

View File

@ -6,6 +6,7 @@ import FlutterMacOS
import Foundation
import connectivity_plus
import device_info_plus
import file_picker
import firebase_auth
import firebase_core
@ -16,11 +17,14 @@ import local_auth_darwin
import open_file_mac
import package_info_plus
import path_provider_foundation
import pdf_render
import shared_preferences_foundation
import syncfusion_pdfviewer_macos
import url_launcher_macos
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin"))
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin"))
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
@ -31,6 +35,8 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
OpenFilePlugin.register(with: registry.registrar(forPlugin: "OpenFilePlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SwiftPdfRenderPlugin.register(with: registry.registrar(forPlugin: "SwiftPdfRenderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SyncfusionFlutterPdfViewerPlugin.register(with: registry.registrar(forPlugin: "SyncfusionFlutterPdfViewerPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
}

View File

@ -233,6 +233,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.7.11"
device_info_plus:
dependency: transitive
description:
name: device_info_plus
sha256: "4df8babf73058181227e18b08e6ea3520cf5fc5d796888d33b7cb0f33f984b7c"
url: "https://pub.dev"
source: hosted
version: "12.3.0"
device_info_plus_platform_interface:
dependency: transitive
description:
name: device_info_plus_platform_interface
sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f
url: "https://pub.dev"
source: hosted
version: "7.0.3"
dropdown_search:
dependency: "direct main"
description:
@ -684,26 +700,26 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0"
sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
url: "https://pub.dev"
source: hosted
version: "10.0.9"
version: "11.0.2"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
url: "https://pub.dev"
source: hosted
version: "3.0.9"
version: "3.0.10"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
version: "3.0.2"
lints:
dependency: transitive
description:
@ -968,6 +984,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.1.0+3"
pdf_render:
dependency: "direct main"
description:
name: pdf_render
sha256: bacd2ad8f4f4c9821827003065f5c2f9ca474dd418ff29c68272aab4c0e1e88b
url: "https://pub.dev"
source: hosted
version: "1.4.12"
petitparser:
dependency: transitive
description:
@ -1189,6 +1213,78 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.1"
syncfusion_flutter_core:
dependency: transitive
description:
name: syncfusion_flutter_core
sha256: e1fdfcc3ed7e1f040ba95838780b2eb1857e3e5eccb817fbe94ea2b09c35eac4
url: "https://pub.dev"
source: hosted
version: "31.2.18"
syncfusion_flutter_pdf:
dependency: transitive
description:
name: syncfusion_flutter_pdf
sha256: "4077abff3d3dcae757317c0a85cb607b98cc6ea8f3b47c7d8488d4144ef01a9f"
url: "https://pub.dev"
source: hosted
version: "31.2.18"
syncfusion_flutter_pdfviewer:
dependency: "direct main"
description:
name: syncfusion_flutter_pdfviewer
sha256: "4bc26c493a017ea615a2c232031f3aa46642ddb22d82a8d88d8c5e5ea7fe4c7d"
url: "https://pub.dev"
source: hosted
version: "31.2.18"
syncfusion_flutter_signaturepad:
dependency: transitive
description:
name: syncfusion_flutter_signaturepad
sha256: "56c35321879b900f59a91e0758af7ca66973447bfdaeb643fe1da0084cbc5b22"
url: "https://pub.dev"
source: hosted
version: "31.2.18"
syncfusion_pdfviewer_linux:
dependency: transitive
description:
name: syncfusion_pdfviewer_linux
sha256: bae7feb109b38ecf9f8be99bd032503adf98e56da048307a17af8515d0f9d2ed
url: "https://pub.dev"
source: hosted
version: "31.2.18"
syncfusion_pdfviewer_macos:
dependency: transitive
description:
name: syncfusion_pdfviewer_macos
sha256: "5c02ead2a430cd3f203639ede38ce2e06fb6c8aab6791b0d15c01436f882f482"
url: "https://pub.dev"
source: hosted
version: "31.2.18"
syncfusion_pdfviewer_platform_interface:
dependency: transitive
description:
name: syncfusion_pdfviewer_platform_interface
sha256: "65641e064385ac65253930ec96a6edc2eea781c9e15bf3d5fa15e459037817e7"
url: "https://pub.dev"
source: hosted
version: "31.2.18"
syncfusion_pdfviewer_web:
dependency: transitive
description:
name: syncfusion_pdfviewer_web
sha256: c55201d9eda49f543b9ad21f539b0f5fbe45ca1a3b30081ee471eb4dff7132f4
url: "https://pub.dev"
source: hosted
version: "31.2.18"
syncfusion_pdfviewer_windows:
dependency: transitive
description:
name: syncfusion_pdfviewer_windows
sha256: "1b706e58a95c794687d037e055cf0580370ceee27a59a8cd4e14368534161af8"
url: "https://pub.dev"
source: hosted
version: "31.2.18"
term_glyph:
dependency: transitive
description:
@ -1201,10 +1297,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00"
url: "https://pub.dev"
source: hosted
version: "0.7.4"
version: "0.7.6"
toastification:
dependency: "direct main"
description:
@ -1321,10 +1417,10 @@ packages:
dependency: transitive
description:
name: vector_math
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
url: "https://pub.dev"
source: hosted
version: "2.1.4"
version: "2.2.0"
vm_service:
dependency: transitive
description:
@ -1373,6 +1469,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.15.0"
win32_registry:
dependency: transitive
description:
name: win32_registry
sha256: "6f1b564492d0147b330dd794fee8f512cec4977957f310f9951b5f9d83618dae"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
xdg_directories:
dependency: transitive
description:
@ -1399,4 +1503,4 @@ packages:
version: "3.1.3"
sdks:
dart: ">=3.8.1 <4.0.0"
flutter: ">=3.32.0"
flutter: ">=3.35.1"

View File

@ -70,6 +70,8 @@ dependencies:
fluttertoast: ^9.0.0
fl_chart: ^0.70.0
flutter_reorderable_grid_view: ^5.5.2
syncfusion_flutter_pdfviewer: ^31.2.18
pdf_render: ^1.4.12
# fl_chart: ^1.1.0

View File

@ -38,6 +38,23 @@
<script src="flutter_bootstrap.js" async></script>
<script src="https://www.gstatic.com/firebasejs/10.7.0/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.7.0/firebase-auth.js"></script>
<!-- IMPORTANT: load pdfjs files -->
<script
src="https://cdn.jsdelivr.net/npm/pdfjs-dist@3.4.120/build/pdf.min.js"
type="text/javascript"
></script>
<script type="text/javascript">
pdfjsLib.GlobalWorkerOptions.workerSrc =
"https://cdn.jsdelivr.net/npm/pdfjs-dist@3.4.120/build/pdf.worker.min.js";
pdfRenderOptions = {
// where cmaps are downloaded from
cMapUrl: "https://cdn.jsdelivr.net/npm/pdfjs-dist@3.4.120/cmaps/",
// The cmaps are compressed in the case
cMapPacked: true,
// any other options for pdfjsLib.getDocument.
// params: {}
};
</script>
<script type="module">
// Import the functions you need from the SDKs you need
import { initializeApp } from "https://www.gstatic.com/firebasejs/10.12.4/firebase-app.js";

View File

@ -11,6 +11,7 @@
#include <firebase_core/firebase_core_plugin_c_api.h>
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
#include <local_auth_windows/local_auth_plugin.h>
#include <syncfusion_pdfviewer_windows/syncfusion_pdfviewer_windows_plugin.h>
#include <url_launcher_windows/url_launcher_windows.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
@ -24,6 +25,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
LocalAuthPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("LocalAuthPlugin"));
SyncfusionPdfviewerWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("SyncfusionPdfviewerWindowsPlugin"));
UrlLauncherWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
}

View File

@ -8,6 +8,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
firebase_core
flutter_secure_storage_windows
local_auth_windows
syncfusion_pdfviewer_windows
url_launcher_windows
)