aboutsummaryrefslogtreecommitdiff
path: root/frontend/lib/viewmodels/task_viewmodel.dart
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/lib/viewmodels/task_viewmodel.dart')
-rw-r--r--frontend/lib/viewmodels/task_viewmodel.dart210
1 files changed, 210 insertions, 0 deletions
diff --git a/frontend/lib/viewmodels/task_viewmodel.dart b/frontend/lib/viewmodels/task_viewmodel.dart
new file mode 100644
index 000000000..61187a760
--- /dev/null
+++ b/frontend/lib/viewmodels/task_viewmodel.dart
@@ -0,0 +1,210 @@
+import 'dart:convert';
+import 'package:auto_gpt_flutter_client/models/task.dart';
+import 'package:auto_gpt_flutter_client/models/test_suite.dart';
+import 'package:auto_gpt_flutter_client/services/shared_preferences_service.dart';
+import 'package:flutter/foundation.dart';
+import 'package:collection/collection.dart';
+import 'package:auto_gpt_flutter_client/services/task_service.dart';
+import 'package:auto_gpt_flutter_client/models/task_request_body.dart';
+
+// TODO: How will all these functions work with test suites?
+class TaskViewModel with ChangeNotifier {
+ final TaskService _taskService;
+ final SharedPreferencesService _prefsService;
+
+ List<Task> _tasks = [];
+ List<TestSuite> _testSuites = [];
+ List<dynamic> combinedDataSource = [];
+ List<Task> tasksDataSource = [];
+
+ Task? _selectedTask;
+ TestSuite? _selectedTestSuite;
+
+ bool _isWaitingForAgentResponse = false;
+
+ bool get isWaitingForAgentResponse => _isWaitingForAgentResponse;
+
+ TaskViewModel(this._taskService, this._prefsService);
+
+ /// Returns the currently selected task.
+ Task? get selectedTask => _selectedTask;
+ TestSuite? get selectedTestSuite => _selectedTestSuite;
+
+ /// Adds a task and returns its ID.
+ Future<String> createTask(String title) async {
+ _isWaitingForAgentResponse = true;
+ notifyListeners();
+ try {
+ final newTask = TaskRequestBody(input: title);
+ // Add to data source
+ final createdTask = await _taskService.createTask(newTask);
+ // Create a Task object from the created task response
+ final newTaskObject =
+ Task(id: createdTask['task_id'], title: createdTask['input']);
+
+ fetchAndCombineData();
+
+ final taskId = newTaskObject.id;
+ print("Task $taskId created successfully!");
+
+ return newTaskObject.id;
+ } catch (e) {
+ // TODO: We are bubbling up the full response. Revisit this.
+ rethrow;
+ } finally {
+ _isWaitingForAgentResponse = false;
+ notifyListeners();
+ }
+ }
+
+ /// Deletes a task.
+ void deleteTask(String taskId) {
+ _taskService.saveDeletedTask(taskId);
+ _tasks.removeWhere((task) => task.id == taskId);
+ notifyListeners();
+ print("Task $taskId deleted successfully!");
+ }
+
+ /// Fetches tasks from the data source.
+ Future<void> fetchTasks() async {
+ try {
+ final tasksFromApi = await _taskService.fetchAllTasks();
+ _tasks = tasksFromApi
+ .where((task) => !_taskService.isTaskDeleted(task.id))
+ .toList();
+
+ _tasks = _tasks.reversed.toList();
+
+ notifyListeners();
+ print("Tasks fetched successfully!");
+ } catch (error) {
+ print("Error fetching tasks: $error");
+ }
+ }
+
+ /// Handles the selection of a task by its ID.
+ void selectTask(String id) {
+ final task = _tasks.firstWhereOrNull((t) => t.id == id);
+
+ if (task != null) {
+ _selectedTask = task;
+ print("Selected task with ID: ${task.id} and Title: ${task.title}");
+ notifyListeners(); // Notify listeners to rebuild UI
+ } else {
+ final errorMessage =
+ "Error: Attempted to select a task with ID: $id that does not exist in the data source.";
+ print(errorMessage);
+ throw ArgumentError(errorMessage);
+ }
+ }
+
+ /// Deselects the currently selected task.
+ void deselectTask() {
+ _selectedTask = null;
+ print("Deselected the current task.");
+ notifyListeners(); // Notify listeners to rebuild UI
+ }
+
+ void selectTestSuite(TestSuite testSuite) {
+ _selectedTestSuite = testSuite;
+ notifyListeners();
+ }
+
+ void deselectTestSuite() {
+ _selectedTestSuite = null;
+ notifyListeners();
+ }
+
+ // Helper method to save test suites to SharedPreferences
+ Future<void> _saveTestSuitesToPrefs() async {
+ final testSuitesToStore =
+ _testSuites.map((testSuite) => jsonEncode(testSuite.toJson())).toList();
+ await _prefsService.setStringList('testSuites', testSuitesToStore);
+ }
+
+ // Adds a new test suite and saves it to SharedPreferences
+ void addTestSuite(TestSuite testSuite) async {
+ _testSuites.add(testSuite);
+ await _saveTestSuitesToPrefs();
+ notifyListeners();
+ print("Test suite successfully added!");
+ }
+
+ // Fetch test suites from SharedPreferences
+ Future<void> fetchTestSuites() async {
+ final storedTestSuites =
+ await _prefsService.getStringList('testSuites') ?? [];
+ _testSuites = storedTestSuites
+ .map((testSuiteMap) => TestSuite.fromJson(jsonDecode(testSuiteMap)))
+ .toList();
+ notifyListeners();
+ }
+
+ // The fetchAndCombineData method performs several tasks:
+ // 1. It fetches the tasks and filters out deleted ones.
+ // 2. It fetches the test suites from SharedPreferences.
+ // 3. It combines both the tasks and test suites into a single data source according to specified logic.
+ Future<void> fetchAndCombineData() async {
+ // Step 1: Fetch tasks from the data source
+ // This will populate the _tasks list with tasks fetched from the backend.
+ await fetchTasks();
+
+ // Step 2: Fetch test suites from SharedPreferences
+ // This will populate the _testSuites list with test suites fetched from SharedPreferences.
+ await fetchTestSuites();
+
+ // Step 3: Combine into a shared data source
+ // Create a map to hold test suites by their timestamp.
+ Map<String, TestSuite> testSuiteMap = {};
+
+ // Clear the existing combined data source to start fresh.
+ combinedDataSource.clear();
+ tasksDataSource.clear();
+
+ // Iterate through each task to check if it's contained in any of the test suites.
+ for (var task in _tasks) {
+ bool found = false;
+
+ // Iterate through each test suite.
+ for (var testSuite in _testSuites) {
+ // Check if the current task is contained in the current test suite.
+ if (testSuite.tests.contains(task)) {
+ found = true;
+
+ // If this test suite is already in the map, add this task to its list of tasks.
+ if (testSuiteMap.containsKey(testSuite.timestamp)) {
+ testSuiteMap[testSuite.timestamp]!.tests.add(task);
+
+ // Find and replace the test suite in the combined data source.
+ final index = combinedDataSource.indexWhere((item) =>
+ item is TestSuite && item.timestamp == testSuite.timestamp);
+ if (index != -1) {
+ combinedDataSource[index] = testSuiteMap[testSuite.timestamp]!;
+ }
+ }
+ // If this test suite is not in the map, add it to the map and to the combined data source.
+ else {
+ final newTestSuite = TestSuite(
+ timestamp: testSuite.timestamp,
+ tests: [task],
+ );
+ testSuiteMap[testSuite.timestamp] = newTestSuite;
+ combinedDataSource.add(
+ newTestSuite); // Add the new test suite to the combined data source.
+ }
+ break; // Exit the loop as the task is found in a test suite.
+ }
+ }
+
+ // If the task was not found in any test suite, add it to the combined data source.
+ if (!found) {
+ combinedDataSource.add(task);
+ tasksDataSource.add(task);
+ }
+ }
+
+ // After processing all tasks, call notifyListeners to rebuild the widgets that depend on this data.
+ notifyListeners();
+ print("Combined tasks and test suites successfully!");
+ }
+}