Initial commit for complete UI

This commit is contained in:
2025-05-29 14:59:31 +05:30
commit 1f0ec17edc
170 changed files with 7211 additions and 0 deletions

47
lib/main.dart Normal file
View File

@@ -0,0 +1,47 @@
// GlowWheels Login and Orders Screen UI
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:glowwheels/models/shop_model.dart';
import 'package:glowwheels/provider/order_provider.dart';
import 'package:glowwheels/provider/serviceboy_provider.dart';
import 'package:glowwheels/provider/shop_provider.dart';
import 'package:glowwheels/screens/login_screen.dart';
import 'package:glowwheels/screens/main_screen.dart';
import 'package:glowwheels/screens/order_screen.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:hive_flutter/adapters.dart';
import 'package:provider/provider.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Hive.initFlutter();
Hive.registerAdapter(ShopModelAdapter());
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => OrderProvider()),
ChangeNotifierProvider(create: (_) => ServiceBoyProvider()),
ChangeNotifierProvider(create: (_) => ShopProvider()),
],
child: GlowWheelsApp(),
),
);
}
class GlowWheelsApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: LoginScreen(),
);
}
}

View File

@@ -0,0 +1,31 @@
import 'package:glowwheels/models/serviceboy_model.dart';
class Order {
final String customerName;
final String mobileNumber;
final String serviceType;
final String service;
final String price;
final String time;
final String date;
final String carName;
final String status;
final String imagePath;
ServiceBoy? assignedBoy;
Order({
required this.customerName,
required this.mobileNumber,
required this.serviceType,
required this.service,
required this.price,
required this.time,
required this.date,
required this.carName,
required this.status,
required this.imagePath,
this.assignedBoy,
});
}

View File

@@ -0,0 +1,6 @@
class ServiceBoy {
final String name;
final String phone;
ServiceBoy({required this.name, required this.phone});
}

View File

@@ -0,0 +1,53 @@
import 'package:hive/hive.dart';
part 'shop_model.g.dart';
@HiveType(typeId: 1)
class ShopModel {
@HiveField(0)
final String id;
@HiveField(1)
final String image;
@HiveField(2)
final String mobile;
@HiveField(3)
final String email;
@HiveField(4)
final String shopName;
@HiveField(5)
final String address; // ✅ NEW
ShopModel({
required this.id,
required this.image,
required this.mobile,
required this.email,
required this.shopName,
required this.address,
});
factory ShopModel.fromJson(Map<String, dynamic> json) {
return ShopModel(
id: json['id'] ?? '',
image: json['image'] ?? '',
mobile: json['mobile'] ?? '',
email: json['email'] ?? '',
shopName: json['shopName'] ?? '',
address: json['address'] ?? '', // ✅ NEW
);
}
Map<String, dynamic> toJson() => {
'id': id,
'image': image,
'mobile': mobile,
'email': email,
'shopName': shopName,
'address': address, // ✅ NEW
};
}

View File

@@ -0,0 +1,56 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'shop_model.dart';
// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************
class ShopModelAdapter extends TypeAdapter<ShopModel> {
@override
final int typeId = 1;
@override
ShopModel read(BinaryReader reader) {
final numOfFields = reader.readByte();
final fields = <int, dynamic>{
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
};
return ShopModel(
id: fields[0] as String,
image: fields[1] as String,
mobile: fields[2] as String,
email: fields[3] as String,
shopName: fields[4] as String,
address: fields[5] as String,
);
}
@override
void write(BinaryWriter writer, ShopModel obj) {
writer
..writeByte(6)
..writeByte(0)
..write(obj.id)
..writeByte(1)
..write(obj.image)
..writeByte(2)
..write(obj.mobile)
..writeByte(3)
..write(obj.email)
..writeByte(4)
..write(obj.shopName)
..writeByte(5)
..write(obj.address);
}
@override
int get hashCode => typeId.hashCode;
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is ShopModelAdapter &&
runtimeType == other.runtimeType &&
typeId == other.typeId;
}

View File

@@ -0,0 +1,41 @@
import 'package:flutter/material.dart';
import '../models/order_model.dart';
import '../models/serviceboy_model.dart';
class OrderProvider with ChangeNotifier {
final List<Order> _orders = [
Order(
customerName: "Ankit Ghosh",
mobileNumber: "8617015476",
serviceType: "Doorstep Service",
service: "Foam Wash",
price: "₹ 104",
time: "10:00 - 11:00 AM",
date: "2025-05-28",
carName: "Mahindra XUV 700",
status: "Confirmed",
imagePath: "assets/images/car.jpg",
),
Order(
customerName: "Ravi Kumar",
mobileNumber: "9876543210",
serviceType: "Workshop",
service: "Interior Cleaning",
price: "₹ 150",
time: "12:00 - 1:00 PM",
date: "2025-05-29",
carName: "Hyundai Creta",
status: "Pending",
imagePath: "assets/images/bike.png",
),
// Add more sample orders if needed
];
List<Order> get orders => _orders;
void assignServiceBoy(int index, ServiceBoy boy) {
_orders[index].assignedBoy = boy;
notifyListeners();
}
}

View File

@@ -0,0 +1,48 @@
import 'package:flutter/material.dart';
import '../models/serviceboy_model.dart';
class ServiceBoyProvider extends ChangeNotifier {
List<ServiceBoy> _serviceBoys = [
ServiceBoy(name: 'John Doe', phone: '9875643210'),
ServiceBoy(name: 'Amit Raj', phone: '9765432180'),
ServiceBoy(name: 'Manoj Sinha', phone: '9543219876'),
];
ServiceBoy? _selectedBoy;
List<ServiceBoy> get serviceBoys => _serviceBoys;
ServiceBoy? get selectedBoy => _selectedBoy;
// Add a new service boy
void addServiceBoy(ServiceBoy boy) {
_serviceBoys.add(boy);
notifyListeners();
}
// Edit an existing service boy
void editServiceBoy(int index, ServiceBoy updatedBoy) {
if (index >= 0 && index < _serviceBoys.length) {
_serviceBoys[index] = updatedBoy;
notifyListeners();
}
}
// Delete a service boy
void deleteServiceBoy(int index) {
if (index >= 0 && index < _serviceBoys.length) {
_serviceBoys.removeAt(index);
notifyListeners();
}
}
// Assign a selected service boy (for dialogs)
void selectBoy(ServiceBoy boy) {
_selectedBoy = boy;
notifyListeners();
}
void clearSelection() {
_selectedBoy = null;
notifyListeners();
}
}

View File

@@ -0,0 +1,52 @@
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import '../models/shop_model.dart';
class ShopProvider with ChangeNotifier {
ShopModel? _shop;
ShopModel? get shop => _shop;
final String _boxName = 'shopBox';
ShopProvider() {
_loadOrCreateDummyShop();
}
void _loadOrCreateDummyShop() async {
final box = await Hive.openBox<ShopModel>(_boxName);
if (box.isNotEmpty) {
_shop = box.getAt(0);
} else {
// Dummy data
_shop = ShopModel(
id: '1',
shopName: "Omkara Car Wash Center",
email: "omkara@gmail.com",
mobile: "8617019854",
image: "assets/images/shop_image.jpg",
address: "Bidhannagar, Kolkata, pin-700017",
);
await box.add(_shop!);
}
notifyListeners();
}
Future<void> setShop(ShopModel shop) async {
_shop = shop;
notifyListeners();
final box = await Hive.openBox<ShopModel>(_boxName);
await box.clear(); // Keep only one shop
await box.add(shop);
}
Future<void> logout() async {
_shop = null;
notifyListeners();
final box = await Hive.openBox<ShopModel>(_boxName);
await box.clear();
}
}

View File

@@ -0,0 +1,204 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../provider/serviceboy_provider.dart';
import 'add_serviceboy_screen.dart';
import 'edit_serviceboy_screen.dart';
import 'package:google_fonts/google_fonts.dart';
class ServiceBoyScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final provider = Provider.of<ServiceBoyProvider>(context);
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color.fromRGBO(208, 235, 255, 1), Colors.white],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
child: Scaffold(
backgroundColor: Colors.transparent,
body: SafeArea(
child: Column(
children: [
SizedBox(height: 40),
Text(
'GLOWWHEELS',
style: GoogleFonts.inter(
fontSize: 32,color: Color.fromRGBO(25, 25, 112, 0.87)
,fontWeight: FontWeight.w700
)
),
Text(
'Service Center',
style: GoogleFonts.inter(
fontSize: 24,color: Color.fromRGBO(25, 25, 112, 0.87)
,fontWeight: FontWeight.w400
)
),
SizedBox(height: 20),
Text(
'Service Boy List',
style: GoogleFonts.inter(
fontSize: 16,color: Color.fromRGBO(33, 33, 33, 1)
,fontWeight: FontWeight.w500
)
),
SizedBox(height: 10),
Expanded(
child: provider.serviceBoys.isEmpty
? Center(child: Text("No service boys found"))
: ListView.builder(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
itemCount: provider.serviceBoys.length,
itemBuilder: (context, index) {
final boy = provider.serviceBoys[index];
return Card(
color: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
elevation: 2,
child: ListTile(
contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
title: Text(
boy.name,
style: GoogleFonts.inter(
fontSize: 18,color: Color.fromRGBO(33, 33, 33, 0.78)
,fontWeight: FontWeight.w600
)
),
subtitle: Text(
boy.phone,
style: GoogleFonts.inter(
fontSize: 16,color: Color.fromRGBO(33, 33, 33, 0.78)
,fontWeight: FontWeight.w400
)
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
_buildIconButton(
icon: Icons.edit,
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => EditServiceBoyScreen(serviceBoy: boy),
),
);
},
),
SizedBox(width: 8),
_buildIconButton(
icon: Icons.delete,
onPressed: () {
_showDeleteDialog(context, '');
},
),
],
),
),
);
},
),
),
],
),
),
floatingActionButton: FloatingActionButton(
shape: CircleBorder(),
backgroundColor: Colors.white,
elevation: 4,
child: Icon(Icons.add, color: Color(0xFF1F1762),size: 25,),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => AddServiceBoyScreen()),
);
},
),
),
);
}
Widget _buildIconButton({required IconData icon, required VoidCallback onPressed}) {
return Container(
height: 40,
width: 40,
child: Center(
child: Ink(
decoration: ShapeDecoration(
color: Color(0xFF1F1762),
shape: CircleBorder(),
),
child: IconButton(
icon: Icon(icon, color: Colors.white, size: 23),
onPressed: onPressed,
splashRadius: 15,
),
),
),
);
}
void _showDeleteDialog(BuildContext context, String id) {
showModalBottomSheet(
context: context,
backgroundColor: Colors.transparent,
isScrollControlled: true,
builder: (_) => Container(
padding: EdgeInsets.all(24),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Image.asset('assets/images/delete_serviceboy.png'),
SizedBox(height: 16),
Text(
'Delete Service boy?',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
SizedBox(height: 8),
Text(
'Are you sure you want to delete this service boy? You wont be able to undo this.',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
color: Colors.black54,
),
),
SizedBox(height: 24),
SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red[700],
padding: EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
onPressed: () {
// Provider.of<ServiceBoyProvider>(context, listen: false).deleteServiceBoy(id);
Navigator.pop(context);
},
child: Text(
'Confirm',
style: TextStyle(fontSize: 16, color: Colors.white),
),
),
),
SizedBox(height: 12),
],
),
),
);
}
}

View File

@@ -0,0 +1,124 @@
import 'package:flutter/material.dart';
import 'package:glowwheels/screens/privacy_policy_screen.dart';
import 'package:glowwheels/screens/profile_details_screen.dart';
import 'package:glowwheels/screens/terms_condition_screen.dart';
import 'package:glowwheels/widgets/profile_header.dart';
import 'package:google_fonts/google_fonts.dart';
class AccountScreen extends StatelessWidget {
const AccountScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
centerTitle: true,
elevation: 0,
backgroundColor: Colors.white,
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
ImageIcon(AssetImage("assets/icon/account_icon.png")),
SizedBox(width: 8),
Text(
"Account",
style: TextStyle(color: Colors.black),
),
],
),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
children: [
// Profile Info
ProfileHeader(),
const SizedBox(height: 24),
// Section Title
Align(
alignment: Alignment.centerLeft,
child: Text("Options",
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
),
const SizedBox(height: 12),
// Option Cards
OptionTile(
icon: "assets/icon/account_icon.png",
title: "Profile Details",
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => ServiceCenterDetailsScreen()),
);
},
),
OptionTile(
icon: "assets/icon/terms_icon.png",
title: "Terms and Conditions",
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => TermsOfServiceScreen()),
);
},
),
OptionTile(
icon: "assets/icon/privacy_icon.png",
title: "Privacy Policy",
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (_) => PrivacyPolicyScreen()),
);
},
),
OptionTile(
icon: "assets/icon/logout_icon.png",
title: "Log Out",
onTap: () {},
isDestructive: true,
),
],
),
),
);
}
}
class OptionTile extends StatelessWidget {
final String icon;
final String title;
final VoidCallback onTap;
final bool isDestructive;
const OptionTile({
super.key,
required this.icon,
required this.title,
required this.onTap,
this.isDestructive = false,
});
@override
Widget build(BuildContext context) {
return Card(
color: isDestructive ? Colors.white : Colors.white,
elevation: 0.5,
margin: const EdgeInsets.symmetric(vertical: 6),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: ListTile(
leading: ImageIcon(AssetImage(icon),
color: Color.fromRGBO(25, 25, 112, 1)),
title: Text(title,
style: GoogleFonts.inter(
fontSize: 14,color: Color.fromRGBO(41, 45, 50, 1)
,fontWeight: FontWeight.w500
),),
trailing: const Icon(Icons.arrow_forward_ios, size: 16),
onTap: onTap,
),
);
}
}

View File

@@ -0,0 +1,101 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../provider/serviceboy_provider.dart';
import 'package:google_fonts/google_fonts.dart';
class AddServiceBoyScreen extends StatelessWidget {
final _formKey = GlobalKey<FormState>();
final TextEditingController nameController = TextEditingController();
final TextEditingController phoneController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFFF9FAF4), // light background as per screenshot
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
onPressed: () => Navigator.pop(context),
),
title: Text(
'Add Service boy',
style: GoogleFonts.nunito(
fontSize: 18,color: Color.fromRGBO(26, 26, 26, 1)
,fontWeight: FontWeight.w500
)
),
//centerTitle: true,
),
body: Padding(
padding: const EdgeInsets.all(16),
child: Form(
key: _formKey,
child: Column(
children: [
SizedBox(height: 30,),
TextFormField(
controller: nameController,
decoration: InputDecoration(
hintText: 'Name',
hintStyle: GoogleFonts.nunito(
fontSize: 14,color: Color.fromRGBO(26, 26, 26, 1)
,fontWeight: FontWeight.w400
),
border: OutlineInputBorder(),
contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 14),
),
validator: (value) => value!.isEmpty ? 'Enter name' : null,
),
SizedBox(height: 25),
TextFormField(
controller: phoneController,
keyboardType: TextInputType.phone,
decoration: InputDecoration(
hintText: 'Mobile Number',
hintStyle: GoogleFonts.nunito(
fontSize: 14,color: Color.fromRGBO(26, 26, 26, 1)
,fontWeight: FontWeight.w400
),
border: OutlineInputBorder(),
contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 14),
),
validator: (value) => value!.isEmpty ? 'Enter phone number' : null,
),
Spacer(),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
/* if (_formKey.currentState!.validate()) {
Provider.of<ServiceBoyProvider>(context, listen: false).addServiceBoy(
nameController.text,
phoneController.text,
);
Navigator.pop(context);
}*/
},
style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFF000B8C), // dark blue
padding: EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
),
child: Text('Submit', style:
GoogleFonts.inter(
fontSize: 18,color: Colors.white
,fontWeight: FontWeight.w600
)
),
),
),
],
),
),
),
);
}
}

View File

@@ -0,0 +1,106 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/serviceboy_model.dart';
import '../provider/serviceboy_provider.dart';
import 'package:google_fonts/google_fonts.dart';
class EditServiceBoyScreen extends StatelessWidget {
final ServiceBoy serviceBoy;
EditServiceBoyScreen({required this.serviceBoy});
final _formKey = GlobalKey<FormState>();
late final TextEditingController nameController =
TextEditingController(text: serviceBoy.name);
late final TextEditingController phoneController =
TextEditingController(text: serviceBoy.phone);
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF9FAF4), // light background
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
onPressed: () => Navigator.pop(context),
),
title: Text(
'Edit Service boy Details',
style: GoogleFonts.nunito(
fontSize: 18,color: Color.fromRGBO(26, 26, 26, 1)
,fontWeight: FontWeight.w500
)
),
),
body: Padding(
padding: const EdgeInsets.all(16),
child: Form(
key: _formKey,
child: Column(
children: [
SizedBox(height: 30,),
TextFormField(
controller: nameController,
decoration: InputDecoration(
hintText: 'Name',
hintStyle: GoogleFonts.nunito(
fontSize: 14,color: Color.fromRGBO(26, 26, 26, 1)
,fontWeight: FontWeight.w400
),
border: OutlineInputBorder(),
contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 14),
),
validator: (value) => value!.isEmpty ? 'Enter name' : null,
),
const SizedBox(height: 25),
TextFormField(
controller: phoneController,
keyboardType: TextInputType.phone,
decoration: InputDecoration(
hintText: 'Mobile Number',
hintStyle: GoogleFonts.nunito(
fontSize: 14,color: Color.fromRGBO(26, 26, 26, 1)
,fontWeight: FontWeight.w400
),
border: OutlineInputBorder(),
contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 14),
),
validator: (value) => value!.isEmpty ? 'Enter phone number' : null,
),
const Spacer(),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {
/* if (_formKey.currentState!.validate()) {
Provider.of<ServiceBoyProvider>(context, listen: false)
.editServiceBoy(
serviceBoy.id,
nameController.text,
phoneController.text,
);
Navigator.pop(context);
}*/
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF000B8C),
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
),
child: Text('Save', style:GoogleFonts.inter(
fontSize: 18,color: Colors.white
,fontWeight: FontWeight.w600
)),
),
),
],
),
),
),
);
}
}

View File

@@ -0,0 +1,141 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'main_screen.dart';
class LoginScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SingleChildScrollView(
child: Column(
children: [
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color.fromRGBO(80, 166, 242, 0.66),
Color.fromRGBO(168, 134, 255, 0.66),
Color.fromRGBO(86, 88, 255, 0.3828),
Color.fromRGBO(214, 246, 255, 0.66),
],
),
borderRadius: BorderRadius.only(bottomRight: Radius.elliptical(300, 110), )
),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
const SizedBox(height: 30),
Image.asset('assets/images/signinlogo.png', height: 250),
const SizedBox(height: 20),
const SizedBox(height: 30),
Align(
alignment: Alignment.centerLeft,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Welcome back!", style:
GoogleFonts.istokWeb(
fontSize: 18,color: Color.fromRGBO(25, 25, 112, 0.87)
,fontWeight: FontWeight.w700
)),
Container(
width: 200,
child: Text("Please sign in to continue",
style:GoogleFonts.radioCanada(
fontSize: 24,
fontWeight: FontWeight.w700,
height: 0.9,
color: Color.fromRGBO(25, 25, 112, 0.87)
)),
),
],
),
),
],
),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: Form(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 20),
Text('Enter Email Id',style:GoogleFonts.radioCanada(
fontSize: 16,
fontWeight: FontWeight.w400,
//color: Color.fromRGBO(25, 25, 112, 0.87)
)),
const SizedBox(height: 5),
TextField(
decoration: InputDecoration(
hintText: 'abcd@gmail.com',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15.0)
),
),
),
const SizedBox(height: 20),
Text('Enter Password',style:GoogleFonts.radioCanada(
fontSize: 16,
fontWeight: FontWeight.w400,
//color: Color.fromRGBO(25, 25, 112, 0.87)
)),
const SizedBox(height: 5),
TextField(
obscureText: true,
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15.0)
),
suffixIcon: Icon(Icons.remove_red_eye_outlined),
),
),
const SizedBox(height: 30),
SizedBox(
width: double.infinity,
height: 50,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFF1F1762),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
),
),
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context)=>MainScreen()));
},
child: Text('Login', style:
GoogleFonts.inter(
fontSize: 18,color: Colors.white
,fontWeight: FontWeight.w600
)
),
),
)
],
),
),
),
],
),
),
);
}
}

View File

@@ -0,0 +1,66 @@
import 'package:flutter/material.dart';
import 'package:glowwheels/screens/profile_details_screen.dart';
import 'Serviceboy_screen.dart';
import 'account_screen.dart';
import 'order_screen.dart';
class MainScreen extends StatefulWidget {
@override
State<MainScreen> createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
int _selectedIndex = 0;
// ✅ Use nested navigators for each tab
final List<Widget> _screens = [];
@override
void initState() {
super.initState();
_screens.addAll([
_buildTabNavigator(OrdersScreen()),
_buildTabNavigator(ServiceBoyScreen()),
_buildTabNavigator(AccountScreen()), // replace with ProfileScreen later
]);
}
// ✅ Each tab gets its own Navigator
Widget _buildTabNavigator(Widget child) {
return Navigator(
onGenerateRoute: (settings) {
return MaterialPageRoute(builder: (_) => child);
},
);
}
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: IndexedStack(
index: _selectedIndex,
children: _screens,
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _selectedIndex,
onTap: _onItemTapped,
selectedItemColor: Color(0xFF1F1762),
unselectedItemColor: Colors.grey,
items: const [
BottomNavigationBarItem(icon:ImageIcon(AssetImage("assets/icon/orders_icon.png")),label: 'Orders'),
BottomNavigationBarItem(icon:ImageIcon(AssetImage("assets/icon/serviceboy_icon.png")), label: 'Service Boy'),
BottomNavigationBarItem(icon:ImageIcon(AssetImage("assets/icon/profile_icon.png")), label: 'My Profile'),
],
),
);
}
}

View File

@@ -0,0 +1,96 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
import '../models/order_model.dart';
import '../provider/order_provider.dart';
import '../widgets/order_card.dart';
class OrdersScreen extends StatelessWidget {
final TextStyle labelStyle = TextStyle(fontWeight: FontWeight.w500);
final TextStyle valueStyle = TextStyle(fontWeight: FontWeight.normal);
List<Order> orders = [
Order(
customerName: "Ankit Ghosh",
mobileNumber: "8617015476",
serviceType: "Doorstep Service",
service: "Foam Wash",
price: "₹ 104",
time: "10:00 - 11:00 AM",
date: "2025-05-28",
carName: "Mahindra XUV 700",
status: "Confirmed",
imagePath: "assets/images/car.jpg",
),
Order(
customerName: "Ravi Kumar",
mobileNumber: "9876543210",
serviceType: "Workshop",
service: "Interior Cleaning",
price: "₹ 150",
time: "12:00 - 1:00 PM",
date: "2025-05-29",
carName: "Hyundai Creta",
status: "Pending",
imagePath: "assets/images/bike.png",
),
// Add more orders...
];
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.white,
automaticallyImplyLeading: false,
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset('assets/icon/order_appbar_icon.png'),
SizedBox(width: 20),
Text(
'Orders',
style: GoogleFonts.poppins(
fontSize: 24,
color: Color.fromRGBO(43, 46, 53, 1),
fontWeight: FontWeight.w600,
),
),
],
),
centerTitle: true,
foregroundColor: Colors.black,
elevation: 1,
),
body: Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Consumer<OrderProvider>(
builder: (context, orderProvider, _) {
final orders = orderProvider.orders;
if (orders.isEmpty) {
return Center(
child: Image.asset(
'assets/images/noorder.png',
width: 200,
height: 200,
),
);
}
return ListView.builder(
itemCount: orders.length,
itemBuilder: (context, index) {
return OrderCard(order: orders[index],);
},
);
},
),
),
);
}
}

View File

@@ -0,0 +1,145 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class PrivacyPolicyScreen extends StatelessWidget {
final ScrollController _scrollController = ScrollController();
void _scrollToBottom() {
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
duration: Duration(milliseconds: 500),
curve: Curves.easeOut,
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
// Top bar
Row(
children: [
IconButton(
icon: Icon(Icons.arrow_back_ios),
onPressed: () => Navigator.pop(context),
),
SizedBox(width: 8),
Text(
'AGREEMENT',
textAlign: TextAlign.center,
style: GoogleFonts.istokWeb(
fontSize: 16,color: Color.fromRGBO(159, 159, 159, 1)
,fontWeight: FontWeight.w400
)
),
],
),
// Title
Align(
alignment: Alignment.centerLeft,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Privacy Policy',
style: GoogleFonts.istokWeb(
fontSize: 30,color: Color.fromRGBO(73, 73, 73, 1)
,fontWeight: FontWeight.w700
)
),
SizedBox(height: 4),
Text(
'Last updated on 5/12/2022',
style: GoogleFonts.lato(
fontSize: 16,color: Color.fromRGBO(124, 124, 124, 1)
,fontWeight: FontWeight.w600
)
),
],
),
),
SizedBox(height: 16),
// Scrollable content
Expanded(
child: Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
),
child: Scrollbar(
thickness: 4,
controller: _scrollController,
child: SingleChildScrollView(
controller: _scrollController,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: List.generate(6, (index) {
return Padding(
padding: const EdgeInsets.only(bottom: 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Clause ${index + 1}',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
SizedBox(height: 6),
Text(
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. '
'Viverra condimentum eget purus in. Consectetur eget id morbi amet amet, '
'in. Ipsum viverra pretium tellus neque. Ullamcorper suspendisse aenean '
'leo pharetra in sit semper et. Amet quam placerat sem.',
style: TextStyle(fontSize: 14, height: 1.5),
),
],
),
);
}),
),
),
),
),
),
SizedBox(height: 12),
// Scroll to bottom button
ElevatedButton(
onPressed: _scrollToBottom,
style: ElevatedButton.styleFrom(
shape: StadiumBorder(
),
side: BorderSide(
width: 1.0,
color: Colors.black,
),
backgroundColor: Colors.white,
padding: EdgeInsets.symmetric(horizontal: 32, vertical: 12),
//backgroundColor: Colors.black,
),
child: Text(
'Scroll to Bottom',
style: TextStyle(color: Colors.black),
),
),
SizedBox(height: 12),
],
),
),
),
);
}
}

View File

@@ -0,0 +1,160 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
import '../provider/shop_provider.dart';
class ServiceCenterDetailsScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final shop = Provider.of<ShopProvider>(context).shop;
if (shop == null) {
return Scaffold(
body: Center(child: CircularProgressIndicator()),
);
}
return Scaffold(
backgroundColor: Color(0xFFEAF5FF),
body: SafeArea(
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color.fromRGBO(208, 235, 255, 1), Colors.white],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// AppBar with back icon and title
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16),
child: Row(
children: [
GestureDetector(
onTap: () => Navigator.pop(context),
child: Icon(Icons.arrow_back_ios, color: Colors.black),
),
SizedBox(width: 25),
Expanded(
child: Padding(
padding: const EdgeInsets.only(top: 15.0),
child: Text(
'SERVICE CENTER DETAILS',
textAlign: TextAlign.center,
style: GoogleFonts.inter(
fontSize: 32,
color: Color.fromRGBO(25, 25, 112, 0.87),
fontWeight: FontWeight.w600,
),
),
),
),
SizedBox(width: 24),
],
),
),
// Main content
Expanded(
child: SingleChildScrollView(
child: Center(
child: Container(
margin: EdgeInsets.symmetric(horizontal: 16, vertical: 10),
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 10,
offset: Offset(0, 4),
),
],
),
child: Column(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.asset(
"assets/images/shop_image.jpg",
height: 230,
width: double.infinity,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) =>
Icon(Icons.broken_image, size: 100),
),
),
SizedBox(height: 16),
Text(
shop.shopName,
style: GoogleFonts.inter(
fontSize: 24,
color: Colors.black,
fontWeight: FontWeight.w600,
),
),
SizedBox(height: 16),
InfoRow(
icon: "assets/icon/location_icon.png",
text: shop.address ?? 'Address not available',
),
InfoRow(
icon: "assets/icon/contact_icon.png",
text: shop.mobile,
),
InfoRow(
icon: "assets/icon/Message_icon.png",
text: shop.email,
),
],
),
),
),
),
),
],
),
),
),
);
}
}
class InfoRow extends StatelessWidget {
final String icon;
final String text;
const InfoRow({
required this.icon,
required this.text,
});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 15),
child: Center(
child: Row(
children: [
ImageIcon(AssetImage(icon)),
SizedBox(width: 10),
Expanded(
child: Text(
text,
style: GoogleFonts.inter(
fontSize: 14,
color: Colors.black,
fontWeight: FontWeight.w400,
),
),
),
],
),
),
);
}
}

View File

@@ -0,0 +1,150 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class TermsOfServiceScreen extends StatefulWidget {
@override
_TermsOfServiceScreenState createState() => _TermsOfServiceScreenState();
}
class _TermsOfServiceScreenState extends State<TermsOfServiceScreen> {
final ScrollController _scrollController = ScrollController();
void _scrollToBottom() {
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
duration: Duration(milliseconds: 500),
curve: Curves.easeOut,
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
// Top bar
Row(
children: [
IconButton(
icon: Icon(Icons.arrow_back_ios),
onPressed: () => Navigator.pop(context),
),
SizedBox(width: 8),
Text(
'AGREEMENT',
textAlign: TextAlign.center,
style: GoogleFonts.istokWeb(
fontSize: 16,color: Color.fromRGBO(159, 159, 159, 1)
,fontWeight: FontWeight.w400
)
),
],
),
// Title
Align(
alignment: Alignment.centerLeft,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Terms of Service',
style: GoogleFonts.istokWeb(
fontSize: 30,color: Color.fromRGBO(73, 73, 73, 1)
,fontWeight: FontWeight.w700
)
),
SizedBox(height: 4),
Text(
'Last updated on 5/12/2022',
style: GoogleFonts.lato(
fontSize: 16,color: Color.fromRGBO(124, 124, 124, 1)
,fontWeight: FontWeight.w600
)
),
],
),
),
SizedBox(height: 16),
// Scrollable content
Expanded(
child: Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
),
child: Scrollbar(
thickness: 4,
controller: _scrollController,
child: SingleChildScrollView(
controller: _scrollController,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: List.generate(6, (index) {
return Padding(
padding: const EdgeInsets.only(bottom: 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Clause ${index + 1}',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
SizedBox(height: 6),
Text(
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. '
'Viverra condimentum eget purus in. Consectetur eget id morbi amet amet, '
'in. Ipsum viverra pretium tellus neque. Ullamcorper suspendisse aenean '
'leo pharetra in sit semper et. Amet quam placerat sem.',
style: TextStyle(fontSize: 14, height: 1.5),
),
],
),
);
}),
),
),
),
),
),
SizedBox(height: 12),
// Scroll to bottom button
ElevatedButton(
onPressed: _scrollToBottom,
style: ElevatedButton.styleFrom(
shape: StadiumBorder(
),
side: BorderSide(
width: 1.0,
color: Colors.black,
),
backgroundColor: Colors.white,
padding: EdgeInsets.symmetric(horizontal: 32, vertical: 12),
//backgroundColor: Colors.black,
),
child: Text(
'Scroll to Bottom',
style: TextStyle(color: Colors.black),
),
),
SizedBox(height: 12),
],
),
),
),
);
}
}

View File

@@ -0,0 +1,97 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/serviceboy_model.dart';
import '../provider/serviceboy_provider.dart';
import 'package:google_fonts/google_fonts.dart';
class AssignServiceBoyDialog extends StatelessWidget {
final List<ServiceBoy> serviceBoys;
const AssignServiceBoyDialog({super.key, required this.serviceBoys});
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => ServiceBoyProvider(),
child: Consumer<ServiceBoyProvider>(
builder: (context, assignProvider, _) {
return AlertDialog(
backgroundColor: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
title: const Text("Select Service Boy", style: TextStyle(fontWeight: FontWeight.bold)),
content: SizedBox(
height: 200,
width: double.maxFinite,
child: ListView.builder(
itemCount: serviceBoys.length,
itemBuilder: (context, index) {
final boy = serviceBoys[index];
final isSelected = assignProvider.selectedBoy == boy;
return GestureDetector(
onTap: () => assignProvider.selectBoy(boy),
child: Container(
padding: const EdgeInsets.all(12),
margin: const EdgeInsets.symmetric(vertical: 4),
decoration: BoxDecoration(
color: isSelected ? Color.fromRGBO(0, 80, 170, 1) : Colors.transparent,
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
boy.name,
style: TextStyle(
color: isSelected ? Colors.white : Colors.black,
fontWeight: FontWeight.w500,
),
),
Text(
"Phone: ${boy.phone}",
style: TextStyle(
color: isSelected ? Colors.white70 : Colors.grey[700],
fontSize: 13,
),
),
],
),
),
);
},
),
),
actions: [
TextButton(
child: Text("CANCEL",style: GoogleFonts.poppins(
fontSize: 14,color: Color.fromRGBO(25, 25, 112, 1)
,fontWeight: FontWeight.w400
),),
onPressed: () {
Navigator.of(context).pop(); // return null
},
),
ElevatedButton(
onPressed: assignProvider.selectedBoy != null
? () {
Navigator.of(context).pop(assignProvider.selectedBoy);
}
: null,
style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFF1B1464),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)),
),
child: Text("Assign",style: GoogleFonts.inter(
fontSize: 12,color: Colors.white
,fontWeight: FontWeight.w500
),),
),
],
);
},
),
);
}
}

138
lib/widgets/order_card.dart Normal file
View File

@@ -0,0 +1,138 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import '../models/order_model.dart';
import '../models/serviceboy_model.dart';
import 'assign_serviceboy_dialog.dart';
class OrderCard extends StatefulWidget {
final Order order;
OrderCard({required this.order});
@override
State<OrderCard> createState() => _OrderCardState();
}
class _OrderCardState extends State<OrderCard> {
ServiceBoy? assignedBoy;
List<ServiceBoy> serviceBoys = [
ServiceBoy(name: 'John Doe', phone: '9875643210'),
ServiceBoy(name: 'Amit Raj', phone: '9765432180'),
ServiceBoy(name: 'Manoj Sinha', phone: '9543219876'),
];
@override
Widget build(BuildContext context) {
return Card(
color: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
margin: EdgeInsets.all(12),
elevation: 4,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Order Details", style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600)),
SizedBox(height: 12),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset(widget.order.imagePath, width: 100, height: 100, fit: BoxFit.contain),
SizedBox(width: 16),
Expanded(
child: Column(
children: [
_buildRow("Customer Name", widget.order.customerName),
_buildRow("Mobile Number", widget.order.mobileNumber),
_buildRow("Service Type", widget.order.serviceType),
_buildRow("Service", widget.order.service),
_buildRow("Price", widget.order.price),
_buildRow("Service Time", widget.order.time),
_buildRow("Service Date", widget.order.date),
],
),
),
],
),
SizedBox(height: 12),
Center(
child: Text(
widget.order.carName,
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
),
Divider(height: 28),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
widget.order.status,
style: TextStyle(
color: widget.order.status == "Confirmed" ? Colors.green : Colors.orange,
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
assignedBoy == null
? ElevatedButton(
onPressed: () async {
final selected = await showDialog<ServiceBoy>(
context: context,
builder: (_) => AssignServiceBoyDialog(serviceBoys: serviceBoys),
);
if (selected != null) {
setState(() {
assignedBoy = selected;
});
}
},
style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFF1B1464),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)),
),
child: Text("Assign",style: GoogleFonts.inter(
fontSize: 12,color: Colors.white
,fontWeight: FontWeight.w500
),),
)
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Assigned to: ${assignedBoy!.name}",
style: const TextStyle(fontWeight: FontWeight.bold)),
Text("Phone: ${assignedBoy!.phone}"),
],
),
],
)
],
),
),
);
}
Widget _buildRow(String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 3),
child: Row(
children: [
Expanded(flex: 2, child: Text(label, style: GoogleFonts.inter(
fontSize: 10,color: Colors.black
,fontWeight: FontWeight.w500
))),
Expanded(flex: 3, child: Text(value, style: GoogleFonts.inter(
fontSize: 10,color: Colors.black
,fontWeight: FontWeight.w500
))),
],
),
);
}
}

View File

@@ -0,0 +1,59 @@
import 'package:flutter/material.dart';
class ProfileHeader extends StatelessWidget {
const ProfileHeader({super.key});
@override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
padding: const EdgeInsets.all(16),
child: Row(
children: [
// Circular Profile Image
CircleAvatar(
radius: 40,
backgroundImage: AssetImage('assets/images/shop_image.jpg'), // Replace with your asset
),
const SizedBox(width: 16),
// Details Column
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Row(
children: [
ImageIcon(AssetImage("assets/icon/account_icon.png")),
SizedBox(width: 8),
Expanded(
child: Text(
'Omkara Car Wash Center',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
),
),
],
),
SizedBox(height: 8),
Row(
children: [
ImageIcon(AssetImage("assets/icon/contact_icon.png")),
SizedBox(width: 8),
Text('+91 9999988888'),
],
),
SizedBox(height: 8),
Row(
children: [
ImageIcon(AssetImage("assets/icon/Message_icon.png")),
SizedBox(width: 8),
Expanded(child: Text('loremipsum@gmail.com')),
],
),
],
),
),
],
),
);
}
}