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

314 lines
9.8 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// lib/Pages/views/tasks_screen.dart
import 'package:flutter/material.dart';
import 'package:Stocky/Pages/controllers/MainController.dart';
import 'package:Stocky/Pages/views/task_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:swipeable_tile/swipeable_tile.dart';
import 'package:get/get.dart';
class TasksScreen extends GetWidget<MainController> {
const TasksScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.backgroundColor,
appBar: _buildAppBar(context),
body: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildDateSelector(context),
const SizedBox(height: 20),
_buildTasksList(context),
],
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// После создания — синхронизация не нужна: addTask сам всё делает
Get.to(() => const TaskFormScreen());
},
child: const Icon(Icons.add),
),
);
}
AppBar _buildAppBar(BuildContext context) {
return AppBar(
backgroundColor: Colors.white,
elevation: 0,
title: const Text(
'Sep 2020',
style: TextStyle(color: Colors.black87, fontWeight: FontWeight.bold),
),
actions: [
IconButton(
icon: Icon(EvaIcons.search, size: 26, color: Colors.blueGrey[700]),
onPressed: () {},
),
],
);
}
Widget _buildDateSelector(BuildContext context) {
return Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.blue[900],
borderRadius: BorderRadius.circular(24),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List.generate(7, (index) {
final dayName = [
'Sun',
'Mon',
'Tue',
'Wed',
'Thu',
'Fri',
'Sat',
][index];
final dayNumber = 20 + index;
return GestureDetector(
onTap: () {
// Логика выбора даты (опционально)
},
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: dayNumber == 21 ? Colors.white : Colors.transparent,
borderRadius: BorderRadius.circular(20),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
dayName,
style: TextStyle(
fontSize: 10,
color: dayNumber == 21 ? Colors.blue[900] : Colors.white,
),
),
const SizedBox(height: 2),
Text(
dayNumber.toString(),
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: dayNumber == 21 ? Colors.blue[900] : Colors.white,
),
),
],
),
),
);
}),
),
);
}
Widget _buildTasksList(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Tasks',
style: AppStyles.sectionHeader.copyWith(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 16),
Obx(() {
// 🔑 ФИЛЬТРУЕМ: скрываем задачи, помеченные на удаление
final visibleTasks = controller.tasks
.where((task) => task.isDeletedLocally != true)
.toList();
if (visibleTasks.isEmpty) {
return Center(
child: Text(
'No tasks found',
style: TextStyle(color: Colors.grey[600]),
),
);
}
return Column(
children: visibleTasks
.map((task) => _buildTaskCard(context, task))
.toList(),
);
}),
],
);
}
Widget _buildTaskCard(BuildContext context, Task task) {
final startDate = task.startTime;
String formatTime(DateTime dt) => dt.toString().substring(11, 16); // HH:mm
return SwipeableTile.card(
color: Colors.white,
shadow: BoxShadow(
color: Colors.black.withOpacity(0.35),
blurRadius: 4,
offset: const Offset(2, 2),
),
key: ValueKey(task.id), // ← лучше использовать id, а не UniqueKey()
horizontalPadding: 8,
verticalPadding: 8,
child: InkWell(
onTap: () {
Get.dialog(_buildTaskExecutionDialog(task), barrierDismissible: true);
},
onLongPress: () => Get.to(
TaskFormScreen(task: task),
), // ← синхронизация происходит автоматически через updateTask
borderRadius: BorderRadius.circular(16),
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.pink[50],
shape: BoxShape.circle,
),
child: Icon(
_getTaskIcon('meeting'),
size: 24,
color: Colors.pink[400],
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
task.title,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 4),
Text(
'${formatTime(startDate)} to ${formatTime(startDate.add(Duration(hours: 2)))}',
style: const TextStyle(
fontSize: 13,
color: Colors.grey,
height: 1.4,
),
),
],
),
),
IconButton(
onPressed: () {
// Доп. действия (например, меню)
},
icon: const Icon(Icons.more_vert, color: Colors.grey),
),
],
),
),
),
onSwiped: (direction) => controller.deleteTask(task),
backgroundBuilder: (context, direction, progress) {
return Container(
color: Colors.redAccent,
child: const Align(
alignment: Alignment.centerRight,
child: Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'Удалить',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
),
);
},
);
}
IconData _getTaskIcon(String category) {
switch (category.toLowerCase()) {
case 'client call':
return Icons.phone_rounded;
default:
return EvaIcons.shoppingCartOutline;
}
}
Widget _buildTaskExecutionDialog(Task task) {
// Здесь можно реализовать логику выполнения подзадач
// Пока оставим как есть (без сохранения изменений)
return Material(
color: Colors.transparent,
child: Padding(
padding: const EdgeInsets.all(30.0),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
),
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
task.title,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 16),
Text(task.description, style: const TextStyle(fontSize: 16)),
const SizedBox(height: 16),
...task.items.map(
(item) => ListTile(
title: Text(item.text),
leading: item.isDone
? const Icon(Icons.check_circle, color: Colors.green)
: const Icon(Icons.radio_button_unchecked),
),
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(onPressed: Get.back, child: const Text('Закрыть')),
],
),
],
),
),
),
);
}
}