import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:marco/controller/layout/layout_controller.dart'; import 'package:marco/helpers/widgets/my_responsive.dart'; import 'package:marco/helpers/widgets/my_text.dart'; import 'package:marco/helpers/services/storage/local_storage.dart'; import 'package:marco/model/employee_info.dart'; import 'package:marco/helpers/services/api_endpoints.dart'; import 'package:marco/images.dart'; import 'package:marco/controller/project_controller.dart'; import 'package:marco/view/layouts/user_profile_right_bar.dart'; class Layout extends StatefulWidget { final Widget? child; final Widget? floatingActionButton; const Layout({super.key, this.child, this.floatingActionButton}); @override State createState() => _LayoutState(); } class _LayoutState extends State { final LayoutController controller = LayoutController(); final EmployeeInfo? employeeInfo = LocalStorage.getEmployeeInfo(); final bool isBetaEnvironment = ApiEndpoints.baseUrl.contains("stage"); final projectController = Get.find(); @override Widget build(BuildContext context) { return MyResponsive(builder: (context, _, screenMT) { return GetBuilder( init: controller, builder: (_) { return (screenMT.isMobile || screenMT.isTablet) ? _buildScaffold(context, isMobile: true) : _buildScaffold(context); }, ); }); } Widget _buildScaffold(BuildContext context, {bool isMobile = false}) { return Scaffold( key: controller.scaffoldKey, endDrawer: UserProfileBar(), floatingActionButton: widget.floatingActionButton, body: SafeArea( child: Column( children: [ _buildHeader(context, isMobile), Expanded( child: SingleChildScrollView( key: controller.scrollKey, padding: EdgeInsets.all(isMobile ? 16 : 32), child: widget.child, ), ), ], ), ), ); } Widget _buildHeader(BuildContext context, bool isMobile) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 0), child: Obx(() { final isExpanded = projectController.isProjectSelectionExpanded.value; final selectedProjectId = projectController.selectedProjectId?.value; final selectedProject = projectController.projects.firstWhereOrNull( (p) => p.id == selectedProjectId, ); if (selectedProject == null && projectController.projects.isNotEmpty) { projectController .updateSelectedProject(projectController.projects.first.id); } return AnimatedContainer( duration: const Duration(milliseconds: 300), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.vertical( bottom: Radius.circular(isExpanded ? 16 : 0), ), boxShadow: [ BoxShadow( color: const Color.fromARGB(255, 67, 73, 84), blurRadius: 4, offset: Offset(0, 2), ), ], ), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ ClipRRect( borderRadius: BorderRadius.circular(8), child: Image.asset( Images.logoDark, height: 50, width: 50, fit: BoxFit.contain, ), ), const SizedBox(width: 12), Expanded( child: GestureDetector( onTap: () => projectController.isProjectSelectionExpanded.toggle(), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Row( children: [ Expanded( child: MyText.bodyLarge( selectedProject?.name ?? "Select Project", fontWeight: 700, maxLines: 1, overflow: TextOverflow.ellipsis, ), ), Icon( isExpanded ? Icons.arrow_drop_up_outlined : Icons.arrow_drop_down_outlined, color: Colors.black, ), ], ), ), ], ), MyText.bodyMedium( "Hi, ${employeeInfo?.firstName ?? ''}", color: Colors.black54, ), ], ), ), ), if (isBetaEnvironment) Container( margin: const EdgeInsets.only(left: 8), padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 2), decoration: BoxDecoration( color: Colors.deepPurple, borderRadius: BorderRadius.circular(6), ), child: MyText.bodySmall( 'BETA', color: Colors.white, fontWeight: 700, ), ), IconButton( icon: Icon(Icons.menu), onPressed: () => controller.scaffoldKey.currentState?.openEndDrawer(), ), ], ), const SizedBox(height: 8), if (isExpanded) _buildProjectList(context, isMobile), ], ), ); }), ); } Widget _buildProjectList(BuildContext context, bool isMobile) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Divider(), MyText.titleSmall("Switch Project", fontWeight: 600), const SizedBox(height: 4), ConstrainedBox( constraints: BoxConstraints( maxHeight: isMobile ? MediaQuery.of(context).size.height * 0.4 : 400, ), child: ListView.builder( shrinkWrap: true, itemCount: projectController.projects.length, itemBuilder: (context, index) { final project = projectController.projects[index]; final selectedId = projectController.selectedProjectId?.value; final isSelected = project.id == selectedId; return RadioListTile( value: project.id, groupValue: selectedId, onChanged: (value) { projectController.updateSelectedProject(value!); projectController.isProjectSelectionExpanded.value = false; }, title: Text( project.name, style: TextStyle( fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, color: isSelected ? Colors.blueAccent : Colors.black87, ), ), contentPadding: const EdgeInsets.symmetric(horizontal: 0), activeColor: Colors.blueAccent, tileColor: isSelected ? Colors.blueAccent.withOpacity(0.1) : Colors.transparent, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(6), ), visualDensity: const VisualDensity(vertical: -4), ); }, ), ), ], ); } }