feat: Update comment task bottom sheet layout and enhance comment display with improved spacing and attachment handling

This commit is contained in:
Vaibhav Surve 2025-06-12 19:14:27 +05:30
parent 1f784d96f4
commit daf132c3b5
2 changed files with 228 additions and 219 deletions

View File

@ -252,8 +252,8 @@ class _CommentTaskBottomSheetState extends State<CommentTaskBottomSheet>
child: ListView.separated( child: ListView.separated(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
itemCount: images.length, itemCount: images.length,
separatorBuilder: (_, __) => separatorBuilder: (context, index) =>
MySpacing.width(12), SizedBox(height: 12),
itemBuilder: (context, index) { itemBuilder: (context, index) {
final file = images[index]; final file = images[index];
return Stack( return Stack(
@ -445,236 +445,240 @@ class _CommentTaskBottomSheetState extends State<CommentTaskBottomSheet>
return SizedBox( return SizedBox(
height: 300, height: 300,
child: ListView.builder( child: ListView.builder(
itemCount: comments.length, padding: const EdgeInsets.symmetric(
itemBuilder: (context, index) { vertical:
final comment = comments[index]; 8), // Added padding around the list
final commentText = itemCount: comments.length,
comment['text'] ?? '-'; itemBuilder: (context, index) {
final commentedBy = final comment = comments[index];
comment['commentedBy'] ?? 'Unknown'; final commentText = comment['text'] ?? '-';
final relativeTime = final commentedBy =
timeAgo(comment['date'] ?? ''); comment['commentedBy'] ?? 'Unknown';
final relativeTime =
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 = [
'https://picsum.photos/seed/${index}a/100', 'https://picsum.photos/seed/${index}a/100',
'https://picsum.photos/seed/${index}b/100', 'https://picsum.photos/seed/${index}b/100',
'https://picsum.photos/seed/${index}a/100', 'https://picsum.photos/seed/${index}a/100',
'https://picsum.photos/seed/${index}b/100', 'https://picsum.photos/seed/${index}b/100',
'https://picsum.photos/seed/${index}a/100', 'https://picsum.photos/seed/${index}a/100',
'https://picsum.photos/seed/${index}b/100', 'https://picsum.photos/seed/${index}b/100',
]; ];
return Container( return Container(
margin: EdgeInsets.symmetric( margin: const EdgeInsets.symmetric(
vertical: 0, horizontal: 0), vertical: 8), // Spacing between items
padding: EdgeInsets.all(12), padding: const EdgeInsets.all(12),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.grey.shade200, color: Colors.grey.shade200,
borderRadius: borderRadius: BorderRadius.circular(12),
BorderRadius.circular(12), ),
), child: Row(
child: Row( crossAxisAlignment:
crossAxisAlignment: CrossAxisAlignment.start,
CrossAxisAlignment.start, children: [
children: [ const SizedBox(width: 12),
SizedBox(width: 12), Expanded(
Expanded( child: Column(
child: Column( crossAxisAlignment:
crossAxisAlignment: CrossAxisAlignment.start,
CrossAxisAlignment.start, children: [
children: [ // 🔹 Top Row: Avatar + Name + Time
// 🔹 Top Row: Avatar + Name + Time Row(
Row( crossAxisAlignment:
crossAxisAlignment: CrossAxisAlignment.center,
CrossAxisAlignment children: [
.center, Avatar(
children: [ firstName: commentedBy
Avatar( .split(' ')
firstName: commentedBy .first,
.split(' ') lastName: commentedBy
.first, .split(' ')
lastName: commentedBy .length >
.split(' ') 1
.length > ? commentedBy
1 .split(' ')
? commentedBy .last
.split(' ') : '',
.last size: 32,
: '', ),
size: 32, const SizedBox(width: 12),
), Expanded(
SizedBox(width: 12), child: Row(
Expanded( mainAxisAlignment:
child: Row( MainAxisAlignment
mainAxisAlignment: .spaceBetween,
MainAxisAlignment
.spaceBetween,
children: [
MyText.bodyMedium(
commentedBy,
fontWeight: 700,
color: Colors
.black87,
),
MyText.bodySmall(
relativeTime,
fontSize: 12,
color: Colors
.black54,
),
],
),
),
],
),
SizedBox(height: 12),
// 🔹 Comment text below attachments
Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
MyText.bodyMedium(
commentText,
fontWeight: 500,
color: Colors.black87,
),
]),
SizedBox(height: 12),
// 🔹 Attachments row: full width below top row
if (imageUrls.isNotEmpty) ...[
Row(
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [ children: [
Icon(
Icons
.attach_file_outlined,
size: 18,
color: Colors
.grey[700]),
MyText.bodyMedium( MyText.bodyMedium(
'Attachments', commentedBy,
fontWeight: 600, fontWeight: 700,
color: color:
Colors.black87, Colors.black87,
), ),
]), MyText.bodySmall(
SizedBox(height: 8), relativeTime,
SizedBox( fontSize: 12,
height: 60, color:
child: ListView.separated( Colors.black54,
padding: EdgeInsets ),
.symmetric( ],
horizontal: 0), ),
scrollDirection: ),
Axis.horizontal, ],
itemCount: ),
imageUrls.length, const SizedBox(height: 12),
itemBuilder: (context, // 🔹 Comment text below attachments
imageIndex) { Row(
final imageUrl = mainAxisAlignment:
imageUrls[ MainAxisAlignment
imageIndex]; .spaceBetween,
return GestureDetector( children: [
onTap: () { MyText.bodyMedium(
showDialog( commentText,
context: fontWeight: 500,
context, color: Colors.black87,
barrierColor: ),
Colors ],
.black54, ),
builder: (_) => const SizedBox(height: 12),
ImageViewerDialog( // 🔹 Attachments row: full width below top row
imageSources: if (imageUrls.isNotEmpty) ...[
imageUrls, Row(
initialIndex: crossAxisAlignment:
imageIndex, CrossAxisAlignment
.start,
children: [
Icon(
Icons
.attach_file_outlined,
size: 18,
color:
Colors.grey[700]),
MyText.bodyMedium(
'Attachments',
fontWeight: 600,
color: Colors.black87,
),
],
),
const SizedBox(height: 8),
SizedBox(
height: 60,
child: ListView.separated(
padding: const EdgeInsets
.symmetric(
horizontal: 0),
scrollDirection:
Axis.horizontal,
itemCount:
imageUrls.length,
itemBuilder: (context,
imageIndex) {
final imageUrl =
imageUrls[
imageIndex];
return GestureDetector(
onTap: () {
showDialog(
context: context,
barrierColor:
Colors
.black54,
builder: (_) =>
ImageViewerDialog(
imageSources:
imageUrls,
initialIndex:
imageIndex,
),
);
},
child: Stack(
children: [
Container(
width: 60,
height: 60,
decoration:
BoxDecoration(
borderRadius:
BorderRadius
.circular(
12),
color: Colors
.grey[
100],
boxShadow: [
BoxShadow(
color: Colors
.black26,
blurRadius:
6,
offset:
Offset(
2,
2),
),
],
), ),
); child:
}, ClipRRect(
child: Stack( borderRadius:
children: [ BorderRadius
Container( .circular(
width: 60, 12),
height: 60, child: Image
decoration: .network(
BoxDecoration( imageUrl,
borderRadius: fit: BoxFit
BorderRadius.circular( .cover,
12), errorBuilder: (context,
color: Colors error,
.grey[ stackTrace) =>
100], Container(
boxShadow: [ color: Colors
BoxShadow( .grey[
color: Colors 300],
.black26, child: Icon(
blurRadius: Icons
6, .broken_image,
offset: Offset( color:
2, Colors.grey[700]),
2),
),
],
),
child:
ClipRRect(
borderRadius:
BorderRadius.circular(
12),
child: Image
.network(
imageUrl,
fit: BoxFit
.cover,
errorBuilder: (context,
error,
stackTrace) =>
Container(
color: Colors
.grey[300],
child: Icon(
Icons
.broken_image,
color:
Colors.grey[700]),
),
), ),
), ),
), ),
Positioned( ),
right: 4, const Positioned(
bottom: 4, right: 4,
child: Icon( bottom: 4,
Icons child: Icon(
.zoom_in, Icons
color: Colors .zoom_in,
.white70, color: Colors
size: 16), .white70,
), size: 16),
], ),
), ],
); ),
}, );
separatorBuilder: (_, },
__) => separatorBuilder:
SizedBox(width: 12), (_, __) =>
), const SizedBox(
width: 12),
), ),
SizedBox(height: 12), ),
], const SizedBox(height: 12),
], ],
), ],
), ),
], ),
), ],
); ),
}), );
},
),
); );
}, },
), ),

View File

@ -124,7 +124,12 @@ class _DailyProgressReportFilterState extends State<DailyProgressReportFilter> {
), ),
child: const Text('Apply Filter'), child: const Text('Apply Filter'),
onPressed: () { onPressed: () {
Navigator.pop(context, {}); WidgetsBinding.instance.addPostFrameCallback((_) {
Navigator.pop(context, {
'startDate': widget.controller.startDateTask,
'endDate': widget.controller.endDateTask,
});
});
}, },
), ),
), ),