Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
Sai Srinivas
GEN_ERP_2025
Commits
b35acfea
Commit
b35acfea
authored
Nov 28, 2025
by
Sai Srinivas
Browse files
local fix
parents
ebb11608
2a087139
Changes
65
Show whitespace changes
Inline
Side-by-side
lib/screens/finance/financeDashboard.dart
View file @
b35acfea
...
...
@@ -487,11 +487,11 @@ class _FinancedashboardState extends State<Financedashboard> {
},
child:
Container
(
padding:
EdgeInsets
.
symmetric
(
vertical:
5
,
vertical:
4.6
,
horizontal:
15
,
),
margin:
EdgeInsets
.
symmetric
(
vertical:
7
,
vertical:
5
,
horizontal:
5
,
),
decoration:
BoxDecoration
(
...
...
lib/screens/finance/paymentDetailsPaymentRequisition.dart
View file @
b35acfea
...
...
@@ -338,6 +338,7 @@ class _PaymentdetailspaymentrequisitionState
fileUrl:
paymentDet
.
attachmentDirFilePath
!,
downloadEnable:
true
,
),
),
);
...
...
@@ -604,6 +605,7 @@ class _PaymentdetailspaymentrequisitionState
fileUrl:
paymentDet
.
attachmentDirFilePath
!,
downloadEnable:
true
,
),
),
);
...
...
lib/screens/finance/paymentReceiptDetails.dart
View file @
b35acfea
...
...
@@ -452,6 +452,7 @@ class _PaymentreceiptdetailsState extends State<Paymentreceiptdetails> {
fileUrl:
paymentDet
.
attachmentDirFilePath
!,
downloadEnable:
true
,
),
),
);
...
...
lib/screens/hrm/AttendanceRequestDetail.dart
View file @
b35acfea
import
'package:dotted_line/dotted_line.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_svg/svg.dart'
;
import
'package:generp/Utils/custom_snackbar.dart'
;
import
'package:geocoding/geocoding.dart'
;
import
'package:provider/provider.dart'
;
import
'package:url_launcher/url_launcher.dart'
;
...
...
@@ -246,12 +247,14 @@ class _AttendanceRequestDetailScreenState
"Check In/Out Details"
,
scaleFactor
,
),
if
(
details
.
type
==
"Check In"
||
details
.
type
==
"Check In/Out"
)
_buildDate_TimeTile
(
"Check In Date & Time"
,
details
.
date
,
details
.
checkInTime
,
scaleFactor
,
),
if
(
details
.
type
==
"Check Out"
||
details
.
type
==
"Check In/Out"
)
_buildDate_TimeTile
(
"Check Out Date & Time"
,
details
.
date
,
...
...
@@ -259,22 +262,28 @@ class _AttendanceRequestDetailScreenState
scaleFactor
,
),
if
(
details
.
type
==
"Check In"
||
details
.
type
==
"Check In/Out"
)
_buildDetailTile
(
"Original Check In"
,
checkInTime
,
scaleFactor
,
),
if
(
details
.
type
==
"Check Out"
||
details
.
type
==
"Check In/Out"
)
_buildDetailTile
(
"Original Check Out"
,
"--"
,
scaleFactor
,
),
if
(
details
.
type
==
"Check In"
||
details
.
type
==
"Check In/Out"
)
_buildDetailTile
(
"Original Check In Location"
,
details
.
checkInLocation
,
scaleFactor
,
),
if
(
details
.
type
==
"Check Out"
||
details
.
type
==
"Check In/Out"
)
_buildDetailTile
(
"Original Check Out Location"
,
details
.
checkOutLocation
,
...
...
@@ -350,16 +359,19 @@ class _AttendanceRequestDetailScreenState
"Other Details"
,
scaleFactor
,
),
if
(
details
.
type
==
"Check In"
||
details
.
type
==
"Check In/Out"
)
_buildDetailTile
(
"Check In Type"
,
details
.
checkInType
,
scaleFactor
,
),
if
(
details
.
type
==
"Check Out"
||
details
.
type
==
"Check In/Out"
)
_buildDetailTile
(
"Check Out Type"
,
details
.
chechOutType
,
scaleFactor
,
),
if
(
details
.
type
==
"Check Out"
||
details
.
type
==
"Check In/Out"
)
_buildDetailTile
(
"Check Out Time"
,
details
.
checkOutTime
,
...
...
@@ -687,15 +699,11 @@ class _AttendanceRequestDetailScreenState
await
onSubmit
(
remark
);
// SnackBar here
Navigator
.
pop
(
context
);
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
Text
(
"Request submitted successfully"
,
),
backgroundColor:
Colors
.
green
,
behavior:
SnackBarBehavior
.
floating
,
),
CustomSnackBar
.
showSuccess
(
context:
context
,
message:
"Request submitted successfully"
);
}
},
child:
Container
(
...
...
@@ -967,6 +975,7 @@ class _AttendanceRequestDetailScreenState
(
context
)
=>
Fileviewer
(
fileName:
filePath
??
""
,
fileUrl:
filePath
??
""
,
downloadEnable:
false
,
),
),
);
...
...
lib/screens/hrm/ContactList.dart
View file @
b35acfea
...
...
@@ -96,13 +96,13 @@ class _ContactListScreenState extends State<ContactListScreen> {
// Clean phone number
final
cleanPhoneNumber
=
_cleanPhoneNumber
(
phoneNumber
);
//
✅
Instead of inserting contact, open system form
// Instead of inserting contact, open system form
final
newContact
=
Contact
()
..
name
=
Name
(
first:
name
)
..
phones
=
[
Phone
(
cleanPhoneNumber
)];
//
🟢
This opens the phone’s native “Add contact” screen (prefilled)
// This opens the phone’s native “Add contact” screen (prefilled)
await
FlutterContacts
.
openExternalInsert
(
newContact
);
// Hide loading
...
...
lib/screens/hrm/TourExpensesDetailsScreen.dart
View file @
b35acfea
...
...
@@ -242,6 +242,7 @@ class _TourExpensesDetailsScreenState extends State<TourExpensesDetailsScreen> {
(
context
)
=>
Fileviewer
(
fileName:
t
.
imageDirFilePath
??
""
,
fileUrl:
t
.
imageDirFilePath
??
""
,
downloadEnable:
false
,
),
),
);
...
...
@@ -301,6 +302,7 @@ class _TourExpensesDetailsScreenState extends State<TourExpensesDetailsScreen> {
(
context
)
=>
Fileviewer
(
fileName:
h
.
imageDirFilePath
??
""
,
fileUrl:
h
.
imageDirFilePath
??
""
,
downloadEnable:
false
,
),
),
);
...
...
@@ -359,6 +361,7 @@ class _TourExpensesDetailsScreenState extends State<TourExpensesDetailsScreen> {
(
context
)
=>
Fileviewer
(
fileName:
o
.
imageDirFilePath
??
""
,
fileUrl:
o
.
imageDirFilePath
??
""
,
downloadEnable:
false
,
),
),
);
...
...
lib/screens/inventory/GeneratorPartDetailsScreen.dart
View file @
b35acfea
...
...
@@ -986,6 +986,7 @@ class _GeneratorPartDetailsScreenState
provider
.
partData
.
imageDirFilePath
!,
downloadEnable:
false
,
),
),
);
...
...
lib/screens/notifierExports.dart
View file @
b35acfea
...
...
@@ -25,6 +25,7 @@ export 'package:generp/Notifiers/commonProvider/accountDetailsProvider.dart';
export
'package:generp/Notifiers/commonProvider/accountsListProvider.dart'
;
export
'package:generp/Notifiers/commonProvider/commonPagesProvider.dart'
;
export
'package:generp/Notifiers/commonProvider/accountLedgerProvider.dart'
;
export
'package:generp/Notifiers/commonProvider/editCommonAccountProvider.dart'
;
export
'package:generp/Notifiers/financeProvider/DashboardProvider.dart'
;
export
'package:generp/Notifiers/financeProvider/RequestionListProvider.dart'
;
...
...
@@ -56,6 +57,7 @@ export 'package:generp/Notifiers/crmProvider/addProspectLeadsProvider.dart';
export
'package:generp/Notifiers/crmProvider/followUpUpdateProvider.dart'
;
export
'package:generp/Notifiers/crmProvider/appointmentCalendarProvider.dart'
;
export
'package:generp/Notifiers/crmProvider/addNewLeadsandProspectsProvider.dart'
;
export
'package:generp/Notifiers/crmProvider/CrmNearByGeneratorsProvider.dart'
;
export
'package:generp/Notifiers/hrmProvider/hrmAccessiblePagesProvider.dart'
;
export
'package:generp/Notifiers/hrmProvider/attendanceListProvider.dart'
;
...
...
lib/screens/old/AllrequesitionListsOld.dart
View file @
b35acfea
...
...
@@ -328,6 +328,7 @@ class _AllpaymentrequesitionlistsbymodesoldState
fileUrl:
requestLists
[
index
]
.
attachmentDirFilePath
!,
downloadEnable:
false
,
),
),
);
...
...
lib/screens/old/paymentListPayReqOld.dart
View file @
b35acfea
...
...
@@ -316,6 +316,7 @@ class _PaymentlistpaymentrequisitionOldState
fileUrl:
requestLists
[
index
]
.
attachmentDirFilePath
!,
downloadEnable:
false
,
),
),
);
...
...
lib/screens/old/paymentreceiptListOld.dart
View file @
b35acfea
...
...
@@ -271,6 +271,7 @@ class _PaymentreceiptlistOldState extends State<PaymentreceiptlistOld> {
fileUrl:
requestLists
[
index
]
.
attachmentDirFilePath
!,
downloadEnable:
false
,
),
),
);
...
...
lib/screens/order/ordersDetailsByModes.dart
View file @
b35acfea
...
...
@@ -1035,6 +1035,7 @@ class _OrdersdetailsbymodesState extends State<Ordersdetailsbymodes> {
fileUrl:
feedbackHistory
[
lp
]
.
attachmentDirFilePath
!,
downloadEnable:
false
,
),
),
);
...
...
@@ -1146,6 +1147,7 @@ class _OrdersdetailsbymodesState extends State<Ordersdetailsbymodes> {
fileUrl:
feedbackHistory
[
lp
]
.
attachmentDirFilePath
!,
downloadEnable:
false
,
),
),
);
...
...
@@ -1439,6 +1441,7 @@ class _OrdersdetailsbymodesState extends State<Ordersdetailsbymodes> {
fileUrl:
feedbackHistory
[
lp
]
.
attachmentDirFilePath
!,
downloadEnable:
false
,
),
),
);
...
...
@@ -2280,6 +2283,7 @@ class _OrdersdetailsbymodesState extends State<Ordersdetailsbymodes> {
fileUrl:
orderDetails
.
tpcPaymentAttachmentDirFilePath
!,
downloadEnable:
false
,
),
),
);
...
...
lib/screens/order/paymentDetailsByMode.dart
View file @
b35acfea
...
...
@@ -1170,6 +1170,7 @@ class _PaymentdetailsbymodeState extends State<Paymentdetailsbymode> {
fileUrl:
paymentDetails
.
attachmentDirFilePath
!,
downloadEnable:
false
,
),
),
);
...
...
lib/screens/order/tpcAgentDetailsByMode.dart
View file @
b35acfea
...
...
@@ -329,6 +329,7 @@ class _TpcagentdetailsbymodeState extends State<Tpcagentdetailsbymode> {
fileUrl:
tpcAgentDetails
.
idProofDirFilePath
??
""
,
downloadEnable:
false
,
),
),
);
...
...
@@ -805,6 +806,7 @@ class _TpcagentdetailsbymodeState extends State<Tpcagentdetailsbymode> {
fileUrl:
tpcAgentDetails
.
idProofDirFilePath
!,
downloadEnable:
false
,
),
),
);
...
...
lib/screens/order/tpcAgentIssueListDetails.dart
View file @
b35acfea
...
...
@@ -851,6 +851,7 @@ class _TpcagentissuelistdetailsState extends State<Tpcagentissuelistdetails> {
fileUrl:
feedbackHistory
[
lp
]
.
attachmentDirFilePath
!,
downloadEnable:
false
,
),
),
);
...
...
@@ -965,6 +966,7 @@ class _TpcagentissuelistdetailsState extends State<Tpcagentissuelistdetails> {
fileUrl:
feedbackHistory
[
lp
]
.
attachmentDirFilePath
!,
downloadEnable:
false
,
),
),
);
...
...
@@ -1263,6 +1265,7 @@ class _TpcagentissuelistdetailsState extends State<Tpcagentissuelistdetails> {
fileUrl:
feedbackHistory
[
lp
]
.
attachmentDirFilePath
!,
downloadEnable:
false
,
),
),
);
...
...
@@ -1878,6 +1881,7 @@ class _TpcagentissuelistdetailsState extends State<Tpcagentissuelistdetails> {
fileUrl:
orderDetails
.
tpcPaymentAttachmentDirFilePath
!,
downloadEnable:
false
,
),
),
);
...
...
lib/screens/order/tpcAgentListByMode.dart
View file @
b35acfea
...
...
@@ -442,6 +442,7 @@ class _TpcagentlistbymodeState extends State<Tpcagentlistbymode> {
tpcAgentsLists
[
index
]
.
idProofDirFilePath
??
"-"
,
downloadEnable:
false
,
),
),
);
...
...
lib/screens/serviceEngineer/Followupdetails.dart
View file @
b35acfea
...
...
@@ -102,6 +102,7 @@ class _FollowupdetailsState extends State<Followupdetails> {
(
context
)
=>
Fileviewer
(
fileName:
followups
[
index
].
fsrExt
!,
fileUrl:
"https://erp.gengroup.in/files_genservices/tech_fsr_report/
${followups[index].fsrExt!}
"
,
downloadEnable:
false
,
),
),
);
...
...
lib/screens/serviceEngineer/PaymentDetails.dart
View file @
b35acfea
...
...
@@ -12,10 +12,12 @@ import 'package:pin_code_fields/pin_code_fields.dart';
import
'package:provider/provider.dart'
;
import
'../../Models/TechnicianLoadNumbersResponse.dart'
;
import
'../../Notifiers/HomeScreenNotifier.dart'
;
import
'../../Utils/dropdownTheme.dart'
;
import
'RazorpayQrScreen.dart'
;
class
Paymentdetails
extends
StatefulWidget
{
final
accountName
,
referenceID
,
name
,
genId
;
final
accountName
,
referenceID
,
name
,
genId
,
complaintType
;
const
Paymentdetails
({
super
.
key
,
...
...
@@ -23,6 +25,7 @@ class Paymentdetails extends StatefulWidget {
required
this
.
name
,
required
this
.
genId
,
required
this
.
referenceID
,
this
.
complaintType
,
});
@override
...
...
@@ -43,6 +46,7 @@ class _PaymentdetailsState extends State<Paymentdetails> {
context
,
listen:
false
,
);
provider
.
resetErrors
();
provider
.
LoadNumbersAPI
(
context
,
widget
.
accountName
,
...
...
@@ -267,7 +271,7 @@ class _PaymentdetailsState extends State<Paymentdetails> {
),
],
),
items:
items:
// here i have payment option
provider
.
paymentModeDropDown
.
map
(
(
paymentMode
)
=>
DropdownMenuItem
<
...
...
@@ -358,39 +362,33 @@ class _PaymentdetailsState extends State<Paymentdetails> {
),
errorWidget
(
context
,
provider
.
selectAmountError
),
SizedBox
(
height:
10
),
if
(
provider
.
selectPaymentMode
?.
name
?.
toLowerCase
()
!=
'qr'
)
...[
Padding
(
padding:
const
EdgeInsets
.
only
(
bottom:
5.0
),
child:
Text
(
"Reference Number"
),
),
Container
(
height:
50
,
alignment:
Alignment
.
center
,
decoration:
BoxDecoration
(
color:
AppColors
.
text_field_color
,
borderRadius:
BorderRadius
.
circular
(
14
),
),
child:
Padding
(
padding:
const
EdgeInsets
.
fromLTRB
(
10.0
,
0.0
,
10
,
0
,
),
padding:
const
EdgeInsets
.
fromLTRB
(
10.0
,
0.0
,
10
,
0
),
child:
TextFormField
(
controller:
provider
.
Referencecontroller
,
keyboardType:
TextInputType
.
text
,
onChanged:
(
value
)
{
provider
.
ReferenceError
=
null
;
},
decoration:
InputDecoration
(
decoration:
const
InputDecoration
(
hintText:
"Enter Reference Number"
,
hintStyle:
TextStyle
(
fontWeight:
FontWeight
.
w400
,
color:
Color
(
0xFFB4BEC0
),
fontSize:
14
,
),
enabledBorder:
InputBorder
.
none
,
focusedBorder:
InputBorder
.
none
,
),
...
...
@@ -398,6 +396,9 @@ class _PaymentdetailsState extends State<Paymentdetails> {
),
),
errorWidget
(
context
,
provider
.
ReferenceError
),
],
// errorWidget(context, provider.ReferenceError),
SizedBox
(
height:
10
),
InkResponse
(
onTap:
()
{
...
...
@@ -479,11 +480,65 @@ class _PaymentdetailsState extends State<Paymentdetails> {
?
null
:
()
{
HapticFeedback
.
selectionClick
();
// Common validation
if
(
provider
.
selectContact
==
null
)
{
provider
.
selectContactError
=
"Please select phone number"
;
provider
.
notifyListeners
();
return
;
}
if
(
provider
.
Amountcontroller
.
text
.
isEmpty
)
{
provider
.
selectAmountError
=
"Please enter amount"
;
provider
.
notifyListeners
();
return
;
}
// For QR payment
if
(
provider
.
selectPaymentMode
?.
name
?.
toLowerCase
()
==
'qr'
)
{
if
(
provider
.
imagePicked
==
0
||
provider
.
imagePath
==
null
)
{
provider
.
imageError
=
"Please upload reference document"
;
provider
.
notifyListeners
();
return
;
}
// All validations passed
var
homeProvider
=
Provider
.
of
<
HomescreenNotifier
>(
context
,
listen:
false
,
);
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
RazorpayQrScreen
(
sessionId:
homeProvider
.
session
,
empId:
homeProvider
.
empId
,
amount:
provider
.
Amountcontroller
.
text
,
refType:
widget
.
complaintType
,
refId:
widget
.
referenceID
,
),
),
);
}
else
{
// For non-QR payments
if
(
provider
.
Referencecontroller
.
text
.
isEmpty
)
{
provider
.
ReferenceError
=
"Please enter reference number"
;
provider
.
notifyListeners
();
return
;
}
if
(
provider
.
imagePicked
==
0
||
provider
.
imagePath
==
null
)
{
provider
.
imageError
=
"Please upload reference document"
;
provider
.
notifyListeners
();
return
;
}
provider
.
PaymentUpdateAPI
(
context
,
provider
.
Referencecontroller
.
text
,
provider
.
Amountcontroller
.
text
,
);
}
},
child:
Container
(
alignment:
Alignment
.
center
,
...
...
@@ -505,10 +560,12 @@ class _PaymentdetailsState extends State<Paymentdetails> {
valueColor:
AlwaysStoppedAnimation
<
Color
>(
Colors
.
white
),
),
)
:
const
Text
(
"Send OTP"
,
:
Text
(
provider
.
selectPaymentMode
?.
name
?.
toLowerCase
()
==
'qr'
?
"Show QR"
:
"Send OTP"
,
textAlign:
TextAlign
.
center
,
style:
TextStyle
(
style:
const
TextStyle
(
fontSize:
15
,
fontFamily:
"JakartaMedium"
,
color:
Colors
.
white
,
...
...
@@ -516,7 +573,9 @@ class _PaymentdetailsState extends State<Paymentdetails> {
),
),
),
)
),
),
),
),
...
...
lib/screens/serviceEngineer/RazorpayQrScreen.dart
0 → 100644
View file @
b35acfea
import
'dart:async'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_svg/svg.dart'
;
import
'package:fluttertoast/fluttertoast.dart'
;
import
'package:provider/provider.dart'
;
import
'../../Notifiers/QrProvider.dart'
;
import
'../../Utils/app_colors.dart'
;
import
'../../Utils/commonWidgets.dart'
;
import
'../../Utils/custom_snackbar.dart'
;
class
RazorpayQrScreen
extends
StatefulWidget
{
final
String
sessionId
;
final
String
empId
;
final
String
amount
;
final
String
refType
;
final
String
refId
;
const
RazorpayQrScreen
({
super
.
key
,
required
this
.
sessionId
,
required
this
.
empId
,
required
this
.
amount
,
required
this
.
refType
,
required
this
.
refId
,
});
@override
State
<
RazorpayQrScreen
>
createState
()
=>
_RazorpayQrScreenState
();
}
class
_RazorpayQrScreenState
extends
State
<
RazorpayQrScreen
>
{
Timer
?
_statusTimer
;
bool
_isCancelling
=
false
;
@override
void
initState
()
{
super
.
initState
();
Future
.
microtask
(()
async
{
final
qrProvider
=
context
.
read
<
QrProvider
>();
// Step 1: Create QR
await
qrProvider
.
fetchRazorpayQr
(
sessionId:
widget
.
sessionId
,
empId:
widget
.
empId
,
amount:
widget
.
amount
,
refType:
widget
.
refType
,
refId:
widget
.
refId
,
);
// Step 2: Start polling only if QR generated successfully
if
(
qrProvider
.
qrResponse
?.
error
==
"0"
&&
qrProvider
.
qrResponse
?.
qrCode
!=
null
)
{
_startStatusPolling
(
qrProvider
);
}
});
}
void
_startStatusPolling
(
QrProvider
provider
)
{
_statusTimer
=
Timer
.
periodic
(
const
Duration
(
seconds:
5
),
(
timer
)
async
{
if
(!
mounted
)
return
;
final
razorpayOrderId
=
provider
.
qrResponse
?.
qrId
;
if
(
razorpayOrderId
==
null
)
return
;
final
response
=
await
provider
.
fetchRazorpayUpiQrStatus
(
context:
context
,
sessionId:
widget
.
sessionId
,
empId:
widget
.
empId
,
razorpayOrderId:
razorpayOrderId
,
);
if
(
response
!=
null
&&
response
.
error
==
"0"
)
{
// success -> stop timer, notify user and pop
CustomSnackBar
.
showSuccess
(
context:
context
,
message:
"Payment received successfully"
,
);
timer
.
cancel
();
if
(
mounted
)
{
Navigator
.
pop
(
context
);
// close QR screen
Navigator
.
pop
(
context
);
// close previous screen
}
}
});
}
/// Called when user explicitly cancels / presses close.
/// This stops polling and checks the final status once — shows failure snack only if payment not completed.
Future
<
void
>
_handleCancel
()
async
{
// Prevent re-entry
if
(
_isCancelling
)
return
;
_isCancelling
=
true
;
try
{
// Stop polling immediately
_statusTimer
?.
cancel
();
_statusTimer
=
null
;
final
provider
=
context
.
read
<
QrProvider
>();
final
razorpayOrderId
=
provider
.
qrResponse
?.
qrId
;
if
(
razorpayOrderId
!=
null
)
{
// Check status once more before showing failure
final
response
=
await
provider
.
fetchRazorpayUpiQrStatus
(
context:
context
,
sessionId:
widget
.
sessionId
,
empId:
widget
.
empId
,
razorpayOrderId:
razorpayOrderId
,
);
// If response == null or not successful -> show warning now (single time)
if
(
response
==
null
||
response
.
error
!=
"0"
)
{
if
(
mounted
)
{
CustomSnackBar
.
showWarning
(
context:
context
,
message:
"⚠️ Payment not yet completed or failed"
,
);
}
}
else
{
if
(
mounted
)
{
CustomSnackBar
.
showSuccess
(
context:
context
,
message:
"Payment received successfully"
,
);
}
}
}
else
{
// No order id — just show failure once
if
(
mounted
)
{
CustomSnackBar
.
showWarning
(
context:
context
,
message:
"⚠️ Payment not yet completed or failed"
,
);
}
}
}
catch
(
e
)
{
// ignore or log
debugPrint
(
'_handleCancel error:
$e
'
);
}
finally
{
// Finally pop the screen (single pop)
if
(
mounted
)
Navigator
.
pop
(
context
);
// small delay to reset guard if this screen somehow remains mounted longer
// but normally screen is popped so _isCancelling reset isn't necessary
}
}
@override
void
dispose
()
{
_statusTimer
?.
cancel
();
super
.
dispose
();
}
@override
Widget
build
(
BuildContext
context
)
{
return
WillPopScope
(
onWillPop:
()
async
{
await
_handleCancel
();
return
false
;
},
child:
Scaffold
(
appBar:
AppBar
(
backgroundColor:
Color
(
0xFFFFFFFF
),
automaticallyImplyLeading:
false
,
title:
SizedBox
(
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
start
,
crossAxisAlignment:
CrossAxisAlignment
.
center
,
children:
[
InkResponse
(
onTap:
()
=>
_handleCancel
(),
child:
SvgPicture
.
asset
(
"assets/svg/appbar_back_button.svg"
,
height:
25
,
),
),
SizedBox
(
width:
10
),
InkResponse
(
onTap:
()
=>
_handleCancel
(),
child:
Text
(
"Scan QR to Pay"
,
style:
TextStyle
(
fontSize:
16
,
height:
1.1
,
fontFamily:
"JakartaSemiBold"
,
color:
AppColors
.
semi_black
,
),
),
),
],
),
),
// shape: RoundedRectangleBorder(
// borderRadius: BorderRadius.vertical(
// bottom: Radius.circular(30), // Adjust the radius as needed
// ),
// ),
),
backgroundColor:
Colors
.
black
,
body:
SafeArea
(
child:
Consumer
<
QrProvider
>(
builder:
(
context
,
provider
,
_
)
{
if
(
provider
.
isLoading
)
{
return
_buildLoadingState
();
}
if
(
provider
.
errorMessage
!=
null
)
{
return
_buildErrorState
(
provider
.
errorMessage
!);
}
if
(
provider
.
qrResponse
==
null
||
provider
.
qrResponse
?.
qrCode
==
null
)
{
return
_buildNoQrState
();
}
if
(
provider
.
secondsLeft
==
0
)
{
Future
.
delayed
(
Duration
.
zero
,
()
{
if
(
mounted
)
Navigator
.
pop
(
context
);
});
return
_buildExpiredState
();
}
return
_buildQrScreen
(
provider
);
},
),
),
),
);
}
Widget
_buildLoadingState
()
{
return
Container
(
color:
Colors
.
black
,
child:
const
Center
(
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
CircularProgressIndicator
(
valueColor:
AlwaysStoppedAnimation
<
Color
>(
Colors
.
white
),
),
SizedBox
(
height:
20
),
Text
(
"Generating QR Code..."
,
style:
TextStyle
(
color:
Colors
.
white
,
fontSize:
16
,
),
),
],
),
),
);
}
Widget
_buildErrorState
(
String
errorMessage
)
{
return
Container
(
color:
Colors
.
black
,
child:
Center
(
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
const
Icon
(
Icons
.
error_outline
,
size:
60
,
color:
Colors
.
redAccent
,
),
const
SizedBox
(
height:
20
),
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
40
),
child:
Text
(
errorMessage
,
style:
const
TextStyle
(
color:
Colors
.
white
,
fontSize:
16
,
),
textAlign:
TextAlign
.
center
,
),
),
const
SizedBox
(
height:
30
),
_buildBackButton
(),
],
),
),
);
}
Widget
_buildNoQrState
()
{
return
Container
(
color:
Colors
.
black
,
child:
Center
(
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
const
Icon
(
Icons
.
qr_code_2
,
size:
60
,
color:
Colors
.
grey
,
),
const
SizedBox
(
height:
20
),
const
Text
(
"No QR Code Found"
,
style:
TextStyle
(
color:
Colors
.
white
,
fontSize:
18
,
),
),
const
SizedBox
(
height:
30
),
_buildBackButton
(),
],
),
),
);
}
Widget
_buildExpiredState
()
{
return
Container
(
color:
Colors
.
black
,
child:
Center
(
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
const
Icon
(
Icons
.
timer_off_rounded
,
size:
60
,
color:
Colors
.
redAccent
,
),
const
SizedBox
(
height:
20
),
const
Text
(
"QR Expired"
,
style:
TextStyle
(
fontSize:
20
,
color:
Colors
.
redAccent
,
fontWeight:
FontWeight
.
w600
,
),
),
const
SizedBox
(
height:
10
),
const
Text
(
"Returning to previous screen..."
,
style:
TextStyle
(
color:
Colors
.
white70
,
fontSize:
14
,
),
),
],
),
),
);
}
Widget
_buildQrScreen
(
QrProvider
provider
)
{
final
screenHeight
=
MediaQuery
.
of
(
context
).
size
.
height
;
final
screenWidth
=
MediaQuery
.
of
(
context
).
size
.
width
;
return
Stack
(
children:
[
// Full Screen QR Code Background - Preserving all text
Positioned
.
fill
(
child:
Image
.
network
(
provider
.
qrResponse
!.
qrCode
!,
fit:
BoxFit
.
contain
,
// Use contain to preserve all content
loadingBuilder:
(
context
,
child
,
loadingProgress
)
{
if
(
loadingProgress
==
null
)
return
child
;
return
Container
(
color:
Colors
.
black
,
child:
const
Center
(
child:
CircularProgressIndicator
(
valueColor:
AlwaysStoppedAnimation
<
Color
>(
Colors
.
white
),
),
),
);
},
errorBuilder:
(
context
,
error
,
stackTrace
)
{
return
Container
(
color:
Colors
.
black
,
child:
const
Center
(
child:
Column
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
children:
[
Icon
(
Icons
.
error
,
size:
60
,
color:
Colors
.
red
),
SizedBox
(
height:
16
),
Text
(
"Failed to load QR code"
,
style:
TextStyle
(
color:
Colors
.
white
,
fontSize:
16
),
),
],
),
),
);
},
),
),
// Top Bar - Timer and Close
Positioned
(
top:
0
,
left:
0
,
right:
0
,
child:
Container
(
height:
80
,
decoration:
BoxDecoration
(
gradient:
LinearGradient
(
begin:
Alignment
.
topCenter
,
end:
Alignment
.
bottomCenter
,
colors:
[
Colors
.
black
.
withOpacity
(
0.8
),
Colors
.
transparent
,
],
),
),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
children:
[
// Timer on left
Container
(
margin:
const
EdgeInsets
.
only
(
left:
20
,
top:
40
),
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
16
,
vertical:
8
),
decoration:
BoxDecoration
(
color:
Colors
.
black
.
withOpacity
(
0.7
),
borderRadius:
BorderRadius
.
circular
(
20
),
border:
Border
.
all
(
color:
Colors
.
orange
,
width:
1
,
),
),
child:
Row
(
mainAxisSize:
MainAxisSize
.
min
,
children:
[
const
Icon
(
Icons
.
timer
,
color:
Colors
.
orange
,
size:
16
,
),
const
SizedBox
(
width:
6
),
Text
(
"
${provider.secondsLeft}
s"
,
style:
const
TextStyle
(
color:
Colors
.
white
,
fontSize:
14
,
fontWeight:
FontWeight
.
w600
,
),
),
],
),
),
// Close button on right
Container
(
margin:
const
EdgeInsets
.
only
(
right:
20
,
top:
40
),
child:
CircleAvatar
(
radius:
20
,
backgroundColor:
Colors
.
transparent
,
child:
IconButton
(
icon:
const
Icon
(
Icons
.
close
,
size:
18
),
color:
Colors
.
transparent
,
onPressed:
()
=>
_handleCancel
(),
),
),
),
],
),
),
),
// Bottom Section - Amount and Action Buttons
// Positioned at the very bottom to avoid covering QR content
Positioned
(
bottom:
0
,
left:
0
,
right:
0
,
child:
Container
(
padding:
const
EdgeInsets
.
all
(
20
),
decoration:
BoxDecoration
(
gradient:
LinearGradient
(
begin:
Alignment
.
bottomCenter
,
end:
Alignment
.
topCenter
,
colors:
[
Colors
.
black
.
withOpacity
(
0.9
),
Colors
.
black
.
withOpacity
(
0.6
),
Colors
.
transparent
,
],
),
),
child:
Column
(
children:
[
// Amount Display
// Container(
// width: double.infinity,
// padding: const EdgeInsets.all(16),
// decoration: BoxDecoration(
// color: AppColors.app_blue.withOpacity(0.9),
// borderRadius: BorderRadius.circular(12),
// boxShadow: [
// BoxShadow(
// color: Colors.black.withOpacity(0.3),
// blurRadius: 10,
// offset: const Offset(0, 4),
// ),
// ],
// ),
// child: Column(
// children: [
// const Text(
// "Amount to Pay",
// style: TextStyle(
// color: Colors.white70,
// fontSize: 14,
// fontWeight: FontWeight.w500,
// ),
// ),
// const SizedBox(height: 8),
// Text(
// "₹${widget.amount}",
// style: const TextStyle(
// fontSize: 28,
// fontWeight: FontWeight.bold,
// color: Colors.white,
// ),
// ),
// ],
// ),
// ),
const
SizedBox
(
height:
20
),
// Action Buttons
Row
(
children:
[
// Cancel Button
Expanded
(
child:
ElevatedButton
.
icon
(
onPressed:
()
=>
_handleCancel
(),
icon:
const
Icon
(
Icons
.
close
,
size:
18
),
label:
const
Text
(
"Cancel"
),
style:
ElevatedButton
.
styleFrom
(
backgroundColor:
Colors
.
red
.
withOpacity
(
0.9
),
foregroundColor:
Colors
.
white
,
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
10
),
),
padding:
const
EdgeInsets
.
symmetric
(
vertical:
12
),
elevation:
3
,
),
),
),
const
SizedBox
(
width:
12
),
// Instructions Button
Expanded
(
child:
ElevatedButton
.
icon
(
onPressed:
_showInstructions
,
icon:
const
Icon
(
Icons
.
help_outline
,
size:
18
),
label:
const
Text
(
"Help"
),
style:
ElevatedButton
.
styleFrom
(
backgroundColor:
Colors
.
grey
.
withOpacity
(
0.8
),
foregroundColor:
Colors
.
white
,
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
10
),
),
padding:
const
EdgeInsets
.
symmetric
(
vertical:
12
),
elevation:
3
,
),
),
),
],
),
],
),
),
),
// Small status indicator at the top center (minimal space usage)
Positioned
(
top:
40
,
left:
0
,
right:
0
,
child:
Center
(
child:
Container
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
16
,
vertical:
6
),
decoration:
BoxDecoration
(
color:
Colors
.
green
.
withOpacity
(
0.9
),
borderRadius:
BorderRadius
.
circular
(
12
),
),
child:
const
Text
(
"READY TO SCAN"
,
style:
TextStyle
(
color:
Colors
.
white
,
fontSize:
12
,
fontWeight:
FontWeight
.
w600
,
letterSpacing:
1.0
,
),
),
),
),
),
],
);
}
void
_showInstructions
()
{
showModalBottomSheet
(
context:
context
,
backgroundColor:
Colors
.
transparent
,
builder:
(
context
)
=>
Container
(
decoration:
BoxDecoration
(
color:
AppColors
.
scaffold_bg_color
,
borderRadius:
const
BorderRadius
.
only
(
topLeft:
Radius
.
circular
(
20
),
topRight:
Radius
.
circular
(
20
),
),
),
padding:
const
EdgeInsets
.
all
(
20
),
child:
Column
(
mainAxisSize:
MainAxisSize
.
min
,
children:
[
Container
(
width:
40
,
height:
4
,
decoration:
BoxDecoration
(
color:
Colors
.
grey
,
borderRadius:
BorderRadius
.
circular
(
2
),
),
),
const
SizedBox
(
height:
20
),
const
Text
(
"How to Pay"
,
style:
TextStyle
(
color:
Colors
.
blue
,
fontSize:
18
,
fontWeight:
FontWeight
.
bold
,
),
),
const
SizedBox
(
height:
16
),
_buildInstructionStep
(
"1"
,
"Open any UPI app on your phone"
),
_buildInstructionStep
(
"2"
,
"Tap on 'Scan QR Code'"
),
_buildInstructionStep
(
"3"
,
"Point your camera at this QR code"
),
_buildInstructionStep
(
"4"
,
"Enter UPI PIN to complete payment"
),
const
SizedBox
(
height:
20
),
SizedBox
(
width:
double
.
infinity
,
child:
ElevatedButton
(
onPressed:
()
=>
Navigator
.
pop
(
context
),
style:
ElevatedButton
.
styleFrom
(
backgroundColor:
AppColors
.
app_blue
,
foregroundColor:
Colors
.
white
,
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
10
),
),
padding:
const
EdgeInsets
.
symmetric
(
vertical:
12
),
),
child:
const
Text
(
"Got It"
),
),
),
const
SizedBox
(
height:
10
),
],
),
),
);
}
Widget
_buildInstructionStep
(
String
number
,
String
text
)
{
return
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
vertical:
8
),
child:
Row
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Container
(
width:
24
,
height:
24
,
decoration:
BoxDecoration
(
color:
AppColors
.
app_blue
,
shape:
BoxShape
.
circle
,
),
child:
Center
(
child:
Text
(
number
,
style:
const
TextStyle
(
color:
Colors
.
white
,
fontSize:
12
,
fontWeight:
FontWeight
.
bold
,
),
),
),
),
const
SizedBox
(
width:
12
),
Expanded
(
child:
Text
(
text
,
style:
const
TextStyle
(
color:
Colors
.
black87
,
fontSize:
14
,
),
),
),
],
),
);
}
Widget
_buildBackButton
()
{
return
ElevatedButton
.
icon
(
onPressed:
()
=>
Navigator
.
pop
(
context
),
icon:
const
Icon
(
Icons
.
arrow_back
),
label:
const
Text
(
"Go Back"
),
style:
ElevatedButton
.
styleFrom
(
backgroundColor:
AppColors
.
app_blue
,
foregroundColor:
Colors
.
white
,
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
12
),
),
padding:
const
EdgeInsets
.
symmetric
(
vertical:
12
,
horizontal:
24
),
),
);
}
}
\ No newline at end of file
lib/screens/serviceEngineer/VisitDetails.dart
View file @
b35acfea
...
...
@@ -7,9 +7,11 @@ import 'package:flutter_svg/svg.dart';
import
'package:generp/Notifiers/VisitDetailsProvider.dart'
;
import
'package:generp/Utils/app_colors.dart'
;
import
'package:generp/Utils/commonWidgets.dart'
;
import
'package:generp/screens/serviceEngineer/RazorpayQrScreen.dart'
;
import
'package:provider/provider.dart'
;
import
'package:url_launcher/url_launcher.dart'
;
import
'../../Notifiers/HomeScreenNotifier.dart'
;
import
'../../Utils/commonServices.dart'
;
import
'../finance/FileViewer.dart'
;
import
'Followupdetails.dart'
;
...
...
@@ -46,6 +48,7 @@ class _VisitdetailsState extends State<Visitdetails> {
visitdetails
.
showMoreDetails
=
false
;
visitdetails
.
LoadVisitDetailsAPI
(
context
,
widget
.
complaintID
);
visitdetails
.
LoadFollowupListAPI
(
context
,
widget
.
complaintID
);
visitdetails
.
serviceComplaintBillList
(
context
,
widget
.
complaintID
);
});
}
...
...
@@ -90,6 +93,7 @@ class _VisitdetailsState extends State<Visitdetails> {
var
generatorDetails
=
provider
.
generatorDetails
;
var
complaintDetails
=
provider
.
complaintDetailsNew
;
var
followups
=
provider
.
followUpList
;
var
complaintBillList
=
provider
.
complaintList
;
return
WillPopScope
(
onWillPop:
()
=>
onBackPressed
(
context
),
child:
SafeArea
(
...
...
@@ -942,6 +946,7 @@ class _VisitdetailsState extends State<Visitdetails> {
.
fsrExt
!,
fileUrl:
"https://erp.gengroup.in/files_genservices/tech_fsr_report/
${followups[lp].fsrExt!}
"
,
downloadEnable:
false
,
),
),
);
...
...
@@ -993,6 +998,129 @@ class _VisitdetailsState extends State<Visitdetails> {
),
),
],
if
(
complaintBillList
.
isNotEmpty
)
...[
Container
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
10
,
vertical:
5
,
),
child:
Text
(
"Complaint Bill List"
,
style:
TextStyle
(
color:
Color
(
0xFF818181
),
fontFamily:
"JakartaMedium"
,
),
),
),
SizedBox
(
width:
double
.
infinity
,
height:
350
,
child:
ListView
.
builder
(
padding:
EdgeInsets
.
all
(
12
),
itemCount:
complaintBillList
!.
length
,
itemBuilder:
(
context
,
index
)
{
final
item
=
complaintBillList
![
index
];
return
Card
(
margin:
EdgeInsets
.
only
(
bottom:
12
),
elevation:
0
,
shape:
RoundedRectangleBorder
(
borderRadius:
BorderRadius
.
circular
(
12
)),
child:
Padding
(
padding:
const
EdgeInsets
.
all
(
14
),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
// _detailRow("Bill ID", item.billId),
// _detailRow("Total Amount", item.totalAmount),
// _detailRow("Raw Amount", item.rawAmount),
// _detailRow("Narration", item.narration),
// _detailRow("Bill Date", item.billDate),
// _detailRow("Due Date", item.dueDate),
// _detailRow("Bill Paid", item.billPaid == "1" ? "Yes" : "No"),
Row
(
children:
[
// 👤 Avatar
Container
(
height:
40
,
width:
40
,
decoration:
const
BoxDecoration
(
color:
Color
(
0xFFE6F6FF
),
shape:
BoxShape
.
circle
,
),
clipBehavior:
Clip
.
antiAlias
,
child:
SvgPicture
.
asset
(
"assets/svg/compliant_list_ic.svg"
,
),
),
const
SizedBox
(
width:
12
),
// 📝 Info
Expanded
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
item
.
narration
??
"-"
,
style:
const
TextStyle
(
fontFamily:
"Plus Jakarta Sans"
,
fontWeight:
FontWeight
.
w400
,
fontSize:
14
,
color:
Colors
.
black87
,
),
),
const
SizedBox
(
height:
3
),
Text
(
item
.
dueDate
??
"-"
,
style:
TextStyle
(
fontFamily:
"JakartaRegular"
,
fontSize:
12
,
fontWeight:
FontWeight
.
w400
,
color:
Colors
.
grey
.
shade600
,
height:
1.4
,
),
),
],
),
),
// Call
if
(
item
.
billPaid
==
"0"
)
InkResponse
(
onTap:
(){
var
homeProvider
=
Provider
.
of
<
HomescreenNotifier
>(
context
,
listen:
false
,
);
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
RazorpayQrScreen
(
sessionId:
homeProvider
.
session
,
empId:
homeProvider
.
empId
,
amount:
item
.
rawAmount
.
toString
(),
refType:
"Bill"
,
refId:
item
.
billId
.
toString
()
))
);
},
child:
Text
(
"Pay Now"
,
style:
TextStyle
(
fontSize:
14
,
color:
AppColors
.
app_blue
,
),),
)
],
),
],
),
),
);
},
)
),
],
SizedBox
(
height:
75
),
],
),
...
...
@@ -1022,6 +1150,7 @@ class _VisitdetailsState extends State<Visitdetails> {
provider
.
complaintDetailsNew
.
complaintId
,
complaintType:
provider
.
complaintDetailsNew
.
complaintType
,
),
),
);
...
...
@@ -1213,6 +1342,28 @@ class _VisitdetailsState extends State<Visitdetails> {
);
}
Widget
_detailRow
(
String
title
,
String
?
value
)
{
return
Padding
(
padding:
const
EdgeInsets
.
only
(
bottom:
8
),
child:
Row
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
"
$title
: "
,
style:
TextStyle
(
fontWeight:
FontWeight
.
bold
,
fontSize:
14
),
),
Expanded
(
child:
Text
(
value
??
"--"
,
style:
TextStyle
(
fontSize:
14
),
),
),
],
),
);
}
Widget
_scaffold
(
BuildContext
context
)
{
return
Consumer
<
Visitdetailsprovider
>(
builder:
(
context
,
provider
,
child
)
{
...
...
Prev
1
2
3
4
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment