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
77774bea
Commit
77774bea
authored
Oct 16, 2025
by
Sai Srinivas
Browse files
Few Correction and fixes
parents
2a8fa440
3ac9e198
Changes
29
Expand all
Hide whitespace changes
Inline
Side-by-side
lib/screens/hrm/Attendancelist.dart
View file @
77774bea
This diff is collapsed.
Click to expand it.
lib/screens/hrm/ContactList.dart
0 → 100644
View file @
77774bea
import
'package:flutter/material.dart'
;
import
'package:flutter_slidable/flutter_slidable.dart'
;
import
'package:flutter_svg/flutter_svg.dart'
;
import
'package:provider/provider.dart'
;
import
'package:url_launcher/url_launcher.dart'
;
import
'../../Notifiers/HomeScreenNotifier.dart'
;
import
'../../Notifiers/hrmProvider/contact_provider.dart'
;
import
'../../Utils/app_colors.dart'
;
import
'package:flutter_contacts/flutter_contacts.dart'
;
import
'package:permission_handler/permission_handler.dart'
;
import
'../../Utils/custom_snackbar.dart'
;
class
ContactListScreen
extends
StatefulWidget
{
const
ContactListScreen
({
super
.
key
});
@override
State
<
ContactListScreen
>
createState
()
=>
_ContactListScreenState
();
}
class
_ContactListScreenState
extends
State
<
ContactListScreen
>
{
final
TextEditingController
_searchController
=
TextEditingController
();
@override
void
initState
()
{
super
.
initState
();
final
homeProv
=
Provider
.
of
<
HomescreenNotifier
>(
context
,
listen:
false
);
Future
.
microtask
(()
{
final
provider
=
Provider
.
of
<
ContactProvider
>(
context
,
listen:
false
);
provider
.
fetchContactList
(
homeProv
.
session
,
homeProv
.
empId
,
1
);
});
}
void
_addToContact
(
String
name
,
String
phoneNumber
)
async
{
if
(
phoneNumber
.
isEmpty
)
{
CustomSnackBar
.
showError
(
context:
context
,
message:
"No phone number available"
,
);
return
;
}
try
{
// Show loading snackbar
CustomSnackBar
.
showLoading
(
context:
context
,
message:
"Opening contact form for
$name
..."
,
);
// Check and request contact permission
var
permissionStatus
=
await
Permission
.
contacts
.
status
;
if
(
permissionStatus
.
isDenied
)
{
final
requestedStatus
=
await
Permission
.
contacts
.
request
();
if
(!
requestedStatus
.
isGranted
)
{
CustomSnackBar
.
hide
(
context
);
CustomSnackBar
.
showError
(
context:
context
,
message:
"Contact permission is required"
,
);
return
;
}
}
if
(
permissionStatus
.
isPermanentlyDenied
)
{
CustomSnackBar
.
hide
(
context
);
_showPermissionDialog
();
return
;
}
// Clean phone number
final
cleanPhoneNumber
=
_cleanPhoneNumber
(
phoneNumber
);
// ✅ 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)
await
FlutterContacts
.
openExternalInsert
(
newContact
);
// Hide loading
CustomSnackBar
.
hide
(
context
);
// Optional confirmation message
CustomSnackBar
.
showSuccess
(
context:
context
,
message:
"Contact form opened for
$name
"
,
);
}
catch
(
e
)
{
debugPrint
(
"❌ Error opening contact form:
$e
"
);
CustomSnackBar
.
hide
(
context
);
CustomSnackBar
.
showError
(
context:
context
,
message:
"Failed to open contact form"
,
);
}
}
// Helper function to clean phone numbers
String
_cleanPhoneNumber
(
String
phoneNumber
)
{
// Remove all non-digit characters except +
String
cleaned
=
phoneNumber
.
replaceAll
(
RegExp
(
r'[^\d+]'
),
''
);
// Remove country code if it's +91 (India) and number is 10 digits
if
(
cleaned
.
startsWith
(
'+91'
)
&&
cleaned
.
length
==
13
)
{
cleaned
=
cleaned
.
substring
(
3
);
}
else
if
(
cleaned
.
startsWith
(
'91'
)
&&
cleaned
.
length
==
12
)
{
cleaned
=
cleaned
.
substring
(
2
);
}
// Remove leading 0 if present
if
(
cleaned
.
startsWith
(
'0'
)
&&
cleaned
.
length
==
11
)
{
cleaned
=
cleaned
.
substring
(
1
);
}
return
cleaned
;
}
void
_showPermissionDialog
()
{
showDialog
(
context:
context
,
builder:
(
BuildContext
context
)
=>
AlertDialog
(
title:
const
Text
(
"Permission Required"
),
content:
const
Text
(
"Contact permission is permanently denied. Please enable it in app settings to add contacts."
),
actions:
[
TextButton
(
onPressed:
()
=>
Navigator
.
pop
(
context
),
child:
const
Text
(
"Cancel"
),
),
TextButton
(
onPressed:
()
{
Navigator
.
pop
(
context
);
openAppSettings
();
},
child:
const
Text
(
"Open Settings"
),
),
],
),
);
}
void
_openWhatsApp
(
String
phoneNumber
)
async
{
if
(
phoneNumber
.
isEmpty
)
{
CustomSnackBar
.
showError
(
context:
context
,
message:
"No phone number available"
,
);
return
;
}
final
whatsappUrl
=
"https://wa.me/
$phoneNumber
"
;
final
Uri
whatsappUri
=
Uri
.
parse
(
whatsappUrl
);
if
(
await
canLaunchUrl
(
whatsappUri
))
{
await
launchUrl
(
whatsappUri
);
}
else
{
CustomSnackBar
.
showError
(
context:
context
,
message:
"Could not open WhatsApp"
,
);
}
}
@override
Widget
build
(
BuildContext
context
)
{
final
screenWidth
=
MediaQuery
.
of
(
context
).
size
.
width
;
final
bool
isSmallScreen
=
screenWidth
<
360
;
final
bool
isTablet
=
screenWidth
>
768
;
return
Scaffold
(
backgroundColor:
AppColors
.
scaffold_bg_color
,
appBar:
AppBar
(
automaticallyImplyLeading:
false
,
backgroundColor:
Colors
.
white
,
title:
Row
(
children:
[
InkResponse
(
onTap:
()
=>
Navigator
.
pop
(
context
,
true
),
child:
SvgPicture
.
asset
(
"assets/svg/appbar_back_button.svg"
,
height:
isSmallScreen
?
22
:
isTablet
?
28
:
25
,
),
),
const
SizedBox
(
width:
10
),
Text
(
"Contacts"
,
style:
TextStyle
(
fontSize:
isSmallScreen
?
16
:
isTablet
?
20
:
18
,
fontFamily:
"Plus Jakarta Sans"
,
fontWeight:
FontWeight
.
w600
,
color:
Colors
.
black87
,
),
),
],
),
),
body:
Consumer
<
ContactProvider
>(
builder:
(
context
,
provider
,
_
)
{
if
(
provider
.
isLoading
)
{
return
const
Center
(
child:
CircularProgressIndicator
());
}
if
(
provider
.
contactList
.
isEmpty
)
{
return
const
Center
(
child:
Text
(
"No contacts found"
,
style:
TextStyle
(
color:
Colors
.
black54
,
fontSize:
16
,
fontFamily:
"Plus Jakarta Sans"
),
),
);
}
final
filteredContacts
=
provider
.
contactList
.
where
((
c
)
=>
(
c
.
name
??
''
)
.
toLowerCase
()
.
contains
(
_searchController
.
text
.
toLowerCase
()))
.
toList
();
return
Padding
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
isSmallScreen
?
10
:
16
),
child:
Column
(
children:
[
const
SizedBox
(
height:
12
),
Container
(
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
12
),
),
child:
TextField
(
controller:
_searchController
,
onChanged:
(
_
)
=>
setState
(()
{}),
decoration:
const
InputDecoration
(
hintText:
"Search"
,
hintStyle:
TextStyle
(
color:
Colors
.
grey
),
prefixIcon:
Icon
(
Icons
.
search
,
color:
Colors
.
grey
),
border:
InputBorder
.
none
,
contentPadding:
EdgeInsets
.
symmetric
(
vertical:
14
),
),
),
),
const
SizedBox
(
height:
12
),
Expanded
(
child:
ListView
.
builder
(
itemCount:
filteredContacts
.
length
,
itemBuilder:
(
context
,
index
)
{
final
contact
=
filteredContacts
[
index
];
final
canSwipe
=
contact
.
mobileNumber
!=
null
&&
contact
.
mobileNumber
!.
trim
().
length
==
10
;
return
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
vertical:
6
),
child:
ClipRRect
(
borderRadius:
BorderRadius
.
circular
(
20
),
child:
Slidable
(
key:
Key
(
contact
.
mobileNumber
?.
toString
()
??
'
${contact.name}
_
$index
'
),
// Left swipe (Add to contact)
startActionPane:
canSwipe
?
ActionPane
(
motion:
const
ScrollMotion
(),
extentRatio:
0.4
,
// Width percentage
dragDismissible:
false
,
children:
[
// This will automatically take full height of the list item
SlidableAction
(
onPressed:
(
_
)
async
{
_addToContact
(
contact
.
name
??
'Contact'
,
contact
.
mobileNumber
??
''
,
);
},
backgroundColor:
const
Color
(
0xFFE5FFE5
),
foregroundColor:
const
Color
(
0xFF38903c
),
icon:
Icons
.
contact_page
,
label:
'Add to Contact'
,
autoClose:
true
,
),
],
)
:
null
,
// Right swipe (WhatsApp)
endActionPane:
canSwipe
?
ActionPane
(
motion:
const
ScrollMotion
(),
extentRatio:
0.4
,
// Width percentage
dragDismissible:
false
,
children:
[
SlidableAction
(
onPressed:
(
_
)
async
{
_openWhatsApp
(
contact
.
mobileNumber
??
''
);
},
backgroundColor:
const
Color
(
0xFFE9FFE8
),
foregroundColor:
const
Color
(
0xFF4CB443
),
icon:
Icons
.
chat
,
label:
'WhatsApp'
,
autoClose:
true
,
),
],
)
:
null
,
// The main content - this determines the height
child:
Container
(
decoration:
BoxDecoration
(
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
1
),
),
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
14
,
vertical:
10
),
child:
Row
(
children:
[
// 👤 Avatar
Container
(
height:
42
,
width:
42
,
decoration:
const
BoxDecoration
(
color:
Color
(
0xFFE6F6FF
),
shape:
BoxShape
.
circle
,
),
clipBehavior:
Clip
.
antiAlias
,
child:
(
contact
.
profileImage
!=
null
&&
contact
.
profileImage
!.
isNotEmpty
)
?
Image
.
network
(
contact
.
profileImage
!,
fit:
BoxFit
.
cover
,
errorBuilder:
(
context
,
error
,
stackTrace
)
{
return
const
Icon
(
Icons
.
person_outline
,
color:
Color
(
0xFF2d2d2d
));
},
loadingBuilder:
(
context
,
child
,
loadingProgress
)
{
if
(
loadingProgress
==
null
)
return
child
;
return
const
Center
(
child:
CircularProgressIndicator
(
strokeWidth:
2
),
);
},
)
:
const
Icon
(
Icons
.
person_outline
,
color:
Color
(
0xFF2d2d2d
)),
),
const
SizedBox
(
width:
12
),
// 📝 Info
Expanded
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Text
(
contact
.
name
??
"-"
,
style:
const
TextStyle
(
fontFamily:
"Plus Jakarta Sans"
,
fontWeight:
FontWeight
.
w400
,
fontSize:
14
,
color:
Colors
.
black87
,
),
),
const
SizedBox
(
height:
3
),
Text
(
"
${contact.designation ?? ''}
\n
${contact.branchName ?? ''}
"
,
style:
TextStyle
(
fontFamily:
"JakartaRegular"
,
fontSize:
12
,
fontWeight:
FontWeight
.
w400
,
color:
Colors
.
grey
.
shade600
,
height:
1.4
,
),
),
],
),
),
// Call
if
(
contact
.
mobileNumber
!=
null
&&
contact
.
mobileNumber
!.
trim
().
length
==
10
)
IconButton
(
icon:
const
Icon
(
Icons
.
call
,
color:
Colors
.
green
,
size:
24
),
onPressed:
()
async
{
final
phone
=
contact
.
mobileNumber
!.
trim
();
final
Uri
callUri
=
Uri
(
scheme:
'tel'
,
path:
phone
);
if
(
await
canLaunchUrl
(
callUri
))
{
await
launchUrl
(
callUri
);
}
else
{
debugPrint
(
"❌ Could not launch dialer for
$phone
"
);
CustomSnackBar
.
showError
(
context:
context
,
message:
"Unable to open dialer"
,
);
}
},
),
],
),
),
),
),
);
},
),
),
],
),
);
},
),
);
}
}
\ No newline at end of file
lib/screens/hrm/HrmDashboardScreen.dart
View file @
77774bea
import
'package:flutter/material.dart'
;
import
'package:flutter_svg/svg.dart'
;
import
'package:generp/screens/hrm/Attendancelist.dart'
;
import
'package:generp/screens/hrm/ContactList.dart'
;
import
'package:provider/provider.dart'
;
import
'../../Utils/app_colors.dart'
;
import
'AdvanceListScreen.dart'
;
...
...
@@ -27,7 +28,7 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
"Rewards List"
,
"Attendance Request List"
,
"Advance List"
,
"Casual Leave List"
"Casual Leave List"
,
];
// Responsive text size function
...
...
@@ -236,7 +237,7 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
return
Padding
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
getResponsivePadding
(
context
),
horizontal:
getResponsivePadding
(
context
)
-
3
,
vertical:
10
,
),
child:
Consumer
<
HrmAccessiblePagesProvider
>(
...
...
@@ -336,8 +337,8 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
horizontal:
constraints
.
maxWidth
*
0.06
,
),
margin:
EdgeInsets
.
symmetric
(
vertical:
isSmallScreen
?
4
:
7
,
horizontal:
isSmallScreen
?
3
:
5
vertical:
isSmallScreen
?
4
:
6.5
,
horizontal:
isSmallScreen
?
2
:
4
),
decoration:
BoxDecoration
(
color:
Colors
.
white
,
...
...
@@ -435,6 +436,8 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
return
"Advance Payment"
;
case
"Casual Leave List"
:
return
"Track Casual Leave"
;
case
"Employee Contact List"
:
return
"Staff Contact"
;
default
:
return
""
;
}
...
...
@@ -459,6 +462,8 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
return
"assets/svg/hrm/advance_list_ic.svg"
;
case
"Casual Leave List"
:
return
"assets/svg/hrm/casual_leave_history_ic.svg"
;
case
"Employee Contact List"
:
return
"assets/svg/hrm/emp_contact_list.svg"
;
default
:
return
"assets/svg/hrm/groupIc.svg"
;
}
...
...
@@ -534,6 +539,15 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
),
);
break
;
case
"Employee Contact List"
:
Navigator
.
push
(
context
,
MaterialPageRoute
(
builder:
(
context
)
=>
ContactListScreen
(),
),
);
break
;
}
}
}
\ No newline at end of file
lib/screens/notifierExports.dart
View file @
77774bea
...
...
@@ -66,5 +66,6 @@ export 'package:generp/Notifiers/hrmProvider/rewardListProvider.dart';
export
'package:generp/Notifiers/hrmProvider/LeaveApplicationListProvider.dart'
;
export
'package:generp/Notifiers/hrmProvider/LeaveApplicationDetailsProvider.dart'
;
export
'package:generp/Notifiers/hrmProvider/CasualLeaveHistoryProvider.dart'
;
export
'package:generp/Notifiers/hrmProvider/contact_provider.dart'
;
export
'package:generp/Notifiers/hrmprovider/orgprovider.dart'
;
lib/screens/serviceEngineer/PaymentDetails.dart
View file @
77774bea
This diff is collapsed.
Click to expand it.
lib/services/api_calling.dart
View file @
77774bea
...
...
@@ -29,6 +29,7 @@ import 'package:generp/Models/financeModels/paymentRequisitionPaymentsListRespon
import
'package:generp/Models/hrmModels/advanceListResponse.dart'
;
import
'package:generp/Models/hrmModels/attendanceRequestListResponse.dart'
;
import
'package:generp/Models/hrmModels/casualLeaveHistoryResponse.dart'
;
import
'package:generp/Models/hrmModels/contactListResponse.dart'
;
import
'package:generp/Models/hrmModels/jobDescriptionResponse.dart'
;
import
'package:generp/Models/hrmModels/leaveApplicationDetailsResponse.dart'
;
import
'package:generp/Models/hrmModels/leaveApplicationLIstResponse.dart'
;
...
...
@@ -3655,6 +3656,7 @@ class ApiCalling {
if
(
res
!=
null
)
{
print
(
data
);
debugPrint
(
"Submit New Leads
${res.body}
"
);
return
crmNewLeadsProspectsSubmitResponse
.
fromJson
(
jsonDecode
(
res
.
body
),
);
...
...
@@ -3819,7 +3821,7 @@ class ApiCalling {
final
res
=
await
post
(
data
,
crmLeadListFilterSubmitUrl
,
{});
if
(
res
!=
null
)
{
print
(
"Lead Filter:
$data
"
);
debugPrint
(
res
.
body
);
debugPrint
(
" Lead list data :
${
res.body
}
"
);
return
SubmitLeadListFilterResponse
.
fromJson
(
jsonDecode
(
res
.
body
));
}
else
{
debugPrint
(
"Null Response"
);
...
...
@@ -5637,6 +5639,33 @@ class ApiCalling {
}
}
// Contact list
static
Future
<
ContactListResponse
?>
contactListAPI
(
session
,
empId
,
pageNumber
)
async
{
debugPrint
(
"🔥🔥🔥🔥🔥🔥🔥Response"
);
try
{
Map
<
String
,
String
>
data
=
{
'session_id'
:
(
session
).
toString
(),
'emp_id'
:
(
empId
).
toString
(),
};
final
res
=
await
post
(
data
,
EmployeeContactListUrl
,
{});
if
(
res
!=
null
)
{
print
(
"Request Data:
$data
"
);
debugPrint
(
"🔥🔥🔥🔥🔥🔥🔥 Response:
${res.body}
"
);
return
ContactListResponse
.
fromJson
(
jsonDecode
(
res
.
body
));
}
else
{
debugPrint
(
"Null Response"
);
return
null
;
}
}
catch
(
e
)
{
debugPrint
(
'API Error:
$e
'
);
return
null
;
}
}
// static Future<CommonResponse?> TpcIssueListApprovalAPI(
// empId,
// session,
...
...
lib/services/api_names.dart
View file @
77774bea
...
...
@@ -205,7 +205,7 @@ const LeaveRequestAdditionUrl ="${baseUrl_test}add_leave_request";
const
LeaveRequestRejectAprroveUrl
=
"
${baseUrl_test}
leaves_approve_reject"
;
const
CasuaLeaveHistoryUrl
=
"
${baseUrl_test}
casual_leave_history"
;
const
EmployeeContactListUrl
=
"
${baseUrl_test}
employee_contact_list"
;
const
AdvanceListUrl
=
"
${baseUrl_test}
advance_list"
;
...
...
pubspec.lock
View file @
77774bea
...
...
@@ -574,6 +574,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.4.1"
flutter_contacts:
dependency: "direct main"
description:
name: flutter_contacts
sha256: "388d32cd33f16640ee169570128c933b45f3259bddbfae7a100bb49e5ffea9ae"
url: "https://pub.dev"
source: hosted
version: "1.1.9+2"
flutter_download_manager:
dependency: "direct main"
description:
...
...
pubspec.yaml
View file @
77774bea
...
...
@@ -93,6 +93,7 @@ dependencies:
file_picker
:
^8.0.0
flutter_html
:
^3.0.0
photo_view
:
^0.14.0
flutter_contacts
:
^1.1.9+2
dev_dependencies
:
...
...
Prev
1
2
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