main
dart 165 lines 4.43 KB
Raw
1 import 'package:hugeicons/hugeicons.dart';
2 import 'package:flutter/material.dart';
3
4 import '../theme/colors.dart';
5 import 'app_sizes.dart';
6
7 class AppButton extends StatelessWidget {
8 const AppButton({
9 super.key,
10 required this.label,
11 this.onPressed,
12 this.icon,
13 this.variant = AppButtonVariant.primary,
14 this.isLoading = false,
15 this.isFullWidth = false,
16 this.size = AppButtonSize.medium,
17 });
18
19 final String label;
20 final VoidCallback? onPressed;
21 final List<List<dynamic>>? icon;
22 final AppButtonVariant variant;
23 final bool isLoading;
24 final bool isFullWidth;
25 final AppButtonSize size;
26
27 @override
28 Widget build(BuildContext context) {
29 final isDark = Theme.of(context).brightness == Brightness.dark;
30 final accent = isDark ? AppColors.darkAccent : AppColors.lightAccent;
31 final height = switch (size) {
32 AppButtonSize.small => 32.0,
33 AppButtonSize.medium => 44.0,
34 AppButtonSize.large => 52.0,
35 };
36
37 final child = isLoading
38 ? SizedBox(
39 width: 18,
40 height: 18,
41 child: CircularProgressIndicator(
42 strokeWidth: 2,
43 color: variant == AppButtonVariant.primary
44 ? (isDark ? AppColors.darkBackground : Colors.white)
45 : accent,
46 ),
47 )
48 : Row(
49 mainAxisSize: MainAxisSize.min,
50 children: [
51 if (icon != null) ...[
52 HugeIcon(icon: icon!, size: 18),
53 const SizedBox(width: AppSizes.sm),
54 ],
55 Text(label),
56 ],
57 );
58
59 return switch (variant) {
60 AppButtonVariant.primary => SizedBox(
61 height: height,
62 width: isFullWidth ? double.infinity : null,
63 child: ElevatedButton(
64 onPressed: isLoading ? null : onPressed,
65 child: child,
66 ),
67 ),
68 AppButtonVariant.outline => SizedBox(
69 height: height,
70 width: isFullWidth ? double.infinity : null,
71 child: OutlinedButton(
72 onPressed: isLoading ? null : onPressed,
73 child: child,
74 ),
75 ),
76 AppButtonVariant.ghost => SizedBox(
77 height: height,
78 width: isFullWidth ? double.infinity : null,
79 child: TextButton(
80 onPressed: isLoading ? null : onPressed,
81 child: child,
82 ),
83 ),
84 AppButtonVariant.destructive => SizedBox(
85 height: height,
86 width: isFullWidth ? double.infinity : null,
87 child: OutlinedButton(
88 onPressed: isLoading ? null : onPressed,
89 style: OutlinedButton.styleFrom(
90 side: const BorderSide(color: Colors.red),
91 foregroundColor: Colors.red,
92 ),
93 child: child,
94 ),
95 ),
96 };
97 }
98 }
99
100 enum AppButtonVariant { primary, outline, ghost, destructive }
101
102 enum AppButtonSize { small, medium, large }
103
104 class AppCard extends StatelessWidget {
105 const AppCard({
106 super.key,
107 required this.child,
108 this.onTap,
109 this.padding,
110 this.margin,
111 this.borderRadius,
112 });
113
114 final Widget child;
115 final VoidCallback? onTap;
116 final EdgeInsetsGeometry? padding;
117 final EdgeInsetsGeometry? margin;
118 final double? borderRadius;
119
120 @override
121 Widget build(BuildContext context) {
122 final isDark = Theme.of(context).brightness == Brightness.dark;
123 final radius = borderRadius ?? AppSizes.radiusLg;
124
125 final container = Container(
126 padding: padding ?? const EdgeInsets.all(AppSizes.lg),
127 margin: margin ?? const EdgeInsets.only(bottom: AppSizes.sm),
128 decoration: BoxDecoration(
129 color: isDark ? AppColors.darkSurfaceCard : AppColors.lightSurface,
130 borderRadius: BorderRadius.circular(radius),
131 border: Border.all(
132 color: isDark ? AppColors.darkBorder : AppColors.lightBorder,
133 ),
134 ),
135 child: child,
136 );
137
138 if (onTap != null) {
139 return GestureDetector(onTap: onTap, child: container);
140 }
141
142 return container;
143 }
144 }
145
146 class AppLoadingIndicator extends StatelessWidget {
147 const AppLoadingIndicator({super.key, this.size = 24, this.strokeWidth = 2});
148
149 final double size;
150 final double strokeWidth;
151
152 @override
153 Widget build(BuildContext context) {
154 return SizedBox(
155 width: size,
156 height: size,
157 child: CircularProgressIndicator(
158 strokeWidth: strokeWidth,
159 color: Theme.of(context).brightness == Brightness.dark
160 ? AppColors.darkAccent
161 : AppColors.lightAccent,
162 ),
163 );
164 }
165 }