resources added

master
gitadmin 1 day ago
parent 49dc00c7d8
commit b3d4bd96fa

Binary file not shown.

After

Width:  |  Height:  |  Size: 532 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 420 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

@ -0,0 +1,352 @@
import 'package:flutter/material.dart';
import 'package:supplier_new/common/settings.dart';
import 'package:supplier_new/resources/resources.dart';
import 'package:supplier_new/resources/source_location2.dart';
void main() => runApp(const MaterialApp(home: AvailabilityScreen()));
class AvailabilityScreen extends StatefulWidget {
const AvailabilityScreen({super.key});
@override
_AvailabilityScreenState createState() => _AvailabilityScreenState();
}
class _AvailabilityScreenState extends State<AvailabilityScreen> {
final TextEditingController _advanceNoticeController =
TextEditingController();
final TextEditingController _minDeliveriesController =
TextEditingController();
final TextEditingController _phoneController = TextEditingController();
TimeOfDay? _weekdayStartTime;
TimeOfDay? _weekdayEndTime;
TimeOfDay? _weekendStartTime;
TimeOfDay? _weekendEndTime;
final List<String> _days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
List<bool> _selectedDays = List.generate(7, (index) => false);
Future<void> _pickTime({required int slot}) async {
final TimeOfDay initialTime = TimeOfDay.now();
final TimeOfDay? picked =
await showTimePicker(context: context, initialTime: initialTime);
if (picked == null) return;
setState(() {
switch (slot) {
case 0:
_weekdayStartTime = picked;
break;
case 1:
_weekdayEndTime = picked;
break;
case 2:
_weekendStartTime = picked;
break;
case 3:
_weekendEndTime = picked;
break;
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.white,
surfaceTintColor: Colors.transparent,
elevation: 0,
scrolledUnderElevation: 0,
title: const Text("Complete Profile"),
actions: [
Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 0, 10),
child: IconButton(
splashRadius: 20,
padding: EdgeInsets.zero,
icon: const Image(
image: AssetImage('images/calendar_appbar.png'),
width: 22,
height: 22,
),
onPressed: () {},
),
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 10, 10),
child: IconButton(
splashRadius: 20,
padding: EdgeInsets.zero,
icon: Image.asset('images/notification_appbar.png',
width: 22, height: 22),
onPressed: () {},
),
),
],
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Step indicator
Text('Step 5/5',
style: fontTextStyle(14, Colors.grey, FontWeight.normal)),
const SizedBox(height: 4),
Row(
children: List.generate(4, (index) {
return Expanded(
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 2),
height: 5,
decoration: BoxDecoration(
color: index < 4 ? const Color(0xFFC3C4C4) : Colors.grey,
borderRadius: BorderRadius.circular(2),
),
),
);
}),
),
const SizedBox(height: 20),
// Availability
Text('AVAILABILITY',
style: fontTextStyle(
16, const Color(0xFF2D2E30), FontWeight.w500)),
const SizedBox(height: 12),
Container(
width: 24,
height: 24,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('images/calendar_check.png'),
fit: BoxFit.contain),
),
),
const SizedBox(height: 5),
Text('Set your operating schedule',
style: fontTextStyle(
14, const Color(0xFF939495), FontWeight.w500)),
const SizedBox(height: 10),
Text('AVAILABILITY',
style: fontTextStyle(
14, const Color(0xFF8270DB), FontWeight.w600)),
const SizedBox(height: 12),
Text('Advance Notice Required (hours) *',
style: fontTextStyle(
12, const Color(0xFF2F3036), FontWeight.w600)),
const SizedBox(height: 5),
TextField(
controller: _advanceNoticeController,
keyboardType: TextInputType.number,
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: "1",
hintStyle:
fontTextStyle(14, const Color(0xFF939495), FontWeight.w400),
),
),
const SizedBox(height: 10),
// Minimum Deliveries
Text('Minimum Deliveries (per day) *',
style: fontTextStyle(
12, const Color(0xFF2F3036), FontWeight.w600)),
const SizedBox(height: 5),
TextField(
controller: _minDeliveriesController,
keyboardType: TextInputType.number,
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: '10',
hintStyle:
fontTextStyle(14, const Color(0xFF939495), FontWeight.w400),
),
),
const SizedBox(height: 10),
// Days of Availability
Text(
'Days of Availability *',
style:
fontTextStyle(12, const Color(0xFF251525), FontWeight.w600),
),
const SizedBox(height: 5),
// Place this inside your build() where you want the row of day boxes
// Place this where you want the row of day boxes
Theme(
data: Theme.of(context).copyWith(
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
visualDensity: VisualDensity.compact,
),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: List.generate(_days.length, (index) {
final day = _days[index];
final selected = _selectedDays[index];
return Padding(
padding: const EdgeInsets.only(right: 7.0), // gap 10px
child: GestureDetector(
onTap: () => setState(
() => _selectedDays[index] = !_selectedDays[index]),
onSecondaryTap: () {},
// swallow right-click / context menu
child: SizedBox(
width: 44, // fixed width
height: 42, // fixed height
child: Container(
padding: const EdgeInsets.all(8),
// inner padding 8px
decoration: BoxDecoration(
color: selected
? const Color(0xFF6F5FBA)
: Colors.white,
// selected background
borderRadius: BorderRadius.circular(9),
// radius 9px
border: Border.all(
color: const Color(0xFF6F5FBA),
width: 0.5, // border 0.5px
),
),
alignment: Alignment.center,
child: Text(
day,
textAlign: TextAlign.center,
style: fontTextStyle(
12,
selected
? Colors.white
: const Color(0xFF515253),
FontWeight.w600,
),
),
),
),
),
);
}),
),
),
),
const SizedBox(height: 10),
// Phone Number
Text('Phone Number *',
style: fontTextStyle(
12, const Color(0xFF2F3036), FontWeight.w600)),
const SizedBox(height: 5),
TextField(
controller: _phoneController,
keyboardType: TextInputType.phone,
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: '+91 | Mobile Number',
hintStyle:
fontTextStyle(14, const Color(0xFF939495), FontWeight.w400),
),
),
const SizedBox(height: 20),
// Operating Hours
Text('Operating Hours',
style: fontTextStyle(
14, const Color(0xFF8270DB), FontWeight.w600)),
const SizedBox(height: 5),
LayoutBuilder(
builder: (context, constraints) {
// compute width for 2 columns with 10px gap and 16px padding (adjust if needed)
final double totalGap = 10.0;
final double itemWidth = (constraints.maxWidth - totalGap) / 2;
Widget buildTimeBox({
required String label,
required TimeOfDay? time,
required int slotIndex,
}) {
return SizedBox(
width: itemWidth,
// smaller height than before
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: fontTextStyle(12, const Color(0xFF515253), FontWeight.w600)),
const SizedBox(height: 5),
GestureDetector(
onTap: () => _pickTime(slot: slotIndex),
child: Container(
height: 42, // smaller height
padding: const EdgeInsets.symmetric(horizontal: 10),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade400),
borderRadius: BorderRadius.circular(6),
),
alignment: Alignment.centerLeft,
child: Text(
time != null ? time.format(context) : '--:--',
style: fontTextStyle(14, Colors.black, FontWeight.normal),
),
),
),
],
),
);
}
return Column(
children: [
Row(
children: [
buildTimeBox(label: 'Weekday Start Time *', time: _weekdayStartTime, slotIndex: 0),
const SizedBox(width: 10),
buildTimeBox(label: 'Weekday End Time *', time: _weekdayEndTime, slotIndex: 1),
],
),
const SizedBox(height: 12),
Row(
children: [
buildTimeBox(label: 'Weekend Start Time', time: _weekendStartTime, slotIndex: 2),
const SizedBox(width: 10),
buildTimeBox(label: 'Weekend End Time', time: _weekendEndTime, slotIndex: 3),
],
),
],
);
},
),
const SizedBox(height: 12),
SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF8270DB),
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24)),
),
onPressed: () {
// TODO: Navigate to the next step/screen
Navigator.push(context, MaterialPageRoute(builder: (_) => const ResourcesScreen()));
},
child: Text(
" Save \$ Continue",
style: fontTextStyle(14, Colors.white, FontWeight.w400),
),
),
),
],
),
),
);
}
}

@ -0,0 +1,420 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:supplier_new/common/settings.dart';
import 'package:supplier_new/resources/source_location.dart';
import 'Fleet_1.dart';
// If you want to navigate on Continue, import your next page here.
// import 'fleet_1.dart';
void main() => runApp(const MaterialApp(home: FleetEmployees()));
class FleetEmployees extends StatefulWidget {
const FleetEmployees({super.key});
@override
State<FleetEmployees> createState() => _FleetEmployeesState();
}
class _FleetEmployeesState extends State<FleetEmployees> {
final _formKey = GlobalKey<FormState>();
// Controllers
final _nameCtrl = TextEditingController();
final _mobileCtrl = TextEditingController();
final _altMobileCtrl = TextEditingController();
// Dropdowns
final List<String> licenseNumbers = [
"UP3220050012345",
"UP3220050012355",
"UP3220050012365",
"UP3220050012375",
];
String? selectedLicense;
final List<String> yearOptions = ["1", "2", "3", "4", "5"];
String? selectedExperience;
// Data bucket
final List<Map<String, dynamic>> _drivers = [];
// Validators
String? _required(String? v, {String field = "This field"}) {
if (v == null || v.trim().isEmpty) return "$field is required";
return null;
}
String? _validatePhone(String? v, {String label = "Phone Number"}) {
if (v == null || v.trim().isEmpty) return "$label is required";
final digits = v.replaceAll(RegExp(r'\D'), '');
if (digits.length != 10) return "Enter a 10-digit $label";
if (!RegExp(r'^[6-9]\d{9}$').hasMatch(digits)) {
return "$label must start with 6/7/8/9";
}
return null;
}
@override
void dispose() {
_nameCtrl.dispose();
_mobileCtrl.dispose();
_altMobileCtrl.dispose();
super.dispose();
}
Map<String, dynamic> _buildPayload() => {
"driver_name": _nameCtrl.text.trim(),
"license_number": selectedLicense,
"experience_years": selectedExperience,
"phone": _mobileCtrl.text.trim(),
"alt_phone": _altMobileCtrl.text.trim(),
};
void _clearForm() {
_nameCtrl.clear();
_mobileCtrl.clear();
_altMobileCtrl.clear();
selectedLicense = null;
selectedExperience = null;
setState(() {});
}
void _addDriver() {
final ok = _formKey.currentState?.validate() ?? false;
setState(() {}); // ensure error texts render
if (!ok ||
selectedLicense == null ||
selectedExperience == null ||
selectedLicense!.isEmpty ||
selectedExperience!.isEmpty) {
if (selectedLicense == null || selectedExperience == null) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Please select License & Experience")),
);
}
return;
}
_drivers.add(_buildPayload());
_clearForm();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Driver added (${_drivers.length})")),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.white,
surfaceTintColor: Colors.transparent,
elevation: 0,
scrolledUnderElevation: 0,
title: const Text("Complete Profile"),
actions: [
Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 0, 10),
child: IconButton(
splashRadius: 20,
padding: EdgeInsets.zero,
icon: const Image(image: AssetImage('images/calendar_appbar.png'), width: 22, height: 22),
onPressed: () {},
),
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 10, 10),
child: IconButton(
splashRadius: 20,
padding: EdgeInsets.zero,
icon: Image.asset('images/notification_appbar.png', width: 22, height: 22),
onPressed: () {},
),
),
],
),
body: SafeArea(
child: Form(
key: _formKey,
child: ListView(
padding: const EdgeInsets.fromLTRB(20, 10, 20, 24),
children: [
// Step indicator
Text(
"Step 1/5",
style: fontTextStyle(16, const Color(0xFFC3C4C4), FontWeight.w500),
),
const SizedBox(height: 16),
// Header block
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("EMPLOYEES", style: fontTextStyle(20, const Color(0xFF515253), FontWeight.w600)),
const SizedBox(height: 8),
Container(
width: 24,
height: 24,
decoration: const BoxDecoration(
image: DecorationImage(image: AssetImage('images/manage-users.png'), fit: BoxFit.contain),
),
),
],
),
const SizedBox(height: 6),
Text(
"Details about your water tanker fleet",
style: fontTextStyle(14, const Color(0xFF939495), FontWeight.w500),
),
const SizedBox(height: 16),
// Section header (just the bar)
_SectionHeaderBar(
title: "DRIVER #1",
icon: Image.asset('images/arrow-up.png', width: 16, height: 16),
radius: 20,
),
const SizedBox(height: 12),
// === Fields
_LabeledField(
label: "Driver Name *",
child: TextFormField(
controller: _nameCtrl,
validator: (v) => _required(v, field: "Driver Name"),
decoration: const InputDecoration(
hintText: "Full Name",
border: OutlineInputBorder(),
isDense: true,
),
textInputAction: TextInputAction.next,
),
),
_LabeledField(
label: "Driver License Number *",
child: DropdownButtonFormField<String>(
value: selectedLicense,
items: licenseNumbers
.map((t) => DropdownMenuItem(value: t, child: Text(t)))
.toList(),
onChanged: (v) => setState(() => selectedLicense = v),
validator: (v) => v == null || v.isEmpty ? "Driver License required" : null,
isExpanded: true,
alignment: Alignment.centerLeft,
hint: Text(
"Select License Number",
style: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400),
),
icon: Image.asset('images/downarrow.png', width: 16, height: 16),
decoration: const InputDecoration(
border: OutlineInputBorder(),
isDense: false,
contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 14),
),
),
),
_LabeledField(
label: "Years of Experience *",
child: DropdownButtonFormField<String>(
value: selectedExperience,
items: yearOptions
.map((t) => DropdownMenuItem(value: t, child: Text(t)))
.toList(),
onChanged: (v) => setState(() => selectedExperience = v),
validator: (v) => v == null || v.isEmpty ? "Experience is required" : null,
isExpanded: true,
alignment: Alignment.centerLeft,
hint: Text(
"Years",
style: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400),
),
icon: Image.asset('images/downarrow.png', width: 16, height: 16),
decoration: const InputDecoration(
border: OutlineInputBorder(),
isDense: false,
contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 14),
),
),
),
_LabeledField(
label: "Phone Number *",
child: TextFormField(
controller: _mobileCtrl,
validator: (v) => _validatePhone(v, label: "Phone Number"),
keyboardType: TextInputType.phone,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
LengthLimitingTextInputFormatter(10),
],
decoration: InputDecoration(
hintText: "Mobile Number",
hintStyle: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400),
border: const OutlineInputBorder(),
isDense: true,
),
textInputAction: TextInputAction.next,
),
),
_LabeledField(
label: "Alternate Phone Number",
child: TextFormField(
controller: _altMobileCtrl,
validator: (v) {
if (v == null || v.trim().isEmpty) return null; // optional
return _validatePhone(v, label: "Alternate Phone Number");
},
keyboardType: TextInputType.phone,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
LengthLimitingTextInputFormatter(10),
],
decoration: InputDecoration(
hintText: "Mobile Number",
hintStyle: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400),
border: const OutlineInputBorder(),
isDense: true,
),
textInputAction: TextInputAction.next,
),
),
const SizedBox(height: 20),
// Actions
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SizedBox(
width: double.infinity,
child: OutlinedButton.icon(
onPressed: _addDriver,
icon: Image.asset('images/Add_icon.png', width: 16, height: 16),
label: Text(
"Add Driver",
style: fontTextStyle(14, const Color(0xFF646566), FontWeight.w600),
),
),
),
const SizedBox(height: 12),
SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF8270DB),
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)),
),
onPressed: () {
// TODO: Navigate to the next step/screen
Navigator.push(context, MaterialPageRoute(builder: (_) => const SourceLocation()));
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(content: Text("Saved ${_drivers.length} driver(s). Proceeding…")),
// );
},
child: Text(
"Continue",
style: fontTextStyle(14, Colors.white, FontWeight.w400),
),
),
),
],
),
],
),
),
),
);
}
}
// ======= UI helpers =======
class _SectionHeaderBar extends StatelessWidget {
final String title;
final Widget? icon;
final Color backgroundColor;
final Color borderColor;
final double radius;
const _SectionHeaderBar({
required this.title,
this.icon,
this.backgroundColor = const Color(0xFFEEEEEE),
this.borderColor = const Color(0xFFE5E7EB),
this.radius = 12,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: backgroundColor,
border: Border.all(color: borderColor, width: 1),
borderRadius: BorderRadius.circular(radius),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.04),
blurRadius: 6,
offset: const Offset(0, 2),
),
],
),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
child: Row(
children: [
Expanded(
child: Text(
title,
style: fontTextStyle(12, const Color(0xFF2D2E30), FontWeight.w600),
),
),
if (icon != null) icon!,
],
),
);
}
}
class _LabeledField extends StatelessWidget {
final String label;
final Widget child;
final String? Function()? validator; // (kept from your earlier helper; not used here)
const _LabeledField({
required this.label,
required this.child,
this.validator,
});
@override
Widget build(BuildContext context) {
final errorText = validator != null ? validator!() : null;
return Padding(
padding: const EdgeInsets.only(bottom: 14.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: fontTextStyle(12, const Color(0xFF515253), FontWeight.w600)),
const SizedBox(height: 6),
child,
if (errorText != null)
Padding(
padding: const EdgeInsets.only(top: 6),
child: Text(
errorText,
style: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400),
),
),
],
),
);
}
}

@ -1,5 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:supplier_new/common/settings.dart';
import 'employees.dart';
import 'fleet_1.dart';
void main() => runApp(const MaterialApp(home: FleetStep1Page())); void main() => runApp(const MaterialApp(home: FleetStep1Page()));
@ -15,8 +19,8 @@ class _FleetStep1PageState extends State<FleetStep1Page> {
// Controllers // Controllers
final _nameCtrl = TextEditingController(); final _nameCtrl = TextEditingController();
final _capacityCtrl = TextEditingController(text: "10,000"); // hint-like final _capacityCtrl = TextEditingController(); // hint-like
final _plateCtrl = TextEditingController(text: "AB 05 H 4948"); final _plateCtrl = TextEditingController();
final _mfgYearCtrl = TextEditingController(); final _mfgYearCtrl = TextEditingController();
final _insExpiryCtrl = TextEditingController(); final _insExpiryCtrl = TextEditingController();
@ -50,9 +54,8 @@ class _FleetStep1PageState extends State<FleetStep1Page> {
helpText: "Select Insurance Expiry Date", helpText: "Select Insurance Expiry Date",
); );
if (date != null) { if (date != null) {
_insExpiryCtrl.text = "${date.year.toString().padLeft(4, '0')}-" _insExpiryCtrl.text =
"${date.month.toString().padLeft(2, '0')}-" "${date.year.toString().padLeft(4, '0')}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}";
"${date.day.toString().padLeft(2, '0')}";
setState(() {}); setState(() {});
} }
} }
@ -72,24 +75,80 @@ class _FleetStep1PageState extends State<FleetStep1Page> {
super.dispose(); super.dispose();
} }
// Store multiple tanker entries
final List<Map<String, dynamic>> _tankers = [];
Map<String, dynamic> _buildPayload() => {
"tanker_name": _nameCtrl.text.trim(),
"capacity": _capacityCtrl.text.trim(),
"type": selectedType,
"features": selectedFeatures.toList(),
"license_plate": _plateCtrl.text.trim(),
"manufacturing_year": _mfgYearCtrl.text.trim(),
"insurance_expiry": _insExpiryCtrl.text.trim(),
};
void _clearForm() {
_nameCtrl.clear();
_capacityCtrl.text = "10,000";
_plateCtrl.text = "AB 05 H 4948";
_mfgYearCtrl.clear();
_insExpiryCtrl.clear();
selectedType = null;
selectedFeatures.clear();
setState(() {});
}
void _addTanker() {
final ok = _formKey.currentState?.validate() ?? false;
setState(() {}); // in case you show chip validation below labels
if (!ok || selectedFeatures.isEmpty) {
if (selectedFeatures.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Select at least one Tanker Feature")),
);
}
return;
}
_tankers.add(_buildPayload());
_clearForm();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Tanker added (${_tankers.length})")),
);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
final grey = Colors.grey.shade600;
return Scaffold( return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar( appBar: AppBar(
backgroundColor: Colors.white,
title: const Text("Complete Profile"), title: const Text("Complete Profile"),
centerTitle: false, actions: [
actions: const [ Padding(padding: EdgeInsets.fromLTRB(10,10,0,10),
Padding( child: IconButton(
padding: EdgeInsets.only(right: 12), icon: Image(
child: Icon(Icons.calendar_today_outlined), image: AssetImage('images/calendar_appbar.png')
),
Padding( ),
padding: EdgeInsets.only(right: 12), onPressed: (){
child: Icon(Icons.more_vert),
},
),
), ),
Padding(padding: EdgeInsets.fromLTRB(0,10,10,10),
child: IconButton(
icon: Image.asset(
'images/notification_appbar.png', // Example URL image
),
onPressed: (){
},
),
)
], ],
), ),
body: SafeArea( body: SafeArea(
@ -98,146 +157,248 @@ class _FleetStep1PageState extends State<FleetStep1Page> {
child: ListView( child: ListView(
padding: const EdgeInsets.fromLTRB(20, 10, 20, 24), padding: const EdgeInsets.fromLTRB(20, 10, 20, 24),
children: [ children: [
Text("Step 1/5", style: theme.textTheme.labelLarge?.copyWith(color: grey)), // Step indicator
Text(
"Step 1/5",
style:
fontTextStyle(16, const Color(0xFFC3C4C4), FontWeight.w500),
),
const SizedBox(height: 16), const SizedBox(height: 16),
// FLEET header Column(
Row( crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [ children: [
Icon(Icons.local_shipping_outlined, color: Colors.deepPurple.shade400), Text(
const SizedBox(width: 8), "FLEET",
Text("FLEET", style: theme.textTheme.titleMedium?.copyWith(letterSpacing: 1.2)), style: fontTextStyle(
20, const Color(0xFF515253), FontWeight.w600),
),
const SizedBox(height: 8),
Container(
width: 24,
height: 24,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('images/truck.png'),
fit: BoxFit.contain,
),
),
),
], ],
), ),
const SizedBox(height: 6), const SizedBox(height: 6),
Text( Text(
"Details about your water tanker fleet", "Details about your water tanker fleet",
style: theme.textTheme.bodySmall?.copyWith(color: grey), style:
fontTextStyle(14, const Color(0xFF939495), FontWeight.w500),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
// Water Tanker card _SectionHeaderBar(
_SectionCard(
title: "WATER TANKER #1", title: "WATER TANKER #1",
child: Column( icon: Image.asset('images/arrow-up.png', width: 16, height: 16),
crossAxisAlignment: CrossAxisAlignment.start, radius: 20,
children: [ ),
_LabeledField( const SizedBox(height: 12),
label: "Tanker Name *",
child: TextFormField( _LabeledField(
controller: _nameCtrl, label: "Tanker Name *",
decoration: const InputDecoration( child: TextFormField(
hintText: "Enter Tanker Name", controller: _nameCtrl,
), validator: (v) => _required(v, field: "Tanker Name"),
validator: (v) => _required(v, field: "Tanker Name"), decoration: const InputDecoration(
), hintText: "Enter Tanker Name",
), border: OutlineInputBorder(),
_LabeledField( isDense: true,
label: "Tanker Capacity (in L) *", ),
child: TextFormField( textInputAction: TextInputAction.next,
controller: _capacityCtrl, ),
keyboardType: TextInputType.number, ),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[0-9,]')), _LabeledField(
], label: "Tanker Capacity (in L) *",
decoration: const InputDecoration( child: TextFormField(
hintText: "10,000", controller: _capacityCtrl,
suffixText: "L", validator: (v) => _required(v, field: "Tanker Capacity"),
), decoration: InputDecoration(
validator: (v) => _required(v, field: "Capacity"), hintText: "10,000 L",
), hintStyle: fontTextStyle(
), 14, const Color(0xFF939495), FontWeight.w400),
_LabeledField( border: const OutlineInputBorder(),
label: "Tanker Type *", isDense: true,
child: DropdownButtonFormField<String>( ),
value: selectedType, keyboardType: TextInputType.number,
items: tankerTypes inputFormatters: [
.map((e) => DropdownMenuItem(value: e, child: Text(e))) FilteringTextInputFormatter.allow(RegExp(r'[0-9,]')),
.toList(), ],
onChanged: (v) => setState(() => selectedType = v), textInputAction: TextInputAction.next,
decoration: const InputDecoration(hintText: "Select Type"), ),
validator: (v) => v == null ? "Tanker Type is required" : null, ),
),
), _LabeledField(
_LabeledField( label: "Tanker Type *",
label: "Tanker Features *", child: DropdownButtonFormField<String>(
child: _MultiSelectChips( value: selectedType,
options: featureOptions, items: tankerTypes
selected: selectedFeatures, .map((t) => DropdownMenuItem(value: t, child: Text(t)))
onChanged: (s) => setState(() => selectedFeatures .toList(),
..clear() onChanged: (v) => setState(() => selectedType = v),
..addAll(s)), validator: (v) =>
), v == null || v.isEmpty ? "Tanker Type is required" : null,
validator: () => isExpanded: true,
selectedFeatures.isEmpty ? "Select at least one feature" : null, alignment: Alignment.centerLeft,
), hint: Text(
_LabeledField( "Select Type",
label: "License Plate *", style: fontTextStyle(
child: TextFormField( 14, const Color(0xFF939495), FontWeight.w400),
controller: _plateCtrl, ),
textCapitalization: TextCapitalization.characters,
decoration: const InputDecoration(hintText: "AB 05 H 4948"), icon: Image.asset('images/downarrow.png',
validator: (v) => _required(v, field: "License Plate"), width: 16, height: 16),
),
), decoration: const InputDecoration(
_LabeledField( border: OutlineInputBorder(),
label: "Manufacturing Year (opt)", isDense: false,
child: TextFormField( contentPadding:
controller: _mfgYearCtrl, EdgeInsets.symmetric(horizontal: 12, vertical: 14),
keyboardType: TextInputType.number, ),
inputFormatters: [ ),
FilteringTextInputFormatter.digitsOnly, ),
LengthLimitingTextInputFormatter(4),
], _LabeledField(
decoration: const InputDecoration(hintText: "YYYY"), label: "Tanker Features *",
validator: (_) => null, // optional child: DropdownButtonFormField<String>(
value: selectedType,
items: tankerTypes
.map((t) => DropdownMenuItem(value: t, child: Text(t)))
.toList(),
onChanged: (v) => setState(() => selectedType = v),
validator: (v) =>
v == null || v.isEmpty ? "Tanker Type is required" : null,
isExpanded: true,
alignment: Alignment.centerLeft,
// <-- Hint: left-aligned, vertically centered by padding
hint: Text(
"Select Features",
style: fontTextStyle(
14, const Color(0xFF939495), FontWeight.w400),
),
icon: Image.asset('images/downarrow.png',
width: 16, height: 16),
decoration: const InputDecoration(
border: OutlineInputBorder(),
isDense: false, // keep some height
contentPadding:
EdgeInsets.symmetric(horizontal: 12, vertical: 14),
),
),
),
_LabeledField(
label: "License Plate *",
child: TextFormField(
controller: _plateCtrl,
validator: (v) => _required(v, field: "License Plate"),
decoration: InputDecoration(
hintText: "AB 05 H 4948",
hintStyle: fontTextStyle(
14, const Color(0xFF939495), FontWeight.w400),
border: const OutlineInputBorder(),
isDense: true,
),
textCapitalization: TextCapitalization.characters,
textInputAction: TextInputAction.next,
),
),
_LabeledField(
label: "Manufacturing Year (opt)",
child: TextFormField(
controller: _mfgYearCtrl,
decoration: InputDecoration(
hintText: "YYYY",
hintStyle: fontTextStyle(
14, const Color(0xFF939495), FontWeight.w400),
border: const OutlineInputBorder(),
isDense: true,
),
keyboardType: TextInputType.number,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
LengthLimitingTextInputFormatter(4),
],
textInputAction: TextInputAction.next,
),
),
_LabeledField(
label: "Insurance Expiry Date (opt)",
child: TextFormField(
controller: _insExpiryCtrl,
readOnly: true,
decoration: InputDecoration(
hintText: "DD-MM-YYYY",
hintStyle: fontTextStyle(
14, const Color(0xFF939495), FontWeight.w400),
border: const OutlineInputBorder(),
isDense: true,
),
onTap: _pickInsuranceDate,
),
),
const SizedBox(height: 20),
// Save / Continue
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SizedBox(
width: double.infinity,
child: OutlinedButton.icon(
onPressed: _addTanker,
icon: Image.asset('images/Add_icon.png',
width: 16, height: 16),
// pulsing image
label: Text(
"Add Tanker",
style: fontTextStyle(
14, const Color(0xFF646566), FontWeight.w600),
), ),
), ),
_LabeledField( ),
label: "Insurance Expiry Date (opt)",
child: TextFormField( const SizedBox(height: 12),
controller: _insExpiryCtrl,
readOnly: true, // Continue (primary)
onTap: _pickInsuranceDate, SizedBox(
decoration: const InputDecoration( width: double.infinity,
hintText: "Select date", child: ElevatedButton(
suffixIcon: Icon(Icons.calendar_month_outlined), style: ElevatedButton.styleFrom(
), backgroundColor: const Color(0xFF8270DB), // purple bg
foregroundColor: Colors.white, // ripple/icon/text color
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24)),
), ),
),
const SizedBox(height: 8),
FilledButton(
onPressed: () { onPressed: () {
// manual validation for multi-select too Navigator.push(
final chipsValid = selectedFeatures.isNotEmpty; context,
final valid = _formKey.currentState!.validate() && chipsValid; MaterialPageRoute(builder: (_) => const FleetStep2Page()),
setState(() {}); // to refresh potential helper text in chips
if (!valid) return;
// Collect values
final data = {
"tanker_name": _nameCtrl.text.trim(),
"capacity_liters": _capacityCtrl.text.replaceAll(",", "").trim(),
"tanker_type": selectedType,
"features": selectedFeatures.toList(),
"license_plate": _plateCtrl.text.trim(),
"manufacturing_year": _mfgYearCtrl.text.trim().isEmpty
? null
: _mfgYearCtrl.text.trim(),
"insurance_expiry": _insExpiryCtrl.text.trim().isEmpty
? null
: _insExpiryCtrl.text.trim(),
};
// TODO: send to backend
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Saved: $data")),
); );
}, },
child: const Text("Save & Continue"), child: Text(
"Continue",
style: fontTextStyle(
14, Colors.white, FontWeight.w400), // white text
),
), ),
], )
), ],
), )
], ],
), ),
), ),
@ -246,42 +407,50 @@ class _FleetStep1PageState extends State<FleetStep1Page> {
} }
} }
/// Section card with a folding-style title bar (static in this example)
class _SectionCard extends StatelessWidget { class _SectionHeaderBar extends StatelessWidget {
final String title; final String title;
final Widget child; final Widget? icon;
final Color backgroundColor;
final Color borderColor;
final double radius;
const _SectionCard({required this.title, required this.child}); const _SectionHeaderBar({
required this.title,
this.icon,
this.backgroundColor = const Color(0xFFEEEEEE),
this.borderColor = const Color(0xFFE5E7EB),
this.radius = 8,
Key? key,
}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final border = RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)); return Container(
return Card( decoration: BoxDecoration(
elevation: 0.8, color: backgroundColor,
shape: border, border: Border.all(color: borderColor, width: 1),
margin: const EdgeInsets.only(top: 12), borderRadius: BorderRadius.circular(radius),
child: Padding( boxShadow: [
padding: const EdgeInsets.fromLTRB(12, 8, 12, 12), BoxShadow(
child: Column( color: Colors.black.withOpacity(0.04),
children: [ blurRadius: 6,
Row( offset: const Offset(0, 2),
children: [ ),
Expanded( ],
child: Text( ),
title, padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
style: Theme.of(context) child: Row(
.textTheme children: [
.labelLarge Expanded(
?.copyWith(letterSpacing: .6, color: Colors.grey.shade700), child: Text(
), title,
), style:
const Icon(Icons.expand_less, size: 18, color: Colors.grey), fontTextStyle(12, const Color(0xFF2D2E30), FontWeight.w600),
],
), ),
const Divider(height: 20), ),
child, if (icon != null) icon!,
], ],
),
), ),
); );
} }
@ -300,11 +469,11 @@ class _LabeledField extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final labelStyle = final labelStyle = Theme.of(context)
Theme.of(context).textTheme.bodyMedium?.copyWith(color: Colors.grey.shade800); .textTheme
.bodyMedium
?.copyWith(color: Colors.grey.shade800);
// If a custom validator is provided (e.g., for multi-select),
// show helper/error text below.
final errorText = validator != null ? validator!() : null; final errorText = validator != null ? validator!() : null;
return Padding( return Padding(
@ -312,67 +481,22 @@ class _LabeledField extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text(label, style: labelStyle), Text(label,
style:
fontTextStyle(12, const Color(0xFF515253), FontWeight.w600)),
const SizedBox(height: 6), const SizedBox(height: 6),
child, child,
if (errorText != null) if (errorText != null)
Padding( Padding(
padding: const EdgeInsets.only(top: 6), padding: const EdgeInsets.only(top: 6),
child: Text(errorText, child: Text(
style: TextStyle(color: Theme.of(context).colorScheme.error, fontSize: 12)), errorText,
style:
fontTextStyle(14, const Color(0xFF939495), FontWeight.w400),
),
), ),
], ],
), ),
); );
} }
} }
class _MultiSelectChips extends StatefulWidget {
final List<String> options;
final Set<String> selected;
final ValueChanged<Set<String>> onChanged;
const _MultiSelectChips({
required this.options,
required this.selected,
required this.onChanged,
});
@override
State<_MultiSelectChips> createState() => _MultiSelectChipsState();
}
class _MultiSelectChipsState extends State<_MultiSelectChips> {
late Set<String> _local;
@override
void initState() {
super.initState();
_local = {...widget.selected};
}
@override
Widget build(BuildContext context) {
return Wrap(
spacing: 8,
runSpacing: -6,
children: [
for (final opt in widget.options)
FilterChip(
label: Text(opt),
selected: _local.contains(opt),
onSelected: (v) {
setState(() {
if (v) {
_local.add(opt);
} else {
_local.remove(opt);
}
});
widget.onChanged(_local);
},
),
],
);
}
}

@ -0,0 +1,213 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:supplier_new/common/settings.dart';
import 'employees.dart';
void main() => runApp(const MaterialApp(home: FleetStep2Page()));
class FleetStep2Page extends StatefulWidget {
const FleetStep2Page({super.key});
@override
State<FleetStep2Page> createState() => _FleetStep2PageState();
}
class _FleetStep2PageState extends State<FleetStep2Page> {
final _formKey = GlobalKey<FormState>();
// Store multiple tanker entries (collected on Add Tanker)
final List<Map<String, dynamic>> _tankers = [];
// Minimal payload + clear (no fields on Step 2 yet)
Map<String, dynamic> _buildPayload() => {
"added_at": DateTime.now().toIso8601String(),
"step": 2,
};
void _clearForm() {
setState(() {});
}
void _addTanker() {
final ok = _formKey.currentState?.validate() ?? true; // no fields => true
if (!ok) return;
_tankers.add(_buildPayload());
_clearForm();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Tanker added (${_tankers.length})")),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.white,
surfaceTintColor: Colors.transparent,
elevation: 0,
scrolledUnderElevation: 0,
title: const Text("Complete Profile"),
actions: [
Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 0, 10),
child: IconButton(
splashRadius: 20,
padding: EdgeInsets.zero,
icon: const Image(image: AssetImage('images/calendar_appbar.png'), width: 22, height: 22),
onPressed: () {},
),
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 10, 10),
child: IconButton(
splashRadius: 20,
padding: EdgeInsets.zero,
icon: Image.asset('images/notification_appbar.png', width: 22, height: 22),
onPressed: () {},
),
),
],
),
body: SafeArea(
child: Form(
key: _formKey,
child: ListView(
padding: const EdgeInsets.fromLTRB(20, 10, 20, 24),
children: [
// Step indicator
Text(
"Step 2/5",
style: fontTextStyle(16, const Color(0xFFC3C4C4), FontWeight.w500),
),
const SizedBox(height: 16),
// FLEET header + small image below (left-aligned)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text("FLEET", style: fontTextStyle(20, const Color(0xFF515253), FontWeight.w600)),
const SizedBox(height: 8),
Container(
width: 24,
height: 24,
decoration: const BoxDecoration(
image: DecorationImage(image: AssetImage('images/truck.png'), fit: BoxFit.contain),
),
),
],
),
const SizedBox(height: 6),
Text(
"Details about your water tanker fleet",
style: fontTextStyle(14, const Color(0xFF939495), FontWeight.w500),
),
const SizedBox(height: 16),
// Header bar ONLY (rounded, separate "card" look)
_SectionHeaderBar(
title: "WATER TANKER #1",
icon: Image.asset('images/arrow-up.png', width: 16, height: 16),
radius: 20, // rounded corners
),
const SizedBox(height: 12),
// (No form fields on Step 2 per your snippet)
const SizedBox(height: 20),
// Actions
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SizedBox(
width: double.infinity,
child: OutlinedButton.icon(
onPressed: _addTanker,
icon: Image.asset('images/Add_icon.png', width: 16, height: 16),
label: Text(
"Add Tanker",
style: fontTextStyle(14, const Color(0xFF646566), FontWeight.w600),
),
),
),
const SizedBox(height: 12),
SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF8270DB),
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)),
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (_) => const FleetEmployees()),
);
},
child: Text(
"Continue",
style: fontTextStyle(14, Colors.white, FontWeight.w400),
),
),
),
],
),
],
),
),
),
);
}
}
class _SectionHeaderBar extends StatelessWidget {
final String title;
final Widget? icon;
final Color backgroundColor;
final Color borderColor;
final double radius;
const _SectionHeaderBar({
required this.title,
this.icon,
this.backgroundColor = const Color(0xFFEEEEEE),
this.borderColor = const Color(0xFFE5E7EB),
this.radius = 12,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: backgroundColor,
border: Border.all(color: borderColor, width: 1),
borderRadius: BorderRadius.circular(radius),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.04),
blurRadius: 6,
offset: const Offset(0, 2),
),
],
),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
child: Row(
children: [
Expanded(
child: Text(
title,
style: fontTextStyle(12, const Color(0xFF2D2E30), FontWeight.w600),
),
),
if (icon != null) icon!,
],
),
);
}
}

@ -0,0 +1,408 @@
import 'package:flutter/material.dart';
import 'package:supplier_new/common/settings.dart';
void main() => runApp(const MaterialApp(home: ResourcesScreen()));
class ResourcesScreen extends StatefulWidget {
const ResourcesScreen({super.key});
@override
State<ResourcesScreen> createState() => _ResourcesScreenState();
}
class _ResourcesScreenState extends State<ResourcesScreen> {
int selectedTab = 0;
String search = '';
final List<Map<String, dynamic>> items = [
{
'title': 'Tanker Name',
'subtitle': 'Drinking water - 10,000 L',
'status': ['filled', 'available'],
'code': 'TS 07 J 3492',
'owner': 'Ramesh Krishna'
},
{
'title': 'Drinking Water - 15,000L',
'subtitle': 'Drinking water - 15,000 L',
'status': ['empty', 'available'],
'code': 'TS 07 J 3492',
'owner': 'Ramesh Krishna'
},
{
'title': 'Tanker Name',
'subtitle': 'Drinking water - 10,000 L',
'status': ['filled', 'in-use'],
'code': 'TS 07 J 3492',
'owner': 'Ramesh Krishna'
},
{
'title': 'Drinking Water - 15,000L',
'subtitle': 'Drinking water - 15,000 L',
'status': ['empty', 'in-use'],
'code': 'TS 07 J 3492',
'owner': 'Ramesh Krishna'
},
{
'title': 'Tanker Name',
'subtitle': 'Drinking water - 10,000 L',
'status': ['filled', 'maintenance'],
'code': 'TS 07 J 3492',
'owner': 'Ramesh Krishna'
},
];
@override
Widget build(BuildContext context) {
final filtered = items.where((it) {
final q = search.trim().toLowerCase();
if (q.isEmpty) return true;
return it['title'].toLowerCase().contains(q) ||
it['subtitle'].toLowerCase().contains(q) ||
it['owner'].toLowerCase().contains(q);
}).toList();
return Scaffold(
backgroundColor: const Color(0xFFF6F6F7),
appBar: AppBar(
backgroundColor: Colors.white,
elevation: 0.7,
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.black87),
onPressed: () => Navigator.of(context).maybePop(),
),
title: Text(
'Resources',
style: fontTextStyle(16, const Color(0xFF2A2A2A), FontWeight.w600),
),
centerTitle: false,
actions: [
TextButton(
onPressed: () {},
child: Text('HELP', style: fontTextStyle(12, const Color(0xFF8270DB), FontWeight.w600)),
),
],
),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.fromLTRB(16, 12, 16, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Segmented tabs
Container(
padding: const EdgeInsets.all(6),
decoration: BoxDecoration(
color: const Color(0xFFF1F1F3),
borderRadius: BorderRadius.circular(24),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: List.generate(3, (i) {
final labels = ['Fleet', 'Drivers', 'Sources'];
final isSelected = selectedTab == i;
return GestureDetector(
onTap: () => setState(() => selectedTab = i),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
margin: const EdgeInsets.symmetric(horizontal: 4),
decoration: BoxDecoration(
color: isSelected ? Colors.white : Colors.transparent,
borderRadius: BorderRadius.circular(20),
),
child: Text(
labels[i],
style: TextStyle(
color: isSelected ? Colors.black87 : Colors.grey.shade700,
fontWeight: isSelected ? FontWeight.w600 : FontWeight.w500,
),
),
),
);
}),
),
),
const SizedBox(height: 16),
// Summary card and small stats row
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Big card
Expanded(
flex: 2,
child: Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 6, offset: const Offset(0, 3))
],
),
child: Row(
children: [
Container(
width: 48,
height: 48,
decoration: BoxDecoration(
color: const Color(0xFFF6F0FF),
borderRadius: BorderRadius.circular(10),
),
child: const Icon(Icons.local_shipping_outlined, color: Color(0xFF6F5FBA)),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text('Total Tankers', style: TextStyle(fontSize: 14, color: Colors.black87)),
SizedBox(height: 6),
Text('14', style: TextStyle(fontSize: 28, fontWeight: FontWeight.w700, color: Color(0xFF173F5F))),
SizedBox(height: 2),
Text('+2 since last month', style: TextStyle(fontSize: 12, color: Colors.grey)),
],
),
),
],
),
),
),
const SizedBox(width: 12),
// Small stat cards
Expanded(
flex: 1,
child: Column(
children: [
StatCard(title: 'Active', value: '2'),
const SizedBox(height: 8),
StatCard(title: 'Inactive', value: '3'),
const SizedBox(height: 8),
StatCard(title: 'Under\nMaintenances', value: '1'),
],
),
)
],
),
const SizedBox(height: 16),
// Search and filter row
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
),
child: Row(
children: [
const Icon(Icons.search, color: Colors.grey),
const SizedBox(width: 8),
Expanded(
child: TextField(
decoration: const InputDecoration(
hintText: 'Search',
border: InputBorder.none,
isDense: true,
),
onChanged: (v) => setState(() => search = v),
),
),
IconButton(
onPressed: () {},
icon: const Icon(Icons.filter_list, color: Colors.grey),
),
IconButton(
onPressed: () {},
icon: const Icon(Icons.swap_vert, color: Colors.grey),
)
],
),
),
const SizedBox(height: 12),
// List
Expanded(
child: ListView.separated(
itemCount: filtered.length,
separatorBuilder: (_, __) => const SizedBox(height: 10),
itemBuilder: (context, idx) {
final it = filtered[idx];
return TankCard(
title: it['title'],
subtitle: it['subtitle'],
code: it['code'],
owner: it['owner'],
status: List<String>.from(it['status']),
);
},
),
),
],
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
backgroundColor: const Color(0xFF2E2B5F),
child: const Icon(Icons.add),
),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: 0,
selectedItemColor: const Color(0xFF6F5FBA),
unselectedItemColor: Colors.grey,
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home_outlined), label: 'Home'),
BottomNavigationBarItem(icon: Icon(Icons.receipt_long_outlined), label: 'Orders'),
BottomNavigationBarItem(icon: Icon(Icons.calendar_month), label: 'Plans'),
BottomNavigationBarItem(icon: Icon(Icons.group_outlined), label: 'Resources'),
BottomNavigationBarItem(icon: Icon(Icons.menu), label: 'More'),
],
),
);
}
}
class StatCard extends StatelessWidget {
final String title;
final String value;
const StatCard({super.key, required this.title, required this.value});
@override
Widget build(BuildContext context) {
return Container(
height: 58,
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
border: Border.all(color: Colors.grey.shade200),
),
child: Row(
children: [
Expanded(child: Text(title, style: const TextStyle(fontSize: 13, color: Colors.black87))),
Text(value, style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w700, color: Color(0xFF173F5F))),
],
),
);
}
}
class TankCard extends StatelessWidget {
final String title;
final String subtitle;
final String code;
final String owner;
final List<String> status;
const TankCard({
super.key,
required this.title,
required this.subtitle,
required this.code,
required this.owner,
required this.status,
});
Color _chipColor(String s) {
switch (s) {
case 'filled':
return const Color(0xFFE8F7F1);
case 'available':
return const Color(0xFFE8F0FF);
case 'empty':
return const Color(0xFFFFEEEE);
case 'in-use':
return const Color(0xFFFFF0E6);
case 'maintenance':
return const Color(0xFFFFF4E6);
default:
return const Color(0xFFECECEC);
}
}
Color _chipTextColor(String s) {
switch (s) {
case 'filled':
return Colors.green.shade700;
case 'available':
return const Color(0xFF2E2B5F);
case 'empty':
return Colors.red.shade600;
case 'in-use':
return Colors.orange.shade700;
case 'maintenance':
return Colors.orange.shade700;
default:
return Colors.black87;
}
}
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.grey.shade100),
),
child: Row(
children: [
// left column: chips + texts
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// chips
Row(
children: status.map((s) {
return Container(
margin: const EdgeInsets.only(right: 6),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: _chipColor(s),
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.grey.withOpacity(0.12)),
),
child: Text(
s,
style: TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: _chipTextColor(s)),
),
);
}).toList(),
),
const SizedBox(height: 8),
Text(title, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w700)),
const SizedBox(height: 6),
Text(subtitle, style: const TextStyle(fontSize: 13, color: Colors.grey)),
const SizedBox(height: 10),
Row(
children: [
CircleAvatar(radius: 10, backgroundColor: const Color(0xFFEEF5FF), child: const Icon(Icons.person, size: 12, color: Color(0xFF6F5FBA))),
const SizedBox(width: 6),
Expanded(child: Text(owner, style: const TextStyle(fontSize: 12, color: Colors.grey))),
],
),
],
),
),
// right column: code
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(code, style: const TextStyle(fontSize: 12, color: Colors.grey)),
const SizedBox(height: 28),
],
),
],
),
);
}
}

@ -0,0 +1,429 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:supplier_new/common/settings.dart';
import 'package:supplier_new/resources/source_location1.dart';
import 'Fleet_1.dart';
void main() => runApp(const MaterialApp(home: SourceLocation()));
class SourceLocation extends StatefulWidget {
const SourceLocation({super.key});
@override
State<SourceLocation> createState() => _SourceLocationState();
}
class _SourceLocationState extends State<SourceLocation> {
final _formKey = GlobalKey<FormState>();
// Controllers
final _nameCtrl = TextEditingController();
final _mobileCtrl = TextEditingController();
final _altMobileCtrl = TextEditingController();
// Dropdowns
final List<String> waterTypes = [
"Drinking Water",
"Industrial",
"Construction",
"Non-potable",
];
String? selectedWaterType;
String? selectedLicense;
final List<String> yearOptions = ["1", "2", "3", "4", "5"];
String? selectedExperience;
// Data bucket
final List<Map<String, dynamic>> _drivers = [];
// Validators
String? _required(String? v, {String field = "This field"}) {
if (v == null || v.trim().isEmpty) return "$field is required";
return null;
}
String? _validatePhone(String? v, {String label = "Phone Number"}) {
if (v == null || v.trim().isEmpty) return "$label is required";
final digits = v.replaceAll(RegExp(r'\D'), '');
if (digits.length != 10) return "Enter a 10-digit $label";
if (!RegExp(r'^[6-9]\d{9}$').hasMatch(digits)) {
return "$label must start with 6/7/8/9";
}
return null;
}
@override
void dispose() {
_nameCtrl.dispose();
_mobileCtrl.dispose();
_altMobileCtrl.dispose();
super.dispose();
}
bool addBusinessAsSource = false;
Map<String, dynamic> _buildPayload() => {
"driver_name": _nameCtrl.text.trim(),
"license_number": selectedLicense,
"experience_years": selectedExperience,
"phone": _mobileCtrl.text.trim(),
"alt_phone": _altMobileCtrl.text.trim(),
};
void _clearForm() {
_nameCtrl.clear();
_mobileCtrl.clear();
_altMobileCtrl.clear();
selectedLicense = null;
selectedExperience = null;
setState(() {});
}
void _addDriver() {
final ok = _formKey.currentState?.validate() ?? false;
setState(() {}); // ensure error texts render
if (!ok ||
selectedLicense == null ||
selectedExperience == null ||
selectedLicense!.isEmpty ||
selectedExperience!.isEmpty) {
if (selectedLicense == null || selectedExperience == null) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Please select License & Experience")),
);
}
return;
}
_drivers.add(_buildPayload());
_clearForm();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Driver added (${_drivers.length})")),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.white,
surfaceTintColor: Colors.transparent,
elevation: 0,
scrolledUnderElevation: 0,
title: const Text("Complete Profile"),
actions: [
Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 0, 10),
child: IconButton(
splashRadius: 20,
padding: EdgeInsets.zero,
icon: const Image(image: AssetImage('images/calendar_appbar.png'), width: 22, height: 22),
onPressed: () {},
),
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 10, 10),
child: IconButton(
splashRadius: 20,
padding: EdgeInsets.zero,
icon: Image.asset('images/notification_appbar.png', width: 22, height: 22),
onPressed: () {},
),
),
],
),
body: SafeArea(
child: Form(
key: _formKey,
child: ListView(
padding: const EdgeInsets.fromLTRB(20, 10, 20, 24),
children: [
// Step indicator
Text(
"Step 1/5",
style: fontTextStyle(16, const Color(0xFFC3C4C4), FontWeight.w500),
),
const SizedBox(height: 16),
Row(
children: List.generate(4, (index) {
return Expanded(
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 2),
height: 5,
decoration: BoxDecoration(
color: index < 4 ? const Color(0xFFC3C4C4) : Colors.grey,
borderRadius: BorderRadius.circular(2),
),
),
);
}),
),
const SizedBox(height: 12),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("SORURCE LOCATION", style: fontTextStyle(20, const Color(0xFF515253), FontWeight.w600)),
const SizedBox(height: 8),
Container(
width: 24,
height: 24,
decoration: const BoxDecoration(
image: DecorationImage(image: AssetImage('images/flag.png'), fit: BoxFit.contain),
),
),
],
),
const SizedBox(height: 6),
Text(
"Add your source Location",
style: fontTextStyle(14, const Color(0xFF939495), FontWeight.w500),
),
const SizedBox(height: 6),
Align(
alignment: Alignment.centerLeft, // keep the whole thing on the left
child: Row(
mainAxisSize: MainAxisSize.min, // don't stretch full width
children: [
Checkbox(
value: addBusinessAsSource,
onChanged: (v) => setState(() => addBusinessAsSource = v ?? false),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
visualDensity: const VisualDensity(horizontal: -4, vertical: -4),
),
const SizedBox(width: 6), // control the exact gap
Text(
"Add Business Location as a Source Location",
style: fontTextStyle(14, const Color(0xFF939495), FontWeight.w500),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
),
const SizedBox(height: 16),
// Section header (just the bar)
_SectionHeaderBar(
title: "SOURCE LOCATION #1",
icon: Image.asset('images/arrow-up.png', width: 16, height: 16),
radius: 20,
),
const SizedBox(height: 12),
// === Fields
_LabeledField(
label: "Location Name *",
child: TextFormField(
controller: _nameCtrl,
validator: (v) => _required(v, field: "Location Name"),
decoration: InputDecoration(
hintText: "Location Name",
hintStyle: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400),
border: OutlineInputBorder(),
isDense: true,
),
textInputAction: TextInputAction.next,
),
),
_LabeledField(
label: "Mobile Number *",
child: TextFormField(
controller: _mobileCtrl,
validator: (v) => _validatePhone(v, label: "Mobile Number"),
keyboardType: TextInputType.phone,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
LengthLimitingTextInputFormatter(10),
],
decoration: InputDecoration(
hintText: "Mobile Number",
hintStyle: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400),
border: const OutlineInputBorder(),
isDense: true,
),
textInputAction: TextInputAction.next,
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SizedBox(
width: double.infinity,
child: OutlinedButton.icon(
onPressed: _addDriver,
icon: Image.asset('images/Add_icon.png', width: 16, height: 16),
label: Text(
"Add Location on map",
style: fontTextStyle(14, const Color(0xFF646566), FontWeight.w600),
),
),
),
const SizedBox(height: 12),
],
),
_LabeledField(
label: "Water Type *",
child: DropdownButtonFormField<String>(
value: selectedWaterType,
items: waterTypes
.map((w) => DropdownMenuItem(value: w, child: Text(w)))
.toList(),
onChanged: (v) => setState(() => selectedWaterType = v),
validator: (v) => v == null || v.isEmpty ? "Water Type is required" : null,
isExpanded: true,
alignment: Alignment.centerLeft,
hint: Text(
"Select Water Type",
style: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400),
),
icon: Image.asset('images/downarrow.png', width: 16, height: 16),
decoration: const InputDecoration(
border: OutlineInputBorder(),
isDense: false,
contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 14),
),
),
),
const SizedBox(height: 20),
// Actions
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SizedBox(
width: double.infinity,
child: OutlinedButton.icon(
onPressed: _addDriver,
icon: Image.asset('images/Add_icon.png', width: 16, height: 16),
label: Text(
"Add Location",
style: fontTextStyle(14, const Color(0xFF646566), FontWeight.w600),
),
),
),
const SizedBox(height: 12),
SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF8270DB),
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)),
),
onPressed: () {
// TODO: Navigate to the next step/screen
Navigator.push(context, MaterialPageRoute(builder: (_) => const SourceLocation1()));
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(content: Text("Saved ${_drivers.length} driver(s). Proceeding…")),
// );
},
child: Text(
"Continue",
style: fontTextStyle(14, Colors.white, FontWeight.w400),
),
),
),
],
),
],
),
),
),
);
}
}
// ======= UI helpers =======
class _SectionHeaderBar extends StatelessWidget {
final String title;
final Widget? icon;
final Color backgroundColor;
final Color borderColor;
final double radius;
const _SectionHeaderBar({
required this.title,
this.icon,
this.backgroundColor = const Color(0xFFEEEEEE),
this.borderColor = const Color(0xFFE5E7EB),
this.radius = 12,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: backgroundColor,
border: Border.all(color: borderColor, width: 1),
borderRadius: BorderRadius.circular(radius),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.04),
blurRadius: 6,
offset: const Offset(0, 2),
),
],
),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
child: Row(
children: [
Expanded(
child: Text(
title,
style: fontTextStyle(12, const Color(0xFF2D2E30), FontWeight.w600),
),
),
if (icon != null) icon!,
],
),
);
}
}
class _LabeledField extends StatelessWidget {
final String label;
final Widget child;
final String? Function()? validator; // (kept from your earlier helper; not used here)
const _LabeledField({
required this.label,
required this.child,
this.validator,
});
@override
Widget build(BuildContext context) {
final errorText = validator != null ? validator!() : null;
return Padding(
padding: const EdgeInsets.only(bottom: 14.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: fontTextStyle(12, const Color(0xFF515253), FontWeight.w600)),
const SizedBox(height: 6),
child,
if (errorText != null)
Padding(
padding: const EdgeInsets.only(top: 6),
child: Text(
errorText,
style: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400),
),
),
],
),
);
}
}

@ -0,0 +1,315 @@
import 'package:flutter/material.dart';
import 'package:supplier_new/common/settings.dart';
import 'package:supplier_new/resources/source_location2.dart';
void main() => runApp(const MaterialApp(home: SourceLocation1()));
class SourceLocation1 extends StatefulWidget {
const SourceLocation1({super.key});
@override
State<SourceLocation1> createState() => _SourceLocation1State();
}
class _SourceLocation1State extends State<SourceLocation1> {
final _formKey = GlobalKey<FormState>();
String _deliveryFrom = 'business';
final TextEditingController _radiusController =
TextEditingController(text: "10");
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.white,
surfaceTintColor: Colors.transparent,
elevation: 0,
scrolledUnderElevation: 0,
title: const Text("Complete Profile"),
actions: [
Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 0, 10),
child: IconButton(
splashRadius: 20,
padding: EdgeInsets.zero,
icon: const Image(
image: AssetImage('images/calendar_appbar.png'),
width: 22,
height: 22),
onPressed: () {},
),
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 10, 10),
child: IconButton(
splashRadius: 20,
padding: EdgeInsets.zero,
icon: Image.asset('images/notification_appbar.png',
width: 22, height: 22),
onPressed: () {},
),
),
],
),
body: SafeArea(
child: Form(
key: _formKey,
child: ListView(
padding: const EdgeInsets.fromLTRB(20, 10, 20, 24),
children: [
// Step indicator
Text(
"Step 1/5",
style:
fontTextStyle(16, const Color(0xFFC3C4C4), FontWeight.w500),
),
const SizedBox(height: 16),
Row(
children: List.generate(4, (index) {
return Expanded(
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 2),
height: 5,
decoration: BoxDecoration(
color: index < 4 ? const Color(0xFFC3C4C4) : Colors.grey,
borderRadius: BorderRadius.circular(2),
),
),
);
}),
),
const SizedBox(height: 16),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("SORURCE LOCATION",
style: fontTextStyle(
20, const Color(0xFF515253), FontWeight.w600)),
const SizedBox(height: 8),
Container(
width: 24,
height: 24,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('images/marker-pin.png'),
fit: BoxFit.contain),
),
),
],
),
const SizedBox(height: 12),
Text(
"Define where you want to provide delivery services",
style:
fontTextStyle(14, const Color(0xFF939495), FontWeight.w500),
maxLines: 1,
softWrap: false,
),
const SizedBox(height: 6),
// Radio ListTiles (vertical)
Column(
mainAxisSize: MainAxisSize.min,
children: [
RadioListTile<String>(
value: 'business',
groupValue: _deliveryFrom,
onChanged: (value) {
if (value == null) return;
setState(() => _deliveryFrom = value);
},
title: Text(
"From Business Location",
style: fontTextStyle(
14, const Color(0xFF2D2E30), FontWeight.w500),
),
dense: true,
contentPadding: EdgeInsets.zero,
visualDensity:
const VisualDensity(horizontal: 0, vertical: -3),
),
RadioListTile<String>(
value: 'source',
groupValue: _deliveryFrom,
onChanged: (value) {
if (value == null) return;
setState(() => _deliveryFrom = value);
},
title: Text(
"From Source Locations",
style: fontTextStyle(
14, const Color(0xFF2D2E30), FontWeight.w500),
),
dense: true,
contentPadding: EdgeInsets.zero,
visualDensity:
const VisualDensity(horizontal: 0, vertical: -3),
),
],
),
const SizedBox(height: 12),
Text(
"Delivery Radius (in Kms) *",
style:
fontTextStyle(14, const Color(0xFF2D2E30), FontWeight.w500),
),
const SizedBox(height: 6),
TextFormField(
controller: _radiusController,
keyboardType: TextInputType.number,
decoration: InputDecoration(
hintText: "Enter radius in kms",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
contentPadding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
),
),
const SizedBox(height: 12),
InkWell(
onTap: () => setState(
() => _customizeEachSource = !_customizeEachSource),
child: Padding(
padding: EdgeInsets.zero,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Checkbox(
value: _customizeEachSource,
onChanged: (val) =>
setState(() => _customizeEachSource = val ?? false),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
const SizedBox(width: 2),
Expanded(
child: Text(
"Customize for every each source location",
style: fontTextStyle(
14, const Color(0xFF2D2E30), FontWeight.w500),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
],
),
),
),
const SizedBox(height: 12),
Container(
width: 343,
height: 166,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('images/google_maps.png'),
fit: BoxFit.contain),
),
),
const SizedBox(height: 20),
Text(
"Types of Services",
style:
fontTextStyle(16, const Color(0xFF2D2E30), FontWeight.w600),
),
const SizedBox(height: 12),
Text(
"Define what type of services you would wish to provide",
style:
fontTextStyle(14, const Color(0xFF939495), FontWeight.w500),
),
const SizedBox(height: 20),
Row(
children: [
const Icon(Icons.check_box_outline_blank, size: 20, color: Color(0xFF939495)),
const SizedBox(width: 8),
Text(
"24/7 Emergency services",
style: fontTextStyle(12, const Color(0xFF2D2E30), FontWeight.w400),
),
],
),
const SizedBox(height: 12),
Row(
children: [
const Icon(Icons.check_box_outline_blank, size: 20, color: Color(0xFF939495)),
const SizedBox(width: 8),
Text(
"Scheduled water deliveries",
style: fontTextStyle(12, const Color(0xFF2D2E30), FontWeight.w400),
),
],
),
const SizedBox(height: 12),
Row(
children: [
const Icon(Icons.check_box_outline_blank, size: 20, color: Color(0xFF939495)),
const SizedBox(width: 8),
Text(
"Bulk water deliveries",
style: fontTextStyle(12, const Color(0xFF2D2E30), FontWeight.w400),
),
],
),
const SizedBox(height: 12),
Row(
children: [
const Icon(Icons.check_box_outline_blank, size: 20, color: Color(0xFF939495)),
const SizedBox(width: 8),
Text(
"Long-term water delivery planes",
style: fontTextStyle(12, const Color(0xFF2D2E30), FontWeight.w400),
),
],
),
const SizedBox(height: 12),
Row(
children: [
const Icon(Icons.check_box_outline_blank, size: 20, color: Color(0xFF939495)),
const SizedBox(width: 8),
Text(
"Industrial/Commercial water deliveries",
style: fontTextStyle(12, const Color(0xFF2D2E30), FontWeight.w400),
),
],
),
const SizedBox(height: 16),
SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF8270DB),
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)),
),
onPressed: () {
// TODO: Navigate to the next step/screen
Navigator.push(context, MaterialPageRoute(builder: (_) => const SourceLocation2()));
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(content: Text("Saved ${_drivers.length} driver(s). Proceeding…")),
// );
},
child: Text(
"Continue",
style: fontTextStyle(14, Colors.white, FontWeight.w400),
),
),
),
],
),
),
),
);
}
bool _customizeEachSource = false;
}

@ -0,0 +1,416 @@
import 'package:flutter/material.dart';
import 'package:supplier_new/common/settings.dart';
import 'package:supplier_new/resources/source_location2.dart';
import 'availability.dart';
void main() => runApp(const MaterialApp(home: SourceLocation2()));
class SourceLocation2 extends StatefulWidget {
const SourceLocation2({super.key});
@override
State<SourceLocation2> createState() => _SourceLocation2State();
}
class _SourceLocation2State extends State<SourceLocation2> {
final _formKey = GlobalKey<FormState>();
String _deliveryFrom = 'business';
final TextEditingController _radiusController =
TextEditingController(text: "10");
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.white,
surfaceTintColor: Colors.transparent,
elevation: 0,
scrolledUnderElevation: 0,
title: const Text("Complete Profile"),
actions: [
Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 0, 10),
child: IconButton(
splashRadius: 20,
padding: EdgeInsets.zero,
icon: const Image(
image: AssetImage('images/calendar_appbar.png'),
width: 22,
height: 22),
onPressed: () {},
),
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 10, 10),
child: IconButton(
splashRadius: 20,
padding: EdgeInsets.zero,
icon: Image.asset('images/notification_appbar.png',
width: 22, height: 22),
onPressed: () {},
),
),
],
),
body: SafeArea(
child: Form(
key: _formKey,
child: ListView(
padding: const EdgeInsets.fromLTRB(20, 10, 20, 24),
children: [
// Step indicator
Text(
"Step 1/5",
style:
fontTextStyle(16, const Color(0xFFC3C4C4), FontWeight.w500),
),
const SizedBox(height: 16),
Row(
children: List.generate(4, (index) {
return Expanded(
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 2),
height: 5,
decoration: BoxDecoration(
color: index < 4 ? const Color(0xFFC3C4C4) : Colors.grey,
borderRadius: BorderRadius.circular(2),
),
),
);
}),
),
const SizedBox(height: 16),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("SORURCE LOCATION",
style: fontTextStyle(
20, const Color(0xFF515253), FontWeight.w600)),
const SizedBox(height: 8),
Container(
width: 24,
height: 24,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('images/marker-pin.png'),
fit: BoxFit.contain),
),
),
],
),
const SizedBox(height: 12),
Text(
"Define where you want to provide delivery services",
style:
fontTextStyle(14, const Color(0xFF939495), FontWeight.w500),
maxLines: 1,
softWrap: false,
),
const SizedBox(height: 6),
// Radio ListTiles (vertical)
Column(
mainAxisSize: MainAxisSize.min,
children: [
RadioListTile<String>(
value: 'business',
groupValue: _deliveryFrom,
onChanged: (value) {
if (value == null) return;
setState(() => _deliveryFrom = value);
},
title: Text(
"From Business Location",
style: fontTextStyle(
14, const Color(0xFF2D2E30), FontWeight.w500),
),
dense: true,
contentPadding: EdgeInsets.zero,
visualDensity:
const VisualDensity(horizontal: 0, vertical: -3),
),
RadioListTile<String>(
value: 'source',
groupValue: _deliveryFrom,
onChanged: (value) {
if (value == null) return;
setState(() => _deliveryFrom = value);
},
title: Text(
"From Source Locations",
style: fontTextStyle(
14, const Color(0xFF2D2E30), FontWeight.w500),
),
dense: true,
contentPadding: EdgeInsets.zero,
visualDensity:
const VisualDensity(horizontal: 0, vertical: -3),
),
],
),
const SizedBox(height: 12),
Text(
"Delivery Radius (in Kms) *",
style:
fontTextStyle(14, const Color(0xFF2D2E30), FontWeight.w500),
),
const SizedBox(height: 6),
TextFormField(
controller: _radiusController,
keyboardType: TextInputType.number,
decoration: InputDecoration(
hintText: "Enter radius in kms",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
contentPadding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
),
),
const SizedBox(height: 12),
InkWell(
onTap: () => setState(
() => _customizeEachSource = !_customizeEachSource),
child: Padding(
padding: EdgeInsets.zero,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Checkbox(
value: _customizeEachSource,
onChanged: (val) =>
setState(() => _customizeEachSource = val ?? false),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
const SizedBox(width: 2),
Expanded(
child: Text(
"Customize for every each source location",
style: fontTextStyle(
14, const Color(0xFF2D2E30), FontWeight.w500),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
],
),
),
),
const SizedBox(height: 12),
_SectionHeaderBar(
title: "SOURCE LOCATION #1",
radius: 29,
),
const SizedBox(height: 12),
Text(
"Delivery Radius (in Kms) *",
style:
fontTextStyle(14, const Color(0xFF2D2E30), FontWeight.w500),
),
const SizedBox(height: 6),
TextFormField(
controller: _radiusController,
keyboardType: TextInputType.number,
decoration: InputDecoration(
hintText: "Enter radius in kms",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
contentPadding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
),
),
const SizedBox(height: 12),
_SectionHeaderBar(
title: "SOURCE LOCATION #2",
radius: 29,
),
const SizedBox(height: 12),
Text(
"Delivery Radius (in Kms) *",
style:
fontTextStyle(14, const Color(0xFF2D2E30), FontWeight.w500),
),
const SizedBox(height: 6),
TextFormField(
controller: _radiusController,
keyboardType: TextInputType.number,
decoration: InputDecoration(
hintText: "Enter radius in kms",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
contentPadding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
),
),
const SizedBox(height: 12),
Container(
width: 343,
height: 166,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('images/google_maps.png'),
fit: BoxFit.contain),
),
),
const SizedBox(height: 20),
Text(
"Types of Services",
style:
fontTextStyle(16, const Color(0xFF2D2E30), FontWeight.w600),
),
const SizedBox(height: 12),
Text(
"Define what type of services you would wish to provide",
style:
fontTextStyle(14, const Color(0xFF939495), FontWeight.w500),
),
const SizedBox(height: 20),
Row(
children: [
const Icon(Icons.check_box_outline_blank, size: 20, color: Color(0xFF939495)),
const SizedBox(width: 8),
Text(
"24/7 Emergency services",
style: fontTextStyle(12, const Color(0xFF2D2E30), FontWeight.w400),
),
],
),
const SizedBox(height: 12),
Row(
children: [
const Icon(Icons.check_box_outline_blank, size: 20, color: Color(0xFF939495)),
const SizedBox(width: 8),
Text(
"Scheduled water deliveries",
style: fontTextStyle(12, const Color(0xFF2D2E30), FontWeight.w400),
),
],
),
const SizedBox(height: 12),
Row(
children: [
const Icon(Icons.check_box_outline_blank, size: 20, color: Color(0xFF939495)),
const SizedBox(width: 8),
Text(
"Bulk water deliveries",
style: fontTextStyle(12, const Color(0xFF2D2E30), FontWeight.w400),
),
],
),
const SizedBox(height: 12),
Row(
children: [
const Icon(Icons.check_box_outline_blank, size: 20, color: Color(0xFF939495)),
const SizedBox(width: 8),
Text(
"Long-term water delivery planes",
style: fontTextStyle(12, const Color(0xFF2D2E30), FontWeight.w400),
),
],
),
const SizedBox(height: 12),
Row(
children: [
const Icon(Icons.check_box_outline_blank, size: 20, color: Color(0xFF939495)),
const SizedBox(width: 8),
Text(
"Industrial/Commercial water deliveries",
style: fontTextStyle(12, const Color(0xFF2D2E30), FontWeight.w400),
),
],
),
const SizedBox(height: 12),
SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF8270DB),
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)),
),
onPressed: () {
// TODO: Navigate to the next step/screen
Navigator.push(context, MaterialPageRoute(builder: (_) => const AvailabilityScreen()));
// ScaffoldMessenger.of(context).showSnackBar(
// SnackBar(content: Text("Saved ${_drivers.length} driver(s). Proceeding…")),
// );
},
child: Text(
" Save \$ Continue",
style: fontTextStyle(14, Colors.white, FontWeight.w400),
),
),
),
],
),
),
),
);
}
bool _customizeEachSource = false;
}
class _SectionHeaderBar extends StatelessWidget {
final String title;
final Widget? icon;
final Color backgroundColor;
final Color borderColor;
final double radius;
const _SectionHeaderBar({
required this.title,
this.icon,
this.backgroundColor = const Color(0xFFEEEEEE),
this.borderColor = const Color(0xFFE5E7EB),
this.radius = 12,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: backgroundColor,
border: Border.all(color: borderColor, width: 1),
borderRadius: BorderRadius.circular(radius),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.04),
blurRadius: 6,
offset: const Offset(0, 2),
),
],
),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
child: Row(
children: [
Expanded(
child: Text(
title,
style: fontTextStyle(10, const Color(0xFF2D2E30), FontWeight.w600),
),
),
if (icon != null) icon!,
],
),
);
}
}

@ -126,7 +126,7 @@ class _PasswordTextBoxesScreenState extends State<PasswordTextBoxesScreen> {
suffixIcon: IconButton( suffixIcon: IconButton(
icon: isObscureTextForReEnter==true?Image.asset('images/eye_icon.png',color: Color(0XFF7E7F80),width: 16,height: 16,):Image.asset('images/open_eye.png',color:Color(0XFF7E7F80),width: 16,height: 16,), icon: isObscureTextForReEnter==true?Image.asset('images/eye_icon.png',color: Color(0XFF7E7F80),width: 16,height: 16,):Image.asset('images/open_eye.png',color:Color(0XFF7E7F80),width: 16,height: 16,),
/* Icon( /* Icon(
icon:Image.asset('assets/your_image.png'), icon:Image.asset('assets/your_image.png'),x
color: isObscureText==true?greyColor:primaryColor, color: isObscureText==true?greyColor:primaryColor,
),*/ ),*/
onPressed: () { onPressed: () {

Loading…
Cancel
Save