sort and filter functionalities added in resources

master
Sneha 2 weeks ago
parent e054f2eb92
commit 849afdd17a

@ -7,6 +7,8 @@ import 'package:supplier_new/common/dashboard.dart';
import 'package:supplier_new/common/settings.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import '../signup/signup_mobilenumber_screen.dart';
class Login extends StatefulWidget {
const Login({super.key});
@ -168,15 +170,15 @@ class _LoginState extends State<Login> {
),
),
SizedBox(height:MediaQuery.of(context).size.height * .016,),
/* SizedBox(height:MediaQuery.of(context).size.height * .016,),
Align(
alignment: Alignment.bottomLeft,
child:GestureDetector(
onTap: (){
/* Navigator.push(
*//* Navigator.push(
context,
MaterialPageRoute(builder: (context) => ForgotpasswordNew()),
);*/
);*//*
},
child: Text(
'Forgot Password?',
@ -184,7 +186,7 @@ class _LoginState extends State<Login> {
),
)
),
),*/
SizedBox(height:MediaQuery.of(context).size.height * .024,),
Container(
width:double.infinity,
@ -268,6 +270,23 @@ class _LoginState extends State<Login> {
},
child: Text('Login',style: fontTextStyle(12,Colors.white,FontWeight.w600),),
)),
SizedBox(height:MediaQuery.of(context).size.height * .024,),
Align(
alignment: Alignment.center,
child:GestureDetector(
onTap: (){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SignUpMobileNumberScreen()),
);
},
child: Text(
'Not a member yet! SignUp',
style: fontTextStyle(12,Color(0XFF1D7AFC),FontWeight.w600),
),
)
),
],
),
)

@ -261,10 +261,11 @@ class _DriverDetailsPageState extends State<DriverDetailsPage> {
_LabeledField(
label: "Driver License Number *",
child: TextFormField(
controller: _licenseController, // create controller
controller: _licenseController,
textCapitalization: TextCapitalization.characters,
decoration: const InputDecoration(
border: OutlineInputBorder(),
hintText: "Enter License Number",
hintText: "Enter Driving License Number",
contentPadding:
EdgeInsets.symmetric(horizontal: 12, vertical: 14),
),
@ -560,13 +561,15 @@ class _DriverDetailsPageState extends State<DriverDetailsPage> {
@override
Widget build(BuildContext context) {
final statusColor = switch (widget.driverDetails.status) {
'available' => const Color(0xFF0A9E04),
'on delivery' => const Color(0xFFD0AE3C),
'offline' => const Color(0xFF939495),
_ => Colors.grey,
final Map<String, Color> statusColors = {
'available' : Color(0xFF0A9E04),
'on delivery' : Color(0xFFD0AE3C),
'offline' : Color(0xFF939495),
};
final statusColor =
statusColors[widget.driverDetails.status.toLowerCase().trim()] ?? Colors.grey;
return WillPopScope(
onWillPop: () async {
Navigator.pop(context, true);

@ -98,6 +98,184 @@ class _ResourcesDriverScreenState extends State<ResourcesDriverScreen> {
return null;
}
String? selectedFilter;
String selectedSort = "Name";
List<String> filterOptions = [
"All",
"Available",
"On delivery",
"Offline"
];
List<String> sortOptions = [
"Name",
"Deliveries"
];
void _showFilterMenu(BuildContext context, Offset position) async {
await showMenu<String>(
context: context,
color: Colors.white,
position: RelativeRect.fromLTRB(
position.dx,
position.dy,
position.dx + 200,
position.dy + 200),
items: [
PopupMenuItem<String>(
enabled:false,
child: Text(
"Filter",
style: fontTextStyle(
12,
Color(0XFF2D2E30),
FontWeight.w600),
),
),
...filterOptions.map((option){
return PopupMenuItem<String>(
child: RadioListTile<String>(
value: option,
groupValue:
selectedFilter ?? "All",
activeColor:
Color(0XFF1D7AFC),
onChanged:(value){
setState(() {
selectedFilter =
value=="All"
? null
: value;
});
Navigator.pop(context);
},
title: Text(
option,
style: fontTextStyle(
12,
Color(0XFF2D2E30),
FontWeight.w400),
),
dense:true,
visualDensity:
VisualDensity(
horizontal:-4,
vertical:-4),
),
);
}).toList()
],
);
}
void _showSortMenu(BuildContext context, Offset position) async {
await showMenu<String>(
context: context,
color: Colors.white,
position: RelativeRect.fromLTRB(
position.dx,
position.dy,
position.dx + 200,
position.dy + 200),
items: [
PopupMenuItem<String>(
enabled:false,
child: Text(
"Sort",
style: fontTextStyle(
12,
Color(0XFF2D2E30),
FontWeight.w600),
),
),
...sortOptions.map((option){
return PopupMenuItem<String>(
child: RadioListTile<String>(
value: option,
groupValue: selectedSort,
activeColor:
Color(0XFF1D7AFC),
onChanged:(value){
setState(() {
selectedSort =
value.toString();
});
Navigator.pop(context);
},
title: Text(
option,
style: fontTextStyle(
12,
Color(0XFF2D2E30),
FontWeight.w400),
),
dense:true,
visualDensity:
VisualDensity(
horizontal:-4,
vertical:-4),
),
);
}).toList()
],
);
}
@override
void initState() {
super.initState();
@ -141,7 +319,7 @@ class _ResourcesDriverScreenState extends State<ResourcesDriverScreen> {
int offline = 0;
for (final d in data) {
switch (d.status) {
switch (d.status.toLowerCase().trim()) {
case 'on delivery':
onDelivery++;
break;
@ -277,10 +455,11 @@ class _ResourcesDriverScreenState extends State<ResourcesDriverScreen> {
_LabeledField(
label: "Driver License Number *",
child: TextFormField(
controller: _licenseController, // create controller
controller: _licenseController,
textCapitalization: TextCapitalization.characters,// create controller
decoration: const InputDecoration(
border: OutlineInputBorder(),
hintText: "Enter License Number",
hintText: "Enter Driving License Number",
contentPadding:
EdgeInsets.symmetric(horizontal: 12, vertical: 14),
),
@ -507,11 +686,45 @@ class _ResourcesDriverScreenState extends State<ResourcesDriverScreen> {
// ---------- UI ----------
@override
Widget build(BuildContext context) {
final filtered = driversList.where((it) {
List<DriversModel> filtered = driversList.where((it) {
final q = search.trim().toLowerCase();
if (q.isEmpty) return true;
return it.driver_name.toLowerCase().contains(q);
bool matchesSearch =
q.isEmpty ||
it.driver_name.toLowerCase().contains(q);
bool matchesFilter = true;
if(selectedFilter!=null){
matchesFilter =
it.status.toLowerCase().trim() ==
selectedFilter!.toLowerCase();
}
return matchesSearch && matchesFilter;
}).toList();
if(selectedSort=="Name"){
filtered.sort(
(a,b)=>a.driver_name
.compareTo(b.driver_name));
}
if(selectedSort=="Deliveries"){
filtered.sort((a,b)=>
(int.tryParse(b.deliveries) ?? 0)
.compareTo(
int.tryParse(a.deliveries) ?? 0));
}
return Scaffold(
backgroundColor: Colors.white,
body: Column(
@ -644,11 +857,39 @@ class _ResourcesDriverScreenState extends State<ResourcesDriverScreen> {
),
),
const SizedBox(width: 16),
Image.asset("images/icon_tune.png",
width: 24, height: 24),
GestureDetector(
onTapDown:(details){
_showFilterMenu(
context,
details.globalPosition);
},
child: Image.asset(
"images/icon_tune.png",
width: 24,
height: 24),
),
const SizedBox(width: 16),
Image.asset("images/up_down_arrow.png",
width: 24, height: 24),
GestureDetector(
onTapDown:(details){
_showSortMenu(
context,
details.globalPosition);
},
child: Image.asset(
"images/up_down_arrow.png",
width: 24,
height: 24),
),
],
),
const SizedBox(height: 12),
@ -773,13 +1014,15 @@ class DriverCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
final statusColor = switch (status) {
'available' => const Color(0xFF0A9E04),
'on delivery' => const Color(0xFFD0AE3C),
'offline' => const Color(0xFF939495),
_ => Colors.grey,
final Map<String, Color> statusColors = {
'available' : Color(0xFF0A9E04),
'on delivery' : Color(0xFFD0AE3C),
'offline' : Color(0xFF939495),
};
final statusColor =
statusColors[status.toLowerCase().trim()] ?? Colors.grey;
Future<void> _makePhoneCall(String phone) async {
final Uri url = Uri(

@ -57,9 +57,8 @@ class _ResourcesFleetScreenState extends State<ResourcesFleetScreen> {
// Dropdown options (adjust to your backend)
final List<String> tankerTypes = const [
"Standard Tanker",
"High-Capacity Tanker",
"Small Tanker",
"Without Pump",
"With Pump",
];
final List<String> typeOfWater = const [
"Drinking water",
@ -79,6 +78,21 @@ class _ResourcesFleetScreenState extends State<ResourcesFleetScreen> {
int inactiveCount = 0;
int maintenanceCount = 0;
String? selectedFilter;
String selectedSort = "name";
List<String> filterOptions = [
"All",
"Active",
"Inactive",
"Maintenance"
];
List<String> sortOptions = [
"Name",
"Capacity"
];
@override
void initState() {
super.initState();
@ -95,6 +109,169 @@ class _ResourcesFleetScreenState extends State<ResourcesFleetScreen> {
super.dispose();
}
void _showFilterMenu(BuildContext context, Offset position) async {
await showMenu<String>(
context: context,
color: Colors.white,
position: RelativeRect.fromLTRB(
position.dx,
position.dy,
position.dx + 200,
position.dy + 200),
items: [
PopupMenuItem<String>(
enabled: false,
child: Text(
"Filter",
style: fontTextStyle(
12,
Color(0XFF2D2E30),
FontWeight.w600),
),
),
...filterOptions.map((option){
return PopupMenuItem<String>(
child: RadioListTile<String>(
value: option,
groupValue:
selectedFilter ?? "All",
activeColor:
Color(0XFF1D7AFC),
onChanged:(value){
setState(() {
selectedFilter =
value=="All"
? null
: value;
});
Navigator.pop(context);
},
title: Text(
option,
style: fontTextStyle(
12,
Color(0XFF2D2E30),
FontWeight.w400),
),
dense:true,
visualDensity:
VisualDensity(
horizontal:-4,
vertical:-4),
),
);
}).toList()
],
);
}
void _showSortMenu(BuildContext context, Offset position) async {
await showMenu<String>(
context: context,
color: Colors.white,
position: RelativeRect.fromLTRB(
position.dx,
position.dy,
position.dx + 200,
position.dy + 200),
items: [
PopupMenuItem<String>(
enabled:false,
child: Text(
"Sort",
style: fontTextStyle(
12,
Color(0XFF2D2E30),
FontWeight.w600),
),
),
...sortOptions.map((option){
return PopupMenuItem<String>(
child: RadioListTile<String>(
value: option,
groupValue: selectedSort,
activeColor:
Color(0XFF1D7AFC),
onChanged:(value){
setState(() {
selectedSort =
value.toString();
});
Navigator.pop(context);
},
title: Text(
option,
style: fontTextStyle(
12,
Color(0XFF2D2E30),
FontWeight.w400),
),
dense:true,
visualDensity:
VisualDensity(
horizontal:-4,
vertical:-4),
),
);
}).toList()
],
);
}
Future<void> _fetchTankers() async {
setState(() => isLoading = true);
try {
@ -261,7 +438,7 @@ class _ResourcesFleetScreenState extends State<ResourcesFleetScreen> {
child: TextFormField(
controller: _nameCtrl,
validator: (v) => _required(v, field: "Tanker Name"),
textCapitalization: TextCapitalization.none,
textCapitalization: TextCapitalization.characters,
inputFormatters: const [
FirstCharUppercaseFormatter(), // << live first-letter caps
],
@ -361,11 +538,11 @@ class _ResourcesFleetScreenState extends State<ResourcesFleetScreen> {
),
_LabeledField(
label: "Manufacturing Year (opt)",
label: " Age of vehicle (opt)",
child: TextFormField(
controller: _mfgYearCtrl,
decoration: InputDecoration(
hintText: "YYYY",
hintText: "12",
hintStyle: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400),
border: const OutlineInputBorder(),
isDense: true,
@ -426,14 +603,54 @@ class _ResourcesFleetScreenState extends State<ResourcesFleetScreen> {
);
}
@override
Widget build(BuildContext context) {
final filtered = tankersList.where((it) {
List<TankersModel> filtered = tankersList.where((it) {
final q = search.trim().toLowerCase();
if (q.isEmpty) return true;
return it.tanker_name.toLowerCase().contains(q);
bool matchesSearch =
q.isEmpty || it.tanker_name.toLowerCase().contains(q);
bool matchesFilter = true;
if(selectedFilter=="Active"){
matchesFilter =
it.availability.contains('available') ||
it.availability.contains('in-use') ||
it.availability.contains('empty');
}
if(selectedFilter=="Inactive"){
matchesFilter =
it.availability.contains('inactive');
}
if(selectedFilter=="Maintenance"){
matchesFilter =
it.availability.contains('undermaintanence');
}
return matchesSearch && matchesFilter;
}).toList();
if(selectedSort=="Name"){
filtered.sort((a,b)=>
a.tanker_name.compareTo(b.tanker_name));
}
if(selectedSort=="Capacity"){
filtered.sort((a,b)=>
int.parse(a.capacity.replaceAll(",",""))
.compareTo(
int.parse(b.capacity.replaceAll(",",""))
));
}
return Scaffold(
backgroundColor: Colors.white,
body: Column(
@ -477,20 +694,36 @@ class _ResourcesFleetScreenState extends State<ResourcesFleetScreen> {
],
),
const Spacer(),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: [
Text(
tankersList.length.toString(),
style: fontTextStyle(24, const Color(0xFF0D3771), FontWeight.w500),
),
/*const SizedBox(height: 6),
Text('+2 since last month',
style: fontTextStyle(10, const Color(0xFF646566), FontWeight.w400),
),*/
],
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: [
Text(
tankersList.length.toString(),
style: fontTextStyle(
24,
const Color(0xFF0D3771),
FontWeight.w500),
),
const SizedBox(height: 6),
tankersList.isEmpty
? Text(
'You have not added any tankers please click + button to add new Tanker.',
textAlign: TextAlign.right,
softWrap: true,
style: fontTextStyle(
10,
const Color(0xFF646566),
FontWeight.w400),
)
: const SizedBox(),
],
),
)
],
),
),
@ -558,26 +791,50 @@ class _ResourcesFleetScreenState extends State<ResourcesFleetScreen> {
),
),
const SizedBox(width: 16),
Container(
width: 24,
height: 24,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('images/icon_tune.png'),
fit: BoxFit.contain,
GestureDetector(
onTapDown:(TapDownDetails details){
_showFilterMenu(
context,
details.globalPosition);
},
child: Container(
width: 24,
height: 24,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('images/icon_tune.png'),
fit: BoxFit.contain,
),
),
),
),
const SizedBox(width: 16),
Container(
width: 24,
height: 24,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('images/up_down_arrow.png'),
fit: BoxFit.contain,
GestureDetector(
onTapDown:(TapDownDetails details){
_showSortMenu(
context,
details.globalPosition);
},
child: Container(
width: 24,
height: 24,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('images/up_down_arrow.png'),
fit: BoxFit.contain,
),
),
),
),
],
),

@ -117,6 +117,184 @@ class _ResourcesSourceScreenState extends State<ResourcesSourceScreen> {
return null;
}
String? selectedFilter;
String selectedSort = "Name";
List<String> filterOptions = [
"All",
"Drinking water",
"Bore water",
"Both"
];
List<String> sortOptions = [
"Name",
"Location"
];
void _showFilterMenu(BuildContext context, Offset position) async {
await showMenu<String>(
context: context,
color: Colors.white,
position: RelativeRect.fromLTRB(
position.dx,
position.dy,
position.dx + 200,
position.dy + 200),
items: [
PopupMenuItem<String>(
enabled:false,
child: Text(
"Filter",
style: fontTextStyle(
12,
Color(0XFF2D2E30),
FontWeight.w600),
),
),
...filterOptions.map((option){
return PopupMenuItem<String>(
child: RadioListTile<String>(
value: option,
groupValue:
selectedFilter ?? "All",
activeColor:
Color(0XFF1D7AFC),
onChanged:(value){
setState(() {
selectedFilter =
value=="All"
? null
: value;
});
Navigator.pop(context);
},
title: Text(
option,
style: fontTextStyle(
12,
Color(0XFF2D2E30),
FontWeight.w400),
),
dense:true,
visualDensity:
VisualDensity(
horizontal:-4,
vertical:-4),
),
);
}).toList()
],
);
}
void _showSortMenu(BuildContext context, Offset position) async {
await showMenu<String>(
context: context,
color: Colors.white,
position: RelativeRect.fromLTRB(
position.dx,
position.dy,
position.dx + 200,
position.dy + 200),
items: [
PopupMenuItem<String>(
enabled:false,
child: Text(
"Sort",
style: fontTextStyle(
12,
Color(0XFF2D2E30),
FontWeight.w600),
),
),
...sortOptions.map((option){
return PopupMenuItem<String>(
child: RadioListTile<String>(
value: option,
groupValue: selectedSort,
activeColor:
Color(0XFF1D7AFC),
onChanged:(value){
setState(() {
selectedSort =
value.toString();
});
Navigator.pop(context);
},
title: Text(
option,
style: fontTextStyle(
12,
Color(0XFF2D2E30),
FontWeight.w400),
),
dense:true,
visualDensity:
VisualDensity(
horizontal:-4,
vertical:-4),
),
);
}).toList()
],
);
}
@override
void initState() {
super.initState();
@ -526,13 +704,49 @@ class _ResourcesSourceScreenState extends State<ResourcesSourceScreen> {
// ---------- UI ----------
@override
Widget build(BuildContext context) {
final filtered = sourceLocationsList.where((it) {
List<SourceLocationsModel> filtered =
sourceLocationsList.where((it){
final q = search.trim().toLowerCase();
if (q.isEmpty) return true;
return it.source_name.toLowerCase().contains(q) ||
it.address.toLowerCase().contains(q);
bool matchesSearch =
q.isEmpty ||
it.source_name.toLowerCase().contains(q) ||
it.address.toLowerCase().contains(q);
bool matchesFilter = true;
if(selectedFilter!=null){
matchesFilter =
it.water_type
.toLowerCase()
.trim() ==
selectedFilter!
.toLowerCase();
}
return matchesSearch && matchesFilter;
}).toList();
if(selectedSort=="Name"){
filtered.sort(
(a,b)=>a.source_name
.compareTo(b.source_name));
}
if(selectedSort=="Location"){
filtered.sort(
(a,b)=>a.address
.compareTo(b.address));
}
return Scaffold(
backgroundColor: Colors.white,
body: Column(
@ -665,9 +879,39 @@ class _ResourcesSourceScreenState extends State<ResourcesSourceScreen> {
),
),
const SizedBox(width: 16),
Image.asset('images/icon_tune.png', width: 24, height: 24),
GestureDetector(
onTapDown:(details){
_showFilterMenu(
context,
details.globalPosition);
},
child: Image.asset(
'images/icon_tune.png',
width:24,
height:24),
),
const SizedBox(width: 16),
Image.asset('images/up_down_arrow.png', width: 24, height: 24),
GestureDetector(
onTapDown:(details){
_showSortMenu(
context,
details.globalPosition);
},
child: Image.asset(
'images/up_down_arrow.png',
width:24,
height:24),
),
],
),
const SizedBox(height: 12),

@ -54,9 +54,8 @@ class _TankerDetailsPageState extends State<TankerDetailsPage> {
String? selectedTypeOfWater;
final List<String> tankerTypes = const [
"Standard Tanker",
"High-Capacity Tanker",
"Small Tanker",
"Without Pump",
"With Pump",
];
final List<String> typeOfWater = const [
"Drinking water",
@ -752,11 +751,11 @@ class _TankerDetailsPageState extends State<TankerDetailsPage> {
),
_LabeledField(
label: "Manufacturing Year (opt)",
label: "Age of vehicle (opt)",
child: TextFormField(
controller: _mfgYearCtrl,
decoration: InputDecoration(
hintText: "YYYY",
hintText: "12",
hintStyle: fontTextStyle(
14,
const Color(0xFF939495),

@ -1,3 +1,5 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:sms_autofill/sms_autofill.dart';
import 'package:supplier_new/signup/password_textbox_screen.dart';
@ -27,6 +29,7 @@ class _OtpscreenState extends State<Otpscreen>
int seconds = 30;
bool canResend = false;
Timer? _timer;
@override
void initState(){
@ -41,18 +44,28 @@ class _OtpscreenState extends State<Otpscreen>
void startTimer(){
Future.delayed(const Duration(seconds:1),(){
_timer?.cancel();
_timer = Timer.periodic(const Duration(seconds:1),(timer){
if(!mounted){
timer.cancel();
return;
}
if(seconds>0){
setState(()=>seconds--);
setState(() {
seconds--;
});
startTimer();
}else{
}
else{
setState(() {
canResend=true;
});
setState(()=>canResend=true);
timer.cancel();
}
@ -162,10 +175,7 @@ class _OtpscreenState extends State<Otpscreen>
if(!canResend) return;
var payload={
"mobileNumbers":
widget.mobileNumber
"mobileNumbers":widget.mobileNumber
};
await AppSettings.getOtp(payload);
@ -173,7 +183,6 @@ class _OtpscreenState extends State<Otpscreen>
setState((){
seconds=30;
canResend=false;
});
@ -185,7 +194,8 @@ class _OtpscreenState extends State<Otpscreen>
@override
void dispose(){
cancel();
_timer?.cancel(); // stop timer
cancel(); // sms autofill cancel
super.dispose();

@ -181,6 +181,21 @@ class _SignUpState extends State<SignUp> {
),
)
),
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: 20),
Text(
"Please check the below address for accuracy please change as required by clicking in the box",
textAlign: TextAlign.center,
style: fontTextStyle(
12,
Color(0xFF2D2E30),
FontWeight.w500),
),
],
),
const SizedBox(height: 20),
_buildTextField('Address Line 1 *', '123 Main St',addressLine1Controller),
_buildTextField('Address Line 2(Optional)', 'Area',addressLine2Controller),

@ -28,7 +28,7 @@ class _VerificationScreenState extends State<VerificationScreen> {
CircleAvatar(radius: 80, backgroundColor: Color(0XFFF3F1FB)),
SizedBox(height: MediaQuery.of(context).size.height * .05),
Center(
child: Text("Your application has been submitted!",
child: Text("Your application has been submitted! We will get back to you soon..",
style: fontTextStyle(20, Color(0XFF343637), FontWeight.w700)),
),
SizedBox(height: MediaQuery.of(context).size.height * .01),

Loading…
Cancel
Save