| 1 | import 'package:cake_wallet/generated/i18n.dart'; |
| 2 | import 'package:cake_wallet/src/widgets/setting_action_button.dart'; |
| 3 | import 'package:cake_wallet/src/widgets/setting_actions.dart'; |
| 4 | import 'package:flutter/material.dart'; |
| 5 | import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; |
| 6 | import 'package:cw_core/wallet_type.dart'; |
| 7 | import 'package:flutter_mobx/flutter_mobx.dart'; |
| 8 | |
| 9 | class MenuWidget extends StatefulWidget { |
| 10 | MenuWidget(this.dashboardViewModel, Key? key); |
| 11 | |
| 12 | final DashboardViewModel dashboardViewModel; |
| 13 | |
| 14 | @override |
| 15 | MenuWidgetState createState() => MenuWidgetState(); |
| 16 | } |
| 17 | |
| 18 | class MenuWidgetState extends State<MenuWidget> { |
| 19 | MenuWidgetState() |
| 20 | : this.menuWidth = 0, |
| 21 | this.screenWidth = 0, |
| 22 | this.screenHeight = 0, |
| 23 | this.headerHeight = 120, |
| 24 | this.tileHeight = 60, |
| 25 | this.fromTopEdge = 50, |
| 26 | this.fromBottomEdge = 25, |
| 27 | this.moneroIcon = Image.asset('assets/new-ui/crypto_full_icons/monero.svg'), |
| 28 | this.bitcoinIcon = Image.asset('assets/new-ui/crypto_full_icons/bitcoin.svg'), |
| 29 | this.litecoinIcon = Image.asset('assets/new-ui/crypto_full_icons/litecoin.svg'), |
| 30 | this.havenIcon = Image.asset('assets/images/haven_menu.webp'), |
| 31 | this.ethereumIcon = Image.asset('assets/new-ui/crypto_full_icons/ethereum.svg'), |
| 32 | this.nanoIcon = Image.asset('assets/new-ui/crypto_full_icons/nano.svg'), |
| 33 | this.bananoIcon = Image.asset('assets/new-ui/crypto_full_icons/nano.svg'), |
| 34 | this.bitcoinCashIcon = Image.asset('assets/new-ui/crypto_full_icons/bitcoin-cash.svg'), |
| 35 | this.polygonIcon = Image.asset('assets/new-ui/crypto_full_icons/polygon.svg'), |
| 36 | this.baseIcon = Image.asset('assets/new-ui/crypto_full_icons/base.svg'), |
| 37 | this.arbitrumIcon = Image.asset('assets/new-ui/crypto_full_icons/arbitrum.svg'), |
| 38 | this.bscIcon = Image.asset('assets/new-ui/crypto_full_icons/bnb.svg'), |
| 39 | this.solanaIcon = Image.asset('assets/new-ui/crypto_full_icons/solana.svg'), |
| 40 | this.tronIcon = Image.asset('assets/new-ui/crypto_full_icons/tron.svg'), |
| 41 | this.wowneroIcon = Image.asset('assets/new-ui/crypto_full_icons/wownero.svg'), |
| 42 | this.zanoIcon = Image.asset('assets/new-ui/crypto_full_icons/zano.svg'), |
| 43 | this.decredIcon = Image.asset('assets/new-ui/crypto_full_icons/decred.svg'), |
| 44 | this.dogecoinIcon = Image.asset('assets/new-ui/crypto_full_icons/dogecoin.svg'), |
| 45 | this.zcashIcon = Image.asset('assets/new-ui/crypto_full_icons/zcash.svg'); |
| 46 | |
| 47 | final largeScreen = 731; |
| 48 | |
| 49 | double menuWidth; |
| 50 | double screenWidth; |
| 51 | double screenHeight; |
| 52 | |
| 53 | double headerHeight; |
| 54 | double tileHeight; |
| 55 | double fromTopEdge; |
| 56 | double fromBottomEdge; |
| 57 | |
| 58 | Image moneroIcon; |
| 59 | Image bitcoinIcon; |
| 60 | Image litecoinIcon; |
| 61 | Image havenIcon; |
| 62 | Image ethereumIcon; |
| 63 | Image bitcoinCashIcon; |
| 64 | Image nanoIcon; |
| 65 | Image bananoIcon; |
| 66 | Image polygonIcon; |
| 67 | Image baseIcon; |
| 68 | Image arbitrumIcon; |
| 69 | Image bscIcon; |
| 70 | Image solanaIcon; |
| 71 | Image tronIcon; |
| 72 | Image wowneroIcon; |
| 73 | Image zanoIcon; |
| 74 | Image decredIcon; |
| 75 | Image dogecoinIcon; |
| 76 | Image zcashIcon; |
| 77 | |
| 78 | @override |
| 79 | void initState() { |
| 80 | menuWidth = 0; |
| 81 | screenWidth = 0; |
| 82 | screenHeight = 0; |
| 83 | |
| 84 | headerHeight = 120; |
| 85 | tileHeight = 60; |
| 86 | fromTopEdge = 50; |
| 87 | fromBottomEdge = 25; |
| 88 | |
| 89 | super.initState(); |
| 90 | WidgetsBinding.instance.addPostFrameCallback(afterLayout); |
| 91 | } |
| 92 | |
| 93 | void afterLayout(dynamic _) { |
| 94 | screenWidth = MediaQuery.of(context).size.width; |
| 95 | screenHeight = MediaQuery.of(context).size.height; |
| 96 | |
| 97 | setState(() { |
| 98 | menuWidth = screenWidth; |
| 99 | |
| 100 | if (screenHeight > largeScreen) { |
| 101 | final scale = screenHeight / largeScreen; |
| 102 | tileHeight *= scale; |
| 103 | headerHeight *= scale; |
| 104 | fromTopEdge *= scale; |
| 105 | fromBottomEdge *= scale; |
| 106 | } |
| 107 | }); |
| 108 | } |
| 109 | |
| 110 | @override |
| 111 | Widget build(BuildContext context) { |
| 112 | List<SettingActions> items = List.of(SettingActions.all); |
| 113 | if (!widget.dashboardViewModel.hasSilentPayments) { |
| 114 | items.removeWhere( |
| 115 | (element) => element.name(context) == S.of(context).silent_payments_settings); |
| 116 | } |
| 117 | if (!widget.dashboardViewModel.isMoneroViewOnly) { |
| 118 | items.removeWhere((element) => element.name(context) == S.of(context).export_outputs); |
| 119 | } |
| 120 | if (!widget.dashboardViewModel.hasMweb) { |
| 121 | items.removeWhere((element) => element.name(context) == S.of(context).litecoin_mweb_settings); |
| 122 | } |
| 123 | int itemCount = items.length; |
| 124 | |
| 125 | moneroIcon = Image.asset('assets/new-ui/crypto_full_icons/monero.svg'); |
| 126 | bitcoinIcon = Image.asset('assets/new-ui/crypto_full_icons/bitcoin.svg'); |
| 127 | |
| 128 | return Row( |
| 129 | mainAxisSize: MainAxisSize.max, |
| 130 | crossAxisAlignment: CrossAxisAlignment.center, |
| 131 | children: <Widget>[ |
| 132 | Padding( |
| 133 | padding: EdgeInsets.only(left: 24), |
| 134 | child: Container( |
| 135 | height: 60, |
| 136 | width: 4, |
| 137 | decoration: BoxDecoration( |
| 138 | borderRadius: BorderRadius.all(Radius.circular(2)), |
| 139 | color: Theme.of(context).colorScheme.outline, |
| 140 | ), |
| 141 | ), |
| 142 | ), |
| 143 | SizedBox(width: 12), |
| 144 | Expanded( |
| 145 | child: ClipRRect( |
| 146 | borderRadius: BorderRadius.only( |
| 147 | topLeft: Radius.circular(24), |
| 148 | bottomLeft: Radius.circular(24), |
| 149 | ), |
| 150 | child: Container( |
| 151 | color: Theme.of(context).colorScheme.surface, |
| 152 | child: ListView.separated( |
| 153 | padding: EdgeInsets.only(top: 0), |
| 154 | itemBuilder: (_, index) { |
| 155 | if (index == 0) { |
| 156 | return Container( |
| 157 | height: headerHeight, |
| 158 | decoration: BoxDecoration( |
| 159 | borderRadius: BorderRadius.only(bottomLeft: Radius.circular(24)), |
| 160 | color: Theme.of(context).colorScheme.surface, |
| 161 | ), |
| 162 | padding: EdgeInsets.only( |
| 163 | left: 24, |
| 164 | top: fromTopEdge, |
| 165 | right: 24, |
| 166 | bottom: fromBottomEdge, |
| 167 | ), |
| 168 | child: Row( |
| 169 | mainAxisAlignment: MainAxisAlignment.start, |
| 170 | children: <Widget>[ |
| 171 | _iconFor(type: widget.dashboardViewModel.type), |
| 172 | SizedBox(width: 12), |
| 173 | SingleChildScrollView( |
| 174 | child: Container( |
| 175 | child: Column( |
| 176 | crossAxisAlignment: CrossAxisAlignment.start, |
| 177 | mainAxisAlignment: widget.dashboardViewModel.subname.isNotEmpty |
| 178 | ? MainAxisAlignment.spaceBetween |
| 179 | : MainAxisAlignment.center, |
| 180 | children: <Widget>[ |
| 181 | Text( |
| 182 | widget.dashboardViewModel.name, |
| 183 | style: Theme.of(context).textTheme.bodyLarge?.copyWith( |
| 184 | fontWeight: FontWeight.w700, |
| 185 | ), |
| 186 | ), |
| 187 | if (widget.dashboardViewModel.subname.isNotEmpty) |
| 188 | Observer( |
| 189 | builder: (_) => Text( |
| 190 | widget.dashboardViewModel.subname, |
| 191 | style: Theme.of(context).textTheme.bodySmall?.copyWith( |
| 192 | color: Theme.of(context).colorScheme.onSurfaceVariant, |
| 193 | fontWeight: FontWeight.w500, |
| 194 | ), |
| 195 | ), |
| 196 | ), |
| 197 | ], |
| 198 | ), |
| 199 | ), |
| 200 | ), |
| 201 | ], |
| 202 | ), |
| 203 | ); |
| 204 | } |
| 205 | |
| 206 | index--; |
| 207 | |
| 208 | final item = items[index]; |
| 209 | final isLastTile = index == itemCount - 1; |
| 210 | |
| 211 | return SettingActionButton( |
| 212 | key: item.key, |
| 213 | isLastTile: isLastTile, |
| 214 | tileHeight: tileHeight, |
| 215 | selectionActive: false, |
| 216 | fromBottomEdge: fromBottomEdge, |
| 217 | fromTopEdge: fromTopEdge, |
| 218 | onTap: () => item.onTap.call(context), |
| 219 | image: item.image, |
| 220 | title: item.name.call(context), |
| 221 | ); |
| 222 | }, |
| 223 | separatorBuilder: (_, index) => Container( |
| 224 | height: 0, |
| 225 | color: Theme.of(context).colorScheme.outline, |
| 226 | ), |
| 227 | itemCount: itemCount + 1, |
| 228 | ), |
| 229 | ), |
| 230 | ), |
| 231 | ), |
| 232 | ], |
| 233 | ); |
| 234 | } |
| 235 | |
| 236 | Widget _iconFor({required WalletType type}) { |
| 237 | switch (type) { |
| 238 | case WalletType.monero: |
| 239 | return moneroIcon; |
| 240 | case WalletType.bitcoin: |
| 241 | return bitcoinIcon; |
| 242 | case WalletType.litecoin: |
| 243 | return litecoinIcon; |
| 244 | case WalletType.haven: |
| 245 | return havenIcon; |
| 246 | case WalletType.ethereum: |
| 247 | return ethereumIcon; |
| 248 | case WalletType.bitcoinCash: |
| 249 | return bitcoinCashIcon; |
| 250 | case WalletType.nano: |
| 251 | return nanoIcon; |
| 252 | case WalletType.banano: |
| 253 | return bananoIcon; |
| 254 | case WalletType.polygon: |
| 255 | return polygonIcon; |
| 256 | case WalletType.solana: |
| 257 | return solanaIcon; |
| 258 | case WalletType.base: |
| 259 | return baseIcon; |
| 260 | case WalletType.arbitrum: |
| 261 | return arbitrumIcon; |
| 262 | case WalletType.bsc: |
| 263 | return bscIcon; |
| 264 | case WalletType.tron: |
| 265 | return tronIcon; |
| 266 | case WalletType.wownero: |
| 267 | return wowneroIcon; |
| 268 | case WalletType.zano: |
| 269 | return zanoIcon; |
| 270 | case WalletType.decred: |
| 271 | return decredIcon; |
| 272 | case WalletType.dogecoin: |
| 273 | return dogecoinIcon; |
| 274 | case WalletType.zcash: |
| 275 | return zcashIcon; |
| 276 | default: |
| 277 | throw Exception('No icon for ${type.toString()}'); |
| 278 | } |
| 279 | } |
| 280 | } |