dev
dart 475 lines 16.4 KB
Raw
1 import 'package:cake_wallet/utils/image_utill.dart';
2 import 'package:flutter/material.dart';
3
4 class ProviderOptionTile extends StatelessWidget {
5 const ProviderOptionTile({
6 required this.onPressed,
7 required this.lightImagePath,
8 required this.darkImagePath,
9 required this.title,
10 this.topLeftSubTitle,
11 this.topRightSubTitle,
12 this.bottomLeftSubTitle,
13 this.bottomRightSubTitle,
14 this.leftSubTitleIconPath,
15 this.rightSubTitleLightIconPath,
16 this.rightSubTitleDarkIconPath,
17 this.description,
18 this.badges,
19 this.borderRadius,
20 this.imageHeight,
21 this.imageWidth,
22 this.padding,
23 this.titleTextStyle,
24 this.firstSubTitleTextStyle,
25 this.secondSubTitleTextStyle,
26 this.leadingIcon,
27 this.selectedBackgroundColor,
28 this.isSelected = false,
29 required this.isLightMode,
30 });
31
32 final VoidCallback onPressed;
33 final String lightImagePath;
34 final String darkImagePath;
35 final String title;
36 final String? topLeftSubTitle;
37 final String? topRightSubTitle;
38 final String? bottomLeftSubTitle;
39 final String? bottomRightSubTitle;
40 final String? leftSubTitleIconPath;
41 final String? rightSubTitleLightIconPath;
42 final String? rightSubTitleDarkIconPath;
43 final String? description;
44 final List<String>? badges;
45 final double? borderRadius;
46 final double? imageHeight;
47 final double? imageWidth;
48 final EdgeInsets? padding;
49 final TextStyle? titleTextStyle;
50 final TextStyle? firstSubTitleTextStyle;
51 final TextStyle? secondSubTitleTextStyle;
52 final IconData? leadingIcon;
53 final Color? selectedBackgroundColor;
54 final bool isSelected;
55 final bool isLightMode;
56
57 @override
58 Widget build(BuildContext context) {
59 final backgroundColor = isSelected
60 ? Theme.of(context).colorScheme.primary
61 : Theme.of(context).colorScheme.surfaceContainer;
62
63 final textColor = isSelected
64 ? Theme.of(context).colorScheme.onPrimary
65 : Theme.of(context).colorScheme.onSurface;
66
67 final badgeColor = isSelected
68 ? Theme.of(context).colorScheme.surfaceContainer
69 : Theme.of(context).colorScheme.onSurface;
70
71 final badgeTextColor = isSelected
72 ? Theme.of(context).colorScheme.onSurface
73 : Theme.of(context).colorScheme.surfaceContainer;
74
75 final imagePath = isSelected
76 ? !isLightMode
77 ? darkImagePath
78 : lightImagePath
79 : !isLightMode
80 ? lightImagePath
81 : darkImagePath;
82
83 final rightSubTitleIconPath = isSelected
84 ? !isLightMode
85 ? rightSubTitleDarkIconPath
86 : rightSubTitleLightIconPath
87 : !isLightMode
88 ? rightSubTitleLightIconPath
89 : rightSubTitleDarkIconPath;
90
91 return GestureDetector(
92 onTap: onPressed,
93 child: Container(
94 width: double.infinity,
95 alignment: Alignment.center,
96 decoration: BoxDecoration(
97 borderRadius: BorderRadius.all(Radius.circular(borderRadius ?? 12)),
98 border: isSelected && !isLightMode ? Border.all(color: textColor) : null,
99 color: backgroundColor,
100 ),
101 child: Padding(
102 padding: padding ?? const EdgeInsets.all(16),
103 child: Column(
104 crossAxisAlignment: CrossAxisAlignment.center,
105 children: [
106 Row(
107 children: [
108 ImageUtil.getImageFromPath(
109 imagePath: imagePath, height: imageHeight, width: imageWidth),
110 SizedBox(width: 8),
111 Expanded(
112 child: Container(
113 child: Row(
114 children: [
115 Expanded(
116 child: Text(
117 title,
118 style: titleTextStyle ??
119 Theme.of(context).textTheme.bodyLarge?.copyWith(
120 color: textColor,
121 fontWeight: FontWeight.w700,
122 fontSize: 18,
123 ),
124 ),
125 ),
126 Row(
127 children: [
128 if (leadingIcon != null)
129 Icon(leadingIcon, size: 16, color: textColor),
130 ],
131 )
132 ],
133 ),
134 ),
135 ),
136 ],
137 ),
138 if (topLeftSubTitle != null || topRightSubTitle != null)
139 subTitleWidget(
140 leftSubTitle: topLeftSubTitle,
141 subTitleIconPath: leftSubTitleIconPath,
142 textColor: textColor,
143 rightSubTitle: topRightSubTitle,
144 rightSubTitleIconPath: rightSubTitleIconPath),
145 if (bottomLeftSubTitle != null || bottomRightSubTitle != null)
146 subTitleWidget(
147 leftSubTitle: bottomLeftSubTitle,
148 textColor: textColor,
149 subTitleFontSize: 12,
150 ),
151 if (badges != null && badges!.isNotEmpty)
152 Padding(
153 padding: const EdgeInsets.only(top: 12),
154 child: Row(
155 children: [
156 ...badges!
157 .map(
158 (badge) => Badge(
159 title: badge,
160 textColor: badgeTextColor,
161 backgroundColor: badgeColor,
162 ),
163 )
164 .toList()
165 ],
166 ),
167 )
168 ],
169 ),
170 ),
171 ),
172 );
173 }
174 }
175
176 class subTitleWidget extends StatelessWidget {
177 const subTitleWidget({
178 super.key,
179 this.leftSubTitle,
180 this.subTitleIconPath,
181 required this.textColor,
182 this.rightSubTitle,
183 this.rightSubTitleIconPath,
184 this.subTitleFontSize = 16,
185 });
186
187 final String? leftSubTitle;
188 final String? subTitleIconPath;
189 final Color textColor;
190 final String? rightSubTitle;
191 final String? rightSubTitleIconPath;
192 final double subTitleFontSize;
193
194 @override
195 Widget build(BuildContext context) {
196 return Row(
197 mainAxisAlignment: MainAxisAlignment.spaceBetween,
198 children: [
199 leftSubTitle != null || subTitleIconPath != null
200 ? Row(
201 children: [
202 if (subTitleIconPath != null && subTitleIconPath!.isNotEmpty)
203 Padding(
204 padding: const EdgeInsets.only(right: 6),
205 child: ImageUtil.getImageFromPath(imagePath: subTitleIconPath!),
206 ),
207 Text(
208 leftSubTitle ?? '',
209 style: Theme.of(context).textTheme.bodyMedium!.copyWith(
210 fontSize: subTitleFontSize, fontWeight: FontWeight.w700, color: textColor),
211 ),
212 ],
213 )
214 : Offstage(),
215 rightSubTitle != null || rightSubTitleIconPath != null
216 ? Row(
217 children: [
218 if (rightSubTitleIconPath != null && rightSubTitleIconPath!.isNotEmpty)
219 Padding(
220 padding: const EdgeInsets.only(right: 4),
221 child: ImageUtil.getImageFromPath(imagePath: rightSubTitleIconPath!),
222 ),
223 Text(
224 rightSubTitle ?? '',
225 style: Theme.of(context).textTheme.bodyMedium!.copyWith(
226 fontSize: subTitleFontSize, fontWeight: FontWeight.w700, color: textColor),
227 ),
228 ],
229 )
230 : Offstage(),
231 ],
232 );
233 }
234 }
235
236 class Badge extends StatelessWidget {
237 Badge({required this.textColor, required this.backgroundColor, required this.title});
238
239 final String title;
240 final Color textColor;
241 final Color backgroundColor;
242
243 @override
244 Widget build(BuildContext context) {
245 return Padding(
246 padding: const EdgeInsets.only(right: 8),
247 child: FittedBox(
248 fit: BoxFit.fitHeight,
249 child: Container(
250 padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4),
251 decoration: BoxDecoration(
252 borderRadius: BorderRadius.all(Radius.circular(24)), color: backgroundColor),
253 alignment: Alignment.center,
254 child: Text(
255 title,
256 style: Theme.of(context).textTheme.bodySmall!.copyWith(
257 color: textColor,
258 fontWeight: FontWeight.w600,
259 ),
260 ),
261 ),
262 ),
263 );
264 }
265 }
266
267 class OptionTilePlaceholder extends StatefulWidget {
268 OptionTilePlaceholder({
269 this.borderRadius,
270 this.imageHeight,
271 this.imageWidth,
272 this.padding,
273 this.leadingIcon,
274 this.withBadge = true,
275 this.withSubtitle = true,
276 this.isDarkTheme = false,
277 this.errorText,
278 });
279
280 final double? borderRadius;
281 final double? imageHeight;
282 final double? imageWidth;
283 final EdgeInsets? padding;
284 final IconData? leadingIcon;
285 final bool withBadge;
286 final bool withSubtitle;
287 final bool isDarkTheme;
288 final String? errorText;
289
290 @override
291 _OptionTilePlaceholderState createState() => _OptionTilePlaceholderState();
292 }
293
294 class _OptionTilePlaceholderState extends State<OptionTilePlaceholder>
295 with SingleTickerProviderStateMixin {
296 late AnimationController _controller;
297 late Animation<double> _animation;
298
299 @override
300 void initState() {
301 super.initState();
302
303 _controller = AnimationController(
304 duration: const Duration(seconds: 2),
305 vsync: this,
306 )..repeat();
307
308 _animation = CurvedAnimation(
309 parent: _controller,
310 curve: Curves.linear,
311 );
312 }
313
314 @override
315 void dispose() {
316 _controller.dispose();
317 super.dispose();
318 }
319
320 @override
321 Widget build(BuildContext context) {
322 final backgroundColor = Theme.of(context).colorScheme.surfaceContainer;
323 final titleColor = Theme.of(context).colorScheme.onSurface.withOpacity(0.4);
324
325 return widget.errorText != null
326 ? Container(
327 width: double.infinity,
328 padding: widget.padding ?? EdgeInsets.all(16),
329 alignment: Alignment.center,
330 decoration: BoxDecoration(
331 borderRadius: BorderRadius.all(
332 Radius.circular(widget.borderRadius ?? 12),
333 ),
334 color: backgroundColor,
335 ),
336 child: Column(
337 children: [
338 Text(
339 widget.errorText!,
340 style: Theme.of(context).textTheme.bodyMedium!.copyWith(
341 color: titleColor,
342 fontSize: 16,
343 ),
344 ),
345 if (widget.withSubtitle) SizedBox(height: 8),
346 Text(
347 '',
348 style: Theme.of(context).textTheme.bodyMedium!.copyWith(
349 color: titleColor,
350 fontSize: 16,
351 ),
352 ),
353 ],
354 ),
355 )
356 : AnimatedBuilder(
357 animation: _animation,
358 builder: (context, child) {
359 return Stack(
360 children: [
361 Container(
362 width: double.infinity,
363 padding: widget.padding ?? EdgeInsets.all(16),
364 alignment: Alignment.center,
365 decoration: BoxDecoration(
366 borderRadius: BorderRadius.all(Radius.circular(widget.borderRadius ?? 12)),
367 color: backgroundColor,
368 ),
369 child: Column(
370 crossAxisAlignment: CrossAxisAlignment.center,
371 children: [
372 Row(
373 children: [
374 Container(
375 height: widget.imageHeight ?? 35,
376 width: widget.imageWidth ?? 35,
377 decoration: BoxDecoration(
378 color: titleColor,
379 shape: BoxShape.circle,
380 ),
381 ),
382 SizedBox(width: 8),
383 Expanded(
384 child: Container(
385 child: Row(
386 mainAxisAlignment: MainAxisAlignment.spaceBetween,
387 children: [
388 Container(
389 height: 20,
390 width: 70,
391 decoration: BoxDecoration(
392 color: titleColor,
393 borderRadius: BorderRadius.all(Radius.circular(8)),
394 ),
395 ),
396 if (widget.leadingIcon != null)
397 Icon(widget.leadingIcon, size: 16, color: titleColor),
398 ],
399 ),
400 ),
401 ),
402 ],
403 ),
404 if (widget.withSubtitle)
405 Padding(
406 padding: EdgeInsets.symmetric(vertical: 8),
407 child: Row(
408 mainAxisAlignment: MainAxisAlignment.spaceBetween,
409 children: [
410 Container(
411 height: 20,
412 width: 170,
413 decoration: BoxDecoration(
414 color: titleColor,
415 borderRadius: BorderRadius.all(Radius.circular(8)),
416 ),
417 ),
418 ],
419 ),
420 ),
421 if (widget.withBadge)
422 Padding(
423 padding: const EdgeInsets.only(top: 16.0),
424 child: Row(
425 children: [
426 Container(
427 height: 30,
428 width: 70,
429 decoration: BoxDecoration(
430 color: titleColor,
431 borderRadius: BorderRadius.all(Radius.circular(20)),
432 ),
433 ),
434 SizedBox(width: 8),
435 Container(
436 height: 30,
437 width: 70,
438 decoration: BoxDecoration(
439 color: titleColor,
440 borderRadius: BorderRadius.all(Radius.circular(20)),
441 ),
442 ),
443 ],
444 ),
445 ),
446 ],
447 ),
448 ),
449 Positioned.fill(
450 child: Container(
451 decoration: BoxDecoration(
452 borderRadius: BorderRadius.all(Radius.circular(widget.borderRadius ?? 12)),
453 gradient: LinearGradient(
454 begin: Alignment(-2, -4),
455 end: Alignment(2, 4),
456 stops: [
457 _animation.value - 0.2,
458 _animation.value,
459 _animation.value + 0.2,
460 ],
461 colors: [
462 backgroundColor.withOpacity(widget.isDarkTheme ? 0.4 : 0.7),
463 backgroundColor.withOpacity(widget.isDarkTheme ? 0.7 : 0.4),
464 backgroundColor.withOpacity(widget.isDarkTheme ? 0.4 : 0.7),
465 ],
466 ),
467 ),
468 ),
469 ),
470 ],
471 );
472 },
473 );
474 }
475 }