Your changes

This commit is contained in:
divya abdar
2025-12-11 18:36:11 +05:30
parent 3bf27cc29d
commit 9faf983b95
36 changed files with 4677 additions and 1046 deletions

View File

@@ -1,8 +1,8 @@
import 'dart:ui';
import 'package:flutter/material.dart';
import '../services/dio_client.dart';
import '../services/order_service.dart';
class OrderDetailScreen extends StatefulWidget {
final String orderId;
const OrderDetailScreen({super.key, required this.orderId});
@@ -14,6 +14,7 @@ class OrderDetailScreen extends StatefulWidget {
class _OrderDetailScreenState extends State<OrderDetailScreen> {
bool loading = true;
Map order = {};
final Map<String, bool> _expanded = {};
@override
void initState() {
@@ -33,105 +34,298 @@ class _OrderDetailScreenState extends State<OrderDetailScreen> {
setState(() {});
}
Widget _row(String label, dynamic value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label,
style: const TextStyle(fontSize: 14, color: Colors.grey)),
Text(value?.toString() ?? 'N/A',
style: const TextStyle(
fontSize: 15, fontWeight: FontWeight.w600)),
],
),
);
String _initials(String? s) {
if (s == null || s.isEmpty) return "I";
final parts = s.split(" ");
return parts.take(2).map((e) => e[0].toUpperCase()).join();
}
@override
Widget build(BuildContext context) {
final items = order['items'] ?? [];
final width = MediaQuery.of(context).size.width;
final scale = (width / 430).clamp(0.85, 1.20);
return Scaffold(
appBar: AppBar(title: const Text("Order Details")),
backgroundColor: const Color(0xFFF0F6FF),
appBar: AppBar(
title: const Text("Order Details"),
elevation: 0,
),
body: loading
? const Center(child: CircularProgressIndicator())
: Padding(
padding: const EdgeInsets.all(16),
child: ListView(
children: [
// ---------------- ORDER SUMMARY ----------------
const Text(
"Order Summary",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
_row("Order ID", order['order_id']),
_row("Mark No", order['mark_no']),
_row("Origin", order['origin']),
_row("Destination", order['destination']),
_row("Status", order['status']),
const Divider(height: 30),
const Text(
"Totals",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
_row("CTN", order['ctn']),
_row("Qty", order['qty']),
_row("Total Qty", order['ttl_qty']),
_row("Amount", "${order['ttl_amount'] ?? 0}"),
_row("CBM", order['cbm']),
_row("Total CBM", order['ttl_cbm']),
_row("KG", order['kg']),
_row("Total KG", order['ttl_kg']),
const Divider(height: 30),
// ---------------- ORDER ITEMS ----------------
const Text(
"Order Items",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
...List.generate(items.length, (i) {
final item = items[i];
return Card(
margin: const EdgeInsets.only(bottom: 12),
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
item['description'] ?? "No description",
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600),
),
const SizedBox(height: 6),
_row("Qty", item['qty']),
_row("Unit", item['unit']),
_row("CBM", item['cbm']),
_row("KG", item['kg']),
_row("Amount", "${item['ttl_amount'] ?? 0}"),
_row("Shop No", item['shop_no']),
],
),
),
);
}),
],
padding: EdgeInsets.all(16 * scale),
child: SingleChildScrollView(
child: Column(
children: [
_summaryCard(scale),
SizedBox(height: 18 * scale),
_itemsSection(items, scale),
SizedBox(height: 18 * scale),
_totalsSection(scale),
],
),
),
),
);
}
// -----------------------------
// SUMMARY CARD
// -----------------------------
Widget _summaryCard(double scale) {
return Container(
padding: EdgeInsets.all(18 * scale),
decoration: _cardDecoration(scale),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Order Summary",
style: TextStyle(fontSize: 20 * scale, fontWeight: FontWeight.bold)),
SizedBox(height: 12 * scale),
_infoRow("Order ID", order['order_id'], scale),
_infoRow("Mark No", order['mark_no'], scale),
_infoRow("Origin", order['origin'], scale),
_infoRow("Destination", order['destination'], scale),
],
),
);
}
Widget _infoRow(String title, dynamic value, double scale) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 6 * scale),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(title,
style: TextStyle(color: Colors.grey, fontSize: 14 * scale)),
Text(value?.toString() ?? "-",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 15 * scale)),
],
),
);
}
// -----------------------------
// ORDER ITEMS SECTION
// -----------------------------
Widget _itemsSection(List items, double scale) {
return Container(
padding: EdgeInsets.all(18 * scale),
decoration: _cardDecoration(scale),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Order Items",
style: TextStyle(fontSize: 18 * scale, fontWeight: FontWeight.bold)),
SizedBox(height: 16 * scale),
...List.generate(items.length, (i) {
return _expandableItem(items[i], i, scale);
})
],
),
);
}
// -----------------------------
// EXPANDABLE ITEM
// -----------------------------
Widget _expandableItem(Map item, int index, double scale) {
final id = "item_$index";
_expanded[id] = _expanded[id] ?? false;
final description = item['description'] ?? "Item";
final initials = _initials(description);
final imageUrl = item['image'] ?? "";
return AnimatedContainer(
duration: const Duration(milliseconds: 300),
margin: EdgeInsets.only(bottom: 16 * scale),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(14 * scale),
border: Border.all(color: Colors.black12),
),
child: Column(
children: [
ListTile(
minVerticalPadding: 10 * scale,
leading: _avatar(imageUrl, initials, scale),
title: Text(description,
style:
TextStyle(fontWeight: FontWeight.bold, fontSize: 15 * scale)),
trailing: Transform.rotate(
angle: (_expanded[id]! ? 3.14 : 0),
child: Icon(Icons.keyboard_arrow_down, size: 24 * scale),
),
onTap: () {
setState(() {
_expanded[id] = !_expanded[id]!;
});
},
),
if (_expanded[id]!)
Padding(
padding: EdgeInsets.all(12 * scale),
child: Column(
children: [
_pill("Qty", Icons.list_alt, "${item['qty']}",
Colors.blue.shade100, scale),
_pill("Unit", Icons.category, "${item['unit']}",
Colors.orange.shade100, scale),
_pill("KG", Icons.scale, "${item['kg']}",
Colors.red.shade100, scale),
_pill("CBM", Icons.straighten, "${item['cbm']}",
Colors.purple.shade100, scale),
_pill("Shop", Icons.storefront, "${item['shop_no']}",
Colors.grey.shade300, scale),
_pill("Amount", Icons.currency_rupee,
"${item['ttl_amount']}",
Colors.green.shade100, scale),
],
),
),
],
),
);
}
// -----------------------------
// AVATAR (RESPONSIVE)
// -----------------------------
Widget _avatar(String url, String initials, double scale) {
return Container(
width: 48 * scale,
height: 48 * scale,
decoration: BoxDecoration(
color: Colors.blue.shade200,
borderRadius: BorderRadius.circular(10 * scale),
),
child: url.isNotEmpty
? ClipRRect(
borderRadius: BorderRadius.circular(10 * scale),
child: Image.network(url, fit: BoxFit.cover,
errorBuilder: (c, e, s) => Center(
child: Text(initials,
style: TextStyle(
fontSize: 18 * scale,
color: Colors.white,
fontWeight: FontWeight.bold)),
)),
)
: Center(
child: Text(initials,
style: TextStyle(
fontSize: 18 * scale,
color: Colors.white,
fontWeight: FontWeight.bold)),
),
);
}
// -----------------------------
// COLOR-CODED PILL (RESPONSIVE)
// -----------------------------
Widget _pill(
String title, IconData icon, String value, Color bgColor, double scale) {
return Container(
margin: EdgeInsets.only(bottom: 12 * scale),
padding:
EdgeInsets.symmetric(horizontal: 14 * scale, vertical: 12 * scale),
decoration: BoxDecoration(
color: bgColor,
borderRadius: BorderRadius.circular(12 * scale),
),
child: Row(
children: [
Icon(icon, size: 20 * scale, color: Colors.black54),
SizedBox(width: 10 * scale),
Text("$title: ",
style:
TextStyle(fontWeight: FontWeight.bold, fontSize: 14 * scale)),
Expanded(
child: Text(value,
style: TextStyle(
fontWeight: FontWeight.w700, fontSize: 15 * scale)),
),
],
),
);
}
// -----------------------------
// TOTAL SECTION
// -----------------------------
Widget _totalsSection(double scale) {
return Container(
padding: EdgeInsets.all(18 * scale),
decoration: _cardDecoration(scale),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Totals",
style: TextStyle(fontSize: 18 * scale, fontWeight: FontWeight.bold)),
SizedBox(height: 12 * scale),
_totalRow("Total Qty", order['ttl_qty'], scale),
_totalRow("Total KG", order['ttl_kg'], scale),
SizedBox(height: 12 * scale),
Container(
width: double.infinity,
padding: EdgeInsets.symmetric(vertical: 20 * scale),
decoration: BoxDecoration(
color: Colors.green.shade50,
borderRadius: BorderRadius.circular(12 * scale),
),
child: Column(
children: [
Text("${order['ttl_amount'] ?? 0}",
style: TextStyle(
color: Colors.green,
fontSize: 28 * scale,
fontWeight: FontWeight.bold,
)),
SizedBox(height: 4 * scale),
Text("Total Amount",
style: TextStyle(
color: Colors.black54, fontSize: 14 * scale)),
],
),
),
],
),
);
}
Widget _totalRow(String title, dynamic value, double scale) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(title,
style: TextStyle(color: Colors.grey, fontSize: 14 * scale)),
Text(value?.toString() ?? "0",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 15 * scale)),
],
);
}
// -----------------------------
// CARD DECORATION
// -----------------------------
BoxDecoration _cardDecoration(double scale) {
return BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16 * scale),
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 8 * scale,
offset: Offset(0, 3 * scale)),
],
);
}
}