import 'dart:io'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:image_cropper/image_cropper.dart'; import 'package:image_picker/image_picker.dart'; import 'package:http/http.dart' as http; import 'package:Intaleq/constant/api_key.dart'; import 'package:Intaleq/constant/box_name.dart'; import 'package:Intaleq/constant/colors.dart'; import 'package:Intaleq/controller/profile/profile_controller.dart'; import 'package:Intaleq/main.dart'; import 'package:Intaleq/views/widgets/mycircular.dart'; import '../../../constant/style.dart'; import '../../../controller/functions/log_out.dart'; // ───────────────────────────────────────────────────────────────────────────── // Main Page // ───────────────────────────────────────────────────────────────────────────── class PassengerProfilePage extends StatefulWidget { const PassengerProfilePage({super.key}); @override State createState() => _PassengerProfilePageState(); } class _PassengerProfilePageState extends State { late final LogOutController logOutController; File? _pickedImage; bool _isUploadingImage = false; @override void initState() { super.initState(); logOutController = Get.put(LogOutController()); Get.put(ProfileController()); } // ─── Image Handling ───────────────────────────────────────────────────────── Future _pickAndUploadImage() async { // 1. Pick source final ImageSource? source = await _showImageSourceSheet(); if (source == null) return; // 2. Pick image final XFile? picked = await ImagePicker().pickImage(source: source, imageQuality: 85); if (picked == null) return; // 3. Crop final CroppedFile? cropped = await ImageCropper().cropImage( sourcePath: picked.path, aspectRatio: const CropAspectRatio(ratioX: 1, ratioY: 1), uiSettings: [ AndroidUiSettings( toolbarTitle: 'Crop Photo'.tr, toolbarColor: AppColor.primaryColor, toolbarWidgetColor: Colors.white, initAspectRatio: CropAspectRatioPreset.square, lockAspectRatio: true, hideBottomControls: false, ), IOSUiSettings( title: 'Crop Photo'.tr, aspectRatioLockEnabled: true, resetAspectRatioEnabled: false, ), ], ); if (cropped == null) return; // 4. Upload setState(() { _pickedImage = File(cropped.path); _isUploadingImage = true; }); try { final passengerId = box.read(BoxName.passengerID).toString(); final uri = Uri.parse('${AK.serverPHP}/upload_passenger_image.php'); final request = http.MultipartRequest('POST', uri) ..fields['passenger_id'] = passengerId ..files.add(await http.MultipartFile.fromPath('image', cropped.path)); final response = await request.send(); if (response.statusCode == 200) { Get.snackbar( 'Success'.tr, 'Profile photo updated'.tr, backgroundColor: Colors.green.withOpacity(0.9), colorText: Colors.white, snackPosition: SnackPosition.BOTTOM, margin: const EdgeInsets.all(16), borderRadius: 12, ); } else { _showUploadError(); } } catch (_) { _showUploadError(); } finally { setState(() => _isUploadingImage = false); } } void _showUploadError() { Get.snackbar( 'Error'.tr, 'Failed to upload photo'.tr, backgroundColor: Colors.red.withOpacity(0.9), colorText: Colors.white, snackPosition: SnackPosition.BOTTOM, margin: const EdgeInsets.all(16), borderRadius: 12, ); } Future _showImageSourceSheet() async { return await showModalBottomSheet( context: context, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(20)), ), builder: (_) => SafeArea( child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( margin: const EdgeInsets.only(top: 10, bottom: 6), width: 40, height: 4, decoration: BoxDecoration( color: AppColor.grayColor.withOpacity(0.3), borderRadius: BorderRadius.circular(2)), ), const SizedBox(height: 8), Text('Change Photo'.tr, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)), const SizedBox(height: 12), ListTile( leading: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: AppColor.primaryColor.withOpacity(0.1), borderRadius: BorderRadius.circular(10), ), child: const Icon(Icons.camera_alt_outlined, color: AppColor.primaryColor), ), title: Text('Take a Photo'.tr, style: const TextStyle(fontWeight: FontWeight.w500)), onTap: () => Navigator.pop(context, ImageSource.camera), ), ListTile( leading: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.blue.withOpacity(0.1), borderRadius: BorderRadius.circular(10), ), child: const Icon(Icons.photo_library_outlined, color: Colors.blue), ), title: Text('Choose from Gallery'.tr, style: const TextStyle(fontWeight: FontWeight.w500)), onTap: () => Navigator.pop(context, ImageSource.gallery), ), const SizedBox(height: 12), ], ), ), ); } // ─── Build ────────────────────────────────────────────────────────────────── @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColor.secondaryColor.withOpacity(0.96), appBar: AppBar( title: Text('My Profile'.tr, style: AppStyle.headTitle2.copyWith(fontSize: 20)), backgroundColor: AppColor.secondaryColor, elevation: 0, centerTitle: true, iconTheme: IconThemeData(color: AppColor.writeColor), ), body: GetBuilder( builder: (controller) { if (controller.isloading) { return const MyCircularProgressIndicator(); } return ListView( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12), physics: const BouncingScrollPhysics(), children: [ _buildProfileHeader(controller), const SizedBox(height: 32), _buildSectionCard( title: 'Personal Information'.tr, sectionIcon: Icons.person_outline_rounded, children: [ _buildTile( icon: Icons.badge_outlined, color: Colors.blueAccent, title: 'Name'.tr, subtitle: '${controller.prfoileData['first_name'] ?? ''} ${controller.prfoileData['last_name'] ?? ''}' .trim(), onTap: () => _showNameSheet(controller), ), _divider(), _buildTile( icon: Icons.wc_outlined, color: Colors.pinkAccent, title: 'Gender'.tr, subtitle: controller.prfoileData['gender']?.toString() ?? 'Not set'.tr, onTap: () => _showGenderSheet(controller), ), _divider(), _buildTile( icon: Icons.school_outlined, color: Colors.orangeAccent, title: 'Education'.tr, subtitle: controller.prfoileData['education']?.toString() ?? 'Not set'.tr, onTap: () => _showEducationSheet(controller), ), ], ), const SizedBox(height: 20), _buildSectionCard( title: 'Work & Contact'.tr, sectionIcon: Icons.work_outline_rounded, children: [ _buildTile( icon: Icons.work_outline, color: Colors.green, title: 'Employment Type'.tr, subtitle: controller.prfoileData['employmentType']?.toString() ?? 'Not set'.tr, onTap: () => _showFieldSheet( controller: controller, fieldKey: 'employmentType', title: 'Employment Type'.tr, icon: Icons.work_outline, iconColor: Colors.green, keyboardType: TextInputType.text, ), ), _divider(), _buildTile( icon: Icons.favorite_border, color: Colors.purpleAccent, title: 'Marital Status'.tr, subtitle: controller.prfoileData['maritalStatus']?.toString() ?? 'Not set'.tr, onTap: () => _showFieldSheet( controller: controller, fieldKey: 'maritalStatus', title: 'Marital Status'.tr, icon: Icons.favorite_border, iconColor: Colors.purpleAccent, keyboardType: TextInputType.text, ), ), _divider(), _buildTile( icon: Icons.sos_outlined, color: Colors.redAccent, title: 'SOS Phone'.tr, subtitle: controller.prfoileData['sosPhone']?.toString() ?? 'Not set'.tr, onTap: () => _showFieldSheet( controller: controller, fieldKey: 'sosPhone', title: 'SOS Phone'.tr, icon: Icons.sos_outlined, iconColor: Colors.redAccent, keyboardType: TextInputType.phone, onSaved: () { box.write(BoxName.sosPhonePassenger, controller.prfoileData['sosPhone']); }, ), ), ], ), const SizedBox(height: 20), _buildSectionCard( title: 'Account'.tr, sectionIcon: Icons.manage_accounts_outlined, children: [ _buildTile( icon: Icons.logout_rounded, color: Colors.blueGrey, title: 'Sign Out'.tr, subtitle: '', onTap: () => logOutController.logOutPassenger(), trailing: const SizedBox.shrink(), ), _divider(), _buildTile( icon: Icons.delete_forever_outlined, color: Colors.redAccent, title: 'Delete My Account'.tr, subtitle: '', onTap: () => _showDeleteSheet(), trailing: const SizedBox.shrink(), ), ], ), const SizedBox(height: 32), ], ); }, ), ); } // ─── Profile Header ───────────────────────────────────────────────────────── Widget _buildProfileHeader(ProfileController controller) { final firstName = controller.prfoileData['first_name']?.toString() ?? ''; final lastName = controller.prfoileData['last_name']?.toString() ?? ''; final fullName = '$firstName $lastName'.trim(); final passengerId = box.read(BoxName.passengerID)?.toString() ?? ''; String email = box.read(BoxName.email) ?? ''; if (email.contains('intaleqapp.com')) email = ''; final initials = fullName.isNotEmpty ? fullName .split(' ') .where((e) => e.isNotEmpty) .map((e) => e[0].toUpperCase()) .take(2) .join() : '?'; final avatarUrl = '${AK.serverPHP}/portrate_passenger_image/$passengerId.jpg'; return Center( child: Column( children: [ // ── Avatar with camera button ────────────────────────────── Stack( alignment: Alignment.bottomRight, children: [ // Outer glow ring Container( padding: const EdgeInsets.all(3), decoration: BoxDecoration( shape: BoxShape.circle, gradient: LinearGradient( colors: [ AppColor.primaryColor.withOpacity(0.6), AppColor.primaryColor.withOpacity(0.1), ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), ), child: CircleAvatar( radius: 52, backgroundColor: AppColor.secondaryColor, child: ClipOval( child: _isUploadingImage ? const SizedBox( width: 104, height: 104, child: Center( child: CircularProgressIndicator( color: AppColor.primaryColor, strokeWidth: 2, ), ), ) : _pickedImage != null ? Image.file( _pickedImage!, width: 104, height: 104, fit: BoxFit.cover, ) : CachedNetworkImage( imageUrl: avatarUrl, width: 104, height: 104, fit: BoxFit.cover, placeholder: (_, __) => Container( width: 104, height: 104, color: AppColor.primaryColor.withOpacity(0.08), child: Center( child: Text( initials, style: const TextStyle( fontSize: 34, fontWeight: FontWeight.bold, color: AppColor.primaryColor, ), ), ), ), errorWidget: (_, __, ___) => Container( width: 104, height: 104, color: AppColor.primaryColor.withOpacity(0.08), child: Center( child: Text( initials, style: const TextStyle( fontSize: 34, fontWeight: FontWeight.bold, color: AppColor.primaryColor, ), ), ), ), ), ), ), ), // Camera button GestureDetector( onTap: _isUploadingImage ? null : _pickAndUploadImage, child: Container( width: 36, height: 36, margin: const EdgeInsets.only(right: 2, bottom: 2), decoration: BoxDecoration( color: AppColor.primaryColor, shape: BoxShape.circle, border: Border.all(color: AppColor.secondaryColor, width: 2.5), boxShadow: [ BoxShadow( color: AppColor.primaryColor.withOpacity(0.4), blurRadius: 8, offset: const Offset(0, 3), ), ], ), child: const Icon(Icons.camera_alt_rounded, color: Colors.white, size: 17), ), ), ], ), const SizedBox(height: 16), // Name + edit hint Row( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ Text( fullName.isEmpty ? 'Passenger'.tr : fullName, style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: AppColor.writeColor, ), ), const SizedBox(width: 6), GestureDetector( onTap: () => _showNameSheet(Get.find()), child: Container( padding: const EdgeInsets.all(4), decoration: BoxDecoration( color: AppColor.primaryColor.withOpacity(0.1), shape: BoxShape.circle, ), child: const Icon(Icons.edit_rounded, size: 14, color: AppColor.primaryColor), ), ), ], ), if (email.isNotEmpty) ...[ const SizedBox(height: 4), Text( email, style: TextStyle( fontSize: 14, color: AppColor.grayColor, fontWeight: FontWeight.w500), ), ], const SizedBox(height: 10), // Passenger badge Container( padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 5), decoration: BoxDecoration( color: AppColor.primaryColor.withOpacity(0.08), borderRadius: BorderRadius.circular(20), border: Border.all(color: AppColor.primaryColor.withOpacity(0.2)), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ const Icon(Icons.verified_user_rounded, size: 13, color: AppColor.primaryColor), const SizedBox(width: 5), Text( 'Verified Passenger'.tr, style: const TextStyle( fontSize: 12, color: AppColor.primaryColor, fontWeight: FontWeight.w600, ), ), ], ), ), ], ), ); } // ─── Section Card ──────────────────────────────────────────────────────────── Widget _buildSectionCard({ required String title, required IconData sectionIcon, required List children, }) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.only(left: 8, bottom: 12), child: Row( children: [ Icon(sectionIcon, size: 15, color: AppColor.grayColor), const SizedBox(width: 8), Text( title.toUpperCase(), style: TextStyle( fontSize: 15, fontWeight: FontWeight.bold, color: AppColor.grayColor, letterSpacing: 1.2, ), ), ], ), ), Container( decoration: BoxDecoration( color: AppColor.secondaryColor, borderRadius: BorderRadius.circular(18), boxShadow: [ BoxShadow( color: Get.isDarkMode ? Colors.black.withOpacity(0.2) : Colors.black.withOpacity(0.04), blurRadius: 12, offset: const Offset(0, 4), ), ], ), child: Column(children: children), ), ], ); } Widget _buildTile({ required IconData icon, required Color color, required String title, required String subtitle, required VoidCallback onTap, Widget? trailing, }) { return InkWell( onTap: onTap, borderRadius: BorderRadius.circular(18), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 13), child: Row( children: [ Container( width: 42, height: 42, decoration: BoxDecoration( color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(12), ), child: Icon(icon, color: color, size: 21), ), const SizedBox(width: 14), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title, style: TextStyle( fontWeight: FontWeight.w600, fontSize: 16, color: AppColor.writeColor)), if (subtitle.isNotEmpty) ...[ const SizedBox(height: 4), Text(subtitle, style: TextStyle(color: AppColor.grayColor, fontSize: 13)), ], ], ), ), trailing ?? Icon(Icons.arrow_forward_ios_rounded, size: 14, color: AppColor.grayColor.withOpacity(0.5)), ], ), ), ); } Widget _divider() => Divider( height: 1, thickness: 1, indent: 72, endIndent: 16, color: AppColor.grayColor.withOpacity(0.1)); // ─── Bottom Sheets ─────────────────────────────────────────────────────────── /// Name: first + last together void _showNameSheet(ProfileController controller) { final firstCtrl = TextEditingController( text: controller.prfoileData['first_name']?.toString() ?? ''); final lastCtrl = TextEditingController( text: controller.prfoileData['last_name']?.toString() ?? ''); _openSheet( title: 'Update Name'.tr, headerIcon: Icons.badge_outlined, headerColor: Colors.blueAccent, child: StatefulBuilder( builder: (ctx, setStateInner) => Column( children: [ _styledField( controller: firstCtrl, label: 'First Name'.tr, hint: 'Enter your first name'.tr, icon: Icons.person_outline, type: TextInputType.name, ), const SizedBox(height: 14), _styledField( controller: lastCtrl, label: 'Last Name'.tr, hint: 'Enter your last name'.tr, icon: Icons.person_outline, type: TextInputType.name, ), const SizedBox(height: 24), _sheetSaveButton( label: 'Save Name'.tr, onPressed: () async { Get.back(); // Update both columns sequentially await controller.updateColumn({ 'id': box.read(BoxName.passengerID).toString(), 'first_name': firstCtrl.text.trim(), 'last_name': lastCtrl.text.trim(), }); }, ), ], ), ), ); } /// Single text field update void _showFieldSheet({ required ProfileController controller, required String fieldKey, required String title, required IconData icon, required Color iconColor, required TextInputType keyboardType, VoidCallback? onSaved, }) { final tempCtrl = TextEditingController( text: controller.prfoileData[fieldKey]?.toString() ?? ''); _openSheet( title: title, headerIcon: icon, headerColor: iconColor, child: Column( children: [ _styledField( controller: tempCtrl, label: title, hint: '', icon: icon, type: keyboardType, ), const SizedBox(height: 24), _sheetSaveButton( onPressed: () async { Get.back(); await controller.updateColumn({ 'id': box.read(BoxName.passengerID).toString(), fieldKey: tempCtrl.text.trim(), }); onSaved?.call(); }, ), ], ), ); } /// Gender picker sheet void _showGenderSheet(ProfileController controller) { final options = ['Male'.tr, 'Female'.tr, 'Other'.tr]; _openSheet( title: 'Select Gender'.tr, headerIcon: Icons.wc_outlined, headerColor: Colors.pinkAccent, child: Column( children: options .map((g) => _choiceTile( label: g, isSelected: controller.prfoileData['gender']?.toString() == g, onTap: () async { Get.back(); await controller.updateColumn({ 'id': box.read(BoxName.passengerID).toString(), 'gender': g, }); }, )) .toList(), ), ); } /// Education picker sheet void _showEducationSheet(ProfileController controller) { final options = [ 'High School Diploma'.tr, 'Associate Degree'.tr, "Bachelor's Degree".tr, "Master's Degree".tr, 'Doctoral Degree'.tr, ]; _openSheet( title: 'Select Education'.tr, headerIcon: Icons.school_outlined, headerColor: Colors.orangeAccent, child: Column( children: options .map((d) => _choiceTile( label: d, isSelected: controller.prfoileData['education']?.toString() == d, onTap: () async { Get.back(); await controller.updateColumn({ 'id': box.read(BoxName.passengerID).toString(), 'education': d, }); }, )) .toList(), ), ); } /// Delete account sheet void _showDeleteSheet() { _openSheet( title: 'Delete Account'.tr, headerIcon: Icons.delete_forever_outlined, headerColor: Colors.redAccent, child: Column( children: [ Container( padding: const EdgeInsets.all(14), decoration: BoxDecoration( color: Colors.red.withOpacity(0.05), borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.red.withOpacity(0.15)), ), child: Row( children: [ const Icon(Icons.warning_amber_rounded, color: Colors.redAccent, size: 20), const SizedBox(width: 10), Expanded( child: Text( 'This action is permanent and cannot be undone.'.tr, style: TextStyle( color: Colors.red.withOpacity(0.8), fontSize: 13), ), ), ], ), ), const SizedBox(height: 16), _styledField( controller: logOutController.emailTextController, label: 'Confirm your Email'.tr, hint: 'example@domain.com', icon: Icons.email_outlined, type: TextInputType.emailAddress, ), const SizedBox(height: 24), Row( children: [ Expanded( child: OutlinedButton( onPressed: () { logOutController.emailTextController.clear(); Get.back(); }, style: OutlinedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 14), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12)), side: BorderSide(color: Colors.grey[300]!), ), child: Text('Cancel'.tr, style: TextStyle(color: AppColor.grayColor)), ), ), const SizedBox(width: 12), Expanded( child: ElevatedButton( onPressed: () async { await logOutController.deletePassengerAccount(); }, style: ElevatedButton.styleFrom( backgroundColor: Colors.redAccent, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 14), elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12)), ), child: Text('Delete'.tr, style: const TextStyle(fontWeight: FontWeight.bold)), ), ), ], ), ], ), ); } // ─── Sheet Primitives ──────────────────────────────────────────────────────── void _openSheet({ required String title, required IconData headerIcon, required Color headerColor, required Widget child, }) { Get.bottomSheet( isScrollControlled: true, _SheetWrapper( title: title, headerIcon: headerIcon, headerColor: headerColor, child: child, ), ); } Widget _styledField({ required TextEditingController controller, required String label, required String hint, required IconData icon, required TextInputType type, }) { return TextField( controller: controller, keyboardType: type, style: TextStyle(fontSize: 16, color: AppColor.writeColor), decoration: InputDecoration( labelText: label, hintText: hint, hintStyle: TextStyle(color: AppColor.grayColor.withOpacity(0.5), fontSize: 14), prefixIcon: Icon(icon, size: 20, color: AppColor.grayColor), filled: true, fillColor: AppColor.secondaryColor, contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 15), border: OutlineInputBorder( borderRadius: BorderRadius.circular(13), borderSide: BorderSide(color: AppColor.grayColor.withOpacity(0.15))), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(13), borderSide: BorderSide(color: AppColor.grayColor.withOpacity(0.15))), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(13), borderSide: BorderSide(color: AppColor.primaryColor, width: 1.5)), labelStyle: TextStyle(color: AppColor.grayColor, fontSize: 14), ), ); } Widget _sheetSaveButton({required VoidCallback onPressed, String? label}) { return SizedBox( width: double.infinity, child: ElevatedButton( onPressed: onPressed, style: ElevatedButton.styleFrom( backgroundColor: AppColor.primaryColor, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 15), elevation: 0, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(13)), ), child: Text( label ?? 'Save Changes'.tr, style: const TextStyle(fontSize: 15, fontWeight: FontWeight.bold), ), ), ); } Widget _choiceTile({ required String label, required bool isSelected, required VoidCallback onTap, }) { return ListTile( contentPadding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), onTap: onTap, leading: AnimatedContainer( duration: const Duration(milliseconds: 200), width: 22, height: 22, decoration: BoxDecoration( shape: BoxShape.circle, border: Border.all( color: isSelected ? AppColor.primaryColor : Colors.grey[300]!, width: 2, ), color: isSelected ? AppColor.primaryColor.withOpacity(0.1) : Colors.transparent, ), child: isSelected ? const Icon(Icons.check_rounded, size: 14, color: AppColor.primaryColor) : null, ), title: Text(label, style: TextStyle( fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal, fontSize: 16, color: isSelected ? AppColor.primaryColor : AppColor.writeColor)), ); } } // ───────────────────────────────────────────────────────────────────────────── // Reusable Sheet Wrapper // ───────────────────────────────────────────────────────────────────────────── class _SheetWrapper extends StatelessWidget { final String title; final IconData headerIcon; final Color headerColor; final Widget child; const _SheetWrapper({ required this.title, required this.headerIcon, required this.headerColor, required this.child, }); @override Widget build(BuildContext context) { return Container( padding: EdgeInsets.fromLTRB( 24, 16, 24, MediaQuery.of(context).viewInsets.bottom + 28, ), decoration: BoxDecoration( color: AppColor.secondaryColor, borderRadius: const BorderRadius.vertical(top: Radius.circular(26)), ), child: SingleChildScrollView( physics: const BouncingScrollPhysics(), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ // Handle bar Center( child: Container( width: 38, height: 4, margin: const EdgeInsets.only(bottom: 20), decoration: BoxDecoration( color: AppColor.grayColor.withOpacity(0.3), borderRadius: BorderRadius.circular(2), ), ), ), // Header row Row( children: [ Container( width: 42, height: 42, decoration: BoxDecoration( color: headerColor.withOpacity(0.12), borderRadius: BorderRadius.circular(12), ), child: Icon(headerIcon, color: headerColor, size: 22), ), const SizedBox(width: 12), Text( title, style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: AppColor.writeColor, ), ), ], ), const SizedBox(height: 24), child, ], ), ), ); } }