diff options
Diffstat (limited to 'frontend/lib/viewmodels/task_viewmodel.dart')
-rw-r--r-- | frontend/lib/viewmodels/task_viewmodel.dart | 210 |
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!"); + } +} |