// Import all task types import 'tasks/generic_task.dart'; import 'tasks/confirmation_task.dart'; import 'tasks/photo_task.dart'; import 'tasks/todolist_task.dart'; import 'tasks/signature_task.dart'; import 'tasks/barcode_task.dart'; import 'tasks/comment_task.dart'; abstract class Task { final String id; final String jobId; final int? stationOrder; final bool completed; final bool optional; final DateTime? completedAt; final String? completedBy; final int? taskOrder; final String? title; final String? description; final String? displayName; Task({ required this.id, required this.jobId, this.stationOrder, this.completed = false, this.optional = false, this.completedAt, this.completedBy, this.taskOrder, this.title, this.description, this.displayName, }); factory Task.fromJson(Map json) { // Get task specific data to determine task type final taskSpecificData = json['taskSpecificData'] as Map?; final taskType = (taskSpecificData?['taskType'] ?? json['taskType'])?.toString(); // Create specific task type based on taskType switch (taskType) { case 'CONFIRMATION': return ConfirmationTask.fromJson(json); case 'PHOTO': return PhotoTask.fromJson(json); case 'TODOLIST': return TodoListTask.fromJson(json); case 'SIGNATURE': return SignatureTask.fromJson(json); case 'BARCODE': return BarcodeTask.fromJson(json); case 'COMMENT': return CommentTask.fromJson(json); case 'GENERIC': return GenericTask.fromJson(json); default: // Fallback to a generic task if no specific type is found return GenericTask.fromJson(json); } } Map toJson(); Task copyWith({ String? id, String? jobId, int? stationOrder, bool? completed, bool? optional, DateTime? completedAt, String? completedBy, int? taskOrder, String? title, String? description, String? displayName, }); @override String toString() { return 'Task(id: $id, jobId: $jobId, stationOrder: $stationOrder, completed: $completed, taskOrder: $taskOrder)'; } @override bool operator ==(Object other) { if (identical(this, other)) return true; return other is Task && other.id == id; } @override int get hashCode => id.hashCode; /// Parse DateTime from either string or array format static DateTime? _parseDateTime(dynamic value) { if (value == null) return null; if (value is String) { return DateTime.tryParse(value); } if (value is List && value.isNotEmpty) { try { // Array format: [year, month, day, hour, minute, second, microsecond] final year = value[0] as int; final month = value.length > 1 ? value[1] as int : 1; final day = value.length > 2 ? value[2] as int : 1; final hour = value.length > 3 ? value[3] as int : 0; final minute = value.length > 4 ? value[4] as int : 0; final second = value.length > 5 ? value[5] as int : 0; final microsecond = value.length > 6 ? value[6] as int : 0; return DateTime(year, month, day, hour, minute, second, microsecond); } catch (e) { return null; } } return null; } static String? _readOptionalString(dynamic value) { if (value == null) { return null; } if (value is String) { return value; } if (value is num || value is bool) { return value.toString(); } return null; } static int? _readOptionalInt(dynamic value) { if (value is int) { return value; } if (value is num) { return value.toInt(); } if (value is String) { return int.tryParse(value); } return null; } // Helper method to parse common properties static Map parseCommonProperties(Map json) { // Parse the complex id object - can be either a Map or a simple string String idValue = ''; if (json['id'] is Map) { final idMap = json['id'] as Map; idValue = idMap['timestamp']?.toString() ?? ''; } else { idValue = json['id']?.toString() ?? ''; } // Parse the complex jobId object - can be either a Map or a simple string String jobIdValue = ''; if (json['jobId'] is Map) { final jobIdMap = json['jobId'] as Map; jobIdValue = jobIdMap['timestamp']?.toString() ?? ''; } else { jobIdValue = json['jobId']?.toString() ?? ''; } // Parse completedAt using the helper method to handle both string and array formats final completedAt = _parseDateTime(json['completedAt']); final taskSpecificData = json['taskSpecificData'] as Map?; final stationOrder = _readOptionalInt(json['stationOrder']); final title = _readOptionalString( json['title'] ?? taskSpecificData?['title'], ); final description = _readOptionalString( json['description'] ?? taskSpecificData?['description'], ); final displayName = _readOptionalString( json['displayName'] ?? taskSpecificData?['displayName'], ); return { 'id': idValue, 'jobId': jobIdValue, 'stationOrder': stationOrder, 'completed': json['completed'] ?? false, 'optional': json['optional'] ?? false, 'completedAt': completedAt, 'completedBy': json['completedBy'], 'taskOrder': json['taskOrder'], 'title': title, 'description': description, 'displayName': displayName, }; } }