m3mo 5cd79e096d Improve touch targets with 48dp minimum size for mobile
- Enlarge calendar priority dots to 10px with pulsing animation
- Increase task tile checkbox and menu button containers to 48x48
- Add proper minVerticalPadding to task tiles (72dp height)
- Update filter chips with MaterialTapTargetSize.padded
- Increase navigation buttons to 48x48 with 28px icons
- Update task form with 48dp height segmented button
2026-02-02 22:57:17 +01:00

212 lines
6.0 KiB
Dart

import 'package:flutter/material.dart';
import 'package:agenda_tasks/l10n/app_localizations.dart';
import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import '../../../../core/di/injection_container.dart';
import '../viewmodels/daily_tasks_viewmodel.dart';
import '../widgets/task_tile.dart';
import '../widgets/filter_chips.dart';
class DailyAgendaPage extends StatelessWidget {
final String? initialDate;
const DailyAgendaPage({super.key, this.initialDate});
@override
Widget build(BuildContext context) {
// Use key to force rebuild when date changes
return ChangeNotifierProvider(
key: ValueKey(initialDate),
create: (_) {
final vm = getIt<DailyTasksViewModel>();
if (initialDate != null) {
final date = DateTime.tryParse(initialDate!);
if (date != null) {
vm.setSelectedDate(date);
return vm;
}
}
vm.loadTasks();
return vm;
},
child: const _DailyAgendaView(),
);
}
}
class _DailyAgendaView extends StatelessWidget {
const _DailyAgendaView();
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
final vm = context.watch<DailyTasksViewModel>();
final locale = Localizations.localeOf(context).languageCode;
return Scaffold(
appBar: AppBar(
title: Text(l10n.appTitle),
actions: [
IconButton(
icon: const Icon(Icons.calendar_month),
onPressed: () => context.push('/calendar'),
tooltip: l10n.calendar,
),
IconButton(
icon: const Icon(Icons.settings),
onPressed: () => context.push('/settings'),
tooltip: l10n.settings,
),
],
),
body: Column(
children: [
_DateNavigation(
date: vm.selectedDate,
locale: locale,
onPrevious: vm.previousDay,
onNext: vm.nextDay,
),
FilterChips(
currentFilter: vm.filter,
onFilterChanged: vm.setFilter,
),
Expanded(
child: _buildBody(context, vm, l10n),
),
],
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
final dateStr = DateFormat('yyyy-MM-dd').format(vm.selectedDate);
final result = await context.push('/task/new?date=$dateStr');
if (result == true) {
vm.loadTasks();
}
},
child: const Icon(Icons.add),
),
);
}
Widget _buildBody(BuildContext context, DailyTasksViewModel vm, AppLocalizations l10n) {
switch (vm.status) {
case TasksStatus.initial:
case TasksStatus.loading:
return const Center(child: CircularProgressIndicator());
case TasksStatus.error:
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
vm.failure?.message ?? l10n.errorOccurred,
style: Theme.of(context).textTheme.bodyLarge,
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: vm.loadTasks,
child: Text(l10n.retry),
),
],
),
);
case TasksStatus.success:
if (vm.tasks.isEmpty) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.task_alt,
size: 64,
color: Theme.of(context).colorScheme.outline,
),
const SizedBox(height: 16),
Text(
l10n.noTasks,
style: Theme.of(context).textTheme.bodyLarge,
),
],
),
);
}
return RefreshIndicator(
onRefresh: vm.loadTasks,
child: ListView.builder(
padding: const EdgeInsets.only(bottom: 80),
itemCount: vm.tasks.length,
itemBuilder: (context, index) {
final task = vm.tasks[index];
return TaskTile(
task: task,
onToggle: () => vm.toggleTask(task.id),
onTap: () async {
final result = await context.push('/task/${task.id}/edit');
if (result == true) {
vm.loadTasks();
}
},
onDelete: () => vm.deleteTask(task.id),
onReschedule: () => vm.rescheduleToTomorrow(task.id),
);
},
),
);
}
}
}
class _DateNavigation extends StatelessWidget {
final DateTime date;
final String locale;
final VoidCallback onPrevious;
final VoidCallback onNext;
const _DateNavigation({
required this.date,
required this.locale,
required this.onPrevious,
required this.onNext,
});
@override
Widget build(BuildContext context) {
final dateFormat = DateFormat.yMMMMEEEEd(locale);
return Container(
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: 48,
height: 48,
child: IconButton(
icon: const Icon(Icons.chevron_left, size: 28),
onPressed: onPrevious,
),
),
Expanded(
child: Text(
dateFormat.format(date),
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleMedium,
),
),
SizedBox(
width: 48,
height: 48,
child: IconButton(
icon: const Icon(Icons.chevron_right, size: 28),
onPressed: onNext,
),
),
],
),
);
}
}