@@ -2,21 +2,23 @@ import 'dart:io';
22
33import 'package:flutter/material.dart' ;
44import 'package:flutter_screenutil/flutter_screenutil.dart' ;
5+ import 'package:whitenoise/domain/models/media_file_upload.dart' ;
56import 'package:whitenoise/ui/chat/widgets/media_thumbnail.dart' ;
67import 'package:whitenoise/ui/core/themes/assets.dart' ;
78import 'package:whitenoise/ui/core/themes/src/extensions.dart' ;
89import 'package:whitenoise/ui/core/ui/wn_icon_button.dart' ;
10+ import 'package:whitenoise/ui/core/ui/wn_image.dart' ;
911
1012class ChatInputMediaPreview extends StatefulWidget {
1113 const ChatInputMediaPreview ({
1214 super .key,
13- required this .imagePaths ,
15+ required this .mediaItems ,
1416 required this .onRemoveImage,
1517 required this .onAddMore,
1618 this .isReply = false ,
1719 });
1820
19- final List <String > imagePaths ;
21+ final List <MediaFileUpload > mediaItems ;
2022 final void Function (int index) onRemoveImage;
2123 final VoidCallback onAddMore;
2224 final bool isReply;
@@ -64,7 +66,7 @@ class _ChatInputMediaPreviewState extends State<ChatInputMediaPreview> {
6466
6567 @override
6668 Widget build (BuildContext context) {
67- if (widget.imagePaths .isEmpty) return const SizedBox .shrink ();
69+ if (widget.mediaItems .isEmpty) return const SizedBox .shrink ();
6870
6971 return Container (
7072 padding: EdgeInsets .symmetric (horizontal: 14. w, vertical: widget.isReply ? 8. h : 16. h),
@@ -75,18 +77,73 @@ class _ChatInputMediaPreviewState extends State<ChatInputMediaPreview> {
7577 ListView .separated (
7678 controller: _scrollController,
7779 scrollDirection: Axis .horizontal,
78- itemCount: widget.imagePaths .length,
80+ itemCount: widget.mediaItems .length,
7981 separatorBuilder: (context, index) => SizedBox (width: _imageSpacing.w),
8082 itemBuilder: (context, index) {
81- final imagePath = widget.imagePaths[index];
82- return ClipRRect (
83- child: Image .file (
84- File (imagePath),
85- height: _imageHeight.h,
86- width: _imageWidth.w,
87- fit: BoxFit .cover,
88- errorBuilder: (context, error, stackTrace) => const SizedBox .shrink (),
89- ),
83+ final mediaItem = widget.mediaItems[index];
84+ return mediaItem.when (
85+ uploading:
86+ (filePath) => Stack (
87+ children: [
88+ ClipRRect (
89+ child: Image .file (
90+ File (filePath),
91+ height: _imageHeight.h,
92+ width: _imageWidth.w,
93+ fit: BoxFit .cover,
94+ ),
95+ ),
96+ Positioned .fill (
97+ child: Container (
98+ color: context.colors.solidNeutralBlack.withValues (alpha: 0.5 ),
99+ child: Center (
100+ child: SizedBox (
101+ width: 32 ,
102+ height: 32 ,
103+ child: CircularProgressIndicator (
104+ strokeWidth: 2 ,
105+ color: context.colors.solidNeutralWhite,
106+ ),
107+ ),
108+ ),
109+ ),
110+ ),
111+ ],
112+ ),
113+ uploaded:
114+ (file, originalFilePath) => ClipRRect (
115+ child: Image .file (
116+ File (originalFilePath),
117+ height: _imageHeight.h,
118+ width: _imageWidth.w,
119+ fit: BoxFit .cover,
120+ ),
121+ ),
122+ failed:
123+ (filePath, error) => Stack (
124+ children: [
125+ ClipRRect (
126+ child: Image .file (
127+ File (filePath),
128+ height: _imageHeight.h,
129+ width: _imageWidth.w,
130+ fit: BoxFit .cover,
131+ ),
132+ ),
133+ Positioned .fill (
134+ child: Container (
135+ color: context.colors.solidNeutralBlack.withValues (alpha: 0.5 ),
136+ child: Center (
137+ child: WnImage (
138+ AssetsPaths .icErrorFilled,
139+ color: context.colors.destructive,
140+ size: 48. w,
141+ ),
142+ ),
143+ ),
144+ ),
145+ ],
146+ ),
90147 );
91148 },
92149 ),
@@ -98,7 +155,7 @@ class _ChatInputMediaPreviewState extends State<ChatInputMediaPreview> {
98155 height: 32. h,
99156 child: ListView .separated (
100157 scrollDirection: Axis .horizontal,
101- itemCount: widget.imagePaths .length + 1 ,
158+ itemCount: widget.mediaItems .length + 1 ,
102159 separatorBuilder: (context, index) => SizedBox (width: _thumbnailSpacing.w),
103160 itemBuilder: (context, index) {
104161 if (index == 0 ) {
@@ -112,12 +169,13 @@ class _ChatInputMediaPreviewState extends State<ChatInputMediaPreview> {
112169 iconColor: context.colors.primary,
113170 );
114171 }
115- final imageIndex = index - 1 ;
116- final imagePath = widget.imagePaths[imageIndex];
172+ final itemIndex = index - 1 ;
173+ final mediaItem = widget.mediaItems[itemIndex];
174+
117175 return MediaThumbnail (
118- path : imagePath ,
119- isActive: _activeThumbIndex == imageIndex ,
120- onTap: () => _handleThumbnailTap (imageIndex ),
176+ mediaItem : mediaItem ,
177+ isActive: _activeThumbIndex == itemIndex ,
178+ onTap: () => _handleThumbnailTap (itemIndex ),
121179 );
122180 },
123181 ),
0 commit comments