Files
Stocky/lib/Pages/views/main_screen.dart

597 lines
20 KiB
Dart

import 'package:flutter/material.dart';
import 'package:Stocky/Pages/controllers/MainController.dart';
import 'package:Stocky/Pages/views/tasks_screen.dart';
import 'package:Stocky/classes/styles.dart';
import 'package:Stocky/models/task_adapter.dart';
import 'package:eva_icons_flutter/eva_icons_flutter.dart';
import 'package:flutter_advanced_avatar/flutter_advanced_avatar.dart';
import 'package:get/get.dart';
class HomeScreen extends GetWidget<MainController> {
HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.backgroundColor,
appBar: _buildAppBar(context),
drawer: _buildDrawer(context),
body: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(16),
child: _buildFilterChips(context),
),
Obx(
() => controller.isProj.value
? SizedBox(
height: 220,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: _buildScrollableSection(
context,
child: _buildProjectsSection(context),
),
),
)
: SizedBox(),
),
// Задачи / Процессы
Padding(
padding: const EdgeInsets.all(8.0),
child: Obx(
() => controller.isTask.value
? _buildProcessSection(context)
: SizedBox(),
),
),
],
),
),
);
}
Widget _buildScrollableSection(
BuildContext context, {
required Widget child,
}) {
return LayoutBuilder(
builder: (context, constraints) {
return SingleChildScrollView(child: child);
},
);
}
AppBar _buildAppBar(BuildContext context) {
return AppBar(
title: const Text('Рабочая область'),
backgroundColor: AppColors.backgroundColor,
actions: [
IconButton(
icon: Icon(
EvaIcons.bellOutline,
size: 26,
color: Colors.blueGrey[700],
),
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Оповещения'),
backgroundColor: Colors.blueAccent,
),
);
},
),
],
);
}
Widget _buildFilterChips(BuildContext context) {
return Row(
children: [
Obx(
() => FilterChip(
label: const Text('Задачи'),
selected: controller.isTask.value,
onSelected: (bool selected) {
controller.isTask.value = selected;
},
selectedColor: Colors.blueAccent.withOpacity(0.1),
checkmarkColor: Colors.blueAccent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
),
),
const SizedBox(width: 8),
Obx(
() => FilterChip(
label: const Text('Проекты'),
selected: controller.isProj.value,
onSelected: (bool selected) {
controller.isProj.value = selected;
},
selectedColor: Colors.blueAccent.withOpacity(0.1),
checkmarkColor: Colors.blueAccent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
),
),
],
);
}
Widget _buildProjectsSection(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Projects',
style: AppStyles.sectionHeader.copyWith(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 12),
SizedBox(
height: 160,
child: ListView.builder(
scrollDirection: Axis.horizontal,
physics: const BouncingScrollPhysics(),
padding: const EdgeInsets.only(right: 8),
itemCount: 4,
itemBuilder: (context, index) =>
_buildProjectCard(context, index + 1),
),
),
],
);
}
Widget _buildProjectCard(BuildContext context, int index) {
final projectColors = [
[Colors.indigo[900]!, Colors.indigo[400]!],
[Colors.blue[900]!, Colors.blue[400]!],
[Colors.red[900]!, Colors.red[400]!],
[Colors.green[900]!, Colors.green[400]!],
];
final titles = [
'Front End Development',
'Graphic Design',
'Graphic Design',
'Graphic Design',
];
final dates = [
'September 2020',
'October 2020',
'October 2020',
'October 2020',
];
return Padding(
padding: const EdgeInsets.only(right: 12),
child: Container(
width: 160,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: projectColors[index - 1],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(24),
),
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.3),
shape: BoxShape.circle,
),
child: Icon(
EvaIcons.personOutline,
color: Colors.white,
size: 20,
),
),
const SizedBox(width: 8),
Text(
'Project $index',
style: TextStyle(
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.w500,
),
),
],
),
const SizedBox(height: 12),
Text(
titles[index - 1],
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 8),
Text(
dates[index - 1],
style: TextStyle(
color: Colors.white.withOpacity(0.8),
fontSize: 12,
),
),
],
),
),
);
}
Widget _buildProcessSection(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Активные задачи',
style: AppStyles.sectionHeader.copyWith(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 16),
Obx(() {
if (controller.tasks.isEmpty) {
return Center(child: Text('Нет активных задач'));
}
return RefreshIndicator(
onRefresh: () => controller.fetchTasks(),
child: Column(
children: controller.tasks
.map((task) => _buildProcessTaskCard(context, task))
.toList(),
),
);
}),
],
);
}
Widget _buildProcessTaskCard(BuildContext context, Task task) {
final now = DateTime.now();
final startDate = task.startTime;
String formatTime(DateTime dt) => dt.toString().substring(11, 16); // HH:mm
String formatDateTime(DateTime dt) {
if (dt.year == now.year && dt.month == now.month && dt.day == now.day) {
return 'Сегодня в ${formatTime(dt)}';
} else if (dt.year == now.year) {
return '${dt.day.toString().padLeft(2, '0')}.${dt.month.toString().padLeft(2, '0')} в ${formatTime(dt)}';
} else {
return '${dt.day.toString().padLeft(2, '0')}.${dt.month.toString().padLeft(2, '0')}.${dt.year} в ${formatTime(dt)}';
}
}
final int subtaskCount = task.subtasks?.length ?? 0;
final String subtaskLabel = subtaskCount == 1
? '1 пункт'
: subtaskCount < 5
? '$subtaskCount пункта'
: '$subtaskCount пунктов';
return InkWell(
onTap: () {
Get.dialog(_buildTaskExecutionDialog(task), barrierDismissible: true);
},
child: Container(
margin: const EdgeInsets.only(bottom: 12),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 4,
spreadRadius: 1,
),
],
),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.pink[50],
shape: BoxShape.circle,
),
child: Icon(
EvaIcons.shoppingCartOutline,
color: Colors.pink[400],
size: 24,
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
task.title,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 4),
if (task.description.isNotEmpty == true)
Text(
task.description,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 12, color: Colors.grey[700]),
),
],
),
),
if (subtaskCount > 0)
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
formatDateTime(startDate),
style: TextStyle(fontSize: 12, color: Colors.grey[600]),
),
if (subtaskCount > 0)
Text(
subtaskLabel,
style: TextStyle(fontSize: 12, color: Colors.grey[600]),
),
],
),
],
),
),
);
}
Widget _buildDrawer(BuildContext context) {
return Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
Obx(
() => DrawerHeader(
decoration: BoxDecoration(color: Colors.blue[900]),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
AdvancedAvatar(
name: controller.username.value,
autoTextSize: true,
size: 80,
statusAlignment: Alignment.topRight,
),
const SizedBox(height: 12),
Text(
controller.username.value,
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
],
),
),
),
ListTile(
leading: const Icon(Icons.home),
title: const Text('Главная'),
onTap: () {
Navigator.pop(context);
},
),
ListTile(
leading: const Icon(Icons.calendar_today),
title: const Text('Задачи'),
onTap: () {
Navigator.pop(context);
Get.to(TasksScreen()); // Переход на страницу задач
},
),
ListTile(
leading: const Icon(Icons.settings),
title: const Text('Настройки'),
onTap: () {
Navigator.pop(context);
},
),
Divider(),
ListTile(
leading: const Icon(Icons.logout),
title: const Text('Выход'),
onTap: () {
// Логика выхода
Navigator.pop(context);
},
),
],
),
);
}
Widget _buildTaskExecutionDialog(Task task) {
return Dialog(
insetPadding: const EdgeInsets.symmetric(horizontal: 24, vertical: 60),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
child: ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 500),
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16),
child: StatefulBuilder(
builder: (context, setState) {
final bool isUnassigned = task.executor.isEmpty;
final bool allSubtasksDone =
task.items.isNotEmpty &&
task.items.every((item) => item.isDone);
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
task.title,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
if (task.description.isNotEmpty)
Text(
task.description,
style: const TextStyle(
fontSize: 15,
color: Colors.grey,
),
textAlign: TextAlign.center,
),
if (task.description.isNotEmpty) const SizedBox(height: 16),
if (task.items.isNotEmpty)
Column(
children: task.items
.map(
(item) => ListTile(
contentPadding: EdgeInsets.zero,
title: Text(item.text),
leading: item.isDone
? const Icon(
Icons.check_circle,
color: Colors.green,
)
: const Icon(
Icons.radio_button_unchecked,
color: Colors.grey,
),
onTap: () {
setState(() {
item.isDone = !item.isDone;
});
controller.updateTask(task);
},
),
)
.toList(),
),
// Автор — внизу, перед кнопками
if (task.author.isNotEmpty)
Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Text(
'Автор: ${task.author}',
style: const TextStyle(
fontSize: 13,
color: Colors.grey,
),
),
),
const SizedBox(height: 16),
// Кнопки
Wrap(
spacing: 12,
runSpacing: 8,
alignment: WrapAlignment.center,
children: [
// Кнопка "Взять заявку"
if (isUnassigned)
ElevatedButton(
onPressed: () {
controller.assignTaskToCurrentUser(task);
// Обновляем состояние, чтобы скрыть кнопку "Взять"
// и, возможно, показать новые данные
setState(() {});
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue[600],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: const Text(
'Взять заявку',
style: TextStyle(color: Colors.white),
),
),
// Кнопка "Завершить" — появляется, если все подзадачи сделаны
if (allSubtasksDone)
ElevatedButton(
onPressed: () {
controller.completeTask(task);
Get.back(); // закрываем диалог ТОЛЬКО при завершении
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green[600],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: const Text(
'Завершить',
style: TextStyle(color: Colors.white),
),
),
// Кнопка "Закрыть" — всегда доступна
OutlinedButton(
onPressed: Get.back,
style: OutlinedButton.styleFrom(
side: const BorderSide(color: Colors.grey),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: const Text('Закрыть'),
),
],
),
],
);
},
),
),
),
),
);
}
}