diff --git a/lib/views/task_list_tile.dart b/lib/views/task_list_tile.dart new file mode 100644 index 00000000..d18a2c16 --- /dev/null +++ b/lib/views/task_list_tile.dart @@ -0,0 +1,81 @@ +import 'package:flutter/material.dart'; +import 'package:auto_gpt_flutter_client/models/task.dart'; + +class TaskListTile extends StatefulWidget { + final Task task; + final VoidCallback onTap; + final VoidCallback onDelete; + + const TaskListTile({ + Key? key, + required this.task, + required this.onTap, + required this.onDelete, + }) : super(key: key); + + @override + _TaskListTileState createState() => _TaskListTileState(); +} + +class _TaskListTileState extends State { + bool _isSelected = false; + + @override + Widget build(BuildContext context) { + // Determine the width of the TaskView + double taskViewWidth = MediaQuery.of(context).size.width; + double tileWidth = taskViewWidth - 20; + if (tileWidth > 260) { + tileWidth = 260; + } + + return GestureDetector( + onTap: () { + setState(() { + _isSelected = !_isSelected; + }); + widget.onTap(); + }, + child: Material( + // Use a transparent color to avoid any unnecessary color overlay + color: Colors.transparent, + child: Padding( + // Provide a horizontal padding to ensure the tile does not touch the edges + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Container( + // Width and height specifications for the tile + width: tileWidth, + height: 50, + decoration: BoxDecoration( + // Use conditional operator to determine background color based on selection + color: _isSelected ? Colors.grey[300] : Colors.white, + borderRadius: BorderRadius.circular(8.0), + ), + child: Row( + children: [ + // Space from the left edge of the tile + const SizedBox(width: 8), + // Message bubble icon indicating a task + const Icon(Icons.messenger_outline, color: Colors.black), + const SizedBox(width: 8), + // Task title + Expanded( + child: Text( + widget.task.title, + style: const TextStyle(color: Colors.black), + ), + ), + // If the task is selected, show a delete icon + if (_isSelected) + IconButton( + icon: const Icon(Icons.close, color: Colors.black), + onPressed: widget.onDelete, + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/test/task_list_tile_test.dart b/test/task_list_tile_test.dart new file mode 100644 index 00000000..39706cda --- /dev/null +++ b/test/task_list_tile_test.dart @@ -0,0 +1,71 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter/material.dart'; +import 'package:auto_gpt_flutter_client/views/task_list_tile.dart'; +import 'package:auto_gpt_flutter_client/models/task.dart'; + +void main() { + final Task testTask = Task(id: 1, title: "Sample Task"); + + testWidgets('TaskListTile displays the task title', + (WidgetTester tester) async { + await tester.pumpWidget(MaterialApp( + home: TaskListTile(task: testTask, onTap: () {}, onDelete: () {}))); + expect(find.text('Sample Task'), findsOneWidget); + }); + + testWidgets('TaskListTile toggles isSelected state on tap', + (WidgetTester tester) async { + await tester.pumpWidget(MaterialApp( + home: TaskListTile(task: testTask, onTap: () {}, onDelete: () {}))); + + // Initially, the delete icon should not be present + expect(find.byIcon(Icons.close), findsNothing); + + // Tap the tile + await tester.tap(find.text('Sample Task')); + await tester.pump(); + + // The delete icon should appear + expect(find.byIcon(Icons.close), findsOneWidget); + }); + + testWidgets('TaskListTile triggers onDelete when delete icon is tapped', + (WidgetTester tester) async { + bool wasDeleteCalled = false; + await tester.pumpWidget(MaterialApp( + home: TaskListTile( + task: testTask, + onTap: () {}, + onDelete: () { + wasDeleteCalled = true; + }))); + + // Tap the tile to make the delete icon appear + await tester.tap(find.text('Sample Task')); + await tester.pump(); + + // Tap the delete icon + await tester.tap(find.byIcon(Icons.close)); + await tester.pump(); + + expect(wasDeleteCalled, true); + }); + + testWidgets('TaskListTile triggers onTap when tapped', + (WidgetTester tester) async { + bool wasTapped = false; + await tester.pumpWidget(MaterialApp( + home: TaskListTile( + task: testTask, + onTap: () { + wasTapped = true; + }, + onDelete: () {}))); + + // Tap the tile + await tester.tap(find.text('Sample Task')); + await tester.pump(); + + expect(wasTapped, true); + }); +} diff --git a/test/widget_test.dart b/test/widget_test.dart deleted file mode 100644 index a69eede9..00000000 --- a/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:auto_gpt_flutter_client/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -}