All checks were successful
Build and Release to F-Droid / build-and-deploy (push) Successful in 10m30s
- Covers empty states, celebration state, and scheduled/overdue task rendering - Verifies proper checkbox behavior for future tasks - Tests AppBar for sort dropdown, edit/delete actions, and calendar strip - Adds necessary test helpers and overrides for room-specific tasks
151 lines
4.9 KiB
Dart
151 lines
4.9 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
|
|
import 'package:household_keeper/core/database/database.dart';
|
|
import 'package:household_keeper/core/providers/database_provider.dart';
|
|
import 'package:household_keeper/features/home/presentation/calendar_day_list.dart';
|
|
import 'package:household_keeper/features/home/presentation/calendar_providers.dart';
|
|
import 'package:household_keeper/features/home/presentation/calendar_strip.dart';
|
|
import 'package:household_keeper/features/tasks/presentation/sort_dropdown.dart';
|
|
import 'package:household_keeper/l10n/app_localizations.dart';
|
|
|
|
/// Screen displaying tasks within a room filtered by the selected calendar day.
|
|
///
|
|
/// Shows a horizontal calendar strip at the top (same as HomeScreen) and
|
|
/// a date-filtered task list below. FAB always visible for quick task creation.
|
|
/// AppBar shows room name with edit and delete actions.
|
|
class TaskListScreen extends ConsumerStatefulWidget {
|
|
const TaskListScreen({super.key, required this.roomId});
|
|
|
|
final int roomId;
|
|
|
|
@override
|
|
ConsumerState<TaskListScreen> createState() => _TaskListScreenState();
|
|
}
|
|
|
|
class _TaskListScreenState extends ConsumerState<TaskListScreen> {
|
|
late final CalendarStripController _stripController =
|
|
CalendarStripController();
|
|
|
|
/// Whether to show the floating "Heute" button.
|
|
/// True when the user has scrolled away from today's card.
|
|
bool _showTodayButton = false;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final l10n = AppLocalizations.of(context);
|
|
|
|
return Scaffold(
|
|
appBar: AppBar(
|
|
title: _RoomTitle(roomId: widget.roomId),
|
|
actions: [
|
|
const SortDropdown(),
|
|
IconButton(
|
|
icon: const Icon(Icons.edit),
|
|
onPressed: () => context.go('/rooms/${widget.roomId}/edit'),
|
|
),
|
|
IconButton(
|
|
icon: const Icon(Icons.delete),
|
|
onPressed: () => _showRoomDeleteConfirmation(context, ref, l10n),
|
|
),
|
|
],
|
|
),
|
|
body: Stack(
|
|
children: [
|
|
Column(
|
|
children: [
|
|
CalendarStrip(
|
|
controller: _stripController,
|
|
onTodayVisibilityChanged: (visible) {
|
|
setState(() => _showTodayButton = !visible);
|
|
},
|
|
),
|
|
Expanded(child: CalendarDayList(roomId: widget.roomId)),
|
|
],
|
|
),
|
|
if (_showTodayButton)
|
|
Positioned(
|
|
bottom: 80, // Above the FAB
|
|
left: 0,
|
|
right: 0,
|
|
child: Center(
|
|
child: FloatingActionButton.extended(
|
|
onPressed: () {
|
|
final now = DateTime.now();
|
|
final today = DateTime(now.year, now.month, now.day);
|
|
ref
|
|
.read(selectedDateProvider.notifier)
|
|
.selectDate(today);
|
|
_stripController.scrollToToday();
|
|
},
|
|
icon: const Icon(Icons.today),
|
|
label: Text(l10n.calendarTodayButton),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
floatingActionButton: FloatingActionButton(
|
|
onPressed: () => context.go('/rooms/${widget.roomId}/tasks/new'),
|
|
child: const Icon(Icons.add),
|
|
),
|
|
);
|
|
}
|
|
|
|
void _showRoomDeleteConfirmation(
|
|
BuildContext context,
|
|
WidgetRef ref,
|
|
AppLocalizations l10n,
|
|
) {
|
|
showDialog(
|
|
context: context,
|
|
builder: (ctx) => AlertDialog(
|
|
title: Text(l10n.roomDeleteConfirmTitle),
|
|
content: Text(l10n.roomDeleteConfirmMessage),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Navigator.pop(ctx),
|
|
child: Text(l10n.cancel),
|
|
),
|
|
FilledButton(
|
|
onPressed: () {
|
|
Navigator.pop(ctx);
|
|
final db = ref.read(appDatabaseProvider);
|
|
db.roomsDao.deleteRoom(widget.roomId);
|
|
// Navigate back to rooms list
|
|
context.go('/rooms');
|
|
},
|
|
style: FilledButton.styleFrom(
|
|
backgroundColor: Theme.of(context).colorScheme.error,
|
|
foregroundColor: Theme.of(context).colorScheme.onError,
|
|
),
|
|
child: Text(l10n.roomDeleteConfirmAction),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Async room name loader for the AppBar title.
|
|
class _RoomTitle extends ConsumerWidget {
|
|
const _RoomTitle({required this.roomId});
|
|
|
|
final int roomId;
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
// Use a FutureBuilder-like approach: read room name from DB
|
|
return FutureBuilder<Room>(
|
|
future: ref.read(appDatabaseProvider).roomsDao.getRoomById(roomId),
|
|
builder: (context, snapshot) {
|
|
if (snapshot.hasData) {
|
|
return Text(snapshot.data!.name);
|
|
}
|
|
return const Text('...');
|
|
},
|
|
);
|
|
}
|
|
}
|