mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-11-18 02:07:43 +00:00
commit
9528ee4389
28 changed files with 5055 additions and 471 deletions
|
@ -147,7 +147,7 @@ Set up Ubuntu 20.04 in WSL2. Follow the entire Linux host section to get set up
|
|||
<!-- TODO: script the copying or installation of libraries from WSL2 to the parent Windows host -->
|
||||
|
||||
### Install Flutter on Windows host
|
||||
Install Flutter 3.7.12 on your Windows host (not in WSL2) by following these instructions: https://docs.flutter.dev/get-started/install/windows or by running `scripts/windows/deps.ps1`. You may still have to add `C:\development\flutter\bin` to PATH before proceeding, even if you ran `deps.ps1`. Run `flutter doctor` in PowerShell to confirm its installation.
|
||||
Install Flutter 3.10.3 on your Windows host (not in WSL2) by following these instructions: https://docs.flutter.dev/get-started/install/windows or by running `scripts/windows/deps.ps1`. You may still have to add `C:\development\flutter\bin` to PATH before proceeding, even if you ran `deps.ps1`. Run `flutter doctor` in PowerShell to confirm its installation.
|
||||
|
||||
### Dependencies
|
||||
Install the Windows SDK: https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/ You may need to install the [Windows 10 SDK](https://developer.microsoft.com/en-us/windows/downloads/sdk-archive/), which can be installed [by Visual Studio](https://stackoverflow.com/a/73923899) (`Tools > Get Tools and Features... > Modify > Individual Components > Windows 10 SDK`).
|
||||
|
|
|
@ -1493,8 +1493,12 @@ class StackTheme {
|
|||
|
||||
late final ThemeAssetsV2? assetsV2;
|
||||
|
||||
// cheat build runner into adding this at end of property id list in isar
|
||||
@Name("zAssetsV3")
|
||||
late final ThemeAssetsV3? assetsV3;
|
||||
|
||||
@ignore
|
||||
IThemeAssets get assets => assetsV2 ?? assetsV1!;
|
||||
IThemeAssets get assets => assetsV3 ?? assetsV2 ?? assetsV1!;
|
||||
|
||||
// ===========================================================================
|
||||
|
||||
|
@ -1517,13 +1521,20 @@ class StackTheme {
|
|||
themeId: json["id"] as String,
|
||||
)
|
||||
: null
|
||||
..assetsV2 = version >= 2
|
||||
..assetsV2 = version == 2
|
||||
? ThemeAssetsV2.fromJson(
|
||||
json: Map<String, dynamic>.from(json["assets"] as Map),
|
||||
applicationThemesDirectoryPath: applicationThemesDirectoryPath,
|
||||
themeId: json["id"] as String,
|
||||
)
|
||||
: null
|
||||
..assetsV3 = version >= 3
|
||||
? ThemeAssetsV3.fromJson(
|
||||
json: Map<String, dynamic>.from(json["assets"] as Map),
|
||||
applicationThemesDirectoryPath: applicationThemesDirectoryPath,
|
||||
themeId: json["id"] as String,
|
||||
)
|
||||
: null
|
||||
..themeId = json["id"] as String
|
||||
..name = json["name"] as String
|
||||
..brightnessString = json["brightness"] as String
|
||||
|
@ -1939,10 +1950,6 @@ class ThemeAssets implements IThemeAssets {
|
|||
@override
|
||||
late final String? background;
|
||||
|
||||
@override
|
||||
@ignore
|
||||
String? get walletSummaryCardBackground => null;
|
||||
|
||||
ThemeAssets();
|
||||
|
||||
factory ThemeAssets.fromJson({
|
||||
|
@ -2104,8 +2111,6 @@ class ThemeAssetsV2 implements IThemeAssets {
|
|||
late final String? loadingGif;
|
||||
@override
|
||||
late final String? background;
|
||||
@override
|
||||
late final String? walletSummaryCardBackground;
|
||||
|
||||
late final String coinPlaceholder;
|
||||
|
||||
|
@ -2200,10 +2205,6 @@ class ThemeAssetsV2 implements IThemeAssets {
|
|||
: null
|
||||
..background = json["background"] is String
|
||||
? "$applicationThemesDirectoryPath/$themeId/assets/${json["background"] as String}"
|
||||
: null
|
||||
..walletSummaryCardBackground = json["walletSummaryCardBackground"]
|
||||
is String
|
||||
? "$applicationThemesDirectoryPath/$themeId/assets/${json["walletSummaryCardBackground"] as String}"
|
||||
: null;
|
||||
}
|
||||
|
||||
|
@ -2254,11 +2255,235 @@ class ThemeAssetsV2 implements IThemeAssets {
|
|||
'txExchangeFailed: $txExchangeFailed, '
|
||||
'loadingGif: $loadingGif, '
|
||||
'background: $background, '
|
||||
'walletSummaryCardBackground: $walletSummaryCardBackground, '
|
||||
'coinPlaceholder: $coinPlaceholder, '
|
||||
'coinIcons: $coinIcons, '
|
||||
'coinImages: $coinImages, '
|
||||
'coinSecondaryImages: $coinSecondaryImages'
|
||||
'coinSecondaryImages: $coinSecondaryImages, '
|
||||
')';
|
||||
}
|
||||
}
|
||||
|
||||
@Embedded(inheritance: false)
|
||||
class ThemeAssetsV3 implements IThemeAssets {
|
||||
@override
|
||||
late final String bellNew;
|
||||
@override
|
||||
late final String buy;
|
||||
@override
|
||||
late final String exchange;
|
||||
@override
|
||||
late final String personaIncognito;
|
||||
@override
|
||||
late final String personaEasy;
|
||||
@override
|
||||
late final String stack;
|
||||
@override
|
||||
late final String stackIcon;
|
||||
@override
|
||||
late final String receive;
|
||||
@override
|
||||
late final String receivePending;
|
||||
@override
|
||||
late final String receiveCancelled;
|
||||
@override
|
||||
late final String send;
|
||||
@override
|
||||
late final String sendPending;
|
||||
@override
|
||||
late final String sendCancelled;
|
||||
@override
|
||||
late final String themeSelector;
|
||||
@override
|
||||
late final String themePreview;
|
||||
@override
|
||||
late final String txExchange;
|
||||
@override
|
||||
late final String txExchangePending;
|
||||
@override
|
||||
late final String txExchangeFailed;
|
||||
@override
|
||||
late final String? loadingGif;
|
||||
@override
|
||||
late final String? background;
|
||||
|
||||
late final String coinPlaceholder;
|
||||
|
||||
// Added some future proof params in case we want to add anything else
|
||||
// This should provide some buffer in stead of creating assetsV4 etc
|
||||
@Name("otherStringParam1")
|
||||
late final String? dummy1;
|
||||
@Name("otherStringParam2")
|
||||
late final String? dummy2;
|
||||
@Name("otherStringParam3")
|
||||
late final String? dummy3;
|
||||
|
||||
@ignore
|
||||
Map<Coin, String> get coinIcons => _coinIcons ??= parseCoinAssetsString(
|
||||
coinIconsString,
|
||||
placeHolder: coinPlaceholder,
|
||||
);
|
||||
@ignore
|
||||
Map<Coin, String>? _coinIcons;
|
||||
late final String coinIconsString;
|
||||
|
||||
@ignore
|
||||
Map<Coin, String> get coinImages => _coinImages ??= parseCoinAssetsString(
|
||||
coinImagesString,
|
||||
placeHolder: coinPlaceholder,
|
||||
);
|
||||
@ignore
|
||||
Map<Coin, String>? _coinImages;
|
||||
late final String coinImagesString;
|
||||
|
||||
@ignore
|
||||
Map<Coin, String> get coinSecondaryImages =>
|
||||
_coinSecondaryImages ??= parseCoinAssetsString(
|
||||
coinSecondaryImagesString,
|
||||
placeHolder: coinPlaceholder,
|
||||
);
|
||||
@ignore
|
||||
Map<Coin, String>? _coinSecondaryImages;
|
||||
late final String coinSecondaryImagesString;
|
||||
|
||||
@ignore
|
||||
Map<Coin, String>? get coinCardImages =>
|
||||
_coinCardImages ??= coinCardImagesString == null
|
||||
? null
|
||||
: parseCoinAssetsString(
|
||||
coinCardImagesString!,
|
||||
placeHolder: coinPlaceholder,
|
||||
);
|
||||
@ignore
|
||||
Map<Coin, String>? _coinCardImages;
|
||||
late final String? coinCardImagesString;
|
||||
|
||||
ThemeAssetsV3();
|
||||
|
||||
factory ThemeAssetsV3.fromJson({
|
||||
required Map<String, dynamic> json,
|
||||
required String applicationThemesDirectoryPath,
|
||||
required String themeId,
|
||||
}) {
|
||||
return ThemeAssetsV3()
|
||||
..bellNew =
|
||||
"$applicationThemesDirectoryPath/$themeId/assets/${json["bell_new"] as String}"
|
||||
..buy =
|
||||
"$applicationThemesDirectoryPath/$themeId/assets/${json["buy"] as String}"
|
||||
..exchange =
|
||||
"$applicationThemesDirectoryPath/$themeId/assets/${json["exchange"] as String}"
|
||||
..personaIncognito =
|
||||
"$applicationThemesDirectoryPath/$themeId/assets/${json["persona_incognito"] as String}"
|
||||
..personaEasy =
|
||||
"$applicationThemesDirectoryPath/$themeId/assets/${json["persona_easy"] as String}"
|
||||
..stack =
|
||||
"$applicationThemesDirectoryPath/$themeId/assets/${json["stack"] as String}"
|
||||
..stackIcon =
|
||||
"$applicationThemesDirectoryPath/$themeId/assets/${json["stack_icon"] as String}"
|
||||
..receive =
|
||||
"$applicationThemesDirectoryPath/$themeId/assets/${json["receive"] as String}"
|
||||
..receivePending =
|
||||
"$applicationThemesDirectoryPath/$themeId/assets/${json["receive_pending"] as String}"
|
||||
..receiveCancelled =
|
||||
"$applicationThemesDirectoryPath/$themeId/assets/${json["receive_cancelled"] as String}"
|
||||
..send =
|
||||
"$applicationThemesDirectoryPath/$themeId/assets/${json["send"] as String}"
|
||||
..sendPending =
|
||||
"$applicationThemesDirectoryPath/$themeId/assets/${json["send_pending"] as String}"
|
||||
..sendCancelled =
|
||||
"$applicationThemesDirectoryPath/$themeId/assets/${json["send_cancelled"] as String}"
|
||||
..themeSelector =
|
||||
"$applicationThemesDirectoryPath/$themeId/assets/${json["theme_selector"] as String}"
|
||||
..themePreview =
|
||||
"$applicationThemesDirectoryPath/$themeId/assets/${json["theme_preview"] as String}"
|
||||
..txExchange =
|
||||
"$applicationThemesDirectoryPath/$themeId/assets/${json["tx_exchange"] as String}"
|
||||
..txExchangePending =
|
||||
"$applicationThemesDirectoryPath/$themeId/assets/${json["tx_exchange_pending"] as String}"
|
||||
..txExchangeFailed =
|
||||
"$applicationThemesDirectoryPath/$themeId/assets/${json["tx_exchange_failed"] as String}"
|
||||
..coinPlaceholder =
|
||||
"$applicationThemesDirectoryPath/$themeId/assets/${json["coin_placeholder"] as String}"
|
||||
..coinIconsString = createCoinAssetsString(
|
||||
"$applicationThemesDirectoryPath/$themeId/assets",
|
||||
Map<String, dynamic>.from(json["coins"]["icons"] as Map),
|
||||
)
|
||||
..coinImagesString = createCoinAssetsString(
|
||||
"$applicationThemesDirectoryPath/$themeId/assets",
|
||||
Map<String, dynamic>.from(json["coins"]["images"] as Map),
|
||||
)
|
||||
..coinSecondaryImagesString = createCoinAssetsString(
|
||||
"$applicationThemesDirectoryPath/$themeId/assets",
|
||||
Map<String, dynamic>.from(json["coins"]["secondaries"] as Map),
|
||||
)
|
||||
..coinCardImagesString = json["coins"]["cards"] is Map
|
||||
? createCoinAssetsString(
|
||||
"$applicationThemesDirectoryPath/$themeId/assets",
|
||||
Map<String, dynamic>.from(json["coins"]["cards"] as Map),
|
||||
)
|
||||
: null
|
||||
..loadingGif = json["loading_gif"] is String
|
||||
? "$applicationThemesDirectoryPath/$themeId/assets/${json["loading_gif"] as String}"
|
||||
: null
|
||||
..background = json["background"] is String
|
||||
? "$applicationThemesDirectoryPath/$themeId/assets/${json["background"] as String}"
|
||||
: null
|
||||
..dummy1 = null
|
||||
..dummy2 = null
|
||||
..dummy3 = null;
|
||||
}
|
||||
|
||||
static String createCoinAssetsString(String path, Map<String, dynamic> json) {
|
||||
final Map<String, dynamic> map = {};
|
||||
for (final entry in json.entries) {
|
||||
map[entry.key] = "$path/${entry.value as String}";
|
||||
}
|
||||
return jsonEncode(map);
|
||||
}
|
||||
|
||||
static Map<Coin, String> parseCoinAssetsString(
|
||||
String jsonString, {
|
||||
required String placeHolder,
|
||||
}) {
|
||||
final json = jsonDecode(jsonString) as Map;
|
||||
final map = Map<String, dynamic>.from(json);
|
||||
|
||||
final Map<Coin, String> result = {};
|
||||
|
||||
for (final coin in Coin.values) {
|
||||
result[coin] = map[coin.name] as String? ?? placeHolder;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ThemeAssetsV3('
|
||||
'bellNew: $bellNew, '
|
||||
'buy: $buy, '
|
||||
'exchange: $exchange, '
|
||||
'personaIncognito: $personaIncognito, '
|
||||
'personaEasy: $personaEasy, '
|
||||
'stack: $stack, '
|
||||
'stackIcon: $stackIcon, '
|
||||
'receive: $receive, '
|
||||
'receivePending: $receivePending, '
|
||||
'receiveCancelled: $receiveCancelled, '
|
||||
'send: $send, '
|
||||
'sendPending: $sendPending, '
|
||||
'sendCancelled: $sendCancelled, '
|
||||
'themeSelector: $themeSelector, '
|
||||
'themePreview: $themePreview, '
|
||||
'txExchange: $txExchange, '
|
||||
'txExchangePending: $txExchangePending, '
|
||||
'txExchangeFailed: $txExchangeFailed, '
|
||||
'loadingGif: $loadingGif, '
|
||||
'background: $background, '
|
||||
'coinPlaceholder: $coinPlaceholder, '
|
||||
'coinIcons: $coinIcons, '
|
||||
'coinImages: $coinImages, '
|
||||
'coinSecondaryImages: $coinSecondaryImages, '
|
||||
'coinCardImages: $coinCardImages'
|
||||
')';
|
||||
}
|
||||
}
|
||||
|
@ -2285,5 +2510,4 @@ abstract class IThemeAssets {
|
|||
|
||||
String? get loadingGif;
|
||||
String? get background;
|
||||
String? get walletSummaryCardBackground;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -73,12 +73,6 @@ class _NewWalletRecoveryPhraseWarningViewState
|
|||
Widget build(BuildContext context) {
|
||||
debugPrint("BUILD: $runtimeType");
|
||||
|
||||
final _numberOfPhraseWords = coin == Coin.monero
|
||||
? Constants.seedPhraseWordCountMonero
|
||||
: coin == Coin.wownero
|
||||
? 14
|
||||
: Constants.seedPhraseWordCountBip39;
|
||||
|
||||
return MasterScaffold(
|
||||
isDesktop: isDesktop,
|
||||
appBar: isDesktop
|
||||
|
@ -177,7 +171,15 @@ class _NewWalletRecoveryPhraseWarningViewState
|
|||
width: isDesktop ? 480 : null,
|
||||
child: isDesktop
|
||||
? Text(
|
||||
"On the next screen you will see $_numberOfPhraseWords words that make up your recovery phrase.\n\nPlease write it down. Keep it safe and never share it with anyone. Your recovery phrase is the only way you can access your funds if you forget your PIN, lose your phone, etc.\n\nStack Wallet does not keep nor is able to restore your recover phrase. Only you have access to your wallet.",
|
||||
"On the next screen you will see "
|
||||
"${Constants.defaultSeedPhraseLengthFor(coin: coin)} "
|
||||
"words that make up your recovery phrase.\n\nPlease "
|
||||
"write it down. Keep it safe and never share it with "
|
||||
"anyone. Your recovery phrase is the only way you can"
|
||||
" access your funds if you forget your PIN, lose your"
|
||||
" phone, etc.\n\nStack Wallet does not keep nor is "
|
||||
"able to restore your recover phrase. Only you have "
|
||||
"access to your wallet.",
|
||||
style: isDesktop
|
||||
? STextStyles.desktopTextMediumRegular(context)
|
||||
: STextStyles.subtitle(context).copyWith(
|
||||
|
@ -214,7 +216,9 @@ class _NewWalletRecoveryPhraseWarningViewState
|
|||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: "$_numberOfPhraseWords words",
|
||||
text:
|
||||
"${Constants.defaultSeedPhraseLengthFor(coin: coin)}"
|
||||
" words",
|
||||
style: STextStyles.desktopH3(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
|
|
|
@ -26,6 +26,7 @@ import 'package:stackwallet/utilities/amount/amount.dart';
|
|||
import 'package:stackwallet/utilities/amount/amount_formatter.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/background.dart';
|
||||
|
@ -156,7 +157,12 @@ class _ConfirmChangeNowSendViewState
|
|||
|
||||
Navigator.of(context).popUntil(ModalRoute.withName(routeOnSuccessName));
|
||||
}
|
||||
} catch (e) {
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"Broadcast transaction failed: $e\n$s",
|
||||
level: LogLevel.Error,
|
||||
);
|
||||
|
||||
// pop sending dialog
|
||||
Navigator.of(context).pop();
|
||||
|
||||
|
@ -205,9 +211,9 @@ class _ConfirmChangeNowSendViewState
|
|||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
const Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: const [
|
||||
children: [
|
||||
DesktopDialogCloseButton(),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -290,6 +290,7 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
|||
walletId: tuple.item1,
|
||||
routeOnSuccessName: HomeView.routeName,
|
||||
trade: model.trade!,
|
||||
shouldSendPublicFiroFunds: firoPublicSend,
|
||||
),
|
||||
settings: const RouteSettings(
|
||||
name: ConfirmChangeNowSendView.routeName,
|
||||
|
|
|
@ -303,11 +303,17 @@ class _ReceiveViewState extends ConsumerState<ReceiveView> {
|
|||
),
|
||||
),
|
||||
),
|
||||
if (coin != Coin.epicCash && coin != Coin.ethereum)
|
||||
if (coin != Coin.epicCash &&
|
||||
coin != Coin.ethereum &&
|
||||
coin != Coin.banano &&
|
||||
coin != Coin.nano)
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
if (coin != Coin.epicCash && coin != Coin.ethereum)
|
||||
if (coin != Coin.epicCash &&
|
||||
coin != Coin.ethereum &&
|
||||
coin != Coin.banano &&
|
||||
coin != Coin.nano)
|
||||
TextButton(
|
||||
onPressed: generateNewAddress,
|
||||
style: Theme.of(context)
|
||||
|
|
|
@ -436,36 +436,38 @@ class _ConfirmTransactionViewState
|
|||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
RoundedWhiteContainer(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Transaction fee",
|
||||
style: STextStyles.smallMed12(context),
|
||||
),
|
||||
Text(
|
||||
ref.watch(pAmountFormatter(coin)).format(
|
||||
(transactionInfo["fee"] is Amount
|
||||
? transactionInfo["fee"] as Amount
|
||||
: (transactionInfo["fee"] as int)
|
||||
.toAmountAsRaw(
|
||||
fractionDigits: ref.watch(
|
||||
managerProvider.select(
|
||||
(value) => value.coin.decimals,
|
||||
),
|
||||
),
|
||||
)),
|
||||
),
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
textAlign: TextAlign.right,
|
||||
),
|
||||
],
|
||||
if (coin != Coin.banano && coin != Coin.nano)
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
if (coin != Coin.banano && coin != Coin.nano)
|
||||
RoundedWhiteContainer(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Transaction fee",
|
||||
style: STextStyles.smallMed12(context),
|
||||
),
|
||||
Text(
|
||||
ref.watch(pAmountFormatter(coin)).format(
|
||||
(transactionInfo["fee"] is Amount
|
||||
? transactionInfo["fee"] as Amount
|
||||
: (transactionInfo["fee"] as int)
|
||||
.toAmountAsRaw(
|
||||
fractionDigits: ref.watch(
|
||||
managerProvider.select(
|
||||
(value) => value.coin.decimals,
|
||||
),
|
||||
),
|
||||
)),
|
||||
),
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
textAlign: TextAlign.right,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:bip47/bip47.dart';
|
||||
import 'package:cw_core/monero_transaction_priority.dart';
|
||||
|
@ -26,7 +27,6 @@ import 'package:stackwallet/pages/coin_control/coin_control_view.dart';
|
|||
import 'package:stackwallet/pages/send_view/confirm_transaction_view.dart';
|
||||
import 'package:stackwallet/pages/send_view/sub_widgets/building_transaction_dialog.dart';
|
||||
import 'package:stackwallet/pages/send_view/sub_widgets/firo_balance_selection_sheet.dart';
|
||||
import 'package:stackwallet/pages/send_view/sub_widgets/openalias_sheet.dart';
|
||||
import 'package:stackwallet/pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/providers/ui/fee_rate_type_state_provider.dart';
|
||||
|
@ -138,7 +138,8 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
cryptoAmount = cryptoAmount.split(" ").first;
|
||||
}
|
||||
|
||||
final shift = ref.read(pAmountUnit(coin)).shift;
|
||||
// ensure we don't shift past minimum atomic value
|
||||
final shift = min(ref.read(pAmountUnit(coin)).shift, coin.decimals);
|
||||
|
||||
_amountToSend = cryptoAmount.contains(",")
|
||||
? Decimal.parse(cryptoAmount.replaceFirst(",", "."))
|
||||
|
|
|
@ -12,11 +12,11 @@ import 'dart:convert';
|
|||
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
// import 'package:flutter_libepiccash/git_versions.dart' as EPIC_VERSIONS;
|
||||
// import 'package:flutter_libmonero/git_versions.dart' as MONERO_VERSIONS;
|
||||
import 'package:flutter_libepiccash/git_versions.dart' as EPIC_VERSIONS;
|
||||
import 'package:flutter_libmonero/git_versions.dart' as MONERO_VERSIONS;
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:http/http.dart';
|
||||
// import 'package:lelantus/git_versions.dart' as FIRO_VERSIONS;
|
||||
import 'package:lelantus/git_versions.dart' as FIRO_VERSIONS;
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:stackwallet/themes/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
|
@ -115,12 +115,9 @@ class AboutView extends ConsumerWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
String firoCommit =
|
||||
"Unable to fetch version"; //FIRO_VERSIONS.getPluginVersion();
|
||||
String epicCashCommit =
|
||||
"Unable to fetch version"; // EPIC_VERSIONS.getPluginVersion();
|
||||
String moneroCommit =
|
||||
"Unable to fetch version"; // MONERO_VERSIONS.getPluginVersion();
|
||||
String firoCommit = FIRO_VERSIONS.getPluginVersion();
|
||||
String epicCashCommit = EPIC_VERSIONS.getPluginVersion();
|
||||
String moneroCommit = MONERO_VERSIONS.getPluginVersion();
|
||||
List<Future> futureFiroList = [
|
||||
doesCommitExist("cypherstack", "flutter_liblelantus", firoCommit),
|
||||
isHeadCommit("cypherstack", "flutter_liblelantus", "main", firoCommit),
|
||||
|
@ -174,14 +171,14 @@ class AboutView extends ConsumerWidget {
|
|||
String appName = "";
|
||||
String build = "";
|
||||
|
||||
// if (snapshot.connectionState ==
|
||||
// ConnectionState.done &&
|
||||
// snapshot.hasData) {
|
||||
// version = snapshot.data!.version;
|
||||
// build = snapshot.data!.buildNumber;
|
||||
// signature = snapshot.data!.buildSignature;
|
||||
// appName = snapshot.data!.appName;
|
||||
// }
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
version = snapshot.data!.version;
|
||||
build = snapshot.data!.buildNumber;
|
||||
signature = snapshot.data!.buildSignature;
|
||||
appName = snapshot.data!.appName;
|
||||
}
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
|
|
|
@ -17,11 +17,11 @@ import 'package:event_bus/event_bus.dart';
|
|||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
// import 'package:flutter_libepiccash/git_versions.dart' as EPIC_VERSIONS;
|
||||
// import 'package:flutter_libmonero/git_versions.dart' as MONERO_VERSIONS;
|
||||
import 'package:flutter_libepiccash/git_versions.dart' as EPIC_VERSIONS;
|
||||
import 'package:flutter_libmonero/git_versions.dart' as MONERO_VERSIONS;
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
// import 'package:lelantus/git_versions.dart' as FIRO_VERSIONS;
|
||||
import 'package:lelantus/git_versions.dart' as FIRO_VERSIONS;
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:stackwallet/models/isar/models/log.dart';
|
||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||
|
@ -302,11 +302,11 @@ class _DebugViewState extends ConsumerState<DebugView> {
|
|||
packageInfo.buildSignature;
|
||||
final appName = packageInfo.appName;
|
||||
String firoCommit =
|
||||
"Unable to fetch version"; //FIRO_VERSIONS.getPluginVersion();
|
||||
FIRO_VERSIONS.getPluginVersion();
|
||||
String epicCashCommit =
|
||||
"Unable to fetch version"; //EPIC_VERSIONS.getPluginVersion();
|
||||
EPIC_VERSIONS.getPluginVersion();
|
||||
String moneroCommit =
|
||||
"Unable to fetch version"; // MONERO_VERSIONS.getPluginVersion();
|
||||
MONERO_VERSIONS.getPluginVersion();
|
||||
DeviceInfoPlugin deviceInfoPlugin =
|
||||
DeviceInfoPlugin();
|
||||
final deviceInfo =
|
||||
|
|
|
@ -9,20 +9,14 @@
|
|||
*/
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:stackwallet/pages/wallet_view/sub_widgets/wallet_summary_info.dart';
|
||||
import 'package:stackwallet/services/coins/manager.dart';
|
||||
import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
|
||||
import 'package:stackwallet/themes/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/widgets/coin_card.dart';
|
||||
|
||||
class WalletSummary extends StatelessWidget {
|
||||
const WalletSummary({
|
||||
Key? key,
|
||||
required this.walletId,
|
||||
required this.managerProvider,
|
||||
required this.initialSyncStatus,
|
||||
this.aspectRatio = 2.0,
|
||||
this.minHeight = 100.0,
|
||||
|
@ -32,7 +26,6 @@ class WalletSummary extends StatelessWidget {
|
|||
}) : super(key: key);
|
||||
|
||||
final String walletId;
|
||||
final ChangeNotifierProvider<Manager> managerProvider;
|
||||
final WalletSyncStatus initialSyncStatus;
|
||||
|
||||
final double aspectRatio;
|
||||
|
@ -52,83 +45,25 @@ class WalletSummary extends StatelessWidget {
|
|||
maxHeight: maxHeight,
|
||||
maxWidth: minWidth,
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
Consumer(
|
||||
builder: (_, ref, __) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.colorForCoin(ref.watch(
|
||||
managerProvider.select((value) => value.coin))),
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
Positioned.fill(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Spacer(
|
||||
flex: 5,
|
||||
),
|
||||
Expanded(
|
||||
flex: 6,
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.ellipse1,
|
||||
// fit: BoxFit.fitWidth,
|
||||
// clipBehavior: Clip.none,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 25,
|
||||
),
|
||||
],
|
||||
child: LayoutBuilder(
|
||||
builder: (_, constraints) => Stack(
|
||||
children: [
|
||||
CoinCard(
|
||||
walletId: walletId,
|
||||
width: constraints.maxWidth,
|
||||
height: constraints.maxHeight,
|
||||
),
|
||||
),
|
||||
// Positioned.fill(
|
||||
// child:
|
||||
// Column(
|
||||
// mainAxisAlignment: MainAxisAlignment.end,
|
||||
// children: [
|
||||
Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Row(
|
||||
children: [
|
||||
const Spacer(
|
||||
flex: 1,
|
||||
Positioned.fill(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: WalletSummaryInfo(
|
||||
walletId: walletId,
|
||||
initialSyncStatus: initialSyncStatus,
|
||||
),
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.ellipse2,
|
||||
// fit: BoxFit.f,
|
||||
// clipBehavior: Clip.none,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 13,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
Positioned.fill(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: WalletSummaryInfo(
|
||||
walletId: walletId,
|
||||
initialSyncStatus: initialSyncStatus,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -148,8 +148,7 @@ class _TransactionDetailsViewState
|
|||
if (_transaction.numberOfMessages == 1) {
|
||||
return "Receiving (waiting for sender)";
|
||||
} else if ((_transaction.numberOfMessages ?? 0) > 1) {
|
||||
return
|
||||
"Receiving (waiting for confirmations)"; // TODO test if the sender still has to open again after the receiver has 2 messages present, ie. sender->receiver->sender->node (yes) vs. sender->receiver->node (no)
|
||||
return "Receiving (waiting for confirmations)"; // TODO test if the sender still has to open again after the receiver has 2 messages present, ie. sender->receiver->sender->node (yes) vs. sender->receiver->node (no)
|
||||
} else {
|
||||
return "Receiving";
|
||||
}
|
||||
|
@ -963,94 +962,99 @@ class _TransactionDetailsViewState
|
|||
],
|
||||
),
|
||||
),
|
||||
isDesktop
|
||||
? const _Divider()
|
||||
: const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
RoundedWhiteContainer(
|
||||
padding: isDesktop
|
||||
? const EdgeInsets.all(16)
|
||||
: const EdgeInsets.all(12),
|
||||
child: Builder(builder: (context) {
|
||||
String feeString = showFeePending
|
||||
? _transaction.isConfirmed(
|
||||
currentHeight,
|
||||
coin.requiredConfirmations,
|
||||
)
|
||||
? ref
|
||||
.watch(pAmountFormatter(coin))
|
||||
.format(
|
||||
fee,
|
||||
withUnitName: isTokenTx,
|
||||
)
|
||||
: "Pending"
|
||||
: ref.watch(pAmountFormatter(coin)).format(
|
||||
fee,
|
||||
withUnitName: isTokenTx,
|
||||
);
|
||||
if (coin != Coin.banano && coin != Coin.nano)
|
||||
isDesktop
|
||||
? const _Divider()
|
||||
: const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
if (coin != Coin.banano && coin != Coin.nano)
|
||||
RoundedWhiteContainer(
|
||||
padding: isDesktop
|
||||
? const EdgeInsets.all(16)
|
||||
: const EdgeInsets.all(12),
|
||||
child: Builder(builder: (context) {
|
||||
String feeString = showFeePending
|
||||
? _transaction.isConfirmed(
|
||||
currentHeight,
|
||||
coin.requiredConfirmations,
|
||||
)
|
||||
? ref
|
||||
.watch(pAmountFormatter(coin))
|
||||
.format(
|
||||
fee,
|
||||
withUnitName: isTokenTx,
|
||||
)
|
||||
: "Pending"
|
||||
: ref
|
||||
.watch(pAmountFormatter(coin))
|
||||
.format(
|
||||
fee,
|
||||
withUnitName: isTokenTx,
|
||||
);
|
||||
|
||||
return Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Transaction fee",
|
||||
style: isDesktop
|
||||
? STextStyles
|
||||
.desktopTextExtraExtraSmall(
|
||||
context)
|
||||
: STextStyles.itemSubtitle(
|
||||
context),
|
||||
),
|
||||
if (isDesktop)
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
if (isDesktop)
|
||||
SelectableText(
|
||||
feeString,
|
||||
return Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Transaction fee",
|
||||
style: isDesktop
|
||||
? STextStyles
|
||||
.desktopTextExtraExtraSmall(
|
||||
context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<
|
||||
StackColors>()!
|
||||
.textDark,
|
||||
)
|
||||
: STextStyles.itemSubtitle12(
|
||||
context),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (!isDesktop)
|
||||
SelectableText(
|
||||
feeString,
|
||||
style: isDesktop
|
||||
? STextStyles
|
||||
.desktopTextExtraExtraSmall(
|
||||
context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark,
|
||||
)
|
||||
: STextStyles.itemSubtitle12(
|
||||
context),
|
||||
: STextStyles.itemSubtitle(
|
||||
context),
|
||||
),
|
||||
if (isDesktop)
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
if (isDesktop)
|
||||
SelectableText(
|
||||
feeString,
|
||||
style: isDesktop
|
||||
? STextStyles
|
||||
.desktopTextExtraExtraSmall(
|
||||
context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<
|
||||
StackColors>()!
|
||||
.textDark,
|
||||
)
|
||||
: STextStyles.itemSubtitle12(
|
||||
context),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (isDesktop)
|
||||
IconCopyButton(data: feeString)
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
if (!isDesktop)
|
||||
SelectableText(
|
||||
feeString,
|
||||
style: isDesktop
|
||||
? STextStyles
|
||||
.desktopTextExtraExtraSmall(
|
||||
context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark,
|
||||
)
|
||||
: STextStyles.itemSubtitle12(
|
||||
context),
|
||||
),
|
||||
if (isDesktop)
|
||||
IconCopyButton(data: feeString)
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
isDesktop
|
||||
? const _Divider()
|
||||
: const SizedBox(
|
||||
|
|
|
@ -680,7 +680,6 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
|||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
child: WalletSummary(
|
||||
walletId: walletId,
|
||||
managerProvider: managerProvider,
|
||||
initialSyncStatus: ref.watch(managerProvider
|
||||
.select((value) => value.isRefreshing))
|
||||
? WalletSyncStatus.syncing
|
||||
|
|
|
@ -21,11 +21,11 @@ import 'package:stackwallet/themes/coin_icon_provider.dart';
|
|||
import 'package:stackwallet/themes/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/amount/amount.dart';
|
||||
import 'package:stackwallet/utilities/amount/amount_formatter.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/util.dart';
|
||||
import 'package:stackwallet/widgets/coin_card.dart';
|
||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
|
@ -145,66 +145,10 @@ class _FavoriteCardState extends ConsumerState<FavoriteCard> {
|
|||
width: widget.width,
|
||||
height: widget.height,
|
||||
child: CardOverlayStack(
|
||||
background: Stack(
|
||||
children: [
|
||||
Container(
|
||||
width: widget.width,
|
||||
height: widget.height,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.colorForCoin(coin),
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
),
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
const Spacer(),
|
||||
SizedBox(
|
||||
height: widget.width * 0.3,
|
||||
child: Row(
|
||||
children: [
|
||||
const Spacer(
|
||||
flex: 9,
|
||||
),
|
||||
SvgPicture.asset(
|
||||
Assets.svg.ellipse2,
|
||||
height: widget.width * 0.3,
|
||||
),
|
||||
// ),
|
||||
const Spacer(
|
||||
flex: 2,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
const Spacer(
|
||||
flex: 5,
|
||||
),
|
||||
SizedBox(
|
||||
width: widget.width * 0.45,
|
||||
child: Column(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
Assets.svg.ellipse1,
|
||||
width: widget.width * 0.45,
|
||||
),
|
||||
const Spacer(),
|
||||
],
|
||||
),
|
||||
),
|
||||
const Spacer(
|
||||
flex: 1,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
background: CoinCard(
|
||||
walletId: widget.walletId,
|
||||
width: widget.width,
|
||||
height: widget.height,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
|
|
|
@ -215,11 +215,17 @@ class _DesktopReceiveState extends ConsumerState<DesktopReceive> {
|
|||
),
|
||||
),
|
||||
),
|
||||
if (coin != Coin.epicCash && coin != Coin.ethereum)
|
||||
if (coin != Coin.epicCash &&
|
||||
coin != Coin.ethereum &&
|
||||
coin != Coin.banano &&
|
||||
coin != Coin.nano)
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
if (coin != Coin.epicCash && coin != Coin.ethereum)
|
||||
if (coin != Coin.epicCash &&
|
||||
coin != Coin.ethereum &&
|
||||
coin != Coin.banano &&
|
||||
coin != Coin.nano)
|
||||
SecondaryButton(
|
||||
buttonHeight: ButtonHeight.l,
|
||||
onPressed: generateNewAddress,
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
*/
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:bip47/bip47.dart';
|
||||
import 'package:decimal/decimal.dart';
|
||||
|
@ -452,7 +453,8 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
cryptoAmount = cryptoAmount.split(" ").first;
|
||||
}
|
||||
|
||||
final shift = ref.read(pAmountUnit(coin)).shift;
|
||||
// ensure we don't shift past minimum atomic value
|
||||
final shift = min(ref.read(pAmountUnit(coin)).shift, coin.decimals);
|
||||
|
||||
_amountToSend = cryptoAmount.contains(",")
|
||||
? Decimal.parse(cryptoAmount.replaceFirst(",", "."))
|
||||
|
|
|
@ -12,11 +12,11 @@ import 'dart:convert';
|
|||
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
// import 'package:flutter_libepiccash/git_versions.dart' as EPIC_VERSIONS;
|
||||
// import 'package:flutter_libmonero/git_versions.dart' as MONERO_VERSIONS;
|
||||
import 'package:flutter_libepiccash/git_versions.dart' as EPIC_VERSIONS;
|
||||
import 'package:flutter_libmonero/git_versions.dart' as MONERO_VERSIONS;
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:http/http.dart';
|
||||
// import 'package:lelantus/git_versions.dart' as FIRO_VERSIONS;
|
||||
import 'package:lelantus/git_versions.dart' as FIRO_VERSIONS;
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:stackwallet/themes/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
|
@ -108,12 +108,9 @@ class DesktopAboutView extends ConsumerWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
String firoCommit =
|
||||
"Unable to fetch version"; // FIRO_VERSIONS.getPluginVersion();
|
||||
String epicCashCommit =
|
||||
"Unable to fetch version"; // EPIC_VERSIONS.getPluginVersion();
|
||||
String moneroCommit =
|
||||
"Unable to fetch version"; //MONERO_VERSIONS.getPluginVersion();
|
||||
String firoCommit = FIRO_VERSIONS.getPluginVersion();
|
||||
String epicCashCommit = EPIC_VERSIONS.getPluginVersion();
|
||||
String moneroCommit = MONERO_VERSIONS.getPluginVersion();
|
||||
List<Future> futureFiroList = [
|
||||
doesCommitExist("cypherstack", "flutter_liblelantus", firoCommit),
|
||||
isHeadCommit("cypherstack", "flutter_liblelantus", "main", firoCommit),
|
||||
|
@ -250,13 +247,13 @@ class DesktopAboutView extends ConsumerWidget {
|
|||
String signature = "";
|
||||
String build = "";
|
||||
|
||||
// if (snapshot.connectionState ==
|
||||
// ConnectionState.done &&
|
||||
// snapshot.hasData) {
|
||||
// version = snapshot.data!.version;
|
||||
// build = snapshot.data!.buildNumber;
|
||||
// signature = snapshot.data!.buildSignature;
|
||||
// }
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
version = snapshot.data!.version;
|
||||
build = snapshot.data!.buildNumber;
|
||||
signature = snapshot.data!.buildSignature;
|
||||
}
|
||||
|
||||
return Column(
|
||||
mainAxisAlignment:
|
||||
|
@ -404,7 +401,7 @@ class DesktopAboutView extends ConsumerWidget {
|
|||
.accentColorGreen);
|
||||
break;
|
||||
case CommitStatus
|
||||
.isOldCommit:
|
||||
.isOldCommit:
|
||||
indicationStyle = STextStyles
|
||||
.itemSubtitle(
|
||||
context)
|
||||
|
@ -416,7 +413,7 @@ class DesktopAboutView extends ConsumerWidget {
|
|||
.accentColorYellow);
|
||||
break;
|
||||
case CommitStatus
|
||||
.notACommit:
|
||||
.notACommit:
|
||||
indicationStyle = STextStyles
|
||||
.itemSubtitle(
|
||||
context)
|
||||
|
@ -510,7 +507,7 @@ class DesktopAboutView extends ConsumerWidget {
|
|||
.accentColorGreen);
|
||||
break;
|
||||
case CommitStatus
|
||||
.isOldCommit:
|
||||
.isOldCommit:
|
||||
indicationStyle = STextStyles
|
||||
.itemSubtitle(
|
||||
context)
|
||||
|
@ -522,7 +519,7 @@ class DesktopAboutView extends ConsumerWidget {
|
|||
.accentColorYellow);
|
||||
break;
|
||||
case CommitStatus
|
||||
.notACommit:
|
||||
.notACommit:
|
||||
indicationStyle = STextStyles
|
||||
.itemSubtitle(
|
||||
context)
|
||||
|
@ -614,7 +611,7 @@ class DesktopAboutView extends ConsumerWidget {
|
|||
.accentColorGreen);
|
||||
break;
|
||||
case CommitStatus
|
||||
.isOldCommit:
|
||||
.isOldCommit:
|
||||
indicationStyle = STextStyles
|
||||
.itemSubtitle(
|
||||
context)
|
||||
|
@ -626,7 +623,7 @@ class DesktopAboutView extends ConsumerWidget {
|
|||
.accentColorYellow);
|
||||
break;
|
||||
case CommitStatus
|
||||
.notACommit:
|
||||
.notACommit:
|
||||
indicationStyle = STextStyles
|
||||
.itemSubtitle(
|
||||
context)
|
||||
|
|
|
@ -11,6 +11,7 @@ import 'package:stackwallet/models/node_model.dart';
|
|||
import 'package:stackwallet/models/paymint/fee_object_model.dart';
|
||||
import 'package:stackwallet/services/coins/coin_service.dart';
|
||||
import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
|
||||
import 'package:stackwallet/services/event_bus/events/global/updated_in_background_event.dart';
|
||||
import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
|
||||
import 'package:stackwallet/services/event_bus/global_event_bus.dart';
|
||||
import 'package:stackwallet/services/mixins/coin_control_interface.dart';
|
||||
|
@ -293,17 +294,31 @@ class BananoWallet extends CoinServiceAPI
|
|||
Future<Amount> estimateFeeFor(Amount amount, int feeRate) {
|
||||
// fees are always 0 :)
|
||||
return Future.value(
|
||||
Amount(rawValue: BigInt.from(0), fractionDigits: coin.decimals));
|
||||
Amount(
|
||||
rawValue: BigInt.from(0),
|
||||
fractionDigits: coin.decimals,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> exit() async {
|
||||
_hasCalledExit = true;
|
||||
timer?.cancel();
|
||||
timer = null;
|
||||
stopNetworkAlivePinging();
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO: implement fees
|
||||
Future<FeeObject> get fees => throw UnimplementedError();
|
||||
// Banano has no fees
|
||||
Future<FeeObject> get fees async => FeeObject(
|
||||
numberOfBlocksFast: 1,
|
||||
numberOfBlocksAverage: 1,
|
||||
numberOfBlocksSlow: 1,
|
||||
fast: 0,
|
||||
medium: 0,
|
||||
slow: 0,
|
||||
);
|
||||
|
||||
Future<void> updateBalance() async {
|
||||
final body = jsonEncode({
|
||||
|
@ -550,7 +565,14 @@ class BananoWallet extends CoinServiceAPI
|
|||
|
||||
await db.addNewTransactionData(transactionList, walletId);
|
||||
|
||||
return;
|
||||
if (transactionList.isNotEmpty) {
|
||||
GlobalEventBus.instance.fire(
|
||||
UpdatedInBackgroundEvent(
|
||||
"Transactions updated/added for: $walletId $walletName ",
|
||||
walletId,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -649,20 +671,14 @@ class BananoWallet extends CoinServiceAPI
|
|||
Map<String, dynamic>? args,
|
||||
}) async {
|
||||
try {
|
||||
int satAmount = amount.raw.toInt();
|
||||
int realfee = 0;
|
||||
|
||||
if (balance.spendable == amount) {
|
||||
satAmount = balance.spendable.raw.toInt() - realfee;
|
||||
if (amount.decimals != coin.decimals) {
|
||||
throw ArgumentError("Banano prepareSend attempted with invalid Amount");
|
||||
}
|
||||
|
||||
Map<String, dynamic> txData = {
|
||||
"fee": realfee,
|
||||
"fee": 0,
|
||||
"addresss": address,
|
||||
"recipientAmt": Amount(
|
||||
rawValue: BigInt.from(satAmount),
|
||||
fractionDigits: coin.decimals,
|
||||
),
|
||||
"recipientAmt": amount,
|
||||
};
|
||||
|
||||
Logging.instance.log("prepare send: $txData", level: LogLevel.Info);
|
||||
|
@ -720,17 +736,29 @@ class BananoWallet extends CoinServiceAPI
|
|||
|
||||
@override
|
||||
Future<void> refresh() async {
|
||||
if (refreshMutex) {
|
||||
Logging.instance.log(
|
||||
"$walletId $walletName refreshMutex denied",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
refreshMutex = true;
|
||||
}
|
||||
|
||||
await _prefs.init();
|
||||
|
||||
GlobalEventBus.instance.fire(
|
||||
WalletSyncStatusChangedEvent(
|
||||
WalletSyncStatus.syncing,
|
||||
walletId,
|
||||
coin,
|
||||
),
|
||||
);
|
||||
|
||||
try {
|
||||
GlobalEventBus.instance.fire(
|
||||
WalletSyncStatusChangedEvent(
|
||||
WalletSyncStatus.syncing,
|
||||
walletId,
|
||||
coin,
|
||||
),
|
||||
);
|
||||
|
||||
await _prefs.init();
|
||||
|
||||
await updateChainHeight();
|
||||
await updateTransactions();
|
||||
await updateBalance();
|
||||
|
@ -742,9 +770,25 @@ class BananoWallet extends CoinServiceAPI
|
|||
coin,
|
||||
),
|
||||
);
|
||||
|
||||
if (shouldAutoSync) {
|
||||
timer ??= Timer.periodic(const Duration(seconds: 30), (timer) async {
|
||||
Logging.instance.log(
|
||||
"Periodic refresh check for $walletId $walletName in object instance: $hashCode",
|
||||
level: LogLevel.Info);
|
||||
|
||||
await refresh();
|
||||
GlobalEventBus.instance.fire(
|
||||
UpdatedInBackgroundEvent(
|
||||
"New data found in $walletId $walletName in background!",
|
||||
walletId,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"Failed to refresh banano wallet \'$walletName\': $e\n$s",
|
||||
"Failed to refresh banano wallet $walletId: '$walletName': $e\n$s",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
GlobalEventBus.instance.fire(
|
||||
|
@ -755,6 +799,8 @@ class BananoWallet extends CoinServiceAPI
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
refreshMutex = false;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -843,9 +889,9 @@ class BananoWallet extends CoinServiceAPI
|
|||
}
|
||||
|
||||
@override
|
||||
Future<void> updateSentCachedTxData(Map<String, dynamic> txData) {
|
||||
// TODO: implement updateSentCachedTxData
|
||||
throw UnimplementedError();
|
||||
Future<void> updateSentCachedTxData(Map<String, dynamic> txData) async {
|
||||
// not currently used for nano
|
||||
return;
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -21,6 +21,7 @@ import 'package:stackwallet/models/node_model.dart';
|
|||
import 'package:stackwallet/models/paymint/fee_object_model.dart';
|
||||
import 'package:stackwallet/services/coins/coin_service.dart';
|
||||
import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
|
||||
import 'package:stackwallet/services/event_bus/events/global/updated_in_background_event.dart';
|
||||
import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
|
||||
import 'package:stackwallet/services/event_bus/global_event_bus.dart';
|
||||
import 'package:stackwallet/services/mixins/coin_control_interface.dart';
|
||||
|
@ -309,11 +310,21 @@ class NanoWallet extends CoinServiceAPI
|
|||
@override
|
||||
Future<void> exit() async {
|
||||
_hasCalledExit = true;
|
||||
timer?.cancel();
|
||||
timer = null;
|
||||
stopNetworkAlivePinging();
|
||||
}
|
||||
|
||||
@override
|
||||
// Nano has no fees
|
||||
Future<FeeObject> get fees => throw UnimplementedError();
|
||||
Future<FeeObject> get fees async => FeeObject(
|
||||
numberOfBlocksFast: 1,
|
||||
numberOfBlocksAverage: 1,
|
||||
numberOfBlocksSlow: 1,
|
||||
fast: 0,
|
||||
medium: 0,
|
||||
slow: 0,
|
||||
);
|
||||
|
||||
Future<void> updateBalance() async {
|
||||
final body = jsonEncode({
|
||||
|
@ -560,7 +571,14 @@ class NanoWallet extends CoinServiceAPI
|
|||
|
||||
await db.addNewTransactionData(transactionList, walletId);
|
||||
|
||||
return;
|
||||
if (transactionList.isNotEmpty) {
|
||||
GlobalEventBus.instance.fire(
|
||||
UpdatedInBackgroundEvent(
|
||||
"Transactions updated/added for: $walletId $walletName ",
|
||||
walletId,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -732,17 +750,27 @@ class NanoWallet extends CoinServiceAPI
|
|||
|
||||
@override
|
||||
Future<void> refresh() async {
|
||||
await _prefs.init();
|
||||
|
||||
GlobalEventBus.instance.fire(
|
||||
WalletSyncStatusChangedEvent(
|
||||
WalletSyncStatus.syncing,
|
||||
walletId,
|
||||
coin,
|
||||
),
|
||||
);
|
||||
if (refreshMutex) {
|
||||
Logging.instance.log(
|
||||
"$walletId $walletName refreshMutex denied",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
refreshMutex = true;
|
||||
}
|
||||
|
||||
try {
|
||||
await _prefs.init();
|
||||
|
||||
GlobalEventBus.instance.fire(
|
||||
WalletSyncStatusChangedEvent(
|
||||
WalletSyncStatus.syncing,
|
||||
walletId,
|
||||
coin,
|
||||
),
|
||||
);
|
||||
|
||||
await updateChainHeight();
|
||||
await updateTransactions();
|
||||
await updateBalance();
|
||||
|
@ -754,7 +782,27 @@ class NanoWallet extends CoinServiceAPI
|
|||
coin,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
|
||||
if (shouldAutoSync) {
|
||||
timer ??= Timer.periodic(const Duration(seconds: 30), (timer) async {
|
||||
Logging.instance.log(
|
||||
"Periodic refresh check for $walletId $walletName in object instance: $hashCode",
|
||||
level: LogLevel.Info);
|
||||
|
||||
await refresh();
|
||||
GlobalEventBus.instance.fire(
|
||||
UpdatedInBackgroundEvent(
|
||||
"New data found in $walletId $walletName in background!",
|
||||
walletId,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"Failed to refresh nano wallet $walletId: '$walletName': $e\n$s",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
GlobalEventBus.instance.fire(
|
||||
WalletSyncStatusChangedEvent(
|
||||
WalletSyncStatus.unableToSync,
|
||||
|
@ -763,6 +811,8 @@ class NanoWallet extends CoinServiceAPI
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
refreshMutex = false;
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -100,7 +100,7 @@ class PriceAPI {
|
|||
Uri.parse("https://api.coingecko.com/api/v3/coins/markets?vs_currency"
|
||||
"=${baseCurrency.toLowerCase()}"
|
||||
"&ids=monero,bitcoin,litecoin,ecash,epic-cash,zcoin,dogecoin,"
|
||||
"bitcoin-cash,namecoin,wownero,ethereum,particl,nano,ban"
|
||||
"bitcoin-cash,namecoin,wownero,ethereum,particl,nano,banano"
|
||||
"&order=market_cap_desc&per_page=50&page=1&sparkline=false");
|
||||
|
||||
final coinGeckoResponse = await client.get(
|
||||
|
@ -115,8 +115,9 @@ class PriceAPI {
|
|||
final coin = coinFromPrettyName(coinName);
|
||||
|
||||
final price = Decimal.parse(map["current_price"].toString());
|
||||
final change24h = map["price_change_percentage_24h"] != null ?
|
||||
double.parse(map["price_change_percentage_24h"].toString()) : 0.0;
|
||||
final change24h = map["price_change_percentage_24h"] != null
|
||||
? double.parse(map["price_change_percentage_24h"].toString())
|
||||
: 0.0;
|
||||
|
||||
result[coin] = Tuple2(price, change24h);
|
||||
}
|
||||
|
|
24
lib/themes/coin_card_provider.dart
Normal file
24
lib/themes/coin_card_provider.dart
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* This file is part of Stack Wallet.
|
||||
*
|
||||
* Copyright (c) 2023 Cypher Stack
|
||||
* All Rights Reserved.
|
||||
* The code is distributed under GPLv3 license, see LICENSE file for details.
|
||||
* Generated by Cypher Stack on 2023-05-26
|
||||
*
|
||||
*/
|
||||
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/models/isar/stack_theme.dart';
|
||||
import 'package:stackwallet/themes/theme_providers.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
|
||||
final coinCardProvider = Provider.family<String?, Coin>((ref, coin) {
|
||||
final assets = ref.watch(themeAssetsProvider);
|
||||
|
||||
if (assets is ThemeAssetsV3) {
|
||||
return assets.coinCardImages?[coin.mainNetVersion];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
|
@ -50,7 +50,9 @@ final coinIconProvider = Provider.family<String, Coin>((ref, coin) {
|
|||
default:
|
||||
return assets.bitcoin;
|
||||
}
|
||||
} else if (assets is ThemeAssetsV2) {
|
||||
return (assets).coinIcons[coin.mainNetVersion]!;
|
||||
} else {
|
||||
return (assets as ThemeAssetsV2).coinIcons[coin.mainNetVersion]!;
|
||||
return (assets as ThemeAssetsV3).coinIcons[coin.mainNetVersion]!;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -52,10 +52,12 @@ final coinImageProvider = Provider.family<String, Coin>((ref, coin) {
|
|||
case Coin.ethereum:
|
||||
return assets.ethereumImage;
|
||||
default:
|
||||
return assets.bitcoinImage;
|
||||
return assets.stackIcon;
|
||||
}
|
||||
} else if (assets is ThemeAssetsV2) {
|
||||
return (assets).coinImages[coin.mainNetVersion]!;
|
||||
} else {
|
||||
return (assets as ThemeAssetsV2).coinImages[coin.mainNetVersion]!;
|
||||
return (assets as ThemeAssetsV3).coinImages[coin.mainNetVersion]!;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -99,9 +101,11 @@ final coinImageSecondaryProvider = Provider.family<String, Coin>((ref, coin) {
|
|||
return assets.ethereumImageSecondary;
|
||||
|
||||
default:
|
||||
return assets.ethereumImageSecondary;
|
||||
return assets.stackIcon;
|
||||
}
|
||||
} else if (assets is ThemeAssetsV2) {
|
||||
return (assets).coinSecondaryImages[coin.mainNetVersion]!;
|
||||
} else {
|
||||
return (assets as ThemeAssetsV2).coinSecondaryImages[coin.mainNetVersion]!;
|
||||
return (assets as ThemeAssetsV3).coinSecondaryImages[coin.mainNetVersion]!;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -40,9 +40,9 @@ abstract class Constants {
|
|||
static final BigInt _satsPerCoinMonero = BigInt.from(1000000000000);
|
||||
static final BigInt _satsPerCoinWownero = BigInt.from(100000000000);
|
||||
static final BigInt _satsPerCoinNano =
|
||||
BigInt.parse("1000000000000000000000000000000");// 1*10^30
|
||||
BigInt.parse("1000000000000000000000000000000"); // 1*10^30
|
||||
static final BigInt _satsPerCoinBanano =
|
||||
BigInt.parse("100000000000000000000000000000");// 1*10^29
|
||||
BigInt.parse("100000000000000000000000000000"); // 1*10^29
|
||||
static final BigInt _satsPerCoin = BigInt.from(100000000);
|
||||
static const int _decimalPlaces = 8;
|
||||
static const int _decimalPlacesNano = 30;
|
||||
|
@ -217,8 +217,36 @@ abstract class Constants {
|
|||
}
|
||||
}
|
||||
|
||||
static const int seedPhraseWordCountBip39 = 12;
|
||||
static const int seedPhraseWordCountMonero = 25;
|
||||
static int defaultSeedPhraseLengthFor({required Coin coin}) {
|
||||
switch (coin) {
|
||||
case Coin.bitcoin:
|
||||
case Coin.bitcoinTestNet:
|
||||
case Coin.bitcoincash:
|
||||
case Coin.bitcoincashTestnet:
|
||||
case Coin.eCash:
|
||||
case Coin.dogecoin:
|
||||
case Coin.dogecoinTestNet:
|
||||
case Coin.litecoin:
|
||||
case Coin.litecoinTestNet:
|
||||
case Coin.firo:
|
||||
case Coin.firoTestNet:
|
||||
case Coin.epicCash:
|
||||
case Coin.namecoin:
|
||||
case Coin.particl:
|
||||
case Coin.ethereum:
|
||||
return 12;
|
||||
|
||||
case Coin.wownero:
|
||||
return 14;
|
||||
|
||||
case Coin.nano:
|
||||
case Coin.banano:
|
||||
return 24;
|
||||
|
||||
case Coin.monero:
|
||||
return 25;
|
||||
}
|
||||
}
|
||||
|
||||
static const Map<int, String> monthMapShort = {
|
||||
1: 'Jan',
|
||||
|
|
|
@ -137,29 +137,31 @@ class _AddressBookCardState extends ConsumerState<AddressBookCard> {
|
|||
const SizedBox(
|
||||
width: 16,
|
||||
),
|
||||
if (isDesktop && !desktopSendFrom) const Spacer(),
|
||||
if (isDesktop)
|
||||
Text(
|
||||
coinsString,
|
||||
style: STextStyles.label(context),
|
||||
),
|
||||
if (!isDesktop)
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: isDesktop && !desktopSendFrom
|
||||
? CrossAxisAlignment.end
|
||||
: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
contact.name,
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
if (!isDesktop)
|
||||
Text(
|
||||
contact.name,
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
),
|
||||
if (!isDesktop)
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
Text(
|
||||
coinsString,
|
||||
style: STextStyles.label(context),
|
||||
textAlign: isDesktop && !desktopSendFrom
|
||||
? TextAlign.right
|
||||
: TextAlign.left,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (isDesktop && desktopSendFrom) const Spacer(),
|
||||
if (isDesktop && desktopSendFrom)
|
||||
SvgPicture.asset(
|
||||
|
|
123
lib/widgets/coin_card.dart
Normal file
123
lib/widgets/coin_card.dart
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* This file is part of Stack Wallet.
|
||||
*
|
||||
* Copyright (c) 2023 Cypher Stack
|
||||
* All Rights Reserved.
|
||||
* The code is distributed under GPLv3 license, see LICENSE file for details.
|
||||
* Generated by Cypher Stack on 2023-05-26
|
||||
*
|
||||
*/
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/themes/coin_card_provider.dart';
|
||||
import 'package:stackwallet/themes/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
|
||||
class CoinCard extends ConsumerWidget {
|
||||
const CoinCard({
|
||||
super.key,
|
||||
required this.walletId,
|
||||
required this.width,
|
||||
required this.height,
|
||||
});
|
||||
|
||||
final String walletId;
|
||||
final double width;
|
||||
final double height;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final coin = ref.watch(
|
||||
walletsChangeNotifierProvider
|
||||
.select((value) => value.getManager(walletId).coin),
|
||||
);
|
||||
|
||||
final bool hasCardImageBg = ref.watch(coinCardProvider(coin)) != null;
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
if (hasCardImageBg)
|
||||
Container(
|
||||
width: width,
|
||||
height: height,
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
fit: BoxFit.fill,
|
||||
image: FileImage(
|
||||
File(
|
||||
ref.watch(coinCardProvider(coin))!,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!hasCardImageBg)
|
||||
Container(
|
||||
width: width,
|
||||
height: height,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.colorForCoin(coin),
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!hasCardImageBg)
|
||||
Column(
|
||||
children: [
|
||||
const Spacer(),
|
||||
SizedBox(
|
||||
height: width * 0.3,
|
||||
child: Row(
|
||||
children: [
|
||||
const Spacer(
|
||||
flex: 9,
|
||||
),
|
||||
SvgPicture.asset(
|
||||
Assets.svg.ellipse2,
|
||||
height: width * 0.3,
|
||||
),
|
||||
// ),
|
||||
const Spacer(
|
||||
flex: 2,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (!hasCardImageBg)
|
||||
Row(
|
||||
children: [
|
||||
const Spacer(
|
||||
flex: 5,
|
||||
),
|
||||
SizedBox(
|
||||
width: width * 0.45,
|
||||
child: Column(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
Assets.svg.ellipse1,
|
||||
width: width * 0.45,
|
||||
),
|
||||
const Spacer(),
|
||||
],
|
||||
),
|
||||
),
|
||||
const Spacer(
|
||||
flex: 1,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -28,7 +28,7 @@ void main() {
|
|||
Uri.parse(
|
||||
"https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids"
|
||||
"=monero,bitcoin,litecoin,ecash,epic-cash,zcoin,dogecoin,bitcoin-cash"
|
||||
",namecoin,wownero,ethereum,particl,nano,ban&order=market_cap_desc&per_page=50"
|
||||
",namecoin,wownero,ethereum,particl,nano,banano&order=market_cap_desc&per_page=50"
|
||||
"&page=1&sparkline=false"),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
|
@ -100,8 +100,9 @@ void main() {
|
|||
expect(
|
||||
price.toString(),
|
||||
'{'
|
||||
'Coin.banano: [0, 0.0], '
|
||||
'Coin.bitcoin: [1, 0.0], '
|
||||
'Coin.monero: [0.00717236, -0.77656], '
|
||||
'Coin.banano: [0, 0.0], '
|
||||
'Coin.bitcoincash: [0, 0.0], '
|
||||
'Coin.dogecoin: [0.00000315, -2.68533], '
|
||||
'Coin.eCash: [0, 0.0], '
|
||||
|
@ -109,7 +110,6 @@ void main() {
|
|||
'Coin.ethereum: [0, 0.0], '
|
||||
'Coin.firo: [0.0001096, -0.89304], '
|
||||
'Coin.litecoin: [0, 0.0], '
|
||||
'Coin.monero: [0.00717236, -0.77656], '
|
||||
'Coin.namecoin: [0, 0.0], '
|
||||
'Coin.nano: [0, 0.0], '
|
||||
'Coin.particl: [0, 0.0], '
|
||||
|
@ -125,7 +125,7 @@ void main() {
|
|||
Uri.parse(
|
||||
"https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc"
|
||||
"&ids=monero,bitcoin,litecoin,ecash,epic-cash,zcoin,dogecoin,"
|
||||
"bitcoin-cash,namecoin,wownero,ethereum,particl,nano,ban"
|
||||
"bitcoin-cash,namecoin,wownero,ethereum,particl,nano,banano"
|
||||
"&order=market_cap_desc&per_page=50&page=1&sparkline=false",
|
||||
),
|
||||
headers: {'Content-Type': 'application/json'})).called(1);
|
||||
|
@ -140,7 +140,7 @@ void main() {
|
|||
Uri.parse(
|
||||
"https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&"
|
||||
"ids=monero,bitcoin,litecoin,ecash,epic-cash,zcoin,dogecoin,"
|
||||
"bitcoin-cash,namecoin,wownero,ethereum,particl,nano,ban"
|
||||
"bitcoin-cash,namecoin,wownero,ethereum,particl,nano,banano"
|
||||
"&order=market_cap_desc&per_page=50&page=1&sparkline=false"),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
|
@ -217,8 +217,9 @@ void main() {
|
|||
expect(
|
||||
cachedPrice.toString(),
|
||||
'{'
|
||||
'Coin.banano: [0, 0.0], '
|
||||
'Coin.bitcoin: [1, 0.0], '
|
||||
'Coin.monero: [0.00717236, -0.77656], '
|
||||
'Coin.banano: [0, 0.0], '
|
||||
'Coin.bitcoincash: [0, 0.0], '
|
||||
'Coin.dogecoin: [0.00000315, -2.68533], '
|
||||
'Coin.eCash: [0, 0.0], '
|
||||
|
@ -226,7 +227,6 @@ void main() {
|
|||
'Coin.ethereum: [0, 0.0], '
|
||||
'Coin.firo: [0.0001096, -0.89304], '
|
||||
'Coin.litecoin: [0, 0.0], '
|
||||
'Coin.monero: [0.00717236, -0.77656], '
|
||||
'Coin.namecoin: [0, 0.0], '
|
||||
'Coin.nano: [0, 0.0], '
|
||||
'Coin.particl: [0, 0.0], '
|
||||
|
@ -244,7 +244,7 @@ void main() {
|
|||
Uri.parse(
|
||||
"https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc&ids"
|
||||
"=monero,bitcoin,litecoin,ecash,epic-cash,zcoin,dogecoin,"
|
||||
"bitcoin-cash,namecoin,wownero,ethereum,particl,nano,ban"
|
||||
"bitcoin-cash,namecoin,wownero,ethereum,particl,nano,banano"
|
||||
"&order=market_cap_desc&per_page=50&page=1&sparkline=false"),
|
||||
headers: {'Content-Type': 'application/json'})).called(1);
|
||||
|
||||
|
@ -258,7 +258,7 @@ void main() {
|
|||
Uri.parse(
|
||||
"https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc"
|
||||
"&ids=monero,bitcoin,litecoin,ecash,epic-cash,zcoin,dogecoin,"
|
||||
"bitcoin-cash,namecoin,wownero,ethereum,particl,nano,ban"
|
||||
"bitcoin-cash,namecoin,wownero,ethereum,particl,nano,banano"
|
||||
"&order=market_cap_desc&per_page=50&page=1&sparkline=false"),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
|
@ -331,8 +331,9 @@ void main() {
|
|||
expect(
|
||||
price.toString(),
|
||||
'{'
|
||||
'Coin.banano: [0, 0.0], '
|
||||
'Coin.bitcoin: [0, 0.0], '
|
||||
'Coin.monero: [0, 0.0], '
|
||||
'Coin.banano: [0, 0.0], '
|
||||
'Coin.bitcoincash: [0, 0.0], '
|
||||
'Coin.dogecoin: [0, 0.0], '
|
||||
'Coin.eCash: [0, 0.0], '
|
||||
|
@ -340,7 +341,6 @@ void main() {
|
|||
'Coin.ethereum: [0, 0.0], '
|
||||
'Coin.firo: [0, 0.0], '
|
||||
'Coin.litecoin: [0, 0.0], '
|
||||
'Coin.monero: [0, 0.0], '
|
||||
'Coin.namecoin: [0, 0.0], '
|
||||
'Coin.nano: [0, 0.0], '
|
||||
'Coin.particl: [0, 0.0], '
|
||||
|
@ -361,7 +361,7 @@ void main() {
|
|||
Uri.parse(
|
||||
"https://api.coingecko.com/api/v3/coins/markets?vs_currency=btc"
|
||||
"&ids=monero,bitcoin,litecoin,ecash,epic-cash,zcoin,dogecoin,"
|
||||
"bitcoin-cash,namecoin,wownero,ethereum,particl,nano,ban"
|
||||
"bitcoin-cash,namecoin,wownero,ethereum,particl,nano,banano"
|
||||
"&order=market_cap_desc&per_page=50&page=1&sparkline=false"),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
|
@ -376,8 +376,9 @@ void main() {
|
|||
expect(
|
||||
price.toString(),
|
||||
'{'
|
||||
'Coin.banano: [0, 0.0], '
|
||||
'Coin.bitcoin: [0, 0.0], '
|
||||
'Coin.monero: [0, 0.0], '
|
||||
'Coin.banano: [0, 0.0], '
|
||||
'Coin.bitcoincash: [0, 0.0], '
|
||||
'Coin.dogecoin: [0, 0.0], '
|
||||
'Coin.eCash: [0, 0.0], '
|
||||
|
@ -385,7 +386,6 @@ void main() {
|
|||
'Coin.ethereum: [0, 0.0], '
|
||||
'Coin.firo: [0, 0.0], '
|
||||
'Coin.litecoin: [0, 0.0], '
|
||||
'Coin.monero: [0, 0.0], '
|
||||
'Coin.namecoin: [0, 0.0], '
|
||||
'Coin.nano: [0, 0.0], '
|
||||
'Coin.particl: [0, 0.0], '
|
||||
|
|
Loading…
Reference in a new issue