| 1 | import 'package:cake_wallet/generated/i18n.dart'; |
| 2 | import 'package:cake_wallet/utils/responsive_layout_util.dart'; |
| 3 | import 'package:dotted_border/dotted_border.dart'; |
| 4 | import 'package:flutter/cupertino.dart'; |
| 5 | import 'package:flutter/material.dart'; |
| 6 | |
| 7 | class PrimaryButton extends StatelessWidget { |
| 8 | const PrimaryButton({ |
| 9 | required this.text, |
| 10 | required this.color, |
| 11 | required this.textColor, |
| 12 | this.onPressed, |
| 13 | this.isDisabled = false, |
| 14 | this.isDottedBorder = false, |
| 15 | this.borderColor = Colors.black, |
| 16 | this.onDisabledPressed, |
| 17 | this.borderRadius, |
| 18 | super.key, |
| 19 | }); |
| 20 | |
| 21 | final VoidCallback? onPressed; |
| 22 | final VoidCallback? onDisabledPressed; |
| 23 | final Color color; |
| 24 | final Color textColor; |
| 25 | final Color borderColor; |
| 26 | final String text; |
| 27 | final bool isDisabled; |
| 28 | final bool isDottedBorder; |
| 29 | final BorderRadius? borderRadius; |
| 30 | |
| 31 | @override |
| 32 | Widget build(BuildContext context) { |
| 33 | final content = ConstrainedBox( |
| 34 | constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint), |
| 35 | child: SizedBox( |
| 36 | width: double.infinity, |
| 37 | height: 52.0, |
| 38 | child: TextButton( |
| 39 | onPressed: |
| 40 | isDisabled ? (onDisabledPressed != null ? onDisabledPressed : null) : onPressed, |
| 41 | style: ButtonStyle( |
| 42 | backgroundColor: WidgetStateProperty.all( |
| 43 | isDisabled ? color.withOpacity(0.5) : color, |
| 44 | ), |
| 45 | shape: WidgetStateProperty.all<RoundedRectangleBorder>( |
| 46 | RoundedRectangleBorder( |
| 47 | borderRadius: borderRadius ?? BorderRadius.circular(18.0), |
| 48 | ), |
| 49 | ), |
| 50 | ), |
| 51 | child: Text( |
| 52 | text, |
| 53 | textAlign: TextAlign.center, |
| 54 | style: Theme.of(context).textTheme.bodyMedium!.copyWith( |
| 55 | fontSize: 15.0, |
| 56 | fontWeight: FontWeight.w600, |
| 57 | color: isDisabled ? textColor.withOpacity(0.5) : textColor, |
| 58 | ), |
| 59 | ), |
| 60 | ), |
| 61 | ), |
| 62 | ); |
| 63 | |
| 64 | return isDottedBorder |
| 65 | ? DottedBorder( |
| 66 | borderType: BorderType.RRect, |
| 67 | dashPattern: [6, 4], |
| 68 | color: borderColor, |
| 69 | strokeWidth: 2, |
| 70 | radius: Radius.circular(15), |
| 71 | child: content) |
| 72 | : content; |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | class LoadingPrimaryButton extends StatelessWidget { |
| 77 | const LoadingPrimaryButton({ |
| 78 | required this.onPressed, |
| 79 | required this.text, |
| 80 | required this.color, |
| 81 | required this.textColor, |
| 82 | this.isDisabled = false, |
| 83 | this.isLoading = false, |
| 84 | super.key, |
| 85 | }); |
| 86 | |
| 87 | final VoidCallback onPressed; |
| 88 | final Color color; |
| 89 | final Color textColor; |
| 90 | final bool isLoading; |
| 91 | final bool isDisabled; |
| 92 | final String text; |
| 93 | |
| 94 | @override |
| 95 | Widget build(BuildContext context) { |
| 96 | final isEnabled = !isLoading && !isDisabled; |
| 97 | |
| 98 | // The spinner replaces the label while loading, so the name is kept on a single |
| 99 | // semantics node that also reports the loading and disabled states. |
| 100 | return Semantics( |
| 101 | button: true, |
| 102 | enabled: isEnabled, |
| 103 | label: text, |
| 104 | value: isLoading ? S.of(context).loading : null, |
| 105 | onTap: isEnabled |
| 106 | ? () { |
| 107 | FocusScope.of(context).unfocus(); |
| 108 | onPressed.call(); |
| 109 | } |
| 110 | : null, |
| 111 | excludeSemantics: true, |
| 112 | child: ConstrainedBox( |
| 113 | constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint), |
| 114 | child: SizedBox( |
| 115 | width: double.infinity, |
| 116 | height: 52.0, |
| 117 | child: TextButton( |
| 118 | onPressed: (isLoading || isDisabled) |
| 119 | ? null |
| 120 | : () { |
| 121 | FocusScope.of(context).unfocus(); |
| 122 | onPressed.call(); |
| 123 | }, |
| 124 | style: ButtonStyle( |
| 125 | backgroundColor: |
| 126 | WidgetStateProperty.all(isDisabled ? color.withOpacity(0.5) : color), |
| 127 | shape: WidgetStateProperty.all<RoundedRectangleBorder>( |
| 128 | RoundedRectangleBorder( |
| 129 | borderRadius: BorderRadius.circular(18.0), |
| 130 | ), |
| 131 | )), |
| 132 | child: isLoading |
| 133 | ? CupertinoActivityIndicator(animating: true, color: textColor) |
| 134 | : Text( |
| 135 | text, |
| 136 | style: Theme.of(context).textTheme.bodyMedium!.copyWith( |
| 137 | fontSize: 15.0, |
| 138 | fontWeight: FontWeight.w600, |
| 139 | color: isDisabled ? textColor.withOpacity(0.5) : textColor, |
| 140 | ), |
| 141 | ), |
| 142 | ), |
| 143 | ), |
| 144 | ), |
| 145 | ); |
| 146 | } |
| 147 | } |
| 148 | |
| 149 | class PrimaryIconButton extends StatelessWidget { |
| 150 | const PrimaryIconButton({ |
| 151 | required this.onPressed, |
| 152 | required this.iconData, |
| 153 | required this.text, |
| 154 | required this.color, |
| 155 | required this.borderColor, |
| 156 | required this.iconColor, |
| 157 | required this.iconBackgroundColor, |
| 158 | required this.textColor, |
| 159 | this.mainAxisAlignment = MainAxisAlignment.start, |
| 160 | this.radius = 18, |
| 161 | super.key, |
| 162 | }); |
| 163 | |
| 164 | final VoidCallback onPressed; |
| 165 | final IconData iconData; |
| 166 | final Color color; |
| 167 | final Color borderColor; |
| 168 | final Color iconColor; |
| 169 | final Color iconBackgroundColor; |
| 170 | final String text; |
| 171 | final MainAxisAlignment mainAxisAlignment; |
| 172 | final Color textColor; |
| 173 | final double radius; |
| 174 | |
| 175 | @override |
| 176 | Widget build(BuildContext context) { |
| 177 | return ConstrainedBox( |
| 178 | constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint), |
| 179 | child: SizedBox( |
| 180 | width: double.infinity, |
| 181 | height: 52.0, |
| 182 | child: TextButton( |
| 183 | onPressed: onPressed, |
| 184 | style: ButtonStyle( |
| 185 | backgroundColor: WidgetStateProperty.all(color), |
| 186 | shape: WidgetStateProperty.all<RoundedRectangleBorder>( |
| 187 | RoundedRectangleBorder( |
| 188 | borderRadius: BorderRadius.circular(radius), |
| 189 | ), |
| 190 | )), |
| 191 | child: Stack( |
| 192 | children: <Widget>[ |
| 193 | Row( |
| 194 | mainAxisAlignment: mainAxisAlignment, |
| 195 | children: <Widget>[ |
| 196 | Container( |
| 197 | width: 26.0, |
| 198 | height: 52.0, |
| 199 | decoration: BoxDecoration(shape: BoxShape.circle, color: iconBackgroundColor), |
| 200 | child: Center( |
| 201 | child: Icon(iconData, color: iconColor, size: 22.0), |
| 202 | ), |
| 203 | ), |
| 204 | ], |
| 205 | ), |
| 206 | Container( |
| 207 | height: 52.0, |
| 208 | child: Center( |
| 209 | child: Text( |
| 210 | text, |
| 211 | style: Theme.of(context).textTheme.bodyMedium?.copyWith( |
| 212 | fontSize: 16, |
| 213 | color: textColor, |
| 214 | ), |
| 215 | ), |
| 216 | ), |
| 217 | ) |
| 218 | ], |
| 219 | ), |
| 220 | )), |
| 221 | ); |
| 222 | } |
| 223 | } |
| 224 | |
| 225 | class PrimaryImageButton extends StatelessWidget { |
| 226 | const PrimaryImageButton( |
| 227 | {required this.onPressed, |
| 228 | required this.image, |
| 229 | required this.text, |
| 230 | required this.color, |
| 231 | required this.textColor, |
| 232 | this.borderColor = Colors.transparent, |
| 233 | super.key}); |
| 234 | |
| 235 | final VoidCallback onPressed; |
| 236 | final Image image; |
| 237 | final Color color; |
| 238 | final Color textColor; |
| 239 | final Color borderColor; |
| 240 | final String text; |
| 241 | |
| 242 | @override |
| 243 | Widget build(BuildContext context) { |
| 244 | return ConstrainedBox( |
| 245 | constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint), |
| 246 | child: SizedBox( |
| 247 | width: double.infinity, |
| 248 | height: 52.0, |
| 249 | child: TextButton( |
| 250 | onPressed: onPressed, |
| 251 | style: ButtonStyle( |
| 252 | backgroundColor: WidgetStateProperty.all(color), |
| 253 | shape: WidgetStateProperty.all<RoundedRectangleBorder>( |
| 254 | RoundedRectangleBorder( |
| 255 | borderRadius: BorderRadius.circular(18.0), |
| 256 | ), |
| 257 | )), |
| 258 | child: Center( |
| 259 | child: Row( |
| 260 | mainAxisSize: MainAxisSize.min, |
| 261 | children: <Widget>[ |
| 262 | image, |
| 263 | SizedBox(width: 15), |
| 264 | Text( |
| 265 | text, |
| 266 | style: Theme.of(context).textTheme.bodyMedium?.copyWith( |
| 267 | fontSize: 15, |
| 268 | fontWeight: FontWeight.w600, |
| 269 | color: textColor, |
| 270 | ), |
| 271 | ) |
| 272 | ], |
| 273 | ), |
| 274 | ), |
| 275 | ), |
| 276 | ), |
| 277 | ); |
| 278 | } |
| 279 | } |