| 1 | import "package:cake_wallet/generated/i18n.dart"; |
| 2 | import "package:cake_wallet/new-ui/widgets/money/money_settings_cubit.dart"; |
| 3 | import "package:cw_core/amount/money.dart"; |
| 4 | import "package:flutter/widgets.dart"; |
| 5 | import "package:flutter_bloc/flutter_bloc.dart"; |
| 6 | |
| 7 | /// The [MoneyText] widget displays [Money] as a formated string of text with single style. |
| 8 | class MoneyText extends StatelessWidget { |
| 9 | const MoneyText( |
| 10 | this.amount, { |
| 11 | super.key, |
| 12 | this.style, |
| 13 | this.strutStyle, |
| 14 | this.textAlign, |
| 15 | this.textDirection, |
| 16 | this.locale, |
| 17 | this.softWrap, |
| 18 | this.overflow, |
| 19 | this.textScaler, |
| 20 | this.maxLines, |
| 21 | this.semanticsLabel, |
| 22 | this.semanticsIdentifier, |
| 23 | this.textWidthBasis, |
| 24 | this.textHeightBehavior, |
| 25 | this.selectionColor, |
| 26 | this.isHiddenAmount, |
| 27 | this.useBaseUnit, |
| 28 | this.fractionalDigits = 8, |
| 29 | this.showSymbol = true, |
| 30 | this.withSymbolPrefix = false, |
| 31 | this.trimZeros = true, |
| 32 | }); |
| 33 | |
| 34 | /// The [MoneyText.optional] returns a widget displaying [Money] as a |
| 35 | /// formated string or an [SizedBox.shrink]. |
| 36 | static Widget optional( |
| 37 | Money? amount, { |
| 38 | Key? key, |
| 39 | TextStyle? style, |
| 40 | StrutStyle? strutStyle, |
| 41 | TextAlign? textAlign, |
| 42 | TextDirection? textDirection, |
| 43 | Locale? locale, |
| 44 | bool? softWrap, |
| 45 | TextOverflow? overflow, |
| 46 | TextScaler? textScaler, |
| 47 | int? maxLines, |
| 48 | String? semanticsLabel, |
| 49 | String? semanticsIdentifier, |
| 50 | TextWidthBasis? textWidthBasis, |
| 51 | TextHeightBehavior? textHeightBehavior, |
| 52 | Color? selectionColor, |
| 53 | bool? isHiddenAmount, |
| 54 | bool? useBaseUnit, |
| 55 | int fractionalDigits = 8, |
| 56 | bool showSymbol = true, |
| 57 | bool withSymbolPrefix = false, |
| 58 | bool trimZeros = true, |
| 59 | }) => |
| 60 | amount != null |
| 61 | ? MoneyText( |
| 62 | amount, |
| 63 | key: key, |
| 64 | style: style, |
| 65 | strutStyle: strutStyle, |
| 66 | textAlign: textAlign, |
| 67 | textDirection: textDirection, |
| 68 | locale: locale, |
| 69 | softWrap: softWrap, |
| 70 | overflow: overflow, |
| 71 | textScaler: textScaler, |
| 72 | maxLines: maxLines, |
| 73 | semanticsLabel: semanticsLabel, |
| 74 | semanticsIdentifier: semanticsIdentifier, |
| 75 | textWidthBasis: textWidthBasis, |
| 76 | textHeightBehavior: textHeightBehavior, |
| 77 | selectionColor: selectionColor, |
| 78 | isHiddenAmount: isHiddenAmount, |
| 79 | useBaseUnit: useBaseUnit, |
| 80 | fractionalDigits: fractionalDigits, |
| 81 | showSymbol: showSymbol, |
| 82 | withSymbolPrefix: withSymbolPrefix, |
| 83 | trimZeros: trimZeros, |
| 84 | ) |
| 85 | : const SizedBox.shrink(); |
| 86 | |
| 87 | /// The amount to display. |
| 88 | final Money amount; |
| 89 | |
| 90 | /// If non-null, the style to use for this text. |
| 91 | /// |
| 92 | /// If the style's "inherit" property is true, the style will be merged with |
| 93 | /// the closest enclosing [DefaultTextStyle]. Otherwise, the style will |
| 94 | /// replace the closest enclosing [DefaultTextStyle]. |
| 95 | /// |
| 96 | /// The user or platform may override this [style]'s [TextStyle.fontWeight], |
| 97 | /// [TextStyle.height], [TextStyle.letterSpacing], and [TextStyle.wordSpacing] |
| 98 | /// via a [MediaQuery] ancestor's [MediaQueryData.boldText], |
| 99 | /// [MediaQueryData.lineHeightScaleFactorOverride], |
| 100 | /// [MediaQueryData.letterSpacingOverride], and [MediaQueryData.wordSpacingOverride] |
| 101 | /// regardless of its [TextStyle.inherit] value. |
| 102 | final TextStyle? style; |
| 103 | |
| 104 | /// The user or platform may override this [strutStyle]'s [StrutStyle.height] |
| 105 | /// via a [MediaQuery] ancestor's [MediaQueryData.lineHeightScaleFactorOverride]. |
| 106 | final StrutStyle? strutStyle; |
| 107 | |
| 108 | /// How the text should be aligned horizontally. |
| 109 | final TextAlign? textAlign; |
| 110 | |
| 111 | /// The directionality of the text. |
| 112 | /// |
| 113 | /// This decides how [textAlign] values like [TextAlign.start] and |
| 114 | /// [TextAlign.end] are interpreted. |
| 115 | /// |
| 116 | /// This is also used to disambiguate how to render bidirectional text. For |
| 117 | /// example, if the [data] is an English phrase followed by a Hebrew phrase, |
| 118 | /// in a [TextDirection.ltr] context the English phrase will be on the left |
| 119 | /// and the Hebrew phrase to its right, while in a [TextDirection.rtl] |
| 120 | /// context, the English phrase will be on the right and the Hebrew phrase on |
| 121 | /// its left. |
| 122 | /// |
| 123 | /// Defaults to the ambient [Directionality], if any. |
| 124 | final TextDirection? textDirection; |
| 125 | |
| 126 | /// Used to select a font when the same Unicode character can |
| 127 | /// be rendered differently, depending on the locale. |
| 128 | /// |
| 129 | /// It's rarely necessary to set this property. By default its value |
| 130 | /// is inherited from the enclosing app with `Localizations.localeOf(context)`. |
| 131 | /// |
| 132 | /// See [RenderParagraph.locale] for more information. |
| 133 | final Locale? locale; |
| 134 | |
| 135 | /// Whether the text should break at soft line breaks. |
| 136 | /// |
| 137 | /// If false, the glyphs in the text will be positioned as if there was unlimited horizontal space. |
| 138 | final bool? softWrap; |
| 139 | |
| 140 | /// How visual overflow should be handled. |
| 141 | /// |
| 142 | /// If this is null [TextStyle.overflow] will be used, otherwise the value |
| 143 | /// from the nearest [DefaultTextStyle] ancestor will be used. |
| 144 | final TextOverflow? overflow; |
| 145 | |
| 146 | final TextScaler? textScaler; |
| 147 | |
| 148 | /// An optional maximum number of lines for the text to span, wrapping if necessary. |
| 149 | /// If the text exceeds the given number of lines, it will be truncated according |
| 150 | /// to [overflow]. |
| 151 | /// |
| 152 | /// If this is 1, text will not wrap. Otherwise, text will be wrapped at the |
| 153 | /// edge of the box. |
| 154 | /// |
| 155 | /// If this is null, but there is an ambient [DefaultTextStyle] that specifies |
| 156 | /// an explicit number for its [DefaultTextStyle.maxLines], then the |
| 157 | /// [DefaultTextStyle] value will take precedence. You can use a [RichText] |
| 158 | /// widget directly to entirely override the [DefaultTextStyle]. |
| 159 | final int? maxLines; |
| 160 | |
| 161 | /// An alternative semantics label for this text. |
| 162 | /// |
| 163 | /// If present, the semantics of this widget will contain this value instead |
| 164 | /// of the actual text. This will overwrite any of the semantics labels applied |
| 165 | /// directly to the [TextSpan]s. |
| 166 | /// |
| 167 | /// This is useful for replacing abbreviations or shorthands with the full |
| 168 | /// text value: |
| 169 | /// |
| 170 | /// ```dart |
| 171 | /// const Text(r'$$', semanticsLabel: 'Double dollars') |
| 172 | /// ``` |
| 173 | final String? semanticsLabel; |
| 174 | |
| 175 | /// A unique identifier for the semantics node for this widget. |
| 176 | /// |
| 177 | /// This is useful for cases where the text widget needs to have a uniquely |
| 178 | /// identifiable ID that is recognized through the automation tools without |
| 179 | /// having a dependency on the actual content of the text that can possibly be |
| 180 | /// dynamic in nature. |
| 181 | final String? semanticsIdentifier; |
| 182 | |
| 183 | final TextWidthBasis? textWidthBasis; |
| 184 | |
| 185 | final TextHeightBehavior? textHeightBehavior; |
| 186 | |
| 187 | /// The color to use when painting the selection. |
| 188 | /// |
| 189 | /// This is ignored if [SelectionContainer.maybeOf] returns null |
| 190 | /// in the [BuildContext] of the [Text] widget. |
| 191 | /// |
| 192 | /// If null, the ambient [DefaultSelectionStyle] is used (if any); failing |
| 193 | /// that, the selection color defaults to [DefaultSelectionStyle.defaultColor] |
| 194 | /// (semi-transparent grey). |
| 195 | final Color? selectionColor; |
| 196 | |
| 197 | /// Show the amount in the base unit format of [Money.currency] |
| 198 | /// |
| 199 | /// If null, the displayAmountsInSatoshi setting is used. |
| 200 | final bool? useBaseUnit; |
| 201 | |
| 202 | /// A limit for the display of the fractional digits of the amount |
| 203 | final int fractionalDigits; |
| 204 | |
| 205 | /// Hide the amount |
| 206 | /// |
| 207 | /// If null, the value from the balanceDisplayMode setting is used. |
| 208 | final bool? isHiddenAmount; |
| 209 | |
| 210 | /// Show the currency symbol |
| 211 | final bool showSymbol; |
| 212 | |
| 213 | /// Prefix the amount with the currency symbol if [showSymbol] is true |
| 214 | final bool withSymbolPrefix; |
| 215 | |
| 216 | /// Trim the zeros at the end of an amount |
| 217 | final bool trimZeros; |
| 218 | |
| 219 | @override |
| 220 | Widget build(BuildContext context) => BlocBuilder<MoneySettingsCubit, MoneySettingsState>( |
| 221 | builder: (context, state) => Text( |
| 222 | isHiddenAmount ?? state.isHidden |
| 223 | ? "●●●●●●" |
| 224 | : showSymbol |
| 225 | ? amount.toLocalStringWithSymbol( |
| 226 | fractionalDigits: fractionalDigits, |
| 227 | trimZeros: trimZeros, |
| 228 | useBaseUnit: useBaseUnit ?? state.useBaseUnit(amount.currency), |
| 229 | withSymbolPrefix: withSymbolPrefix, |
| 230 | locale: (locale ?? Localizations.localeOf(context)).toString(), |
| 231 | ) |
| 232 | : amount.toLocalStringWithPrecision( |
| 233 | fractionalDigits: fractionalDigits, |
| 234 | trimZeros: trimZeros, |
| 235 | useBaseUnit: useBaseUnit ?? state.useBaseUnit(amount.currency), |
| 236 | locale: (locale ?? Localizations.localeOf(context)).toString(), |
| 237 | ), |
| 238 | style: style, |
| 239 | strutStyle: strutStyle, |
| 240 | textAlign: textAlign, |
| 241 | textDirection: textDirection, |
| 242 | locale: locale, |
| 243 | softWrap: softWrap, |
| 244 | overflow: overflow, |
| 245 | textScaler: textScaler, |
| 246 | maxLines: maxLines, |
| 247 | semanticsLabel: isHiddenAmount ?? state.isHidden |
| 248 | ? (semanticsLabel ?? S.of(context).amount_hidden) |
| 249 | : semanticsLabel, |
| 250 | semanticsIdentifier: semanticsIdentifier, |
| 251 | textWidthBasis: textWidthBasis, |
| 252 | textHeightBehavior: textHeightBehavior, |
| 253 | selectionColor: selectionColor, |
| 254 | ), |
| 255 | ); |
| 256 | } |