import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; import '../config.dart'; import 'dart:async'; import 'package:google_fonts/google_fonts.dart'; import 'package:firebase_database/firebase_database.dart'; import 'home/order_list.dart'; import 'home/payments.dart'; import 'laundry.dart'; import 'profile.dart'; import 'request_pickup.dart'; class BerandaPage extends StatefulWidget { final Map userData; const BerandaPage({super.key, required this.userData}); @override State createState() => _BerandaPageState(); } class _BerandaPageState extends State { int _selectedIndex = 0; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFFF7F9FB), // bg-surface body: AnimatedSwitcher( duration: const Duration(milliseconds: 300), child: _selectedIndex == 0 ? HomeTab(key: const ValueKey("home"), userData: widget.userData) : _selectedIndex == 1 ? LaundryPage( key: const ValueKey("laundry"), userData: widget.userData, isTab: true) : ProfilePage( key: const ValueKey("profile"), userData: widget.userData, isTab: true), transitionBuilder: (Widget child, Animation animation) { return FadeTransition(opacity: animation, child: child); }, ), bottomNavigationBar: _buildPersistentBottomNav(), ); } Widget _buildPersistentBottomNav() { return Container( height: 64 + MediaQuery.of(context).padding.bottom, decoration: BoxDecoration( color: const Color(0xFFFFFFFF).withOpacity(0.95), border: const Border(top: BorderSide(color: Color(0xFFE6E8EA), width: 1.0)), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.03), blurRadius: 10, offset: const Offset(0, -1)) ], ), child: SafeArea( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ _navItem(Icons.home, "Beranda", _selectedIndex == 0, () { setState(() => _selectedIndex = 0); }), _navItem(Icons.add_circle, "Input", _selectedIndex == 1, () async { setState(() => _selectedIndex = 1); try { await FirebaseDatabase.instance .ref('laundry/screen_status') .set("RESTART"); // Otomatis kembalikan ke ON dari sisi HP agar tidak nyangkut await Future.delayed(const Duration(milliseconds: 500)); await FirebaseDatabase.instance .ref('laundry/screen_status') .set("ON"); // ignore: empty_catches } catch (e) {} }), _navItem(Icons.person, "Profil", _selectedIndex == 2, () { setState(() => _selectedIndex = 2); }), ], ), ), ), ); } Widget _navItem( IconData icon, String label, bool isActive, VoidCallback onTap) { return InkWell( onTap: onTap, splashColor: Colors.transparent, highlightColor: Colors.transparent, child: Container( width: 64, padding: const EdgeInsets.symmetric(vertical: 8), child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( icon, size: 24, color: isActive ? const Color(0xFF0058BE) : const Color(0xFF424754).withOpacity(0.6), ), const SizedBox(height: 2), Text( label, style: GoogleFonts.inter( fontSize: 10, fontWeight: isActive ? FontWeight.w700 : FontWeight.w500, color: isActive ? const Color(0xFF0058BE) : const Color(0xFF424754).withOpacity(0.6), ), ), ], ), ), ); } } class HomeTab extends StatefulWidget { final Map userData; const HomeTab({super.key, required this.userData}); @override State createState() => _HomeTabState(); } class _HomeTabState extends State { // Tailwind Colors final Color primary = const Color(0xFF0058BE); final Color surface = const Color(0xFFF7F9FB); final Color surfaceContainerHigh = const Color(0xFFE6E8EA); final Color onSurface = const Color(0xFF191C1E); final Color onSurfaceVariant = const Color(0xFF424754); final Color primaryFixed = const Color(0xFFD8E2FF); final Color surfaceContainerLowest = const Color(0xFFFFFFFF); final Color surfaceContainerLow = const Color(0xFFF2F4F6); final Color secondaryContainer = const Color(0xFFC3ECD7); final Color onSecondaryContainer = const Color(0xFF294E3F); final Color outline = const Color(0xFF727785); int countAntrian = 0; int countProses = 0; int countSelesai = 0; List aktivitasTerbaru = []; List pesananTiba = []; bool isLoading = true; Timer? _refreshTimer; String _selectedTab = 'antrian'; static Map? _cachedStats; static Map? _cachedActs; static Map? _cachedTiba; @override void initState() { super.initState(); if (_cachedStats != null && _cachedActs != null) { _loadFromCache(); } fetchAllData(showLoading: _cachedStats == null); _startRefreshTimer(); } void _loadFromCache() { countAntrian = _cachedStats!['data']['antrian'] ?? 0; countProses = _cachedStats!['data']['proses'] ?? 0; countSelesai = _cachedStats!['data']['selesai'] ?? 0; aktivitasTerbaru = _cachedActs!['data'] ?? []; pesananTiba = _cachedTiba!['data'] ?? []; isLoading = false; } void _startRefreshTimer() { _refreshTimer?.cancel(); _refreshTimer = Timer.periodic(const Duration(seconds: 3), (timer) { if (mounted) fetchAllData(showLoading: false); }); } @override void dispose() { _refreshTimer?.cancel(); super.dispose(); } Future fetchAllData({bool showLoading = true}) async { if (showLoading) setState(() => isLoading = true); String baseUrl = AppConfig.baseUrl; try { final String? token = widget.userData['access_token']; final responses = await Future.wait([ http.get(Uri.parse('$baseUrl/dashboard/stats'), headers: { 'Authorization': 'Bearer $token', 'Accept': 'application/json', }), http.get(Uri.parse('$baseUrl/dashboard/activities'), headers: { 'Authorization': 'Bearer $token', 'Accept': 'application/json', }), http.get(Uri.parse('$baseUrl/orders/status/TIBA%20DI%20TOKO'), headers: { 'Authorization': 'Bearer $token', 'Accept': 'application/json', }), http.get(Uri.parse('$baseUrl/shop/settings'), headers: { 'Authorization': 'Bearer $token', 'Accept': 'application/json', }), ]); if (responses[0].statusCode == 200 && responses[1].statusCode == 200) { final dataStats = json.decode(responses[0].body); final dataActs = json.decode(responses[1].body); final dataTiba = responses.length > 2 && responses[2].statusCode == 200 ? json.decode(responses[2].body) : {'data': []}; if (responses.length > 3 && responses[3].statusCode == 200) { final dataSettings = json.decode(responses[3].body); if (dataSettings['data'] != null) { widget.userData['shop'] = dataSettings['data']; } } _cachedStats = dataStats; _cachedActs = dataActs; _cachedTiba = dataTiba; setState(() { countAntrian = dataStats['data']['antrian'] ?? 0; countProses = dataStats['data']['proses'] ?? 0; countSelesai = dataStats['data']['selesai'] ?? 0; aktivitasTerbaru = dataActs['data'] ?? []; pesananTiba = dataTiba['data'] ?? []; isLoading = false; }); } else { if (mounted && _cachedStats == null) setState(() => isLoading = false); } } catch (e) { if (mounted && _cachedStats == null) setState(() => isLoading = false); } } String formatHarga(dynamic value) { if (value == null) return "0"; String val = value.toString(); RegExp reg = RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'); return val.replaceAllMapped(reg, (Match m) => '${m[1]}.'); } String formatWeightInString(String input) { return input.replaceAllMapped(RegExp(r'\((\d+\.?\d*)\s*([a-zA-Z]+)\)'), (match) { double val = double.tryParse(match.group(1) ?? "0") ?? 0; String unit = match.group(2) ?? "Kg"; if (unit.toUpperCase() == 'PCS') return "(${val.toInt()} $unit)"; // Format the display string exactly with 3 decimal places (e.g. 2.500 instead of 2.5) String valStr = val.toStringAsFixed(3); return "($valStr $unit)"; }); } List get _filteredActivities { List filtered = aktivitasTerbaru.where((item) { String status = item['status']?.toString().toUpperCase() ?? ""; if (_selectedTab == 'antrian' && (status == 'ANTRIAN' || status == 'MENUNGGU JEMPUT')) return true; if (_selectedTab == 'proses' && (status == 'PROSES' || status == 'JEMPUTAN TIBA' || status == 'MENCUCI' || status == 'MENYETRIKA')) return true; if (_selectedTab == 'selesai' && status == 'SELESAI') return true; return false; }).toList(); filtered.sort((a, b) { int priority(String type) { String t = type.toLowerCase(); if (t.contains('kilat')) return 1; if (t.contains('ekspres') || t.contains('express')) return 2; return 3; } int pA = priority((a['estimation_type'] ?? '').toString()); int pB = priority((b['estimation_type'] ?? '').toString()); if (pA != pB) return pA.compareTo(pB); final fallbackTime = DateTime(2100, 1, 1); DateTime parseTime(dynamic timeStr) { if (timeStr == null || timeStr.toString().isEmpty) { return fallbackTime; } return DateTime.tryParse(timeStr.toString()) ?? fallbackTime; } DateTime timeA = parseTime(a['estimation_time']); DateTime timeB = parseTime(b['estimation_time']); int comp = timeA.compareTo(timeB); if (comp != 0) return comp; return (a['id'] as int) .compareTo(b['id'] as int); // tertiary sort oldest first }); return filtered; } @override Widget build(BuildContext context) { return isLoading ? Center(child: CircularProgressIndicator(color: primary)) : Column( children: [ _buildAppBar(), Expanded( child: RefreshIndicator( onRefresh: () => fetchAllData(), color: primary, backgroundColor: Colors.white, child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics( parent: BouncingScrollPhysics()), slivers: [ SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.fromLTRB(16, 16, 16, 80), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // HERO BANNER GestureDetector( onTap: () async { final result = await Navigator.push( context, MaterialPageRoute( builder: (context) => RequestPickupPage( userData: widget.userData))); if (result == true) fetchAllData(); }, child: Container( width: double.infinity, height: 160, decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), border: Border.all(color: surfaceContainerHigh), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.02), blurRadius: 4, offset: const Offset(0, 2)) ], image: const DecorationImage( image: AssetImage('assets/beranda.jpg'), fit: BoxFit.cover, ), ), child: Stack( children: [ Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), gradient: LinearGradient( colors: [ primary.withOpacity(0.8), primary.withOpacity(0.4), Colors.transparent ], begin: Alignment.centerLeft, end: Alignment.centerRight, ), ), ), Padding( padding: const EdgeInsets.symmetric( horizontal: 20, vertical: 24), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ Text( "Halo, ${(widget.userData['user']?['name'] ?? 'Staf').toString().split(' ')[0]}", style: GoogleFonts.inter( fontSize: 22, fontWeight: FontWeight.w700, color: Colors.white, height: 1.1, ), ), const SizedBox(height: 4), Text( "Siap mengelola pesanan hari ini?", style: GoogleFonts.inter( fontSize: 12, color: Colors.white .withOpacity(0.9), ), ), const SizedBox(height: 12), Container( padding: const EdgeInsets.symmetric( horizontal: 20, vertical: 8), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(999), boxShadow: [ BoxShadow( color: Colors.black .withOpacity(0.05), blurRadius: 4, offset: const Offset(0, 2)) ], ), child: Text( "Buat Jadwal Pickup", style: GoogleFonts.inter( fontSize: 13, fontWeight: FontWeight.w700, color: primary, ), ), ), ], ), ), ], ), ), ), const SizedBox(height: 24), // ORDER TABS Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.end, children: [ Text("Status Pesanan", style: GoogleFonts.inter( fontSize: 16, fontWeight: FontWeight.w600, color: onSurface)), GestureDetector( onTap: () { String initialFilter = "Semua"; if (_selectedTab == 'antrian') { initialFilter = "Antrian"; } if (_selectedTab == 'proses') { initialFilter = "Proses"; } if (_selectedTab == 'selesai') { initialFilter = "Selesai"; } Navigator.push( context, MaterialPageRoute( builder: (c) => OrderListPage( initialFilter: initialFilter, userData: widget.userData))); }, child: Text("Lihat Semua", style: GoogleFonts.inter( fontSize: 13, fontWeight: FontWeight.w600, color: primary)), ), ], ), const SizedBox(height: 12), Container( padding: const EdgeInsets.all(4), decoration: BoxDecoration( color: surfaceContainerLow, borderRadius: BorderRadius.circular(12), ), child: Row( children: [ _buildTabItem( 'antrian', 'Antrian ($countAntrian)'), _buildTabItem( 'proses', 'Proses ($countProses)'), _buildTabItem( 'selesai', 'Selesai ($countSelesai)'), ], ), ), const SizedBox(height: 12), // TAB CONTENT (Filtered Orders) AnimatedSwitcher( duration: const Duration(milliseconds: 200), child: _buildFilteredList( key: ValueKey(_selectedTab)), ), const SizedBox(height: 24), // PESANAN TIBA DI TOKO if (pesananTiba.isNotEmpty) ...[ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.end, children: [ Text("Tiba di Toko (Belum Diinput)", style: GoogleFonts.inter( fontSize: 15, fontWeight: FontWeight.w700, color: onSurface)), if (pesananTiba.length > 3) GestureDetector( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (c) => OrderListPage( initialFilter: "Proses", userData: widget.userData))); }, child: Text("Lihat Semua", style: GoogleFonts.inter( fontSize: 13, fontWeight: FontWeight.w600, color: primary)), ), ], ), const SizedBox(height: 12), Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), border: Border.all( color: primary.withOpacity(0.2)), ), child: Column( children: pesananTiba .take(3) .toList() .asMap() .entries .map((entry) { return _buildTibaRow( entry.value, entry.key == (pesananTiba.take(3).length - 1)); }).toList(), ), ), const SizedBox(height: 24), ], // LAST ACTIVITY Text("Aktivitas Terakhir", style: GoogleFonts.inter( fontSize: 16, fontWeight: FontWeight.w600, color: onSurface)), const SizedBox(height: 12), _buildRecentActivityList(), ], ), ), ), ], ), ), // End of RefreshIndicator ), // End of Expanded ], // End of Column children ); // End of Column } Widget _buildTabItem(String tabId, String label) { bool isActive = _selectedTab == tabId; return Expanded( child: GestureDetector( onTap: () => setState(() => _selectedTab = tabId), child: Container( padding: const EdgeInsets.symmetric(vertical: 6), decoration: BoxDecoration( color: isActive ? surfaceContainerLowest : Colors.transparent, borderRadius: BorderRadius.circular(8), boxShadow: isActive ? [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 2, offset: const Offset(0, 1)) ] : null, ), alignment: Alignment.center, child: Text( label, style: GoogleFonts.inter( fontSize: 13, fontWeight: FontWeight.w500, color: isActive ? primary : onSurfaceVariant, ), ), ), ), ); } Widget _buildFilteredList({Key? key}) { List items = _filteredActivities; if (items.isEmpty) { return Container( key: key, width: double.infinity, padding: const EdgeInsets.all(24), alignment: Alignment.center, child: Text("Belum ada pesanan", style: GoogleFonts.inter(fontSize: 13, color: outline)), ); } return Column( key: key, children: items.take(2).map((item) => _buildOrderCard(item)).toList(), ); } Widget _buildRecentActivityList() { if (aktivitasTerbaru.isEmpty) { return Container( width: double.infinity, padding: const EdgeInsets.all(24), alignment: Alignment.center, child: Text("Belum ada aktivitas", style: GoogleFonts.inter(fontSize: 13, color: outline)), ); } return Column( children: aktivitasTerbaru .take(5) .map((item) => _buildOrderCard(item, isClickable: false)) .toList(), ); } Widget _buildOrderCard(dynamic item, {bool isClickable = true}) { String title = item['title']?.toString() ?? "Pesanan"; String rawSubtitle = item['subtitle']?.toString() ?? "-"; String subtitle = formatWeightInString(rawSubtitle.split('||').first); String status = item['status']?.toString().toUpperCase() ?? "PROSES"; String orderId = "#${item['order_number'] ?? item['id'] ?? 'ACT'}"; String price = ""; if (item['total'] != null) { price = "Rp ${formatHarga(item['total'])}"; } if (status == 'MENUNGGU JEMPUT') status = 'PICKUP'; if (status == 'JEMPUTAN TIBA') status = 'DI TOKO'; IconData icon = Icons.local_laundry_service; if (status == 'ANTRIAN' || status == 'PICKUP') icon = Icons.dry_cleaning; if (status == 'SELESAI') icon = Icons.checkroom; if (status == 'DI DRIVER') icon = Icons.delivery_dining; return InkWell( onTap: isClickable ? () { if (item['status']?.toString().toUpperCase() == 'ANTRIAN' || item['status']?.toString().toUpperCase() == 'PROSES' || item['status']?.toString().toUpperCase() == 'SELESAI') { _showUpdateStatusDialog(item); } } : null, child: Container( margin: const EdgeInsets.only(bottom: 10), padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: surfaceContainerLowest, borderRadius: BorderRadius.circular(12), border: Border.all(color: surfaceContainerHigh), ), child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Container( width: 40, height: 40, decoration: BoxDecoration( color: primary.withOpacity(0.05), borderRadius: BorderRadius.circular(8), border: Border.all(color: primary.withOpacity(0.1)), ), alignment: Alignment.center, child: Icon(icon, color: primary, size: 22), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(orderId, style: GoogleFonts.inter( fontSize: 11, fontWeight: FontWeight.w500, color: onSurfaceVariant.withOpacity(0.7), letterSpacing: 0.5)), Text(title, style: GoogleFonts.inter( fontSize: 14, fontWeight: FontWeight.w600, color: onSurface, height: 1.2), maxLines: 1, overflow: TextOverflow.ellipsis), if (subtitle.isNotEmpty && subtitle != "-") ...[ const SizedBox(height: 2), Text(subtitle, style: GoogleFonts.inter(fontSize: 11, color: outline), maxLines: 1, overflow: TextOverflow.ellipsis), ] ], ), ), const SizedBox(width: 8), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), decoration: BoxDecoration( color: secondaryContainer.withOpacity(0.5), borderRadius: BorderRadius.circular(6), ), child: Text( status, style: GoogleFonts.inter( fontSize: 9, fontWeight: FontWeight.w700, color: onSecondaryContainer, letterSpacing: 0.5), ), ), if (price.isNotEmpty && price != "Rp 0") ...[ const SizedBox(height: 4), Text(price, style: GoogleFonts.inter( fontSize: 14, fontWeight: FontWeight.w700, color: primary)), ] ], ), ], ), )); } void _showUpdateStatusDialog(dynamic item) { String currentStatus = item['status']?.toString().toUpperCase() ?? ""; String orderIdStr = item['order_number']?.toString() ?? item['id']?.toString() ?? ""; int id = int.tryParse(item['id']?.toString() ?? "0") ?? 0; if (id == 0) return; String promptText = ""; bool isUnpaid = false; if (currentStatus == 'ANTRIAN') { promptText = "Mulai proses cucian (Mencuci/Menyetrika) untuk pesanan #$orderIdStr?"; } else if (currentStatus == 'PROSES') { promptText = "Tandai pesanan #$orderIdStr sebagai SELESAI?"; } else if (currentStatus == 'SELESAI') { String deliveryType = item['delivery_type']?.toString().toLowerCase() ?? 'none'; if (deliveryType == 'delivery' || deliveryType == 'both') { promptText = "Tugaskan pesanan #$orderIdStr ke Driver untuk pengiriman (DELIVERY)?"; } else { String paymentStatus = item['payment_status']?.toString().toUpperCase() ?? "UNPAID"; if (paymentStatus != 'PAID') { isUnpaid = true; promptText = "Pesanan #$orderIdStr belum lunas. Lanjutkan ke halaman pelunasan?"; } else { promptText = "Selesaikan pesanan #$orderIdStr dan ubah menjadi DIAMBIL?"; } } } else { return; } showDialog( context: context, builder: (ctx) => AlertDialog( title: Text("Lanjutkan Pesanan?", style: GoogleFonts.inter(fontWeight: FontWeight.w700)), content: Text(promptText, style: GoogleFonts.inter(fontSize: 14)), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12)), actions: [ TextButton( onPressed: () => Navigator.pop(ctx), child: Text("Batal", style: GoogleFonts.inter(color: Colors.grey)), ), ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: primary, foregroundColor: Colors.white), onPressed: () { Navigator.pop(ctx); if (isUnpaid) { Navigator.push( context, MaterialPageRoute( builder: (context) => HomePaymentPage( order: item, userData: widget.userData, ), ), ).then((_) => fetchAllData()); } else { _updateOrderStatus(id); } }, child: Text("Ya, Lanjutkan", style: GoogleFonts.inter(fontWeight: FontWeight.w600)), ), ], )); } Future _updateOrderStatus(int id) async { setState(() => isLoading = true); try { final String? token = widget.userData['access_token']; final response = await http.put( Uri.parse('${AppConfig.baseUrl}/orders/$id/update-status'), headers: { 'Authorization': 'Bearer $token', 'Accept': 'application/json', 'Content-Type': 'application/json', }, ); if (response.statusCode == 200) { fetchAllData(); } else { setState(() => isLoading = false); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text("Gagal memperbarui status"))); } } } catch (e) { if (mounted) setState(() => isLoading = false); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text("Terjadi kesalahan jaringan"))); } } } Widget _buildTibaRow(dynamic order, bool isLast) { String orderId = "#${order['order_number'] ?? order['id'] ?? 'ACT'}"; String name = order['customer_name'] ?? "Pelanggan"; return InkWell( onTap: () async { final result = await Navigator.push( context, MaterialPageRoute( builder: (c) => Scaffold( appBar: AppBar( title: Text("Input Layanan Pickup", style: GoogleFonts.inter( fontWeight: FontWeight.w700, fontSize: 16)), leading: IconButton( icon: const Icon(Icons.arrow_back_ios_new_rounded, size: 20), onPressed: () => Navigator.pop(c)), ), body: LaundryPage( userData: widget.userData, isTab: false, pickupData: order)))); if (result == true) fetchAllData(); }, child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: BoxDecoration( border: isLast ? null : Border( bottom: BorderSide(color: surfaceContainerHigh.withOpacity(0.5))), ), child: Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: primary.withOpacity(0.1), borderRadius: BorderRadius.circular(8)), child: Icon(Icons.inventory_2_rounded, color: primary, size: 20), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(name, style: GoogleFonts.inter( fontWeight: FontWeight.w600, fontSize: 14, color: onSurface)), const SizedBox(height: 2), Text(orderId, style: GoogleFonts.inter(fontSize: 11, color: outline)), ], ), ), Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: primary, borderRadius: BorderRadius.circular(6)), child: Text("Input", style: GoogleFonts.inter( fontSize: 11, fontWeight: FontWeight.w700, color: Colors.white)), ) ], ), ), ); } Widget _buildAppBar() { return Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration( color: surface.withOpacity(0.9), border: Border( bottom: BorderSide( color: const Color(0xFFE6E8EA) .withOpacity(0.5), // surfaceContainerHigh width: 1.0, ), ), ), child: SafeArea( bottom: false, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Container( width: 32, height: 32, decoration: const BoxDecoration( color: Color(0xFFD8E2FF), // primaryFixed shape: BoxShape.circle, ), clipBehavior: Clip.hardEdge, child: Image.asset( 'assets/app_icon.png', fit: BoxFit.cover, errorBuilder: (context, error, stackTrace) => Icon( Icons.local_laundry_service_rounded, color: primary, size: 20), ), ), const SizedBox(width: 8), Text("My Laundry", style: GoogleFonts.inter( fontSize: 18, fontWeight: FontWeight.w600, color: primary, )), ], ), const SizedBox( width: 48), // Padding equivalent to empty action area to align center if needed, or just leave it empty. ], ), ), ); } }