Aidra Driver 1.3.5+68
Aidra Driver - Your path to green energy
Loading...
Searching...
No Matches
rating_dialog.dart
Go to the documentation of this file.
1import 'package:easy_localization/easy_localization.dart';
2import 'package:flutter/material.dart';
3import 'package:flutter_bloc/flutter_bloc.dart';
4import 'package:flutter_rating_bar/flutter_rating_bar.dart';
5import 'package:flutter_screenutil/flutter_screenutil.dart';
6
7import '../../../bloc/collections_information_bloc/collections_information_bloc.dart';
8
9class RatingDialog extends StatefulWidget {
11 final Function() onRatingSuccess;
12
14 super.key,
15 required this.collectionId,
16 required this.onRatingSuccess,
17 });
18
19 @override
20 State<RatingDialog> createState() => _RatingDialogState();
21}
22
23class _RatingDialogState extends State<RatingDialog> {
24 double _rating = 5;
26 final TextEditingController _noteController = TextEditingController();
27
28 @override
29 void initState() {
30 super.initState();
31 context.read<CollectionsInformationBloc>().add(GetLowRatingResonsListEvent());
32 }
33
34 @override
35 void dispose() {
36 _noteController.dispose();
37 super.dispose();
38 }
39
40 @override
41 Widget build(BuildContext context) {
42 final theme = Theme.of(context);
43
44 return BlocListener<CollectionsInformationBloc, CollectionsInformationState>(
45 listener: (context, state) {
46 if (state is CollectionRatingSuccess) {
47 widget.onRatingSuccess();
48 Navigator.pop(context);
49 } else if (state is CollectionRatingError) {
50 ScaffoldMessenger.of(context).showSnackBar(
51 SnackBar(
52 content: Text(
53 'Error submitting rating: ${state.failure}',
54 style: TextStyle(color: theme.colorScheme.onError),
55 ),
56 backgroundColor: theme.colorScheme.error,
57 behavior: SnackBarBehavior.floating,
58 shape: RoundedRectangleBorder(
59 borderRadius: BorderRadius.circular(8.sp),
60 ),
61 ),
62 );
63 }
64 },
65 child: Dialog(
66 backgroundColor: Colors.transparent,
67 elevation: 0,
68 child: Container(
69 decoration: BoxDecoration(
70 color: theme.colorScheme.surface,
71 borderRadius: BorderRadius.circular(24.sp),
72 boxShadow: [
73 BoxShadow(
74 color: Colors.black.withValues(alpha: 0.1),
75 blurRadius: 20,
76 offset: const Offset(0, 10),
77 ),
78 ],
79 ),
80 child: SingleChildScrollView(
81 child: Padding(
82 padding: EdgeInsets.all(24.sp),
84 mainAxisSize: MainAxisSize.min,
85 children: [
86 // Header with illustration
87 Container(
88 padding: EdgeInsets.symmetric(vertical: 16.sp),
89 child: Icon(
90 Icons.rate_review_rounded,
91 size: 48.sp,
92 color: theme.colorScheme.primary,
93 ),
94 ),
95
96 // Title
97 Text(
98 'full_fill_collection.how_was_the_collection'.tr(),
99 style: theme.textTheme.headlineSmall?.copyWith(
100 fontWeight: FontWeight.bold,
101 color: theme.colorScheme.onSurface,
102 ),
103 textAlign: TextAlign.center,
104 ),
105
106 SizedBox(height: 8.sp),
107
108 // Subtitle
109 Text(
110 'full_fill_collection.your_feedback'.tr(),
111 style: theme.textTheme.bodyMedium?.copyWith(
112 color: theme.colorScheme.onSurface.withValues(alpha: 0.6),
113 ),
114 textAlign: TextAlign.center,
115 ),
116
117 SizedBox(height: 24.sp),
118
119 // Rating Stars
120 Container(
121 decoration: BoxDecoration(
122 color: theme.colorScheme.primary.withValues(alpha: 0.05),
123 borderRadius: BorderRadius.circular(16.sp),
124 ),
125 padding: EdgeInsets.symmetric(vertical: 16.sp),
126 child: RatingBar.builder(
127 initialRating: 5,
128 minRating: 1,
129 direction: Axis.horizontal,
130 allowHalfRating: false,
131 itemCount: 5,
132 itemPadding: EdgeInsets.symmetric(horizontal: 4.sp),
133 itemBuilder: (context, _) => Icon(
134 Icons.star_rounded,
135 color: theme.colorScheme.primary,
136 ),
137 onRatingUpdate: (rating) {
138 setState(() {
139 _rating = rating;
140 _selectedReasonId = null;
141 });
142 },
143 ),
144 ),
145
146 if (_rating <= 3) ...[
147 SizedBox(height: 24.sp),
148 BlocBuilder<CollectionsInformationBloc, CollectionsInformationState>(
149 buildWhen: (previous, current) => current is CollectionLowRatingReasonsLoaded || current is CollectionLowRatingReasonsLoading || current is CollectionLowRatingReasonsError,
150 builder: (context, state) {
151 if (state is CollectionLowRatingReasonsLoading) {
152 return Center(
153 child: CircularProgressIndicator(
154 color: theme.colorScheme.primary,
155 ),
156 );
157 } else if (state is CollectionLowRatingReasonsError) {
158 return Text(
159 'Error loading reasons: ${state.failure}',
160 style: TextStyle(color: theme.colorScheme.error),
161 );
162 } else if (state is CollectionLowRatingReasonsLoaded) {
163 if (state.reasons.isEmpty) {
164 return Text(
165 'full_fill_collection.no_rating_reason'.tr(),
166 style: theme.textTheme.bodyLarge?.copyWith(
167 color: theme.colorScheme.onSurface.withValues(alpha: 0.6),
168 ),
169 textAlign: TextAlign.center,
170 );
171 }
172 return Container(
173 decoration: BoxDecoration(
174 borderRadius: BorderRadius.circular(12.sp),
175 border: Border.all(
176 color: theme.colorScheme.outline.withValues(alpha: 0.2),
177 ),
178 ),
179 child: DropdownButtonHideUnderline(
180 child: DropdownButton<String>(
181 isExpanded: true,
182 value: _selectedReasonId,
183 hint: Padding(
184 padding: EdgeInsets.symmetric(horizontal: 16.sp),
185 child: Text(
186 'full_fill_collection.what_went_wrong'.tr(),
187 style: theme.textTheme.bodyLarge?.copyWith(
188 color: theme.colorScheme.onSurface.withValues(alpha: 0.6),
189 ),
190 ),
191 ),
192 icon: Icon(
193 Icons.keyboard_arrow_down_rounded,
194 color: theme.colorScheme.primary,
195 ),
196 padding: EdgeInsets.symmetric(horizontal: 16.sp),
197 borderRadius: BorderRadius.circular(12.sp),
198 items: state.reasons.map((reason) {
199 return DropdownMenuItem<String>(
200 value: reason.id?.toString(),
201 child: Text(
202 reason.name ?? '',
203 style: theme.textTheme.bodyLarge,
204 ),
205 );
206 }).toList(),
207 onChanged: (String? newValue) {
208 setState(() {
209 _selectedReasonId = newValue;
210 });
211 },
212 ),
213 ),
214 );
215 }
216 return const SizedBox.shrink();
217 },
218 ),
219
220 SizedBox(height: 16.sp),
221
222 TextField(
223 controller: _noteController,
224 maxLines: 3,
225 style: theme.textTheme.bodyLarge,
226 decoration: InputDecoration(
227 hintText: 'full_fill_collection.tell_us_more'.tr(),
228 hintStyle: theme.textTheme.bodyLarge?.copyWith(
229 color: theme.colorScheme.onSurface.withValues(alpha: 0.6),
230 ),
231 border: OutlineInputBorder(
232 borderRadius: BorderRadius.circular(12.sp),
233 borderSide: BorderSide(
234 color: theme.colorScheme.outline.withValues(alpha: 0.2),
235 ),
236 ),
237 enabledBorder: OutlineInputBorder(
238 borderRadius: BorderRadius.circular(12.sp),
239 borderSide: BorderSide(
240 color: theme.colorScheme.outline.withValues(alpha: 0.2),
241 ),
242 ),
243 focusedBorder: OutlineInputBorder(
244 borderRadius: BorderRadius.circular(12.sp),
245 borderSide: BorderSide(
246 color: theme.colorScheme.primary,
247 ),
248 ),
249 contentPadding: EdgeInsets.all(16.sp),
250 filled: true,
251 fillColor: theme.colorScheme.surface,
252 ),
253 ),
254 ],
255 SizedBox(height: 24.sp),
256 BlocBuilder<CollectionsInformationBloc, CollectionsInformationState>(
257 buildWhen: (previous, current) => current is CollectionRatingLoading || current is CollectionRatingSuccess || current is CollectionRatingError,
258 builder: (context, state) {
259 final isLoading = state is CollectionRatingLoading;
260
261 return ElevatedButton(
262 onPressed: isLoading ? null : () {
263 final state = context.read<CollectionsInformationBloc>().state;
264 final hasReasons = state is CollectionLowRatingReasonsLoaded && state.reasons.isNotEmpty;
265
266 if (_rating <= 3 && hasReasons && _selectedReasonId == null) {
267 ScaffoldMessenger.of(context).showSnackBar(
268 SnackBar(
269 content: Text(
270 'full_fill_collection.select_a_reason'.tr(),
271 style: TextStyle(color: theme.colorScheme.onError),
272 ),
273 backgroundColor: theme.colorScheme.error,
274 behavior: SnackBarBehavior.floating,
275 shape: RoundedRectangleBorder(
276 borderRadius: BorderRadius.circular(8.sp),
277 ),
278 ),
279 );
280 return;
281 }
282
283 context.read<CollectionsInformationBloc>().add(
284 SendCollectionRatingEvent(
285 id: widget.collectionId,
286 rate: _rating.toInt().toString(),
287 reasonId: _rating <= 3 ? _selectedReasonId : null,
288 note: _rating <= 3 ? _noteController.text : null,
289 ),
290 );
291 },
292 style: ElevatedButton.styleFrom(
293 backgroundColor: theme.colorScheme.primary,
294 foregroundColor: theme.colorScheme.onPrimary,
295 padding: EdgeInsets.symmetric(
296 horizontal: 24.sp,
297 vertical: 12.sp,
298 ),
299 shape: RoundedRectangleBorder(
300 borderRadius: BorderRadius.circular(8.sp),
301 ),
302 ),
304 ? SizedBox(
305 height: 20.sp,
306 width: 20.sp,
307 child: CircularProgressIndicator(
308 strokeWidth: 2.sp,
309 valueColor: AlwaysStoppedAnimation<Color>(
310 theme.colorScheme.onPrimary,
311 ),
312 ),
313 )
314 : Text(
315 'full_fill_collection.submit'.tr(),
316 style: theme.textTheme.bodyLarge?.copyWith(
317 color: theme.colorScheme.onPrimary,
318 fontWeight: FontWeight.bold,
319 ),
320 ),
321 );
322 },
323 ),
324 ],
325 ),
326 ),
327 ),
328 ),
329 ),
330 );
331 }
332}
override void initState()
override void dispose()
class App extends StatefulWidget build(BuildContext context)
Definition app.dart:31
AuthGuard _()
bool isLoading
final Function() onRatingSuccess
const RatingDialog({ super.key, required this.collectionId, required this.onRatingSuccess, })
override State< RatingDialog > createState()
final String note
const CollectionLowRatingReasonsLoaded({required this.reasons})
const CollectionRatingSuccess({required this.isDone})
final Widget child
final EdgeInsets padding
class Partner String
final Color color
Definition failures.dart:1
List< DashboardItem > get items
final VoidCallback onPressed
class RatingDialog extends StatefulWidget _rating
final TextEditingController _noteController
String _selectedReasonId
style Text( '${ 'scheduling.reference'.tr()}:${collection.internalCode}', style:Theme.of(context).textTheme.bodySmall,)
style SizedBox(height:2.h)
style Column(crossAxisAlignment:CrossAxisAlignment.end, children:[Container(padding:EdgeInsets.symmetric(horizontal:8.w, vertical:4.h), decoration:BoxDecoration(color:ColorPalette.tiffanyBlue.withValues(alpha:0.1), borderRadius:BorderRadius.circular(12),), child:Text(collection.type ?? '', style:Theme.of(context).textTheme.bodySmall?.copyWith(color:ColorPalette.tiffanyBlue, fontWeight:FontWeight.bold,),),),],)