From b07033dda73625820ca5666e13018e8a4c46fe4f Mon Sep 17 00:00:00 2001 From: gitadmin Date: Thu, 25 Sep 2025 17:34:41 +0530 Subject: [PATCH] resources added --- images/drivers.png | Bin 0 -> 2034 bytes images/icon_tune.png | Bin 0 -> 1649 bytes images/phone_icon.png | Bin 0 -> 2108 bytes images/up_down arrow.png | Bin 0 -> 945 bytes lib/resources/availability.dart | 4 +- lib/resources/resources.dart | 408 ---------------------- lib/resources/resources_drivers.dart | 469 +++++++++++++++++++++++++ lib/resources/resources_fleet.dart | 504 +++++++++++++++++++++++++++ lib/resources/resources_sources.dart | 392 +++++++++++++++++++++ 9 files changed, 1367 insertions(+), 410 deletions(-) create mode 100644 images/drivers.png create mode 100644 images/icon_tune.png create mode 100644 images/phone_icon.png create mode 100644 images/up_down arrow.png delete mode 100644 lib/resources/resources.dart create mode 100644 lib/resources/resources_drivers.dart create mode 100644 lib/resources/resources_fleet.dart create mode 100644 lib/resources/resources_sources.dart diff --git a/images/drivers.png b/images/drivers.png new file mode 100644 index 0000000000000000000000000000000000000000..d53b37720b424bff4a690732d55f4c71514c3bb4 GIT binary patch literal 2034 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 literal 0 HcmV?d00001 diff --git a/images/phone_icon.png b/images/phone_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3656e606de3f0c8c6b4ccc0e274edc1496b63586 GIT binary patch literal 2108 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 literal 0 HcmV?d00001 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, + ), + ), + ], + ), + ); + } +}