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
Show whitespace changes
Inline
Side-by-side
lib/screens/hrm/Attendancelist.dart
View file @
77774bea
...
@@ -12,6 +12,7 @@ import '../../Notifiers/HomeScreenNotifier.dart';
...
@@ -12,6 +12,7 @@ import '../../Notifiers/HomeScreenNotifier.dart';
import
'../../Notifiers/hrmProvider/attendanceListProvider.dart'
;
import
'../../Notifiers/hrmProvider/attendanceListProvider.dart'
;
import
'../../Utils/app_colors.dart'
;
import
'../../Utils/app_colors.dart'
;
import
'../../Utils/commonWidgets.dart'
;
import
'../../Utils/commonWidgets.dart'
;
import
'../../Utils/custom_snackbar.dart'
;
import
'../CommonFilter2.dart'
;
import
'../CommonFilter2.dart'
;
import
'../commonDateRangeFilter.dart'
;
import
'../commonDateRangeFilter.dart'
;
import
'AddLiveAttendance.dart'
;
import
'AddLiveAttendance.dart'
;
...
@@ -158,7 +159,7 @@ class _AttendanceListScreenState extends State<AttendanceListScreen> {
...
@@ -158,7 +159,7 @@ class _AttendanceListScreenState extends State<AttendanceListScreen> {
// }
// }
if
(
provider
.
response
?.
requestList
==
null
||
if
(
provider
.
response
?.
requestList
==
null
||
provider
.
response
!.
requestList
!.
isEmpty
)
{
provider
.
response
!.
requestList
!.
isEmpty
)
{
return
const
Center
(
return
Center
(
child:
Text
(
child:
Text
(
"No attendance records found"
,
"No attendance records found"
,
style:
TextStyle
(
style:
TextStyle
(
...
@@ -171,7 +172,7 @@ class _AttendanceListScreenState extends State<AttendanceListScreen> {
...
@@ -171,7 +172,7 @@ class _AttendanceListScreenState extends State<AttendanceListScreen> {
final
list
=
provider
.
response
!.
requestList
!;
final
list
=
provider
.
response
!.
requestList
!;
return
ListView
.
builder
(
return
ListView
.
builder
(
padding:
const
EdgeInsets
.
all
(
8
),
padding:
EdgeInsets
.
all
(
8
),
itemCount:
list
.
length
,
itemCount:
list
.
length
,
itemBuilder:
(
context
,
index
)
{
itemBuilder:
(
context
,
index
)
{
final
item
=
list
[
index
];
final
item
=
list
[
index
];
...
@@ -186,7 +187,11 @@ class _AttendanceListScreenState extends State<AttendanceListScreen> {
...
@@ -186,7 +187,11 @@ class _AttendanceListScreenState extends State<AttendanceListScreen> {
context
,
context
,
listen:
false
,
listen:
false
,
);
);
return
Slidable
(
return
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
vertical:
6
),
child:
ClipRRect
(
borderRadius:
BorderRadius
.
circular
(
20
),
child:
Slidable
(
key:
ValueKey
(
item
.
id
),
key:
ValueKey
(
item
.
id
),
// Left swipe (Reject)
// Left swipe (Reject)
...
@@ -194,49 +199,33 @@ class _AttendanceListScreenState extends State<AttendanceListScreen> {
...
@@ -194,49 +199,33 @@ class _AttendanceListScreenState extends State<AttendanceListScreen> {
canSwipe
canSwipe
?
ActionPane
(
?
ActionPane
(
motion:
const
ScrollMotion
(),
motion:
const
ScrollMotion
(),
extentRatio:
0.4
,
dragDismissible:
false
,
dragDismissible:
false
,
children:
[
children:
[
SlidableAction
(
SlidableAction
(
onPressed:
(
_
)
{
onPressed:
(
_
)
async
{
showRemarkSheet
(
await
showRemarkSheet
(
context:
context
,
context:
context
,
actionType:
"Reject"
,
actionType:
"Reject"
,
onSubmit:
(
remark
)
async
{
onSubmit:
(
remark
)
async
{
await
provider
await
provider
.
rejectApproveAttendanceRequest
(
.
rejectApproveAttendanceRequest
(
session:
homeProvider
.
session
,
session:
empId:
homeProvider
.
empId
,
homeProvider
.
session
,
empId:
homeProvider
.
empId
,
mode:
widget
.
mode
,
mode:
widget
.
mode
,
type:
"Rejected"
,
type:
"Rejected"
,
remarks:
remark
,
remarks:
remark
,
id:
item
.
id
??
"0"
,
id:
item
.
id
??
"0"
,
);
);
ScaffoldMessenger
.
of
(
if
(
context
.
mounted
)
{
context
,
CustomSnackBar
.
showSuccess
(
).
showSnackBar
(
context:
context
,
const
SnackBar
(
message:
"Attendance request rejected."
,
content:
Text
(
"Attendance request rejected successfully."
,
),
),
);
// refresh list
provider
.
fetchAttendanceRequests
(
context
,
widget
.
mode
,
);
);
// ✅ refresh here after completion
await
provider
.
fetchAttendanceRequests
(
context
,
widget
.
mode
);
}
},
},
).
then
((
_
)
{
);
provider
.
fetchAttendanceRequests
(
context
,
widget
.
mode
,
);
// or setState(() {}) if needed
});
},
},
backgroundColor:
const
Color
(
backgroundColor:
const
Color
(
0xFFFFE5E5
,
0xFFFFE5E5
,
...
@@ -256,37 +245,35 @@ class _AttendanceListScreenState extends State<AttendanceListScreen> {
...
@@ -256,37 +245,35 @@ class _AttendanceListScreenState extends State<AttendanceListScreen> {
canSwipe
canSwipe
?
ActionPane
(
?
ActionPane
(
motion:
const
ScrollMotion
(),
motion:
const
ScrollMotion
(),
extentRatio:
0.4
,
// Width percentage
dragDismissible:
false
,
dragDismissible:
false
,
children:
[
children:
[
SlidableAction
(
SlidableAction
(
onPressed:
(
context
)
{
onPressed:
(
_
)
async
{
showRemarkSheet
(
await
showRemarkSheet
(
context:
context
,
context:
context
,
actionType:
"Approve"
,
actionType:
"Approve"
,
onSubmit:
(
remark
)
async
{
onSubmit:
(
remark
)
async
{
await
provider
await
provider
.
rejectApproveAttendanceRequest
(
.
rejectApproveAttendanceRequest
(
session:
homeProvider
.
session
,
session:
empId:
homeProvider
.
empId
,
homeProvider
.
session
,
empId:
homeProvider
.
empId
,
mode:
widget
.
mode
,
mode:
widget
.
mode
,
type:
"Approved"
,
type:
"Approved"
,
remarks:
remark
,
remarks:
remark
,
id:
item
.
id
??
"0"
,
id:
item
.
id
??
"0"
,
);
);
},
if
(
context
.
mounted
)
{
).
then
((
_
)
{
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
provider
const
SnackBar
(
content:
Text
(
"Attendance request approved."
)),
.
fetchAttendanceRequests
(
context
,
widget
.
mode
,
);
);
});
CustomSnackBar
.
showSuccess
(
print
(
context:
context
,
"######################################"
,
message:
"Attendance request approved."
,
);
// refresh here after API success
await
provider
.
fetchAttendanceRequests
(
context
,
widget
.
mode
);
}
},
);
);
},
},
backgroundColor:
const
Color
(
backgroundColor:
const
Color
(
...
@@ -303,7 +290,7 @@ class _AttendanceListScreenState extends State<AttendanceListScreen> {
...
@@ -303,7 +290,7 @@ class _AttendanceListScreenState extends State<AttendanceListScreen> {
:
null
,
:
null
,
child:
InkWell
(
child:
InkWell
(
borderRadius:
BorderRadius
.
circular
(
16
),
borderRadius:
BorderRadius
.
circular
(
0
),
onTap:
()
{
onTap:
()
{
Navigator
.
push
(
Navigator
.
push
(
context
,
context
,
...
@@ -318,17 +305,17 @@ class _AttendanceListScreenState extends State<AttendanceListScreen> {
...
@@ -318,17 +305,17 @@ class _AttendanceListScreenState extends State<AttendanceListScreen> {
);
);
},
},
child:
Container
(
child:
Container
(
margin:
const
EdgeInsets
.
symmetric
(
//
margin: const EdgeInsets.symmetric(
horizontal:
8.5
,
//
horizontal:
0
,
vertical:
5
,
//
vertical: 5,
),
//
),
padding:
const
EdgeInsets
.
symmetric
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
1
2
,
horizontal:
1
4
,
vertical:
8.5
,
vertical:
12
,
),
),
decoration:
BoxDecoration
(
decoration:
BoxDecoration
(
color:
Colors
.
white
,
color:
Colors
.
white
,
borderRadius:
BorderRadius
.
circular
(
16
),
borderRadius:
BorderRadius
.
circular
(
2
),
),
),
child:
Row
(
child:
Row
(
children:
[
children:
[
...
@@ -427,6 +414,8 @@ class _AttendanceListScreenState extends State<AttendanceListScreen> {
...
@@ -427,6 +414,8 @@ class _AttendanceListScreenState extends State<AttendanceListScreen> {
),
),
),
),
),
),
),
),
);
);
},
},
);
);
...
...
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/material.dart'
;
import
'package:flutter_svg/svg.dart'
;
import
'package:flutter_svg/svg.dart'
;
import
'package:generp/screens/hrm/Attendancelist.dart'
;
import
'package:generp/screens/hrm/Attendancelist.dart'
;
import
'package:generp/screens/hrm/ContactList.dart'
;
import
'package:provider/provider.dart'
;
import
'package:provider/provider.dart'
;
import
'../../Utils/app_colors.dart'
;
import
'../../Utils/app_colors.dart'
;
import
'AdvanceListScreen.dart'
;
import
'AdvanceListScreen.dart'
;
...
@@ -27,7 +28,7 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
...
@@ -27,7 +28,7 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
"Rewards List"
,
"Rewards List"
,
"Attendance Request List"
,
"Attendance Request List"
,
"Advance List"
,
"Advance List"
,
"Casual Leave List"
"Casual Leave List"
,
];
];
// Responsive text size function
// Responsive text size function
...
@@ -236,7 +237,7 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
...
@@ -236,7 +237,7 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
return
Padding
(
return
Padding
(
padding:
EdgeInsets
.
symmetric
(
padding:
EdgeInsets
.
symmetric
(
horizontal:
getResponsivePadding
(
context
),
horizontal:
getResponsivePadding
(
context
)
-
3
,
vertical:
10
,
vertical:
10
,
),
),
child:
Consumer
<
HrmAccessiblePagesProvider
>(
child:
Consumer
<
HrmAccessiblePagesProvider
>(
...
@@ -336,8 +337,8 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
...
@@ -336,8 +337,8 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
horizontal:
constraints
.
maxWidth
*
0.06
,
horizontal:
constraints
.
maxWidth
*
0.06
,
),
),
margin:
EdgeInsets
.
symmetric
(
margin:
EdgeInsets
.
symmetric
(
vertical:
isSmallScreen
?
4
:
7
,
vertical:
isSmallScreen
?
4
:
6.5
,
horizontal:
isSmallScreen
?
3
:
5
horizontal:
isSmallScreen
?
2
:
4
),
),
decoration:
BoxDecoration
(
decoration:
BoxDecoration
(
color:
Colors
.
white
,
color:
Colors
.
white
,
...
@@ -435,6 +436,8 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
...
@@ -435,6 +436,8 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
return
"Advance Payment"
;
return
"Advance Payment"
;
case
"Casual Leave List"
:
case
"Casual Leave List"
:
return
"Track Casual Leave"
;
return
"Track Casual Leave"
;
case
"Employee Contact List"
:
return
"Staff Contact"
;
default
:
default
:
return
""
;
return
""
;
}
}
...
@@ -459,6 +462,8 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
...
@@ -459,6 +462,8 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
return
"assets/svg/hrm/advance_list_ic.svg"
;
return
"assets/svg/hrm/advance_list_ic.svg"
;
case
"Casual Leave List"
:
case
"Casual Leave List"
:
return
"assets/svg/hrm/casual_leave_history_ic.svg"
;
return
"assets/svg/hrm/casual_leave_history_ic.svg"
;
case
"Employee Contact List"
:
return
"assets/svg/hrm/emp_contact_list.svg"
;
default
:
default
:
return
"assets/svg/hrm/groupIc.svg"
;
return
"assets/svg/hrm/groupIc.svg"
;
}
}
...
@@ -534,6 +539,15 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
...
@@ -534,6 +539,15 @@ class _HrmdashboardScreenState extends State<HrmdashboardScreen> {
),
),
);
);
break
;
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';
...
@@ -66,5 +66,6 @@ export 'package:generp/Notifiers/hrmProvider/rewardListProvider.dart';
export
'package:generp/Notifiers/hrmProvider/LeaveApplicationListProvider.dart'
;
export
'package:generp/Notifiers/hrmProvider/LeaveApplicationListProvider.dart'
;
export
'package:generp/Notifiers/hrmProvider/LeaveApplicationDetailsProvider.dart'
;
export
'package:generp/Notifiers/hrmProvider/LeaveApplicationDetailsProvider.dart'
;
export
'package:generp/Notifiers/hrmProvider/CasualLeaveHistoryProvider.dart'
;
export
'package:generp/Notifiers/hrmProvider/CasualLeaveHistoryProvider.dart'
;
export
'package:generp/Notifiers/hrmProvider/contact_provider.dart'
;
export
'package:generp/Notifiers/hrmprovider/orgprovider.dart'
;
export
'package:generp/Notifiers/hrmprovider/orgprovider.dart'
;
lib/screens/serviceEngineer/PaymentDetails.dart
View file @
77774bea
...
@@ -2,6 +2,7 @@ import 'dart:io';
...
@@ -2,6 +2,7 @@ import 'dart:io';
import
'package:dropdown_button2/dropdown_button2.dart'
;
import
'package:dropdown_button2/dropdown_button2.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter_svg/svg.dart'
;
import
'package:flutter_svg/svg.dart'
;
import
'package:generp/Notifiers/PaymentDetailsProvider.dart'
;
import
'package:generp/Notifiers/PaymentDetailsProvider.dart'
;
import
'package:generp/Utils/app_colors.dart'
;
import
'package:generp/Utils/app_colors.dart'
;
...
@@ -474,7 +475,10 @@ class _PaymentdetailsState extends State<Paymentdetails> {
...
@@ -474,7 +475,10 @@ class _PaymentdetailsState extends State<Paymentdetails> {
floatingActionButtonLocation:
floatingActionButtonLocation:
FloatingActionButtonLocation
.
centerFloat
,
FloatingActionButtonLocation
.
centerFloat
,
floatingActionButton:
InkWell
(
floatingActionButton:
InkWell
(
onTap:
()
{
onTap:
provider
.
isPaymentUpdating
?
null
:
()
{
HapticFeedback
.
selectionClick
();
provider
.
PaymentUpdateAPI
(
provider
.
PaymentUpdateAPI
(
context
,
context
,
provider
.
Referencecontroller
.
text
,
provider
.
Referencecontroller
.
text
,
...
@@ -484,18 +488,24 @@ class _PaymentdetailsState extends State<Paymentdetails> {
...
@@ -484,18 +488,24 @@ class _PaymentdetailsState extends State<Paymentdetails> {
child:
Container
(
child:
Container
(
alignment:
Alignment
.
center
,
alignment:
Alignment
.
center
,
height:
45
,
height:
45
,
margin:
EdgeInsets
.
only
(
margin:
const
EdgeInsets
.
symmetric
(
horizontal:
5
,
vertical:
5
),
left:
5.0
,
right:
5.0
,
top:
5.0
,
bottom:
5.0
,
),
decoration:
BoxDecoration
(
decoration:
BoxDecoration
(
color:
AppColors
.
app_blue
,
//1487C9
color:
provider
.
isPaymentUpdating
?
Colors
.
grey
.
shade400
:
AppColors
.
app_blue
,
borderRadius:
BorderRadius
.
circular
(
15.0
),
borderRadius:
BorderRadius
.
circular
(
15.0
),
),
),
child:
Center
(
child:
Center
(
child:
Text
(
child:
provider
.
isPaymentUpdating
?
const
SizedBox
(
height:
22
,
width:
22
,
child:
CircularProgressIndicator
(
strokeWidth:
2.5
,
valueColor:
AlwaysStoppedAnimation
<
Color
>(
Colors
.
white
),
),
)
:
const
Text
(
"Send OTP"
,
"Send OTP"
,
textAlign:
TextAlign
.
center
,
textAlign:
TextAlign
.
center
,
style:
TextStyle
(
style:
TextStyle
(
...
@@ -506,7 +516,7 @@ class _PaymentdetailsState extends State<Paymentdetails> {
...
@@ -506,7 +516,7 @@ class _PaymentdetailsState extends State<Paymentdetails> {
),
),
),
),
),
),
)
,
)
),
),
),
),
),
),
...
@@ -607,24 +617,19 @@ class _PaymentdetailsState extends State<Paymentdetails> {
...
@@ -607,24 +617,19 @@ class _PaymentdetailsState extends State<Paymentdetails> {
Future
<
void
>
showOTPSheetSheet
(
BuildContext
context
)
{
Future
<
void
>
showOTPSheetSheet
(
BuildContext
context
)
{
return
showModalBottomSheet
(
return
showModalBottomSheet
(
useSafeArea:
true
,
useSafeArea:
true
,
isDismissible:
true
,
isDismissible:
false
,
// Prevent dismiss while processing
isScrollControlled:
true
,
isScrollControlled:
true
,
showDragHandle:
true
,
showDragHandle:
true
,
backgroundColor:
Colors
.
white
,
backgroundColor:
Colors
.
white
,
enableDrag:
true
,
enableDrag:
false
,
// Disable drag while processing
context:
context
,
context:
context
,
builder:
(
context
)
{
builder:
(
context
)
{
return
StatefulBuilder
(
builder:
(
context
,
setState
)
{
return
SafeArea
(
return
SafeArea
(
child:
Consumer
<
Paymentdetailsprovider
>(
child:
Consumer
<
Paymentdetailsprovider
>(
builder:
(
context
,
provider
,
child
)
{
builder:
(
context
,
provider
,
child
)
{
return
Padding
(
return
Padding
(
padding:
EdgeInsets
.
only
(
padding:
EdgeInsets
.
only
(
bottom:
bottom:
MediaQuery
.
of
(
context
).
viewInsets
.
bottom
,
MediaQuery
.
of
(
context
,
).
viewInsets
.
bottom
,
// This handles keyboard
),
),
child:
Container
(
child:
Container
(
margin:
EdgeInsets
.
only
(
margin:
EdgeInsets
.
only
(
...
@@ -633,7 +638,6 @@ class _PaymentdetailsState extends State<Paymentdetails> {
...
@@ -633,7 +638,6 @@ class _PaymentdetailsState extends State<Paymentdetails> {
right:
15
,
right:
15
,
top:
10
,
top:
10
,
),
),
child:
SingleChildScrollView
(
child:
SingleChildScrollView
(
child:
Column
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
crossAxisAlignment:
CrossAxisAlignment
.
start
,
...
@@ -654,7 +658,6 @@ class _PaymentdetailsState extends State<Paymentdetails> {
...
@@ -654,7 +658,6 @@ class _PaymentdetailsState extends State<Paymentdetails> {
children:
[
children:
[
Container
(
Container
(
alignment:
Alignment
.
center
,
alignment:
Alignment
.
center
,
height:
50
,
height:
50
,
margin:
EdgeInsets
.
only
(
margin:
EdgeInsets
.
only
(
left:
5.0
,
left:
5.0
,
...
@@ -667,28 +670,18 @@ class _PaymentdetailsState extends State<Paymentdetails> {
...
@@ -667,28 +670,18 @@ class _PaymentdetailsState extends State<Paymentdetails> {
),
),
length:
4
,
length:
4
,
blinkWhenObscuring:
true
,
blinkWhenObscuring:
true
,
animationType:
AnimationType
.
fade
,
animationType:
AnimationType
.
fade
,
// validator: (v) {
enabled:
!
provider
.
isVerifyingOtp
,
// Disable during verification
// if (v!.length < 3) {
// return "I'm from validator";
// } else {
// return null;
// }
// },
pinTheme:
PinTheme
(
pinTheme:
PinTheme
(
shape:
PinCodeFieldShape
.
underline
,
shape:
PinCodeFieldShape
.
underline
,
borderRadius:
BorderRadius
.
circular
(
16
),
borderRadius:
BorderRadius
.
circular
(
16
),
fieldHeight:
60
,
fieldHeight:
60
,
fieldWidth:
60
,
fieldWidth:
60
,
activeFillColor:
activeFillColor:
AppColors
.
text_field_color
,
AppColors
.
text_field_color
,
activeColor:
AppColors
.
app_blue
,
activeColor:
AppColors
.
app_blue
,
selectedColor:
AppColors
.
text_field_color
,
selectedColor:
AppColors
.
text_field_color
,
selectedFillColor:
selectedFillColor:
AppColors
.
text_field_color
,
AppColors
.
text_field_color
,
inactiveFillColor:
AppColors
.
text_field_color
,
inactiveFillColor:
AppColors
.
text_field_color
,
inactiveColor:
AppColors
.
text_field_color
,
inactiveColor:
AppColors
.
text_field_color
,
fieldOuterPadding:
EdgeInsets
.
only
(
fieldOuterPadding:
EdgeInsets
.
only
(
left:
5
,
left:
5
,
...
@@ -707,86 +700,123 @@ class _PaymentdetailsState extends State<Paymentdetails> {
...
@@ -707,86 +700,123 @@ class _PaymentdetailsState extends State<Paymentdetails> {
),
),
],
],
onCompleted:
(
String
enteredCode
)
{
onCompleted:
(
String
enteredCode
)
{
if
(!
provider
.
isVerifyingOtp
)
{
provider
.
enteredOtp
=
enteredCode
;
provider
.
enteredOtp
=
enteredCode
;
// clearText = true;
provider
.
OTPVerifyAPI
(
context
);
provider
.
OTPVerifyAPI
(
context
);
}
debugPrint
(
"Completed"
);
debugPrint
(
"Completed"
);
},
},
// onTap: () {
// print("Pressed");
// },
onChanged:
(
String
enteredCode
)
{
onChanged:
(
String
enteredCode
)
{
debugPrint
(
enteredCode
);
debugPrint
(
enteredCode
);
provider
.
enteredOtp
=
enteredCode
;
provider
.
enteredOtp
=
enteredCode
;
},
},
onSubmitted:
(
String
enteredCode
)
{
onSubmitted:
(
String
enteredCode
)
{
if
(!
provider
.
isVerifyingOtp
)
{
provider
.
enteredOtp
=
enteredCode
;
provider
.
enteredOtp
=
enteredCode
;
// clearText = true
;
provider
.
OTPVerifyAPI
(
context
)
;
// Verify_otp();
}
},
},
enablePinAutofill:
true
,
enablePinAutofill:
true
,
useExternalAutoFillGroup:
true
,
useExternalAutoFillGroup:
true
,
beforeTextPaste:
(
text
)
{
beforeTextPaste:
(
text
)
{
debugPrint
(
"Allowing to paste
$text
"
);
debugPrint
(
"Allowing to paste
$text
"
);
//if you return true then it will show the paste confirmation dialog. Otherwise if false, then nothing will happen.
//but you can show anything you want here, like your pop up saying wrong paste format or etc
return
true
;
return
true
;
},
},
),
),
),
),
SizedBox
(
height:
15
),
SizedBox
(
height:
15
),
// 🔁 Resend Button
Container
(
Container
(
alignment:
Alignment
.
center
,
alignment:
Alignment
.
center
,
height:
45
,
height:
45
,
margin:
EdgeInsets
.
only
(
margin:
const
EdgeInsets
.
symmetric
(
horizontal:
5
,
vertical:
5
),
left:
5.0
,
right:
5.0
,
top:
5.0
,
bottom:
5.0
,
),
child:
InkResponse
(
child:
InkResponse
(
onTap:
()
{
onTap:
provider
.
isResendingOtp
||
provider
.
isVerifyingOtp
?
null
:
()
{
HapticFeedback
.
selectionClick
();
provider
.
ResendOtpAPI
(
context
);
provider
.
ResendOtpAPI
(
context
);
},
},
child:
Center
(
child:
Center
(
child:
Text
(
child:
provider
.
isResendingOtp
"Resend"
,
?
Row
(
style:
TextStyle
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
fontWeight:
FontWeight
.
w300
,
mainAxisSize:
MainAxisSize
.
min
,
children:
const
[
SizedBox
(
height:
18
,
width:
18
,
child:
CircularProgressIndicator
(
strokeWidth:
2.2
,
valueColor:
AlwaysStoppedAnimation
<
Color
>(
Colors
.
grey
),
),
),
),
SizedBox
(
width:
8
),
Text
(
"Sending..."
,
style:
TextStyle
(
color:
Colors
.
grey
),
),
],
)
:
const
Text
(
"Resend"
,
style:
TextStyle
(
fontWeight:
FontWeight
.
w300
),
),
),
),
),
),
),
),
),
// Submit Button
InkResponse
(
InkResponse
(
onTap:
()
{
onTap:
provider
.
isVerifyingOtp
||
provider
.
enteredOtp
.
length
!=
4
Navigator
.
of
(
context
).
pop
(
false
);
?
null
:
()
{
HapticFeedback
.
selectionClick
();
provider
.
OTPVerifyAPI
(
context
);
provider
.
OTPVerifyAPI
(
context
);
},
},
child:
Container
(
child:
Container
(
alignment:
Alignment
.
center
,
alignment:
Alignment
.
center
,
height:
45
,
height:
45
,
margin:
EdgeInsets
.
only
(
margin:
const
EdgeInsets
.
symmetric
(
horizontal:
5
,
vertical:
5
),
left:
5.0
,
right:
5.0
,
top:
5.0
,
bottom:
5.0
,
),
decoration:
BoxDecoration
(
decoration:
BoxDecoration
(
color:
AppColors
.
app_blue
,
//1487C9
color:
provider
.
isVerifyingOtp
?
Colors
.
grey
.
shade400
:
(
provider
.
enteredOtp
.
length
==
4
?
AppColors
.
app_blue
:
Colors
.
grey
.
shade300
),
borderRadius:
BorderRadius
.
circular
(
15.0
),
borderRadius:
BorderRadius
.
circular
(
15.0
),
),
),
child:
Center
(
child:
Center
(
child:
Text
(
child:
provider
.
isVerifyingOtp
?
Row
(
mainAxisAlignment:
MainAxisAlignment
.
center
,
mainAxisSize:
MainAxisSize
.
min
,
children:
const
[
SizedBox
(
height:
20
,
width:
20
,
child:
CircularProgressIndicator
(
strokeWidth:
2.3
,
valueColor:
AlwaysStoppedAnimation
<
Color
>(
Colors
.
white
),
),
),
SizedBox
(
width:
8
),
Text
(
"Verifying..."
,
style:
TextStyle
(
fontSize:
15
,
fontFamily:
"JakartaMedium"
,
color:
Colors
.
white
,
),
),
],
)
:
Text
(
"Submit"
,
"Submit"
,
textAlign:
TextAlign
.
center
,
textAlign:
TextAlign
.
center
,
style:
TextStyle
(
style:
TextStyle
(
fontSize:
15
,
fontSize:
15
,
fontFamily:
"JakartaMedium"
,
fontFamily:
"JakartaMedium"
,
color:
Colors
.
white
,
color:
provider
.
enteredOtp
.
length
==
4
?
Colors
.
white
:
Colors
.
grey
,
),
),
),
),
),
),
...
@@ -804,10 +834,9 @@ class _PaymentdetailsState extends State<Paymentdetails> {
...
@@ -804,10 +834,9 @@ class _PaymentdetailsState extends State<Paymentdetails> {
);
);
},
},
);
);
},
);
}
}
Future
<
void
>
_addContactSheet
(
BuildContext
context
)
{
Future
<
void
>
_addContactSheet
(
BuildContext
context
)
{
final
controllersNames
=
[
final
controllersNames
=
[
"Name"
,
"Name"
,
...
...
lib/services/api_calling.dart
View file @
77774bea
...
@@ -29,6 +29,7 @@ import 'package:generp/Models/financeModels/paymentRequisitionPaymentsListRespon
...
@@ -29,6 +29,7 @@ import 'package:generp/Models/financeModels/paymentRequisitionPaymentsListRespon
import
'package:generp/Models/hrmModels/advanceListResponse.dart'
;
import
'package:generp/Models/hrmModels/advanceListResponse.dart'
;
import
'package:generp/Models/hrmModels/attendanceRequestListResponse.dart'
;
import
'package:generp/Models/hrmModels/attendanceRequestListResponse.dart'
;
import
'package:generp/Models/hrmModels/casualLeaveHistoryResponse.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/jobDescriptionResponse.dart'
;
import
'package:generp/Models/hrmModels/leaveApplicationDetailsResponse.dart'
;
import
'package:generp/Models/hrmModels/leaveApplicationDetailsResponse.dart'
;
import
'package:generp/Models/hrmModels/leaveApplicationLIstResponse.dart'
;
import
'package:generp/Models/hrmModels/leaveApplicationLIstResponse.dart'
;
...
@@ -3655,6 +3656,7 @@ class ApiCalling {
...
@@ -3655,6 +3656,7 @@ class ApiCalling {
if
(
res
!=
null
)
{
if
(
res
!=
null
)
{
print
(
data
);
print
(
data
);
debugPrint
(
"Submit New Leads
${res.body}
"
);
debugPrint
(
"Submit New Leads
${res.body}
"
);
return
crmNewLeadsProspectsSubmitResponse
.
fromJson
(
return
crmNewLeadsProspectsSubmitResponse
.
fromJson
(
jsonDecode
(
res
.
body
),
jsonDecode
(
res
.
body
),
);
);
...
@@ -3819,7 +3821,7 @@ class ApiCalling {
...
@@ -3819,7 +3821,7 @@ class ApiCalling {
final
res
=
await
post
(
data
,
crmLeadListFilterSubmitUrl
,
{});
final
res
=
await
post
(
data
,
crmLeadListFilterSubmitUrl
,
{});
if
(
res
!=
null
)
{
if
(
res
!=
null
)
{
print
(
"Lead Filter:
$data
"
);
print
(
"Lead Filter:
$data
"
);
debugPrint
(
res
.
body
);
debugPrint
(
" Lead list data :
${
res.body
}
"
);
return
SubmitLeadListFilterResponse
.
fromJson
(
jsonDecode
(
res
.
body
));
return
SubmitLeadListFilterResponse
.
fromJson
(
jsonDecode
(
res
.
body
));
}
else
{
}
else
{
debugPrint
(
"Null Response"
);
debugPrint
(
"Null Response"
);
...
@@ -5637,6 +5639,33 @@ class ApiCalling {
...
@@ -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(
// static Future<CommonResponse?> TpcIssueListApprovalAPI(
// empId,
// empId,
// session,
// session,
...
...
lib/services/api_names.dart
View file @
77774bea
...
@@ -205,7 +205,7 @@ const LeaveRequestAdditionUrl ="${baseUrl_test}add_leave_request";
...
@@ -205,7 +205,7 @@ const LeaveRequestAdditionUrl ="${baseUrl_test}add_leave_request";
const
LeaveRequestRejectAprroveUrl
=
"
${baseUrl_test}
leaves_approve_reject"
;
const
LeaveRequestRejectAprroveUrl
=
"
${baseUrl_test}
leaves_approve_reject"
;
const
CasuaLeaveHistoryUrl
=
"
${baseUrl_test}
casual_leave_history"
;
const
CasuaLeaveHistoryUrl
=
"
${baseUrl_test}
casual_leave_history"
;
const
EmployeeContactListUrl
=
"
${baseUrl_test}
employee_contact_list"
;
const
AdvanceListUrl
=
"
${baseUrl_test}
advance_list"
;
const
AdvanceListUrl
=
"
${baseUrl_test}
advance_list"
;
...
...
pubspec.lock
View file @
77774bea
...
@@ -574,6 +574,14 @@ packages:
...
@@ -574,6 +574,14 @@ packages:
url: "https://pub.dev"
url: "https://pub.dev"
source: hosted
source: hosted
version: "3.4.1"
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:
flutter_download_manager:
dependency: "direct main"
dependency: "direct main"
description:
description:
...
...
pubspec.yaml
View file @
77774bea
...
@@ -93,6 +93,7 @@ dependencies:
...
@@ -93,6 +93,7 @@ dependencies:
file_picker
:
^8.0.0
file_picker
:
^8.0.0
flutter_html
:
^3.0.0
flutter_html
:
^3.0.0
photo_view
:
^0.14.0
photo_view
:
^0.14.0
flutter_contacts
:
^1.1.9+2
dev_dependencies
:
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