Initial commit for complete UI
This commit is contained in:
47
lib/main.dart
Normal file
47
lib/main.dart
Normal 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(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
31
lib/models/order_model.dart
Normal file
31
lib/models/order_model.dart
Normal 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,
|
||||
});
|
||||
}
|
||||
6
lib/models/serviceboy_model.dart
Normal file
6
lib/models/serviceboy_model.dart
Normal file
@@ -0,0 +1,6 @@
|
||||
class ServiceBoy {
|
||||
final String name;
|
||||
final String phone;
|
||||
|
||||
ServiceBoy({required this.name, required this.phone});
|
||||
}
|
||||
53
lib/models/shop_model.dart
Normal file
53
lib/models/shop_model.dart
Normal 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
|
||||
};
|
||||
}
|
||||
56
lib/models/shop_model.g.dart
Normal file
56
lib/models/shop_model.g.dart
Normal 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;
|
||||
}
|
||||
41
lib/provider/order_provider.dart
Normal file
41
lib/provider/order_provider.dart
Normal 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();
|
||||
}
|
||||
}
|
||||
48
lib/provider/serviceboy_provider.dart
Normal file
48
lib/provider/serviceboy_provider.dart
Normal 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();
|
||||
}
|
||||
}
|
||||
52
lib/provider/shop_provider.dart
Normal file
52
lib/provider/shop_provider.dart
Normal 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();
|
||||
}
|
||||
}
|
||||
204
lib/screens/Serviceboy_screen.dart
Normal file
204
lib/screens/Serviceboy_screen.dart
Normal 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 won’t 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),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
124
lib/screens/account_screen.dart
Normal file
124
lib/screens/account_screen.dart
Normal 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,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
101
lib/screens/add_serviceboy_screen.dart
Normal file
101
lib/screens/add_serviceboy_screen.dart
Normal 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
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
106
lib/screens/edit_serviceboy_screen.dart
Normal file
106
lib/screens/edit_serviceboy_screen.dart
Normal 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
|
||||
)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
141
lib/screens/login_screen.dart
Normal file
141
lib/screens/login_screen.dart
Normal 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
|
||||
)
|
||||
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
66
lib/screens/main_screen.dart
Normal file
66
lib/screens/main_screen.dart
Normal 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'),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
96
lib/screens/order_screen.dart
Normal file
96
lib/screens/order_screen.dart
Normal 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],);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
145
lib/screens/privacy_policy_screen.dart
Normal file
145
lib/screens/privacy_policy_screen.dart
Normal 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),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
160
lib/screens/profile_details_screen.dart
Normal file
160
lib/screens/profile_details_screen.dart
Normal 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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
150
lib/screens/terms_condition_screen.dart
Normal file
150
lib/screens/terms_condition_screen.dart
Normal 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),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
97
lib/widgets/assign_serviceboy_dialog.dart
Normal file
97
lib/widgets/assign_serviceboy_dialog.dart
Normal 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
138
lib/widgets/order_card.dart
Normal 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
|
||||
))),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
59
lib/widgets/profile_header.dart
Normal file
59
lib/widgets/profile_header.dart
Normal 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')),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user