feat: Add support for reported pre-signed URLs in comments and daily progress report
This commit is contained in:
parent
5cf0202cc1
commit
916cfa3af4
@ -60,6 +60,7 @@ class _CommentTaskBottomSheetState extends State<CommentTaskBottomSheet>
|
|||||||
controller.basicValidator.getController('task_id')?.text =
|
controller.basicValidator.getController('task_id')?.text =
|
||||||
data['taskId'] ?? '';
|
data['taskId'] ?? '';
|
||||||
controller.basicValidator.getController('comment')?.clear();
|
controller.basicValidator.getController('comment')?.clear();
|
||||||
|
controller.basicValidator.getController('preSignedUrls')?.clear();
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
if (_scrollController.hasClients) {
|
if (_scrollController.hasClients) {
|
||||||
_scrollController.jumpTo(_scrollController.position.maxScrollExtent);
|
_scrollController.jumpTo(_scrollController.position.maxScrollExtent);
|
||||||
@ -178,6 +179,90 @@ class _CommentTaskBottomSheetState extends State<CommentTaskBottomSheet>
|
|||||||
icon: Icons.done_all_outlined,
|
icon: Icons.done_all_outlined,
|
||||||
),
|
),
|
||||||
buildTeamMembers(),
|
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(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.comment_outlined,
|
Icon(Icons.comment_outlined,
|
||||||
@ -456,17 +541,9 @@ class _CommentTaskBottomSheetState extends State<CommentTaskBottomSheet>
|
|||||||
comment['commentedBy'] ?? 'Unknown';
|
comment['commentedBy'] ?? 'Unknown';
|
||||||
final relativeTime =
|
final relativeTime =
|
||||||
timeAgo(comment['date'] ?? '');
|
timeAgo(comment['date'] ?? '');
|
||||||
|
|
||||||
// Dummy image URLs (simulate as if coming from backend)
|
// Dummy image URLs (simulate as if coming from backend)
|
||||||
final imageUrls = [
|
final imageUrls = List<String>.from(
|
||||||
'https://picsum.photos/seed/${index}a/100',
|
comment['preSignedUrls'] ?? []);
|
||||||
'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',
|
|
||||||
];
|
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
margin: const EdgeInsets.symmetric(
|
margin: const EdgeInsets.symmetric(
|
||||||
vertical: 8), // Spacing between items
|
vertical: 8), // Spacing between items
|
||||||
|
|||||||
@ -9,6 +9,7 @@ class TaskModel {
|
|||||||
final AssignedBy assignedBy;
|
final AssignedBy assignedBy;
|
||||||
final List<TeamMember> teamMembers;
|
final List<TeamMember> teamMembers;
|
||||||
final List<Comment> comments;
|
final List<Comment> comments;
|
||||||
|
final List<String> reportedPreSignedUrls;
|
||||||
|
|
||||||
TaskModel({
|
TaskModel({
|
||||||
required this.assignmentDate,
|
required this.assignmentDate,
|
||||||
@ -21,6 +22,7 @@ class TaskModel {
|
|||||||
required this.assignedBy,
|
required this.assignedBy,
|
||||||
required this.teamMembers,
|
required this.teamMembers,
|
||||||
required this.comments,
|
required this.comments,
|
||||||
|
required this.reportedPreSignedUrls,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory TaskModel.fromJson(Map<String, dynamic> json) {
|
factory TaskModel.fromJson(Map<String, dynamic> json) {
|
||||||
@ -41,6 +43,10 @@ class TaskModel {
|
|||||||
.toList(),
|
.toList(),
|
||||||
comments:
|
comments:
|
||||||
(json['comments'] as List).map((e) => Comment.fromJson(e)).toList(),
|
(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 WorkArea? workArea;
|
||||||
final int? plannedWork;
|
final int? plannedWork;
|
||||||
final int? completedWork;
|
final int? completedWork;
|
||||||
|
final List<String> preSignedUrls;
|
||||||
|
|
||||||
WorkItem({
|
WorkItem({
|
||||||
this.id,
|
this.id,
|
||||||
@ -58,6 +65,7 @@ class WorkItem {
|
|||||||
this.workArea,
|
this.workArea,
|
||||||
this.plannedWork,
|
this.plannedWork,
|
||||||
this.completedWork,
|
this.completedWork,
|
||||||
|
this.preSignedUrls = const [],
|
||||||
});
|
});
|
||||||
|
|
||||||
factory WorkItem.fromJson(Map<String, dynamic> json) {
|
factory WorkItem.fromJson(Map<String, dynamic> json) {
|
||||||
@ -70,6 +78,10 @@ class WorkItem {
|
|||||||
json['workArea'] != null ? WorkArea.fromJson(json['workArea']) : null,
|
json['workArea'] != null ? WorkArea.fromJson(json['workArea']) : null,
|
||||||
plannedWork: json['plannedWork'],
|
plannedWork: json['plannedWork'],
|
||||||
completedWork: json['completedWork'],
|
completedWork: json['completedWork'],
|
||||||
|
preSignedUrls: (json['preSignedUrls'] as List<dynamic>?)
|
||||||
|
?.map((e) => e.toString())
|
||||||
|
.toList() ??
|
||||||
|
[],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -167,11 +179,13 @@ class Comment {
|
|||||||
final String comment;
|
final String comment;
|
||||||
final TeamMember commentedBy;
|
final TeamMember commentedBy;
|
||||||
final DateTime timestamp;
|
final DateTime timestamp;
|
||||||
|
final List<String> preSignedUrls;
|
||||||
|
|
||||||
Comment({
|
Comment({
|
||||||
required this.comment,
|
required this.comment,
|
||||||
required this.commentedBy,
|
required this.commentedBy,
|
||||||
required this.timestamp,
|
required this.timestamp,
|
||||||
|
required this.preSignedUrls,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory Comment.fromJson(Map<String, dynamic> json) {
|
factory Comment.fromJson(Map<String, dynamic> json) {
|
||||||
@ -181,6 +195,10 @@ class Comment {
|
|||||||
? TeamMember.fromJson(json['employee'])
|
? TeamMember.fromJson(json['employee'])
|
||||||
: TeamMember(id: '', firstName: '', lastName: null),
|
: TeamMember(id: '', firstName: '', lastName: null),
|
||||||
timestamp: DateTime.parse(json['commentDate'] ?? ''),
|
timestamp: DateTime.parse(json['commentDate'] ?? ''),
|
||||||
|
preSignedUrls: (json['preSignedUrls'] as List<dynamic>?)
|
||||||
|
?.map((e) => e.toString())
|
||||||
|
.toList() ??
|
||||||
|
[],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -607,8 +607,12 @@ class _DailyProgressReportScreenState extends State<DailyProgressReportScreen>
|
|||||||
'text': comment.comment,
|
'text': comment.comment,
|
||||||
'date': isoDate,
|
'date': isoDate,
|
||||||
'commentedBy': commenterName,
|
'commentedBy': commenterName,
|
||||||
|
'preSignedUrls':
|
||||||
|
comment.preSignedUrls,
|
||||||
};
|
};
|
||||||
}).toList();
|
}).toList();
|
||||||
|
final taskLevelPreSignedUrls =
|
||||||
|
task.reportedPreSignedUrls;
|
||||||
|
|
||||||
final taskData = {
|
final taskData = {
|
||||||
'activity': activityName,
|
'activity': activityName,
|
||||||
@ -622,6 +626,8 @@ class _DailyProgressReportScreenState extends State<DailyProgressReportScreen>
|
|||||||
'teamSize': task.teamMembers.length,
|
'teamSize': task.teamMembers.length,
|
||||||
'teamMembers': teamMembers,
|
'teamMembers': teamMembers,
|
||||||
'taskComments': taskComments,
|
'taskComments': taskComments,
|
||||||
|
'reportedPreSignedUrls':
|
||||||
|
taskLevelPreSignedUrls,
|
||||||
};
|
};
|
||||||
|
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user