mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-12-24 12:29:37 +00:00
add fiat crypto toggle and crypto selection list
This commit is contained in:
parent
c746eb8865
commit
9724b40848
6 changed files with 754 additions and 88 deletions
|
@ -1,14 +1,14 @@
|
||||||
class Currency {
|
class Crypto {
|
||||||
/// Currency ticker
|
/// Crypto ticker
|
||||||
final String ticker;
|
final String ticker;
|
||||||
|
|
||||||
/// Currency name
|
/// Crypto name
|
||||||
final String name;
|
final String name;
|
||||||
|
|
||||||
/// Currency network
|
/// Crypto network
|
||||||
final String network;
|
final String network;
|
||||||
|
|
||||||
/// Currency logo url
|
/// Crypto logo url
|
||||||
final String image;
|
final String image;
|
||||||
|
|
||||||
/// Indicates if a currency has an Extra ID
|
/// Indicates if a currency has an Extra ID
|
||||||
|
@ -33,7 +33,7 @@ class Currency {
|
||||||
/// currently supported by change now
|
/// currently supported by change now
|
||||||
final bool? isAvailable;
|
final bool? isAvailable;
|
||||||
|
|
||||||
Currency({
|
Crypto({
|
||||||
required this.ticker,
|
required this.ticker,
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.network,
|
required this.network,
|
||||||
|
@ -47,9 +47,9 @@ class Currency {
|
||||||
this.isAvailable,
|
this.isAvailable,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory Currency.fromJson(Map<String, dynamic> json) {
|
factory Crypto.fromJson(Map<String, dynamic> json) {
|
||||||
try {
|
try {
|
||||||
return Currency(
|
return Crypto(
|
||||||
ticker: json["ticker"] as String,
|
ticker: json["ticker"] as String,
|
||||||
name: json["name"] as String,
|
name: json["name"] as String,
|
||||||
network: json["network"] as String? ?? "",
|
network: json["network"] as String? ?? "",
|
||||||
|
@ -88,7 +88,7 @@ class Currency {
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
Currency copyWith({
|
Crypto copyWith({
|
||||||
String? ticker,
|
String? ticker,
|
||||||
String? name,
|
String? name,
|
||||||
String? network,
|
String? network,
|
||||||
|
@ -101,7 +101,7 @@ class Currency {
|
||||||
bool? supportsFixedRate,
|
bool? supportsFixedRate,
|
||||||
bool? isAvailable,
|
bool? isAvailable,
|
||||||
}) {
|
}) {
|
||||||
return Currency(
|
return Crypto(
|
||||||
ticker: ticker ?? this.ticker,
|
ticker: ticker ?? this.ticker,
|
||||||
name: name ?? this.name,
|
name: name ?? this.name,
|
||||||
network: network ?? this.network,
|
network: network ?? this.network,
|
||||||
|
@ -118,6 +118,6 @@ class Currency {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return "Currency: ${toJson()}";
|
return "Crypto: ${toJson()}";
|
||||||
}
|
}
|
||||||
}
|
}
|
73
lib/models/buy/response_objects/pair.dart
Normal file
73
lib/models/buy/response_objects/pair.dart
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
|
|
||||||
|
class Pair {
|
||||||
|
final String from;
|
||||||
|
final String fromNetwork;
|
||||||
|
|
||||||
|
final String to;
|
||||||
|
final String toNetwork;
|
||||||
|
|
||||||
|
final bool fixedRate;
|
||||||
|
final bool floatingRate;
|
||||||
|
|
||||||
|
Pair({
|
||||||
|
required this.from,
|
||||||
|
required this.fromNetwork,
|
||||||
|
required this.to,
|
||||||
|
required this.toNetwork,
|
||||||
|
required this.fixedRate,
|
||||||
|
required this.floatingRate,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory Pair.fromMap(Map<String, dynamic> map) {
|
||||||
|
try {
|
||||||
|
return Pair(
|
||||||
|
from: map["from"] as String,
|
||||||
|
fromNetwork: map["fromNetwork"] as String,
|
||||||
|
to: map["to"] as String,
|
||||||
|
toNetwork: map["toNetwork"] as String,
|
||||||
|
fixedRate: map["fixedRate"] as bool,
|
||||||
|
floatingRate: map["floatingRate"] as bool,
|
||||||
|
);
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log("Pair.fromMap(): $e\n$s", level: LogLevel.Error);
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toMap() {
|
||||||
|
return {
|
||||||
|
"from": from,
|
||||||
|
"fromNetwork": fromNetwork,
|
||||||
|
"to": to,
|
||||||
|
"toNetwork": toNetwork,
|
||||||
|
"fixedRate": fixedRate,
|
||||||
|
"floatingRate": floatingRate,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(other) =>
|
||||||
|
other is Pair &&
|
||||||
|
from == other.from &&
|
||||||
|
fromNetwork == other.fromNetwork &&
|
||||||
|
to == other.to &&
|
||||||
|
toNetwork == other.toNetwork &&
|
||||||
|
fixedRate == other.fixedRate &&
|
||||||
|
floatingRate == other.floatingRate;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => hashValues(
|
||||||
|
from,
|
||||||
|
fromNetwork,
|
||||||
|
to,
|
||||||
|
toNetwork,
|
||||||
|
fixedRate,
|
||||||
|
floatingRate,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => "Pair: ${toMap()}";
|
||||||
|
}
|
332
lib/pages/buy_view/buy_coin_selection/crypto_selection_view.dart
Normal file
332
lib/pages/buy_view/buy_coin_selection/crypto_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/crypto.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 CryptoSelectionView extends StatefulWidget {
|
||||||
|
const CryptoSelectionView({
|
||||||
|
Key? key,
|
||||||
|
required this.coins,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final List<Crypto> coins;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<CryptoSelectionView> createState() => _CryptoSelectionViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CryptoSelectionViewState extends State<CryptoSelectionView> {
|
||||||
|
late TextEditingController _searchController;
|
||||||
|
final _searchFocusNode = FocusNode();
|
||||||
|
|
||||||
|
late final List<Crypto> coins;
|
||||||
|
late List<Crypto> _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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,19 @@
|
||||||
import 'package:decimal/decimal.dart';
|
import 'package:decimal/decimal.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:stackwallet/models/buy/response_objects/crypto.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/fiat_crypto_toggle.dart';
|
||||||
import 'package:stackwallet/providers/providers.dart';
|
import 'package:stackwallet/providers/providers.dart';
|
||||||
import 'package:stackwallet/utilities/constants.dart';
|
import 'package:stackwallet/utilities/constants.dart';
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
import 'package:stackwallet/utilities/text_styles.dart';
|
import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||||
import 'package:stackwallet/utilities/util.dart';
|
import 'package:stackwallet/utilities/util.dart';
|
||||||
|
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
|
||||||
|
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||||
import 'package:stackwallet/widgets/textfields/buy_textfield.dart';
|
import 'package:stackwallet/widgets/textfields/buy_textfield.dart';
|
||||||
|
|
||||||
class BuyForm extends ConsumerStatefulWidget {
|
class BuyForm extends ConsumerStatefulWidget {
|
||||||
|
@ -50,11 +57,245 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void selectFiatCurrency() async {
|
void selectFiatCrypto() async {
|
||||||
// await Future<void>.delayed(const Duration(milliseconds: 300));
|
// await Future<void>.delayed(const Duration(milliseconds: 300));
|
||||||
//
|
//
|
||||||
// Navigator.of(context, rootNavigator: true).pop();
|
// Navigator.of(context, rootNavigator: true).pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cryptoFieldOnChanged(String value) async {
|
||||||
|
if (_cryptoFocusNode.hasFocus) {
|
||||||
|
final newCryptoAmount = Decimal.tryParse(value);
|
||||||
|
|
||||||
|
await ref.read(buyFormStateProvider).setFromAmountAndCalculateToAmount(
|
||||||
|
newCryptoAmount ?? Decimal.zero, true);
|
||||||
|
|
||||||
|
if (newCryptoAmount == null) {
|
||||||
|
_cryptoController.text = "XXX";
|
||||||
|
// ref.read(prefsChangeNotifierProvider).exchangeRateType ==
|
||||||
|
// ExchangeRateType.estimated
|
||||||
|
// ? "-"
|
||||||
|
// : "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void selectCryptoCrypto() async {
|
||||||
|
final fromTicker = ref.read(exchangeFormStateProvider).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 = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
await _showFloatingCryptoSelectionSheet(
|
||||||
|
coins: coins,
|
||||||
|
excludedTicker: ref.read(buyFormStateProvider).toTicker ?? "-",
|
||||||
|
fromTicker: fromTicker,
|
||||||
|
onSelected: (from) =>
|
||||||
|
ref.read(buyFormStateProvider).updateFrom(from, true));
|
||||||
|
|
||||||
|
// unawaited(
|
||||||
|
// showDialog<void>(
|
||||||
|
// context: context,
|
||||||
|
// barrierDismissible: false,
|
||||||
|
// builder: (_) => WillPopScope(
|
||||||
|
// onWillPop: () async => false,
|
||||||
|
// child: Container(
|
||||||
|
// color: Theme.of(context)
|
||||||
|
// .extension<StackColors>()!
|
||||||
|
// .overlay
|
||||||
|
// .withOpacity(0.6),
|
||||||
|
// child: const CustomLoadingOverlay(
|
||||||
|
// message: "Updating exchange rate",
|
||||||
|
// eventBus: null,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
|
||||||
|
await Future<void>.delayed(const Duration(milliseconds: 300));
|
||||||
|
|
||||||
|
Navigator.of(context, rootNavigator: true).pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _showFloatingCryptoSelectionSheet({
|
||||||
|
required List<Crypto> coins,
|
||||||
|
required String excludedTicker,
|
||||||
|
required String fromTicker,
|
||||||
|
required void Function(Crypto) 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<Crypto> tickers = coins.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 coin to exchange",
|
||||||
|
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: CryptoSelectionView(
|
||||||
|
coins: tickers,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
})
|
||||||
|
: await Navigator.of(context).push(
|
||||||
|
MaterialPageRoute<dynamic>(
|
||||||
|
builder: (_) => CryptoSelectionView(
|
||||||
|
coins: tickers,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (mounted && result is Crypto) {
|
||||||
|
onSelected(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String? _fetchIconUrlFromTicker(String? ticker) {
|
||||||
|
if (ticker == null) return null;
|
||||||
|
|
||||||
|
// Iterable<Crypto> possibleCurrencies;
|
||||||
|
//
|
||||||
|
// switch (ref.read(currentExchangeNameStateProvider.state).state) {
|
||||||
|
// case ChangeNowExchange.exchangeName:
|
||||||
|
// possibleCurrencies = ref
|
||||||
|
// .read(availableChangeNowCurrenciesProvider)
|
||||||
|
// .coins
|
||||||
|
// .where((e) => e.ticker.toUpperCase() == ticker.toUpperCase());
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// possibleCurrencies = [];
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// for (final Crypto in possibleCurrencies) {
|
||||||
|
// if (Crypto.image.isNotEmpty) {
|
||||||
|
// return Crypto.image;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isWalletCoin(Coin? coin, bool isSend) {
|
||||||
|
if (coin == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String? ticker;
|
||||||
|
|
||||||
|
if (isSend) {
|
||||||
|
ticker = ref.read(buyFormStateProvider).fromTicker;
|
||||||
|
} else {
|
||||||
|
ticker = ref.read(buyFormStateProvider).toTicker;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ticker == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return coin.ticker.toUpperCase() == ticker.toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_fiatController = TextEditingController();
|
_fiatController = TextEditingController();
|
||||||
|
@ -106,20 +347,30 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: isDesktop ? 10 : 4,
|
height: isDesktop ? 10 : 4,
|
||||||
),
|
),
|
||||||
SizedBox(
|
BuyTextField(
|
||||||
height: isDesktop ? 10 : 4,
|
controller: _cryptoController,
|
||||||
|
focusNode: _cryptoFocusNode,
|
||||||
|
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 (_cryptoController.text == "-") {
|
||||||
|
_cryptoController.text = "";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onChanged: cryptoFieldOnChanged,
|
||||||
|
onButtonTap: selectCryptoCrypto,
|
||||||
|
isWalletCoin: isWalletCoin(coin, true),
|
||||||
|
image: _fetchIconUrlFromTicker(ref
|
||||||
|
.watch(buyFormStateProvider.select((value) => value.fromTicker))),
|
||||||
|
ticker: ref
|
||||||
|
.watch(buyFormStateProvider.select((value) => value.fromTicker)),
|
||||||
),
|
),
|
||||||
SizedBox(
|
|
||||||
height: isDesktop ? 10 : 4,
|
|
||||||
),
|
|
||||||
// if (ref
|
|
||||||
// .watch(buyFormStateProvider.select((value) => value.warning))
|
|
||||||
// .isNotEmpty &&
|
|
||||||
// !ref.watch(buyFormStateProvider.select((value) => value.reversed)))
|
|
||||||
// Text(
|
|
||||||
// ref.watch(buyFormStateProvider.select((value) => value.warning)),
|
|
||||||
// style: STextStyles.errorSmall(context),
|
|
||||||
// ),
|
|
||||||
Row(
|
Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
@ -132,58 +383,9 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
// SizedBox(
|
|
||||||
// height: isDesktop ? 10 : 7,
|
|
||||||
// ),
|
|
||||||
// ExchangeTextField(
|
|
||||||
// focusNode: _receiveFocusNode,
|
|
||||||
// controller: _receiveController,
|
|
||||||
// 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 (!(ref.read(prefsChangeNotifierProvider).exchangeRateType ==
|
|
||||||
// ExchangeRateType.estimated) &&
|
|
||||||
// _receiveController.text == "-") {
|
|
||||||
// _receiveController.text = "";
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// onChanged: receiveFieldOnChanged,
|
|
||||||
// onButtonTap: selectReceiveCurrency,
|
|
||||||
// isWalletCoin: isWalletCoin(coin, true),
|
|
||||||
// image: _fetchIconUrlFromTicker(ref.watch(
|
|
||||||
// buyFormStateProvider.select((value) => value.toTicker))),
|
|
||||||
// ticker: ref.watch(
|
|
||||||
// buyFormStateProvider.select((value) => value.toTicker)),
|
|
||||||
// readOnly: ref.watch(prefsChangeNotifierProvider
|
|
||||||
// .select((value) => value.exchangeRateType)) ==
|
|
||||||
// ExchangeRateType.estimated,
|
|
||||||
// // ||
|
|
||||||
// // ref.watch(exchangeProvider).name ==
|
|
||||||
// // SimpleSwapExchange.exchangeName,
|
|
||||||
// ),
|
|
||||||
// if (ref
|
|
||||||
// .watch(buyFormStateProvider.select((value) => value.warning))
|
|
||||||
// .isNotEmpty &&
|
|
||||||
// ref.watch(buyFormStateProvider.select((value) => value.reversed)))
|
|
||||||
// Text(
|
|
||||||
// ref.watch(buyFormStateProvider.select((value) => value.warning)),
|
|
||||||
// style: STextStyles.errorSmall(context),
|
|
||||||
// ),
|
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: isDesktop ? 20 : 12,
|
height: isDesktop ? 10 : 4,
|
||||||
),
|
),
|
||||||
// SizedBox(
|
|
||||||
// height: 60,
|
|
||||||
// child: RateTypeToggle(
|
|
||||||
// onChanged: onRateTypeChanged,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
Row(
|
Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
@ -194,13 +396,14 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
||||||
color: Theme.of(context).extension<StackColors>()!.textDark3,
|
color: Theme.of(context).extension<StackColors>()!.textDark3,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
const FiatCryptoToggle(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
// // these reads should be watch
|
// // these reads should be watch
|
||||||
// if (ref.watch(buyFormStateProvider).fromAmount != null &&
|
// if (ref.watch(buyFormStateProvider).fromAmount != null &&
|
||||||
// ref.watch(buyFormStateProvider).fromAmount != Decimal.zero)
|
// ref.watch(buyFormStateProvider).fromAmount != Decimal.zero)
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: isDesktop ? 20 : 12,
|
height: isDesktop ? 10 : 4,
|
||||||
),
|
),
|
||||||
BuyTextField(
|
BuyTextField(
|
||||||
controller: _fiatController,
|
controller: _fiatController,
|
||||||
|
@ -219,7 +422,7 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onChanged: fiatFieldOnChanged,
|
onChanged: fiatFieldOnChanged,
|
||||||
onButtonTap: selectFiatCurrency,
|
onButtonTap: selectFiatCrypto,
|
||||||
// isWalletCoin: isWalletCoin(coin, true),
|
// isWalletCoin: isWalletCoin(coin, true),
|
||||||
isWalletCoin: false,
|
isWalletCoin: false,
|
||||||
// image: _fetchIconUrlFromTicker(ref
|
// image: _fetchIconUrlFromTicker(ref
|
||||||
|
|
58
lib/pages/buy_view/sub_widgets/fiat_crypto_toggle.dart
Normal file
58
lib/pages/buy_view/sub_widgets/fiat_crypto_toggle.dart
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:stackwallet/utilities/util.dart';
|
||||||
|
import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
|
||||||
|
|
||||||
|
class FiatCryptoToggle extends ConsumerWidget {
|
||||||
|
const FiatCryptoToggle({
|
||||||
|
Key? key,
|
||||||
|
// this.onChanged,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
// final void Function(ExchangeRateType)? onChanged;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
debugPrint("BUILD: $runtimeType");
|
||||||
|
final isDesktop = Util.isDesktop;
|
||||||
|
|
||||||
|
// final estimated = ref.watch(prefsChangeNotifierProvider
|
||||||
|
// .select((value) => value.exchangeRateType)) ==
|
||||||
|
// ExchangeRateType.estimated;
|
||||||
|
|
||||||
|
// return Toggle(
|
||||||
|
// onValueChanged: (value) {
|
||||||
|
// // if (!estimated) {
|
||||||
|
// // ref.read(prefsChangeNotifierProvider).exchangeRateType =
|
||||||
|
// // ExchangeRateType.estimated;
|
||||||
|
// // onChanged?.call(ExchangeRateType.estimated);
|
||||||
|
// // } else {
|
||||||
|
// // onChanged?.call(ExchangeRateType.fixed);
|
||||||
|
// // }
|
||||||
|
// },
|
||||||
|
// isOn: true,
|
||||||
|
// onColor: Theme.of(context).extension<StackColors>()!.textFieldDefaultBG,
|
||||||
|
// offColor: isDesktop
|
||||||
|
// ? Theme.of(context).extension<StackColors>()!.buttonBackSecondary
|
||||||
|
// : Theme.of(context).extension<StackColors>()!.popupBG,
|
||||||
|
// decoration: BoxDecoration(
|
||||||
|
// borderRadius: BorderRadius.circular(
|
||||||
|
// Constants.size.circularBorderRadius,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// onIcon: Assets.svg.lockOpen,
|
||||||
|
// onText: "Estimate rate",
|
||||||
|
// offIcon: Assets.svg.lock,
|
||||||
|
// offText: "Fixed rate",
|
||||||
|
// );
|
||||||
|
return BlueTextButton(
|
||||||
|
text: "Use crypto amount",
|
||||||
|
textSize: 14,
|
||||||
|
onTap: () {
|
||||||
|
// Navigator.of(context).pushNamed(
|
||||||
|
// ForgotPasswordDesktopView.routeName,
|
||||||
|
// );
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
// import 'package:stackwallet/pages/buy_view/buy_form.dart';
|
import 'package:stackwallet/pages/buy_view/buy_form.dart';
|
||||||
// import 'package:stackwallet/pages_desktop_specific/desktop_buy/subwidgets/desktop_buy_history.dart';
|
|
||||||
import 'package:stackwallet/utilities/text_styles.dart';
|
import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
||||||
|
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||||
|
|
||||||
class DesktopBuyView extends StatefulWidget {
|
class DesktopBuyView extends StatefulWidget {
|
||||||
const DesktopBuyView({Key? key}) : super(key: key);
|
const DesktopBuyView({Key? key}) : super(key: key);
|
||||||
|
@ -25,7 +25,7 @@ class _DesktopBuyViewState extends State<DesktopBuyView> {
|
||||||
left: 24,
|
left: 24,
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
"Buy",
|
"Buy crypto",
|
||||||
style: STextStyles.desktopH3(context),
|
style: STextStyles.desktopH3(context),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -44,17 +44,17 @@ class _DesktopBuyViewState extends State<DesktopBuyView> {
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
// Text(
|
||||||
"Coming soon",
|
// "Coming soon",
|
||||||
style: STextStyles.desktopTextExtraExtraSmall(context),
|
// style: STextStyles.desktopTextExtraExtraSmall(context),
|
||||||
),
|
// ),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 16,
|
height: 16,
|
||||||
),
|
),
|
||||||
// const RoundedWhiteContainer(
|
const RoundedWhiteContainer(
|
||||||
// padding: EdgeInsets.all(24),
|
padding: EdgeInsets.all(24),
|
||||||
// child: BuyForm(),
|
child: BuyForm(),
|
||||||
// ),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
Loading…
Reference in a new issue