import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:tm_app/core/theme/colors.dart'; import 'package:tm_app/core/utils/size_config.dart'; import 'package:tm_app/views/shared/desktop_navigation_widget.dart'; import '../../core/constants/assets.dart'; class TaskItem { final String id; final String description; final DateTime deadline; final String assignedTo; final bool isReady; TaskStatus status; TaskItem({ required this.id, required this.description, required this.deadline, required this.assignedTo, required this.isReady, required this.status, }); } enum TaskStatus { toDo, inProgress, done } class BoardScreen extends StatefulWidget { const BoardScreen({super.key}); @override State createState() => _BoardScreenState(); } class _BoardScreenState extends State { List tasks = [ TaskItem( id: '1', description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua', deadline: DateTime(2025, 6, 15), assignedTo: 'Pratyush Tewari', isReady: false, status: TaskStatus.toDo, ), TaskItem( id: '2', description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua', deadline: DateTime(2025, 6, 15), assignedTo: 'Pratyush Tewari', isReady: true, status: TaskStatus.toDo, ), TaskItem( id: '3', description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua', deadline: DateTime(2025, 6, 15), assignedTo: 'Pratyush Tewari', isReady: false, status: TaskStatus.inProgress, ), TaskItem( id: '4', description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua', deadline: DateTime(2025, 6, 15), assignedTo: 'Pratyush Tewari', isReady: true, status: TaskStatus.inProgress, ), TaskItem( id: '5', description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua', deadline: DateTime(2025, 6, 15), assignedTo: 'Pratyush Tewari', isReady: false, status: TaskStatus.done, ), ]; void _updateTaskStatus(TaskItem task, TaskStatus newStatus) { if (task.status == newStatus) { return; } final oldStatus = task.status; setState(() { task.status = newStatus; }); _showStatusChangeMessage(context, task, oldStatus, newStatus); } void _showStatusChangeMessage( BuildContext context, TaskItem task, TaskStatus oldStatus, TaskStatus newStatus, ) { final statusNames = { TaskStatus.toDo: 'To Do', TaskStatus.inProgress: 'In Progress', TaskStatus.done: 'Done', }; ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( 'Task "${task.description}" moved from ${statusNames[oldStatus]} to ${statusNames[newStatus]}', style: const TextStyle(fontFamily: 'Peyda'), ), duration: const Duration(seconds: 2), backgroundColor: AppColors.successColor, behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), ), ); } List _getTasksByStatus(TaskStatus status) { return tasks.where((task) => task.status == status).toList(); } @override Widget build(BuildContext context) { SizeConfig.init(context); return Scaffold( backgroundColor: AppColors.backgroundColor, body: Column( children: [ const DesktopNavigationWidget( currentIndex: 2, // Tenders index ), SizedBox( width: 740, height: 735, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 64), Text( 'My board', style: TextStyle( fontSize: 20.0.sp(), fontWeight: FontWeight.w600, color: AppColors.titleColor, ), ), const SizedBox(height: 20), Expanded( child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), color: AppColors.primary20, ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ // To Do Expanded( child: _BoardColumn( title: 'To do', color: AppColors.primary20, textColor: const Color(0xFF1976D2), tasks: _getTasksByStatus(TaskStatus.toDo), status: TaskStatus.toDo, onTaskDropped: _updateTaskStatus, ), ), const SizedBox(width: 12), // In Progress Expanded( child: _BoardColumn( title: 'In progress', color: AppColors.orange20, textColor: AppColors.orange, tasks: _getTasksByStatus(TaskStatus.inProgress), status: TaskStatus.inProgress, onTaskDropped: _updateTaskStatus, ), ), const SizedBox(width: 12), // Done Expanded( child: _BoardColumn( title: 'Done', color: AppColors.secondary20, textColor: AppColors.secondary70, tasks: _getTasksByStatus(TaskStatus.done), status: TaskStatus.done, onTaskDropped: _updateTaskStatus, ), ), ], ), ), ), ], ), ), ], ), ); } } class _BoardColumn extends StatelessWidget { final String title; final Color color; final Color textColor; final List tasks; final TaskStatus status; final Function(TaskItem, TaskStatus) onTaskDropped; const _BoardColumn({ required this.title, required this.color, required this.textColor, required this.tasks, required this.status, required this.onTaskDropped, }); @override Widget build(BuildContext context) { return DragTarget( onWillAcceptWithDetails: (details) { return details.data.status != status; }, onAcceptWithDetails: (details) { onTaskDropped(details.data, status); }, builder: (context, candidateData, rejectedData) { final isHovering = candidateData.isNotEmpty; return Container( decoration: BoxDecoration( color: isHovering ? color.withValues(alpha: 0.3) : AppColors.primary0, borderRadius: BorderRadius.circular(12), border: Border.all( color: isHovering ? textColor : AppColors.borderBlue, width: isHovering ? 2 : 1, ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( width: double.infinity, height: 34, margin: const EdgeInsets.all(8), decoration: BoxDecoration( color: color, borderRadius: BorderRadius.circular(4), ), alignment: Alignment.center, child: Text( title, style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: textColor, ), ), ), Expanded( child: ListView.builder( padding: const EdgeInsets.all(12), itemCount: tasks.length, itemBuilder: (context, index) { return _TaskCard(task: tasks[index]); }, ), ), ], ), ); }, ); } } class _TaskCard extends StatelessWidget { final TaskItem task; const _TaskCard({required this.task}); String _formatDate(DateTime date) { return '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}'; } @override Widget build(BuildContext context) { return Draggable( data: task, feedback: Material( elevation: 8, borderRadius: BorderRadius.circular(12), child: Container( width: 280, padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: AppColors.primary0, borderRadius: BorderRadius.circular(12), border: Border.all(color: AppColors.borderBlue, width: 2), ), child: _buildCardContent(context), ), ), childWhenDragging: Opacity(opacity: 0.3, child: _buildCard(context)), child: _buildCard(context), ); } Widget _buildCard(BuildContext context) { return Container( margin: const EdgeInsets.only(bottom: 12), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: AppColors.primary0, borderRadius: BorderRadius.circular(12), border: Border.all(color: AppColors.grey30), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.05), blurRadius: 4, offset: const Offset(0, 2), ), ], ), child: _buildCardContent(context), ); } Widget _buildCardContent(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( height: 24.0, padding: EdgeInsets.symmetric(horizontal: 10.0.w()), decoration: BoxDecoration( color: task.status == TaskStatus.toDo ? AppColors.primary20 : task.status == TaskStatus.inProgress ? AppColors.orange10 : AppColors.secondary10, borderRadius: BorderRadius.circular(4), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Deadline :', style: TextStyle( fontSize: 14.0, fontWeight: FontWeight.w500, color: AppColors.textBlue, ), ), Text( _formatDate(task.deadline), style: TextStyle( fontSize: 14.0, fontWeight: FontWeight.w500, color: AppColors.grey80, ), ), ], ), ), const SizedBox(height: 12), Text( task.description, style: TextStyle(fontSize: 14, color: AppColors.grey70), maxLines: 3, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 12), Container( padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0), decoration: BoxDecoration( color: task.isReady ? AppColors.primary20 : AppColors.red0, borderRadius: BorderRadius.circular(8), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Container( width: 8, height: 8, decoration: BoxDecoration( color: task.isReady ? AppColors.textBlue : AppColors.error, shape: BoxShape.circle, ), ), const SizedBox(width: 6), Text( task.isReady ? 'Ready' : 'Incomplete', style: TextStyle( fontSize: 12, color: task.isReady ? AppColors.textBlue : AppColors.red20, fontWeight: FontWeight.w400, ), ), ], ), ), const SizedBox(height: 12), Row( children: [ SvgPicture.asset(AssetsManager.profile), const SizedBox(width: 4), Text( task.assignedTo, style: TextStyle(fontSize: 12, color: AppColors.grey60), ), ], ), ], ); } }