mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-12-23 11:59:30 +00:00
add fiat selection view
This commit is contained in:
parent
9724b40848
commit
2d6447eedd
4 changed files with 644 additions and 23 deletions
123
lib/models/buy/response_objects/fiat.dart
Normal file
123
lib/models/buy/response_objects/fiat.dart
Normal file
|
@ -0,0 +1,123 @@
|
|||
class Fiat {
|
||||
/// Fiat ticker
|
||||
final String ticker;
|
||||
|
||||
/// Fiat name
|
||||
final String name;
|
||||
|
||||
/// Fiat network
|
||||
final String network;
|
||||
|
||||
/// Fiat logo url
|
||||
final String image;
|
||||
|
||||
/// Indicates if a currency has an Extra ID
|
||||
final bool hasExternalId;
|
||||
|
||||
/// external id if it exists
|
||||
final String? externalId;
|
||||
|
||||
/// Indicates if a currency is a fiat currency (EUR, USD)
|
||||
final bool isFiat;
|
||||
|
||||
/// Indicates if a currency is popular
|
||||
final bool featured;
|
||||
|
||||
/// Indicates if a currency is stable
|
||||
final bool isStable;
|
||||
|
||||
/// Indicates if a currency is available on a fixed-rate flow
|
||||
final bool supportsFixedRate;
|
||||
|
||||
/// (Optional - based on api call) Indicates whether the pair is
|
||||
/// currently supported by change now
|
||||
final bool? isAvailable;
|
||||
|
||||
Fiat({
|
||||
required this.ticker,
|
||||
required this.name,
|
||||
required this.network,
|
||||
required this.image,
|
||||
required this.hasExternalId,
|
||||
this.externalId,
|
||||
required this.isFiat,
|
||||
required this.featured,
|
||||
required this.isStable,
|
||||
required this.supportsFixedRate,
|
||||
this.isAvailable,
|
||||
});
|
||||
|
||||
factory Fiat.fromJson(Map<String, dynamic> json) {
|
||||
try {
|
||||
return Fiat(
|
||||
ticker: json["ticker"] as String,
|
||||
name: json["name"] as String,
|
||||
network: json["network"] as String? ?? "",
|
||||
image: json["image"] as String,
|
||||
hasExternalId: json["hasExternalId"] as bool,
|
||||
externalId: json["externalId"] as String?,
|
||||
isFiat: json["isFiat"] as bool,
|
||||
featured: json["featured"] as bool,
|
||||
isStable: json["isStable"] as bool,
|
||||
supportsFixedRate: json["supportsFixedRate"] as bool,
|
||||
isAvailable: json["isAvailable"] as bool?,
|
||||
);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final map = {
|
||||
"ticker": ticker,
|
||||
"name": name,
|
||||
"network": network,
|
||||
"image": image,
|
||||
"hasExternalId": hasExternalId,
|
||||
"externalId": externalId,
|
||||
"isFiat": isFiat,
|
||||
"featured": featured,
|
||||
"isStable": isStable,
|
||||
"supportsFixedRate": supportsFixedRate,
|
||||
};
|
||||
|
||||
if (isAvailable != null) {
|
||||
map["isAvailable"] = isAvailable!;
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
Fiat copyWith({
|
||||
String? ticker,
|
||||
String? name,
|
||||
String? network,
|
||||
String? image,
|
||||
bool? hasExternalId,
|
||||
String? externalId,
|
||||
bool? isFiat,
|
||||
bool? featured,
|
||||
bool? isStable,
|
||||
bool? supportsFixedRate,
|
||||
bool? isAvailable,
|
||||
}) {
|
||||
return Fiat(
|
||||
ticker: ticker ?? this.ticker,
|
||||
name: name ?? this.name,
|
||||
network: network ?? this.network,
|
||||
image: image ?? this.image,
|
||||
hasExternalId: hasExternalId ?? this.hasExternalId,
|
||||
externalId: externalId ?? this.externalId,
|
||||
isFiat: isFiat ?? this.isFiat,
|
||||
featured: featured ?? this.featured,
|
||||
isStable: isStable ?? this.isStable,
|
||||
supportsFixedRate: supportsFixedRate ?? this.supportsFixedRate,
|
||||
isAvailable: isAvailable ?? this.isAvailable,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "Fiat: ${toJson()}";
|
||||
}
|
||||
}
|
|
@ -2,9 +2,11 @@ import 'package:decimal/decimal.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/models/buy/response_objects/crypto.dart';
|
||||
import 'package:stackwallet/models/buy/response_objects/fiat.dart';
|
||||
import 'package:stackwallet/models/buy/response_objects/pair.dart';
|
||||
import 'package:stackwallet/pages/buy_view/buy_coin_selection/crypto_selection_view.dart';
|
||||
import 'package:stackwallet/pages/buy_view/sub_widgets/crypto_selection_view.dart';
|
||||
import 'package:stackwallet/pages/buy_view/sub_widgets/fiat_crypto_toggle.dart';
|
||||
import 'package:stackwallet/pages/buy_view/sub_widgets/fiat_selection_view.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
|
@ -57,12 +59,6 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
|||
}
|
||||
}
|
||||
|
||||
void selectFiatCrypto() async {
|
||||
// await Future<void>.delayed(const Duration(milliseconds: 300));
|
||||
//
|
||||
// Navigator.of(context, rootNavigator: true).pop();
|
||||
}
|
||||
|
||||
void cryptoFieldOnChanged(String value) async {
|
||||
if (_cryptoFocusNode.hasFocus) {
|
||||
final newCryptoAmount = Decimal.tryParse(value);
|
||||
|
@ -80,8 +76,8 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
|||
}
|
||||
}
|
||||
|
||||
void selectCryptoCrypto() async {
|
||||
final fromTicker = ref.read(exchangeFormStateProvider).fromTicker ?? "-";
|
||||
void selectCrypto() async {
|
||||
final fromTicker = ref.read(buyFormStateProvider).fromTicker ?? "-";
|
||||
// ref.read(estimatedRateExchangeFormProvider).from?.ticker ?? "-";
|
||||
|
||||
// if (walletInitiated &&
|
||||
|
@ -91,18 +87,18 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
|||
// }
|
||||
|
||||
List<Crypto> coins;
|
||||
switch (ref.read(currentExchangeNameStateProvider.state).state) {
|
||||
// case ChangeNowExchange.exchangeName:
|
||||
// coins = ref.read(availableChangeNowCurrenciesProvider).coins;
|
||||
// break;
|
||||
// case SimpleSwapExchange.exchangeName:
|
||||
// coins = ref
|
||||
// .read(availableSimpleswapCurrenciesProvider)
|
||||
// .floatingRateCurrencies;
|
||||
// break;
|
||||
default:
|
||||
coins = [];
|
||||
}
|
||||
// switch (ref.read(currentExchangeNameStateProvider.state).state) {
|
||||
// // case ChangeNowExchange.exchangeName:
|
||||
// // coins = ref.read(availableChangeNowCurrenciesProvider).coins;
|
||||
// // break;
|
||||
// // case SimpleSwapExchange.exchangeName:
|
||||
// // coins = ref
|
||||
// // .read(availableSimpleswapCurrenciesProvider)
|
||||
// // .floatingRateCurrencies;
|
||||
// // break;
|
||||
// default:
|
||||
coins = [];
|
||||
// }
|
||||
|
||||
await _showFloatingCryptoSelectionSheet(
|
||||
coins: coins,
|
||||
|
@ -251,6 +247,146 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
|||
}
|
||||
}
|
||||
|
||||
void selectFiat() async {
|
||||
final fromTicker = ref.read(buyFormStateProvider).fromTicker ?? "-";
|
||||
// ref.read(estimatedRateExchangeFormProvider).from?.ticker ?? "-";
|
||||
|
||||
// if (walletInitiated &&
|
||||
// fromTicker.toLowerCase() == coin!.ticker.toLowerCase()) {
|
||||
// // do not allow changing away from wallet coin
|
||||
// return;
|
||||
// }
|
||||
|
||||
List<Crypto> coins;
|
||||
// switch (ref.read(currentExchangeNameStateProvider.state).state) {
|
||||
// // case ChangeNowExchange.exchangeName:
|
||||
// // coins = ref.read(availableChangeNowCurrenciesProvider).coins;
|
||||
// // break;
|
||||
// // case SimpleSwapExchange.exchangeName:
|
||||
// // coins = ref
|
||||
// // .read(availableSimpleswapCurrenciesProvider)
|
||||
// // .floatingRateCurrencies;
|
||||
// // break;
|
||||
// default:
|
||||
coins = [];
|
||||
// }
|
||||
}
|
||||
|
||||
Future<void> _showFloatingFiatSelectionSheet({
|
||||
required List<Fiat> fiats,
|
||||
required String excludedTicker,
|
||||
required String fromTicker,
|
||||
required void Function(Fiat) onSelected,
|
||||
}) async {
|
||||
_fiatFocusNode.unfocus();
|
||||
_cryptoFocusNode.unfocus();
|
||||
|
||||
List<Pair> allPairs;
|
||||
|
||||
// switch (ref.read(currentExchangeNameStateProvider.state).state) {
|
||||
// // case ChangeNowExchange.exchangeName:
|
||||
// // allPairs = ref.read(availableChangeNowCurrenciesProvider).pairs;
|
||||
// // break;
|
||||
// // case SimpleSwapExchange.exchangeName:
|
||||
// // allPairs = ref.read(exchangeFormStateProvider).exchangeType ==
|
||||
// // ExchangeRateType.fixed
|
||||
// // ? ref.read(availableSimpleswapCurrenciesProvider).fixedRatePairs
|
||||
// // : ref.read(availableSimpleswapCurrenciesProvider).floatingRatePairs;
|
||||
// // break;
|
||||
// default:
|
||||
allPairs = [];
|
||||
// }
|
||||
|
||||
List<Pair> availablePairs;
|
||||
if (fromTicker.isEmpty ||
|
||||
fromTicker == "-" ||
|
||||
excludedTicker.isEmpty ||
|
||||
excludedTicker == "-") {
|
||||
availablePairs = allPairs;
|
||||
} else if (excludedTicker == fromTicker) {
|
||||
availablePairs = allPairs
|
||||
.where((e) => e.from == excludedTicker)
|
||||
.toList(growable: false);
|
||||
} else {
|
||||
availablePairs =
|
||||
allPairs.where((e) => e.to == excludedTicker).toList(growable: false);
|
||||
}
|
||||
|
||||
final List<Fiat> tickers = fiats.where((e) {
|
||||
if (excludedTicker == fromTicker) {
|
||||
return e.ticker != excludedTicker &&
|
||||
availablePairs.where((e2) => e2.to == e.ticker).isNotEmpty;
|
||||
} else {
|
||||
return e.ticker != excludedTicker &&
|
||||
availablePairs.where((e2) => e2.from == e.ticker).isNotEmpty;
|
||||
}
|
||||
}).toList(growable: false);
|
||||
|
||||
final result = isDesktop
|
||||
? await showDialog<Crypto?>(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return DesktopDialog(
|
||||
maxHeight: 700,
|
||||
maxWidth: 580,
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 32,
|
||||
),
|
||||
child: Text(
|
||||
"Choose a fiat with which to pay",
|
||||
style: STextStyles.desktopH3(context),
|
||||
),
|
||||
),
|
||||
const DesktopDialogCloseButton(),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 32,
|
||||
right: 32,
|
||||
bottom: 32,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: RoundedWhiteContainer(
|
||||
padding: const EdgeInsets.all(16),
|
||||
borderColor: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.background,
|
||||
child: FiatSelectionView(
|
||||
coins: tickers,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
})
|
||||
: await Navigator.of(context).push(
|
||||
MaterialPageRoute<dynamic>(
|
||||
builder: (_) => FiatSelectionView(
|
||||
coins: tickers,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
if (mounted && result is Fiat) {
|
||||
onSelected(result);
|
||||
}
|
||||
}
|
||||
|
||||
String? _fetchIconUrlFromTicker(String? ticker) {
|
||||
if (ticker == null) return null;
|
||||
|
||||
|
@ -364,13 +500,16 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
|||
}
|
||||
},
|
||||
onChanged: cryptoFieldOnChanged,
|
||||
onButtonTap: selectCryptoCrypto,
|
||||
onButtonTap: selectCrypto,
|
||||
isWalletCoin: isWalletCoin(coin, true),
|
||||
image: _fetchIconUrlFromTicker(ref
|
||||
.watch(buyFormStateProvider.select((value) => value.fromTicker))),
|
||||
ticker: ref
|
||||
.watch(buyFormStateProvider.select((value) => value.fromTicker)),
|
||||
),
|
||||
SizedBox(
|
||||
height: isDesktop ? 20 : 12,
|
||||
),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
|
@ -386,6 +525,33 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
|||
SizedBox(
|
||||
height: isDesktop ? 10 : 4,
|
||||
),
|
||||
BuyTextField(
|
||||
controller: _fiatController,
|
||||
focusNode: _fiatFocusNode,
|
||||
textStyle: STextStyles.smallMed14(context).copyWith(
|
||||
color: Theme.of(context).extension<StackColors>()!.textDark,
|
||||
),
|
||||
buttonColor:
|
||||
Theme.of(context).extension<StackColors>()!.buttonBackSecondary,
|
||||
borderRadius: Constants.size.circularBorderRadius,
|
||||
background:
|
||||
Theme.of(context).extension<StackColors>()!.textFieldDefaultBG,
|
||||
onTap: () {
|
||||
if (_fiatController.text == "-") {
|
||||
_fiatController.text = "";
|
||||
}
|
||||
},
|
||||
onChanged: fiatFieldOnChanged,
|
||||
onButtonTap: selectFiat,
|
||||
isWalletCoin: isWalletCoin(coin, true),
|
||||
image: _fetchIconUrlFromTicker(ref
|
||||
.watch(buyFormStateProvider.select((value) => value.fromTicker))),
|
||||
ticker: ref
|
||||
.watch(buyFormStateProvider.select((value) => value.fromTicker)),
|
||||
),
|
||||
SizedBox(
|
||||
height: isDesktop ? 20 : 12,
|
||||
),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
|
@ -422,7 +588,7 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
|||
}
|
||||
},
|
||||
onChanged: fiatFieldOnChanged,
|
||||
onButtonTap: selectFiatCrypto,
|
||||
onButtonTap: selectFiat,
|
||||
// isWalletCoin: isWalletCoin(coin, true),
|
||||
isWalletCoin: false,
|
||||
// image: _fetchIconUrlFromTicker(ref
|
||||
|
|
332
lib/pages/buy_view/sub_widgets/fiat_selection_view.dart
Normal file
332
lib/pages/buy_view/sub_widgets/fiat_selection_view.dart
Normal file
|
@ -0,0 +1,332 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/models/buy/response_objects/fiat.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/background.dart';
|
||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
|
||||
import 'package:stackwallet/widgets/loading_indicator.dart';
|
||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
import 'package:stackwallet/widgets/stack_text_field.dart';
|
||||
import 'package:stackwallet/widgets/textfield_icon_button.dart';
|
||||
|
||||
class FiatSelectionView extends StatefulWidget {
|
||||
const FiatSelectionView({
|
||||
Key? key,
|
||||
required this.coins,
|
||||
}) : super(key: key);
|
||||
|
||||
final List<Fiat> coins;
|
||||
|
||||
@override
|
||||
State<FiatSelectionView> createState() => _FiatSelectionViewState();
|
||||
}
|
||||
|
||||
class _FiatSelectionViewState extends State<FiatSelectionView> {
|
||||
late TextEditingController _searchController;
|
||||
final _searchFocusNode = FocusNode();
|
||||
|
||||
late final List<Fiat> coins;
|
||||
late List<Fiat> _coins;
|
||||
|
||||
void filter(String text) {
|
||||
setState(() {
|
||||
_coins = [
|
||||
...coins.where((e) =>
|
||||
e.name.toLowerCase().contains(text.toLowerCase()) ||
|
||||
e.ticker.toLowerCase().contains(text.toLowerCase()))
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_searchController = TextEditingController();
|
||||
|
||||
coins = [...widget.coins];
|
||||
coins.sort(
|
||||
(a, b) => a.ticker.toLowerCase().compareTo(b.ticker.toLowerCase()));
|
||||
for (Coin coin in Coin.values.reversed) {
|
||||
int index = coins.indexWhere((element) =>
|
||||
element.ticker.toLowerCase() == coin.ticker.toLowerCase());
|
||||
if (index > 0) {
|
||||
final currency = coins.removeAt(index);
|
||||
coins.insert(0, currency);
|
||||
}
|
||||
}
|
||||
|
||||
_coins = [...coins];
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_searchController.dispose();
|
||||
_searchFocusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isDesktop = Util.isDesktop;
|
||||
return ConditionalParent(
|
||||
condition: !isDesktop,
|
||||
builder: (child) {
|
||||
return Background(
|
||||
child: Scaffold(
|
||||
backgroundColor:
|
||||
Theme.of(context).extension<StackColors>()!.background,
|
||||
appBar: AppBar(
|
||||
leading: AppBarBackButton(
|
||||
onPressed: () async {
|
||||
if (FocusScope.of(context).hasFocus) {
|
||||
FocusScope.of(context).unfocus();
|
||||
await Future<void>.delayed(
|
||||
const Duration(milliseconds: 50));
|
||||
}
|
||||
if (mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
),
|
||||
title: Text(
|
||||
"Choose a crypto to buy",
|
||||
style: STextStyles.pageTitleH2(context),
|
||||
),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
),
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: isDesktop ? MainAxisSize.min : MainAxisSize.max,
|
||||
children: [
|
||||
if (!isDesktop)
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
child: TextField(
|
||||
autofocus: isDesktop,
|
||||
autocorrect: !isDesktop,
|
||||
enableSuggestions: !isDesktop,
|
||||
controller: _searchController,
|
||||
focusNode: _searchFocusNode,
|
||||
onChanged: filter,
|
||||
style: STextStyles.field(context),
|
||||
decoration: standardInputDecoration(
|
||||
"Search",
|
||||
_searchFocusNode,
|
||||
context,
|
||||
desktopMed: isDesktop,
|
||||
).copyWith(
|
||||
prefixIcon: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 16,
|
||||
),
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.search,
|
||||
width: 16,
|
||||
height: 16,
|
||||
),
|
||||
),
|
||||
suffixIcon: _searchController.text.isNotEmpty
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(right: 0),
|
||||
child: UnconstrainedBox(
|
||||
child: Row(
|
||||
children: [
|
||||
TextFieldIconButton(
|
||||
child: const XIcon(),
|
||||
onTap: () async {
|
||||
setState(() {
|
||||
_searchController.text = "";
|
||||
});
|
||||
filter("");
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Text(
|
||||
"Popular coins",
|
||||
style: STextStyles.smallMed12(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
Flexible(
|
||||
child: Builder(builder: (context) {
|
||||
final items = _coins
|
||||
.where((e) => Coin.values
|
||||
.where((coin) =>
|
||||
coin.ticker.toLowerCase() == e.ticker.toLowerCase())
|
||||
.isNotEmpty)
|
||||
.toList(growable: false);
|
||||
|
||||
return RoundedWhiteContainer(
|
||||
padding: const EdgeInsets.all(0),
|
||||
child: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
primary: isDesktop ? false : null,
|
||||
itemCount: items.length,
|
||||
itemBuilder: (builderContext, index) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop(items[index]);
|
||||
},
|
||||
child: RoundedWhiteContainer(
|
||||
child: Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 24,
|
||||
height: 24,
|
||||
child: SvgPicture.network(
|
||||
items[index].image,
|
||||
width: 24,
|
||||
height: 24,
|
||||
placeholderBuilder: (_) =>
|
||||
const LoadingIndicator(),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
items[index].name,
|
||||
style: STextStyles.largeMedium14(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
Text(
|
||||
items[index].ticker.toUpperCase(),
|
||||
style: STextStyles.smallMed12(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Text(
|
||||
"All coins",
|
||||
style: STextStyles.smallMed12(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
Flexible(
|
||||
child: RoundedWhiteContainer(
|
||||
padding: const EdgeInsets.all(0),
|
||||
child: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
primary: isDesktop ? false : null,
|
||||
itemCount: _coins.length,
|
||||
itemBuilder: (builderContext, index) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop(_coins[index]);
|
||||
},
|
||||
child: RoundedWhiteContainer(
|
||||
child: Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 24,
|
||||
height: 24,
|
||||
child: SvgPicture.network(
|
||||
_coins[index].image,
|
||||
width: 24,
|
||||
height: 24,
|
||||
placeholderBuilder: (_) =>
|
||||
const LoadingIndicator(),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
_coins[index].name,
|
||||
style: STextStyles.largeMedium14(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
Text(
|
||||
_coins[index].ticker.toUpperCase(),
|
||||
style: STextStyles.smallMed12(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue