feat: Add support for reported pre-signed URLs in comments and daily progress report

This commit is contained in:
Vaibhav Surve 2025-06-12 22:02:19 +05:30
parent 5cf0202cc1
commit 916cfa3af4
3 changed files with 113 additions and 12 deletions

View File

@ -60,6 +60,7 @@ class _CommentTaskBottomSheetState extends State<CommentTaskBottomSheet>
controller.basicValidator.getController('task_id')?.text =
data['taskId'] ?? '';
controller.basicValidator.getController('comment')?.clear();
controller.basicValidator.getController('preSignedUrls')?.clear();
WidgetsBinding.instance.addPostFrameCallback((_) {
if (_scrollController.hasClients) {
_scrollController.jumpTo(_scrollController.position.maxScrollExtent);
@ -178,6 +179,90 @@ class _CommentTaskBottomSheetState extends State<CommentTaskBottomSheet>
icon: Icons.done_all_outlined,
),
buildTeamMembers(),
if ((widget.taskData['reportedPreSignedUrls']
as List<dynamic>?)
?.isNotEmpty ==
true) ...[
MySpacing.height(8),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 0.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(Icons.image_outlined,
size: 18, color: Colors.grey[700]),
MySpacing.width(8),
MyText.titleSmall(
"Reported Images",
fontWeight: 600,
),
],
),
),
MySpacing.height(8),
Builder(
builder: (context) {
final allImageUrls = List<String>.from(
widget.taskData['reportedPreSignedUrls'] ?? [],
);
if (allImageUrls.isEmpty) return const SizedBox();
return Padding(
padding: const EdgeInsets.symmetric(
horizontal:
16.0), // Same horizontal padding
child: SizedBox(
height: 70,
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: allImageUrls.length,
separatorBuilder: (_, __) =>
const SizedBox(width: 12),
itemBuilder: (context, index) {
final url = allImageUrls[index];
return GestureDetector(
onTap: () {
showDialog(
context: context,
barrierColor: Colors.black54,
builder: (_) => ImageViewerDialog(
imageSources: allImageUrls,
initialIndex: index,
),
);
},
child: ClipRRect(
borderRadius:
BorderRadius.circular(12),
child: Image.network(
url,
width: 70,
height: 70,
fit: BoxFit.cover,
errorBuilder:
(context, error, stackTrace) =>
Container(
width: 70,
height: 70,
color: Colors.grey.shade200,
child: Icon(Icons.broken_image,
color: Colors.grey[600]),
),
),
),
);
},
),
),
);
},
),
MySpacing.height(16),
],
Row(
children: [
Icon(Icons.comment_outlined,
@ -456,17 +541,9 @@ class _CommentTaskBottomSheetState extends State<CommentTaskBottomSheet>
comment['commentedBy'] ?? 'Unknown';
final relativeTime =
timeAgo(comment['date'] ?? '');
// Dummy image URLs (simulate as if coming from backend)
final imageUrls = [
'https://picsum.photos/seed/${index}a/100',
'https://picsum.photos/seed/${index}b/100',
'https://picsum.photos/seed/${index}a/100',
'https://picsum.photos/seed/${index}b/100',
'https://picsum.photos/seed/${index}a/100',
'https://picsum.photos/seed/${index}b/100',
];
final imageUrls = List<String>.from(
comment['preSignedUrls'] ?? []);
return Container(
margin: const EdgeInsets.symmetric(
vertical: 8), // Spacing between items

View File

@ -9,10 +9,11 @@ class TaskModel {
final AssignedBy assignedBy;
final List<TeamMember> teamMembers;
final List<Comment> comments;
final List<String> reportedPreSignedUrls;
TaskModel({
required this.assignmentDate,
this.reportedDate,
this.reportedDate,
required this.id,
required this.workItem,
required this.workItemId,
@ -21,13 +22,14 @@ class TaskModel {
required this.assignedBy,
required this.teamMembers,
required this.comments,
required this.reportedPreSignedUrls,
});
factory TaskModel.fromJson(Map<String, dynamic> json) {
return TaskModel(
assignmentDate: DateTime.parse(json['assignmentDate']),
reportedDate: json['reportedDate'] != null
? DateTime.tryParse(json['reportedDate'])
? DateTime.tryParse(json['reportedDate'])
: null,
id: json['id'],
workItem:
@ -41,6 +43,10 @@ class TaskModel {
.toList(),
comments:
(json['comments'] as List).map((e) => Comment.fromJson(e)).toList(),
reportedPreSignedUrls: (json['reportedPreSignedUrls'] as List<dynamic>?)
?.map((e) => e.toString())
.toList() ??
[],
);
}
}
@ -51,6 +57,7 @@ class WorkItem {
final WorkArea? workArea;
final int? plannedWork;
final int? completedWork;
final List<String> preSignedUrls;
WorkItem({
this.id,
@ -58,6 +65,7 @@ class WorkItem {
this.workArea,
this.plannedWork,
this.completedWork,
this.preSignedUrls = const [],
});
factory WorkItem.fromJson(Map<String, dynamic> json) {
@ -70,6 +78,10 @@ class WorkItem {
json['workArea'] != null ? WorkArea.fromJson(json['workArea']) : null,
plannedWork: json['plannedWork'],
completedWork: json['completedWork'],
preSignedUrls: (json['preSignedUrls'] as List<dynamic>?)
?.map((e) => e.toString())
.toList() ??
[],
);
}
}
@ -167,11 +179,13 @@ class Comment {
final String comment;
final TeamMember commentedBy;
final DateTime timestamp;
final List<String> preSignedUrls;
Comment({
required this.comment,
required this.commentedBy,
required this.timestamp,
required this.preSignedUrls,
});
factory Comment.fromJson(Map<String, dynamic> json) {
@ -181,6 +195,10 @@ class Comment {
? TeamMember.fromJson(json['employee'])
: TeamMember(id: '', firstName: '', lastName: null),
timestamp: DateTime.parse(json['commentDate'] ?? ''),
preSignedUrls: (json['preSignedUrls'] as List<dynamic>?)
?.map((e) => e.toString())
.toList() ??
[],
);
}
}

View File

@ -607,8 +607,12 @@ class _DailyProgressReportScreenState extends State<DailyProgressReportScreen>
'text': comment.comment,
'date': isoDate,
'commentedBy': commenterName,
'preSignedUrls':
comment.preSignedUrls,
};
}).toList();
final taskLevelPreSignedUrls =
task.reportedPreSignedUrls;
final taskData = {
'activity': activityName,
@ -622,6 +626,8 @@ class _DailyProgressReportScreenState extends State<DailyProgressReportScreen>
'teamSize': task.teamMembers.length,
'teamMembers': teamMembers,
'taskComments': taskComments,
'reportedPreSignedUrls':
taskLevelPreSignedUrls,
};
showModalBottomSheet(