diff --git a/images/drivers.png b/images/drivers.png new file mode 100644 index 0000000..d53b377 Binary files /dev/null and b/images/drivers.png differ diff --git a/images/icon_tune.png b/images/icon_tune.png new file mode 100644 index 0000000..bc7ad2d Binary files /dev/null and b/images/icon_tune.png differ diff --git a/images/phone_icon.png b/images/phone_icon.png new file mode 100644 index 0000000..3656e60 Binary files /dev/null and b/images/phone_icon.png differ diff --git a/images/up_down arrow.png b/images/up_down arrow.png new file mode 100644 index 0000000..6c83823 Binary files /dev/null and b/images/up_down arrow.png differ diff --git a/lib/resources/availability.dart b/lib/resources/availability.dart index 78bbd20..b556c57 100644 --- a/lib/resources/availability.dart +++ b/lib/resources/availability.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:supplier_new/common/settings.dart'; -import 'package:supplier_new/resources/resources.dart'; +import 'package:supplier_new/resources/resources_fleet.dart'; import 'package:supplier_new/resources/source_location2.dart'; void main() => runApp(const MaterialApp(home: AvailabilityScreen())); @@ -335,7 +335,7 @@ class _AvailabilityScreenState extends State { ), onPressed: () { // TODO: Navigate to the next step/screen - Navigator.push(context, MaterialPageRoute(builder: (_) => const ResourcesScreen())); + Navigator.push(context, MaterialPageRoute(builder: (_) => const ResourcesFleetScreen())); }, child: Text( diff --git a/lib/resources/resources.dart b/lib/resources/resources.dart deleted file mode 100644 index 23be4ed..0000000 --- a/lib/resources/resources.dart +++ /dev/null @@ -1,408 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:supplier_new/common/settings.dart'; -void main() => runApp(const MaterialApp(home: ResourcesScreen())); - - -class ResourcesScreen extends StatefulWidget { - const ResourcesScreen({super.key}); - @override - State createState() => _ResourcesScreenState(); -} - -class _ResourcesScreenState extends State { - int selectedTab = 0; - String search = ''; - - final List> items = [ - { - 'title': 'Tanker Name', - 'subtitle': 'Drinking water - 10,000 L', - 'status': ['filled', 'available'], - 'code': 'TS 07 J 3492', - 'owner': 'Ramesh Krishna' - }, - { - 'title': 'Drinking Water - 15,000L', - 'subtitle': 'Drinking water - 15,000 L', - 'status': ['empty', 'available'], - 'code': 'TS 07 J 3492', - 'owner': 'Ramesh Krishna' - }, - { - 'title': 'Tanker Name', - 'subtitle': 'Drinking water - 10,000 L', - 'status': ['filled', 'in-use'], - 'code': 'TS 07 J 3492', - 'owner': 'Ramesh Krishna' - }, - { - 'title': 'Drinking Water - 15,000L', - 'subtitle': 'Drinking water - 15,000 L', - 'status': ['empty', 'in-use'], - 'code': 'TS 07 J 3492', - 'owner': 'Ramesh Krishna' - }, - { - 'title': 'Tanker Name', - 'subtitle': 'Drinking water - 10,000 L', - 'status': ['filled', 'maintenance'], - 'code': 'TS 07 J 3492', - 'owner': 'Ramesh Krishna' - }, - ]; - - @override - Widget build(BuildContext context) { - final filtered = items.where((it) { - final q = search.trim().toLowerCase(); - if (q.isEmpty) return true; - return it['title'].toLowerCase().contains(q) || - it['subtitle'].toLowerCase().contains(q) || - it['owner'].toLowerCase().contains(q); - }).toList(); - - return Scaffold( - backgroundColor: const Color(0xFFF6F6F7), - appBar: AppBar( - backgroundColor: Colors.white, - elevation: 0.7, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.black87), - onPressed: () => Navigator.of(context).maybePop(), - ), - title: Text( - 'Resources', - style: fontTextStyle(16, const Color(0xFF2A2A2A), FontWeight.w600), - ), - centerTitle: false, - actions: [ - TextButton( - onPressed: () {}, - child: Text('HELP', style: fontTextStyle(12, const Color(0xFF8270DB), FontWeight.w600)), - ), - ], - ), - - body: SafeArea( - child: Padding( - padding: const EdgeInsets.fromLTRB(16, 12, 16, 0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Segmented tabs - Container( - padding: const EdgeInsets.all(6), - decoration: BoxDecoration( - color: const Color(0xFFF1F1F3), - borderRadius: BorderRadius.circular(24), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: List.generate(3, (i) { - final labels = ['Fleet', 'Drivers', 'Sources']; - final isSelected = selectedTab == i; - return GestureDetector( - onTap: () => setState(() => selectedTab = i), - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8), - margin: const EdgeInsets.symmetric(horizontal: 4), - decoration: BoxDecoration( - color: isSelected ? Colors.white : Colors.transparent, - borderRadius: BorderRadius.circular(20), - ), - child: Text( - labels[i], - style: TextStyle( - color: isSelected ? Colors.black87 : Colors.grey.shade700, - fontWeight: isSelected ? FontWeight.w600 : FontWeight.w500, - ), - ), - ), - ); - }), - ), - ), - - const SizedBox(height: 16), - - // Summary card and small stats row - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Big card - Expanded( - flex: 2, - child: Container( - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow(color: Colors.black.withOpacity(0.03), blurRadius: 6, offset: const Offset(0, 3)) - ], - ), - child: Row( - children: [ - Container( - width: 48, - height: 48, - decoration: BoxDecoration( - color: const Color(0xFFF6F0FF), - borderRadius: BorderRadius.circular(10), - ), - child: const Icon(Icons.local_shipping_outlined, color: Color(0xFF6F5FBA)), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: const [ - Text('Total Tankers', style: TextStyle(fontSize: 14, color: Colors.black87)), - SizedBox(height: 6), - Text('14', style: TextStyle(fontSize: 28, fontWeight: FontWeight.w700, color: Color(0xFF173F5F))), - SizedBox(height: 2), - Text('+2 since last month', style: TextStyle(fontSize: 12, color: Colors.grey)), - ], - ), - ), - ], - ), - ), - ), - - const SizedBox(width: 12), - - // Small stat cards - Expanded( - flex: 1, - child: Column( - children: [ - StatCard(title: 'Active', value: '2'), - const SizedBox(height: 8), - StatCard(title: 'Inactive', value: '3'), - const SizedBox(height: 8), - StatCard(title: 'Under\nMaintenances', value: '1'), - ], - ), - ) - ], - ), - - const SizedBox(height: 16), - - // Search and filter row - Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(10), - ), - child: Row( - children: [ - const Icon(Icons.search, color: Colors.grey), - const SizedBox(width: 8), - Expanded( - child: TextField( - decoration: const InputDecoration( - hintText: 'Search', - border: InputBorder.none, - isDense: true, - ), - onChanged: (v) => setState(() => search = v), - ), - ), - IconButton( - onPressed: () {}, - icon: const Icon(Icons.filter_list, color: Colors.grey), - ), - IconButton( - onPressed: () {}, - icon: const Icon(Icons.swap_vert, color: Colors.grey), - ) - ], - ), - ), - - const SizedBox(height: 12), - - // List - Expanded( - child: ListView.separated( - itemCount: filtered.length, - separatorBuilder: (_, __) => const SizedBox(height: 10), - itemBuilder: (context, idx) { - final it = filtered[idx]; - return TankCard( - title: it['title'], - subtitle: it['subtitle'], - code: it['code'], - owner: it['owner'], - status: List.from(it['status']), - ); - }, - ), - ), - ], - ), - ), - ), - - floatingActionButton: FloatingActionButton( - onPressed: () {}, - backgroundColor: const Color(0xFF2E2B5F), - child: const Icon(Icons.add), - ), - - bottomNavigationBar: BottomNavigationBar( - type: BottomNavigationBarType.fixed, - currentIndex: 0, - selectedItemColor: const Color(0xFF6F5FBA), - unselectedItemColor: Colors.grey, - items: const [ - BottomNavigationBarItem(icon: Icon(Icons.home_outlined), label: 'Home'), - BottomNavigationBarItem(icon: Icon(Icons.receipt_long_outlined), label: 'Orders'), - BottomNavigationBarItem(icon: Icon(Icons.calendar_month), label: 'Plans'), - BottomNavigationBarItem(icon: Icon(Icons.group_outlined), label: 'Resources'), - BottomNavigationBarItem(icon: Icon(Icons.menu), label: 'More'), - ], - ), - ); - } -} - -class StatCard extends StatelessWidget { - final String title; - final String value; - const StatCard({super.key, required this.title, required this.value}); - @override - Widget build(BuildContext context) { - return Container( - height: 58, - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(10), - border: Border.all(color: Colors.grey.shade200), - ), - child: Row( - children: [ - Expanded(child: Text(title, style: const TextStyle(fontSize: 13, color: Colors.black87))), - Text(value, style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w700, color: Color(0xFF173F5F))), - ], - ), - ); - } -} - -class TankCard extends StatelessWidget { - final String title; - final String subtitle; - final String code; - final String owner; - final List status; - const TankCard({ - super.key, - required this.title, - required this.subtitle, - required this.code, - required this.owner, - required this.status, - }); - - Color _chipColor(String s) { - switch (s) { - case 'filled': - return const Color(0xFFE8F7F1); - case 'available': - return const Color(0xFFE8F0FF); - case 'empty': - return const Color(0xFFFFEEEE); - case 'in-use': - return const Color(0xFFFFF0E6); - case 'maintenance': - return const Color(0xFFFFF4E6); - default: - return const Color(0xFFECECEC); - } - } - - Color _chipTextColor(String s) { - switch (s) { - case 'filled': - return Colors.green.shade700; - case 'available': - return const Color(0xFF2E2B5F); - case 'empty': - return Colors.red.shade600; - case 'in-use': - return Colors.orange.shade700; - case 'maintenance': - return Colors.orange.shade700; - default: - return Colors.black87; - } - } - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all(color: Colors.grey.shade100), - ), - child: Row( - children: [ - // left column: chips + texts - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // chips - Row( - children: status.map((s) { - return Container( - margin: const EdgeInsets.only(right: 6), - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - decoration: BoxDecoration( - color: _chipColor(s), - borderRadius: BorderRadius.circular(8), - border: Border.all(color: Colors.grey.withOpacity(0.12)), - ), - child: Text( - s, - style: TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: _chipTextColor(s)), - ), - ); - }).toList(), - ), - const SizedBox(height: 8), - Text(title, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w700)), - const SizedBox(height: 6), - Text(subtitle, style: const TextStyle(fontSize: 13, color: Colors.grey)), - const SizedBox(height: 10), - Row( - children: [ - CircleAvatar(radius: 10, backgroundColor: const Color(0xFFEEF5FF), child: const Icon(Icons.person, size: 12, color: Color(0xFF6F5FBA))), - const SizedBox(width: 6), - Expanded(child: Text(owner, style: const TextStyle(fontSize: 12, color: Colors.grey))), - ], - ), - ], - ), - ), - - // right column: code - Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text(code, style: const TextStyle(fontSize: 12, color: Colors.grey)), - const SizedBox(height: 28), - ], - ), - ], - ), - ); - } -} diff --git a/lib/resources/resources_drivers.dart b/lib/resources/resources_drivers.dart new file mode 100644 index 0000000..dee7342 --- /dev/null +++ b/lib/resources/resources_drivers.dart @@ -0,0 +1,469 @@ +import 'package:flutter/material.dart'; +import 'package:supplier_new/common/settings.dart'; +import 'package:supplier_new/resources/resources_sources.dart'; +import 'fleet.dart'; +import 'resources_drivers.dart'; +import 'resources_sources.dart'; + + +import 'employees.dart'; + +void main() => runApp(const MaterialApp(home: ResourcesDriverScreen())); + +class ResourcesDriverScreen extends StatefulWidget { + const ResourcesDriverScreen({super.key}); + + @override + State createState() => _ResourcesDriverScreenState(); +} + +class _ResourcesDriverScreenState extends State { + int selectedTab = 1; // default "Drivers" + String search = ''; + + final List> drivers = [ + { + 'name': 'Ravi Kumar', + 'status': 'available', + 'location': 'Gandipet', + 'deliveries': 134, + 'commission': '₹500/day', + }, + { + 'name': 'Ravi Kumar', + 'status': 'offline', + 'location': 'Gandipet', + 'deliveries': 134, + 'commission': '₹500/day', + }, + ]; + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( + backgroundColor: Colors.white, + elevation: 0.7, + leading: IconButton( + icon: const Icon(Icons.arrow_back, color: Colors.black87), + onPressed: () => Navigator.of(context).maybePop(), + ), + title: Text( + 'Resources', + style: fontTextStyle(16, Color(0xFF2A2A2A), FontWeight.w600), + ), + actions: [ + TextButton( + onPressed: () {}, + child: Text( + 'HELP', + style: fontTextStyle(12, Color(0xFF8270DB), FontWeight.w600), + ), + ), + ], + ), + body: Column( + children: [ + // Segmented pill + Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: Row( + children: List.generate(3, (i) { + final labels = ['Fleet', 'Drivers', 'Sources']; + final isSelected = selectedTab == i; + return Expanded( + child: GestureDetector( + onTap: () => setState(() => selectedTab = i), + child: Container( + padding: const EdgeInsets.symmetric(vertical: 8), + margin: const EdgeInsets.symmetric(horizontal: 4), + decoration: BoxDecoration( + color: isSelected + ? const Color(0xFFF1F1F1) + : Colors.transparent, + borderRadius: BorderRadius.circular(20), + ), + alignment: Alignment.center, + child: Text( + labels[i], + style: TextStyle( + color: isSelected + ? const Color(0xFF101214) + : const Color(0xFF646464), + fontWeight: + isSelected ? FontWeight.w600 : FontWeight.w500, + ), + ), + ), + ), + ); + }), + ), + ), + + // Total Drivers card + Container( + margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + padding: const EdgeInsets.all(14), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: const Color(0xFF939495)), + ), + child: Row( + children: [ + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: 40, + height: 40, + decoration: const BoxDecoration( + color: Color(0xFFF6F0FF), + borderRadius: BorderRadius.all(Radius.circular(8)), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Image.asset('images/drivers.png', + fit: BoxFit.contain), + ), + ), + const SizedBox(height: 8), + Text('Total Drivers', + style: fontTextStyle( + 12, const Color(0xFF2D2E30), FontWeight.w500)), + ], + ), + const Spacer(), + Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text('09', + style: fontTextStyle( + 24, const Color(0xFF0D3771), FontWeight.w500)), + const SizedBox(height: 6), + Text('+1 since last month', + style: fontTextStyle( + 10, const Color(0xFF646566), FontWeight.w400)), + ], + ), + ], + ), + ), + + // Metrics row + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: IntrinsicHeight( + child: Row( + children: const [ + Expanded( + child: SmallMetricBox(title: 'On delivery', value: '2')), + SizedBox(width: 8), + Expanded( + child: SmallMetricBox(title: 'Available', value: '3')), + SizedBox(width: 8), + Expanded(child: SmallMetricBox(title: 'Offline', value: '1')), + ], + ), + ), + ), + + const SizedBox(height: 12), + + // Gray background with search and list + Expanded( + child: Container( + color: const Color(0xFFF5F5F5), + child: Padding( + padding: const EdgeInsets.fromLTRB(16, 12, 16, 0), + child: Column( + children: [ + Row( + children: [ + Expanded( + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, vertical: 6), + decoration: BoxDecoration( + border: Border.all( + color: const Color(0xFF939495), width: 0.5), + borderRadius: BorderRadius.circular(22), + ), + child: Row( + children: [ + Image.asset('images/search.png', + width: 18, height: 18), + const SizedBox(width: 8), + Expanded( + child: TextField( + decoration: InputDecoration( + hintText: 'Search', + hintStyle: fontTextStyle(12, + Color(0xFF939495), FontWeight.w400), + border: InputBorder.none, + isDense: true, + ), + onChanged: (v) => + setState(() => search = v), + ), + ), + ], + ), + ), + ), + const SizedBox(width: 16), + Image.asset("images/icon_tune.png", + width: 24, height: 24), + const SizedBox(width: 16), + Image.asset("images/up_down arrow.png", + width: 24, height: 24), + ], + ), + const SizedBox(height: 12), + + // Driver list + Expanded( + child: ListView.separated( + itemCount: drivers.length, + separatorBuilder: (_, __) => const SizedBox(height: 12), + itemBuilder: (context, idx) { + final d = drivers[idx]; + return DriverCard( + name: d['name'], + status: d['status'], + location: d['location'], + deliveries: d['deliveries'], + commission: d['commission'], + ); + }, + ), + ), + ], + ), + ), + ), + ), + ], + ), + + // Floating Action Button + floatingActionButton: FloatingActionButton( + onPressed: () { + // TODO: Navigate to the next step/screen + Navigator.push(context, MaterialPageRoute(builder: (_) => FleetEmployees())); + + }, + backgroundColor: Colors.black, + shape: const CircleBorder(), + child: const Icon(Icons.add, color: Colors.white), + ), + ); + } +} + +// Metric Box widget +class SmallMetricBox extends StatelessWidget { + final String title; + final String value; + + const SmallMetricBox({super.key, required this.title, required this.value}); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + border: Border.all(color: const Color(0xFF939495)), + color: Colors.white, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(title, + style: + fontTextStyle(12, const Color(0xFF2D2E30), FontWeight.w500)), + const SizedBox(height: 4), + Text(value, + style: + fontTextStyle(24, const Color(0xFF0D3771), FontWeight.w500)), + ], + ), + ); + } +} + +// Driver Card widget +class DriverCard extends StatelessWidget { + final String name; + final String status; + final String location; + final int deliveries; + final String commission; + + const DriverCard({ + super.key, + required this.name, + required this.status, + required this.location, + required this.deliveries, + required this.commission, + }); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(14), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.grey.shade300), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Row with name + phone + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + ClipOval( + child: Image.asset("images/profile_pic.png", + height: 36, width: 36, fit: BoxFit.cover), + ), + const SizedBox(width: 10), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(name, + style: fontTextStyle( + 14, const Color(0xFF2D2E30), FontWeight.w500)), + const SizedBox(height: 4), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 6, vertical: 2), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4), + border: Border.all( + color: status == "available" + ? Colors.green + : Colors.grey, + ), + ), + child: Text( + status, + style: fontTextStyle( + 10, + status == "available" ? Colors.green : Colors.grey, + FontWeight.w400, + ), + ), + ), + ], + ), + ], + ), + Container( + padding: const EdgeInsets.all(8), // spacing around the icon + decoration: const BoxDecoration( + color: Color(0xFFF5F6F6), // background color + shape: BoxShape.circle, // makes it perfectly round + ), + child: Image.asset( + "images/phone_icon.png", + width: 20, + height: 20, + ), + ), + ], + ), + const SizedBox(height: 12), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text.rich( + TextSpan( + children: [ + TextSpan( + text: "Location\n", style: fontTextStyle(8, Color(0xFF939495), FontWeight.w500, + ), + ), + TextSpan( + text: location, style: fontTextStyle(12, const Color(0xFF515253), FontWeight.w500,), + ), + ], + ), + textAlign: TextAlign.center, + ), + Text.rich( + TextSpan( + children: [ + TextSpan( + text: "Deliveries\n", style: fontTextStyle(8, const Color(0xFF939495), FontWeight.w400, + ), + ), + TextSpan( + text: deliveries.toString(), style: fontTextStyle(12, const Color(0xFF515253), FontWeight.w500,), + ), + ], + ), + textAlign: TextAlign.center, + ), + + // Commission + Text.rich( + TextSpan( + children: [ + TextSpan( + text: "Commission\n", style: fontTextStyle(8, Color(0xFF939495), FontWeight.w400, + ), + ), + TextSpan( + text: commission, style: fontTextStyle(12, Color(0xFF515253), FontWeight.w500,), + ), + ], + ), + textAlign: TextAlign.center, + ), + ], + ), + + const SizedBox(height: 12), + + // Buttons row + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + OutlinedButton( + style: OutlinedButton.styleFrom( + side: const BorderSide(color: Color(0xFF939495)), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16)), + ), + onPressed: () {}, + child: Text("View Schedule", + style: fontTextStyle( + 12, Color(0xFF515253), FontWeight.w400)), + ), + const SizedBox(width: 12), + ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF8270DB), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16)), + ), + onPressed: () {}, + + child: Text("Assign", style: fontTextStyle(12, Color(0xFFFFFFFF), FontWeight.w400) + ), + ), + ], + ) + ], + ), + ); + } +} diff --git a/lib/resources/resources_fleet.dart b/lib/resources/resources_fleet.dart new file mode 100644 index 0000000..c87ebef --- /dev/null +++ b/lib/resources/resources_fleet.dart @@ -0,0 +1,504 @@ +import 'package:flutter/material.dart'; +import 'package:supplier_new/common/settings.dart'; +import 'fleet.dart'; +import 'resources_drivers.dart'; +import 'resources_sources.dart'; + +import 'package:supplier_new/resources/resources_drivers.dart'; + + +import 'package:supplier_new/resources/resources_sources.dart'; + +import 'fleet.dart';void main() => runApp(const MaterialApp(home: ResourcesFleetScreen())); + +class ResourcesFleetScreen extends StatefulWidget { + const ResourcesFleetScreen({super.key}); + + @override + State createState() => _ResourcesFleetScreenState(); +} + +class _ResourcesFleetScreenState extends State { + int selectedTab = 0; + String search = ''; + + final List> items = [ + { + 'title': 'Tanker Name', + 'subtitle': 'Drinking water - 10,000 L', + 'status': ['filled', 'available'], + 'code': 'TS 07 J 3492', + 'owner': 'Ramesh Krishna' + }, + { + 'title': 'Drinking Water - 15,000L', + 'subtitle': 'Drinking water - 15,000 L', + 'status': ['empty', 'available'], + 'code': 'TS 07 J 3492', + 'owner': 'Ramesh Krishna' + }, + { + 'title': 'Tanker Name', + 'subtitle': 'Drinking water - 10,000 L', + 'status': ['filled', 'in-use'], + 'code': 'TS 07 J 3492', + 'owner': 'Ramesh Krishna' + }, + { + 'title': 'Drinking Water - 15,000L', + 'subtitle': 'Drinking water - 15,000 L', + 'status': ['empty', 'in-use'], + 'code': 'TS 07 J 3492', + 'owner': 'Ramesh Krishna' + }, + { + 'title': 'Tanker Name', + 'subtitle': 'Drinking water - 10,000 L', + 'status': ['filled', 'maintenance'], + 'code': 'TS 07 J 3492', + 'owner': 'Ramesh Krishna' + }, + ]; + + @override + Widget build(BuildContext context) { + final filtered = items.where((it) { + final q = search.trim().toLowerCase(); + if (q.isEmpty) return true; + return it['title'].toLowerCase().contains(q) || + it['subtitle'].toLowerCase().contains(q) || + it['owner'].toLowerCase().contains(q); + }).toList(); + + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( + backgroundColor: Colors.white, + elevation: 0.7, + leading: IconButton( + icon: const Icon(Icons.arrow_back, color: Colors.black87), + onPressed: () => Navigator.of(context).maybePop(), + ), + title: Text( + 'Resources', + style: fontTextStyle(16, const Color(0xFF2A2A2A), FontWeight.w600), + ), + centerTitle: false, + actions: [ + TextButton( + onPressed: () {}, + child: Text('HELP', + style: fontTextStyle( + 12, const Color(0xFF8270DB), FontWeight.w600)), + ), + ], + ), + body: Column( + children: [ + Container( + color: Colors.white, + padding: const EdgeInsets.fromLTRB(16, 12, 16, 12), + child: Column( + children: [ + // Segmented pill + Container( + padding: const EdgeInsets.all(6), + child: Row( + children: List.generate(3, (i) { + final labels = ['Fleet', 'Drivers', 'Sources']; + final isSelected = selectedTab == i; + return Expanded( + child: GestureDetector( + onTap: () => setState(() => selectedTab = i), + child: Container( + padding: const EdgeInsets.symmetric(vertical: 8), + margin: const EdgeInsets.symmetric(horizontal: 4), + decoration: BoxDecoration( + color: isSelected + ? const Color(0xFFF1F1F1) + : Colors.transparent, + borderRadius: BorderRadius.circular(20), + ), + alignment: Alignment.center, + child: Text( + labels[i], + style: TextStyle( + color: isSelected + ? const Color(0xFF101214) + : const Color(0xFF646464), + fontWeight: isSelected + ? FontWeight.w600 + : FontWeight.w500, + ), + ), + ), + ), + ); + }), + ), + ), + + const SizedBox(height: 12), + Container( + width: double.infinity, + padding: const EdgeInsets.all(14), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Color(0xFF939495)), + ), + child: Row( + children: [ + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: 40, + height: 40, + decoration: const BoxDecoration( + color: Color(0xFFF6F0FF), + borderRadius: + BorderRadius.all(Radius.circular(8)), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Image.asset( + 'images/truck.png', + fit: BoxFit.contain, + ), + ), + ), + const SizedBox(height: 8), + Text('Total Tankers', style: fontTextStyle(12, Color(0xFF2D2E30), FontWeight.w500, // or w500 if you want slightly bolder + ), + ), + + ], + ), + const Spacer(), + Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [Text('14', style: fontTextStyle(24, const Color(0xFF0D3771), FontWeight.w500, + ), + ), + + SizedBox(height: 6), + Text('+2 since last month', + style: fontTextStyle(10, Color(0xFF646566), FontWeight.w400,)), + ], + ), + ], + ), + ), + + const SizedBox(height: 12), + + IntrinsicHeight( + child: Row( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: SmallMetricBox(title: 'Active', value: '2')), + const SizedBox(width: 8), + Expanded( + child: SmallMetricBox(title: 'Inactive', value: '3')), + const SizedBox(width: 8), + Expanded( + child: SmallMetricBox( + title: 'Under Maintenances', value: '1')), + ], + ), + ), + ], + ), + ), + + // -------- SECOND SECTION (gray background) ---------- + Expanded( + child: Container( + color: const Color(0xFFF5F5F5), // Gray background + child: Padding( + padding: const EdgeInsets.fromLTRB(16, 12, 16, 0), + child: Column( + children: [ + Row( + children: [ + SizedBox( + width: 270, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, vertical: 6), + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFF939495), // 👈 border color + width: 0.5, // 👈 border width + ), + borderRadius: BorderRadius.circular(22), + ), + child: Row( + children: [ + Container( + width: 20, + height: 20, + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage('images/search.png'), + fit: BoxFit.contain), + ), + ), + const SizedBox(width: 8), + Expanded( + child: TextField( + decoration: InputDecoration( + hintText: 'Search', + hintStyle: fontTextStyle( + 12, + const Color(0xFF939495), + FontWeight.w400), + border: InputBorder.none, + isDense: true, + ), + onChanged: (v) => + setState(() => search = v), + ), + ), + ], + ), + ), + ), + const SizedBox(width: 16), + Container( + width: 24, + height: 24, + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage('images/icon_tune.png'), + fit: BoxFit.contain), + ), + ), + const SizedBox(width: 16), + Container( + width: 24, + height: 24, + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage('images/up_down arrow.png'), + fit: BoxFit.contain), + ), + ), + ], + ), + + const SizedBox(height: 12), + + // Cards List + Expanded( + child: ListView.separated( + itemCount: filtered.length, + separatorBuilder: (_, __) => const SizedBox(height: 10), + itemBuilder: (context, idx) { + final it = filtered[idx]; + return TankCard( + title: it['title'], + subtitle: it['subtitle'], + code: it['code'], + owner: it['owner'], + status: List.from(it['status']), + ); + }, + ), + ), + ], + ), + ), + ), + ), + ], + ), + floatingActionButton: FloatingActionButton( + onPressed: () { + // TODO: Navigate to the next step/screen + Navigator.push(context, MaterialPageRoute(builder: (_) => const FleetStep1Page())); + + }, + backgroundColor: const Color(0xFF000000), + shape: const CircleBorder(), // ✅ ensures circle + child: const Icon(Icons.add,color: Colors.white,), + ), + ); + } +} + +// ====== SmallMetricBox ====== +class SmallMetricBox extends StatelessWidget { + final String title; + final String value; + + const SmallMetricBox({super.key, required this.title, required this.value}); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Color(0xFF939495)), + + color: Colors.white, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(title, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: + fontTextStyle(12, const Color(0xFF2D2E30), FontWeight.w500)), + Text(value, + style: + fontTextStyle(24, const Color(0xFF0D3771), FontWeight.w500)), + ], + ), + ); + } +} + +// ====== TankCard ====== +class TankCard extends StatelessWidget { + final String title; + final String subtitle; + final String code; + final String owner; + final List status; + + const TankCard({ + super.key, + required this.title, + required this.subtitle, + required this.code, + required this.owner, + required this.status, + }); + + Color _chipColor(String s) { + switch (s) { + case 'filled': + return const Color(0xFFFFFFFF); + case 'available': + return const Color(0xFFE8F0FF); + case 'empty': + return const Color(0xFFFFEEEE); + case 'in-use': + return const Color(0xFFFFF0E6); + case 'maintenance': + return const Color(0xFFFFF4E6); + default: + return const Color(0xFFECECEC); + } + } + + Color _chipTextColor(String s) { + switch (s) { + case 'filled': + return const Color(0xFF1D7AFC); + case 'available': + return const Color(0xFF0A9E04); + case 'empty': + return const Color(0xFFE2483D); + case 'in-use': + return const Color(0xFFEA843B); + case 'maintenance': + return const Color(0xFFD0AE3C); + default: + return Colors.black87; + } + } + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.grey.shade200), + ), + child: Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: status.map((s) { + final chipTextColor = _chipTextColor(s); + return Container( + margin: const EdgeInsets.only(right: 6), + padding: const EdgeInsets.symmetric( + horizontal: 8, vertical: 4), + decoration: BoxDecoration( + color: _chipColor(s), + borderRadius: BorderRadius.circular(8), + border: Border.all(color: chipTextColor, width: 1), + ), + child: Text( + s, style: + fontTextStyle(10, chipTextColor, FontWeight.w400), + ), + ); + }).toList(), + ), + const SizedBox(height: 8), + Text(title, + style: fontTextStyle( + 14, const Color(0xFF343637), FontWeight.w600)), + const SizedBox(height: 6), + Text(subtitle, + style: fontTextStyle( + 10, const Color(0xFF515253), FontWeight.w600)), + const SizedBox(height: 10), + Row( + children: [ + ClipOval( + child: Container( + height: 12, + width: 12, + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: (AppSettings.profilePictureUrl != '' && + AppSettings.profilePictureUrl != 'null') + ? NetworkImage(AppSettings.profilePictureUrl) + as ImageProvider + : const AssetImage("images/profile_pic.png"), + fit: BoxFit.cover), + ), + ), + ), + const SizedBox(width: 6), + Expanded( + child: Text(owner, + style: fontTextStyle( + 8, const Color(0xFF646566), FontWeight.w400)), + ), + ], + ), + ], + ), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text(code, + style: fontTextStyle( + 10, const Color(0xFF515253), FontWeight.w400)), + const SizedBox(height: 28), + ], + ), + ], + ), + ); + } +} diff --git a/lib/resources/resources_sources.dart b/lib/resources/resources_sources.dart new file mode 100644 index 0000000..6ccba8b --- /dev/null +++ b/lib/resources/resources_sources.dart @@ -0,0 +1,392 @@ +import 'package:flutter/material.dart'; +import 'package:supplier_new/common/settings.dart'; +import 'package:supplier_new/resources/source_location.dart'; +import 'fleet.dart'; +import 'resources_drivers.dart'; +import 'resources_sources.dart'; + + +void main() => runApp(const MaterialApp(home: ResourcesSourceScreen())); + +class ResourcesSourceScreen extends StatefulWidget { + const ResourcesSourceScreen({super.key}); + + @override + State createState() => _ResourcesSourceScreenState(); +} + +class _ResourcesSourceScreenState extends State { + int selectedTab = 2; + String search = ''; + + final List> items = [ + { + 'title': 'Gandipet Water Supply', + 'subtitle': 'Road No.34, Blah', + }, + { + 'title': 'Gandipet Water Supply', + 'subtitle': 'Road No.34, Blah', + }, + { + 'title': 'Gandipet Water Supply', + 'subtitle': 'Road No.34, Blah', + }, + { + 'title': 'Gandipet Water Supply', + 'subtitle': 'Road No.34, Blah', + }, + { + 'title': 'Gandipet Water Supply', + 'subtitle': 'Road No.34, Blah', + }, + ]; + + @override + Widget build(BuildContext context) { + final filtered = items.where((it) { + final q = search.trim().toLowerCase(); + if (q.isEmpty) return true; + return it['title'].toLowerCase().contains(q) || + it['subtitle'].toLowerCase().contains(q) || + (it['owner']?.toLowerCase() ?? '').contains(q); + }).toList(); + + return Scaffold( + backgroundColor: Colors.white, + appBar: AppBar( + backgroundColor: Colors.white, + elevation: 0.7, + leading: IconButton( + icon: const Icon(Icons.arrow_back, color: Colors.black87), + onPressed: () => Navigator.of(context).maybePop(), + ), + title: Text( + 'Resources', + style: fontTextStyle(16, const Color(0xFF2A2A2A), FontWeight.w600), + ), + centerTitle: false, + actions: [ + TextButton( + onPressed: () {}, + child: Text('HELP', + style: fontTextStyle( + 12, const Color(0xFF8270DB), FontWeight.w600)), + ), + ], + ), + body: Column( + children: [ + // Top card section + Container( + color: Colors.white, + padding: const EdgeInsets.fromLTRB(16, 12, 16, 12), + child: Column( + children: [ + // Segmented pill + Container( + padding: const EdgeInsets.all(6), + child: Row( + children: List.generate(3, (i) { + final labels = ['Fleet', 'Drivers', 'Sources']; + final isSelected = selectedTab == i; + return Expanded( + child: GestureDetector( + onTap: () => setState(() => selectedTab = i), + child: Container( + padding: const EdgeInsets.symmetric(vertical: 8), + margin: const EdgeInsets.symmetric(horizontal: 4), + decoration: BoxDecoration( + color: isSelected + ? const Color(0xFFF1F1F1) + : Colors.transparent, + borderRadius: BorderRadius.circular(20), + ), + alignment: Alignment.center, + child: Text( + labels[i], + style: TextStyle( + color: isSelected + ? const Color(0xFF101214) + : const Color(0xFF646464), + fontWeight: isSelected + ? FontWeight.w600 + : FontWeight.w500, + ), + ), + ), + ), + ); + }), + ), + ), + + const SizedBox(height: 12), + // Total Source Locations card + Container( + width: double.infinity, + padding: const EdgeInsets.all(14), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: const Color(0xFF939495)), + ), + child: Row( + children: [ + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + width: 40, + height: 40, + decoration: const BoxDecoration( + color: Color(0xFFF6F0FF), + borderRadius: BorderRadius.all(Radius.circular(8)), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Image.asset( + 'images/drivers.png', + fit: BoxFit.contain, + ), + ), + ), + const SizedBox(height: 8), + Text( + 'Total Source Locations', + style: fontTextStyle(12, const Color(0xFF2D2E30), FontWeight.w500), + ), + ], + ), + const Spacer(), + Column( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + '04', + style: fontTextStyle(24, const Color(0xFF0D3771), FontWeight.w500), + ), + const SizedBox(height: 6), + Text('no recent changes', + style: fontTextStyle(10, const Color(0xFF646566), FontWeight.w400)), + ], + ), + ], + ), + ), + + const SizedBox(height: 12), + // Metrics boxes + IntrinsicHeight( + child: Row( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded(child: SmallMetricBox(title: 'Drinking water', value: '2')), + const SizedBox(width: 8), + Expanded(child: SmallMetricBox(title: 'Bore water', value: '3')), + const SizedBox(width: 8), + Expanded(child: SmallMetricBox(title: 'Both', value: '1')), + ], + ), + ), + ], + ), + ), + + // SECOND SECTION (gray background) + Expanded( + child: Container( + color: const Color(0xFFF5F5F5), + child: Padding( + padding: const EdgeInsets.fromLTRB(16, 12, 16, 0), + child: Column( + children: [ + // Search row + Row( + children: [ + SizedBox( + width: 270, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), + decoration: BoxDecoration( + border: Border.all( + color: const Color(0xFF939495), + width: 0.5, + ), + borderRadius: BorderRadius.circular(22), + ), + child: Row( + children: [ + Container( + width: 20, + height: 20, + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage('images/search.png'), + fit: BoxFit.contain), + ), + ), + const SizedBox(width: 8), + Expanded( + child: TextField( + decoration: InputDecoration( + hintText: 'Search', + hintStyle: fontTextStyle(12, const Color(0xFF939495), FontWeight.w400), + border: InputBorder.none, + isDense: true, + ), + onChanged: (v) => setState(() => search = v), + ), + ), + ], + ), + ), + ), + const SizedBox(width: 16), + Container( + width: 24, + height: 24, + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage('images/icon_tune.png'), + fit: BoxFit.contain), + ), + ), + const SizedBox(width: 16), + Container( + width: 24, + height: 24, + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage('images/up_down arrow.png'), + fit: BoxFit.contain), + ), + ), + ], + ), + + const SizedBox(height: 12), + + // Cards List + Expanded( + child: ListView.separated( + itemCount: filtered.length, + separatorBuilder: (_, __) => const SizedBox(height: 10), + itemBuilder: (context, idx) { + final it = filtered[idx]; + return TankCard( + title: it['title'], + subtitle: it['subtitle'], + ); + }, + ), + ), + ], + ), + ), + ), + ), + ], + ), + + floatingActionButton: FloatingActionButton( + onPressed: () { + // TODO: Navigate to the next step/screen + Navigator.push(context, MaterialPageRoute(builder: (_) => const SourceLocation())); + + }, + backgroundColor: const Color(0xFF000000), + shape: const CircleBorder(), + child: const Icon(Icons.add, color: Colors.white), + ), + ); + } +} + +// ====== SmallMetricBox ====== +class SmallMetricBox extends StatelessWidget { + final String title; + final String value; + + const SmallMetricBox({super.key, required this.title, required this.value}); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + border: Border.all(color: const Color(0xFF939495)), + color: Colors.white, + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: fontTextStyle(12, const Color(0xFF2D2E30), FontWeight.w500)), + Text(value, + style: fontTextStyle(24, const Color(0xFF0D3771), FontWeight.w500)), + ], + ), + ); + } +} + +// ====== TankCard (with phone icon inside) ====== +class TankCard extends StatelessWidget { + final String title; + final String subtitle; + + const TankCard({ + super.key, + required this.title, + required this.subtitle, + }); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + border: Border.all(color: Colors.grey.shade200), + ), + child: Row( + children: [ + // Title and subtitle + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(title, + style: fontTextStyle(14, const Color(0xFF343637), FontWeight.w600)), + const SizedBox(height: 6), + Text(subtitle, + style: fontTextStyle(10, const Color(0xFF515253), FontWeight.w600)), + ], + ), + ), + const SizedBox(width: 8), + // Phone icon inside card + Container( + padding: const EdgeInsets.all(8), + decoration: const BoxDecoration( + color: Color(0xFFF5F6F6), + shape: BoxShape.circle, + ), + child: Image.asset( + "images/phone_icon.png", + width: 20, + height: 20, + ), + ), + ], + ), + ); + } +}