Merge remote-tracking branch 'origin/ordinals' into ordinals-desktop
BIN
assets/icon/macos-icon.png
Normal file
After Width: | Height: | Size: 15 KiB |
|
@ -1 +1 @@
|
|||
Subproject commit 686559344a58f77732c3d0134fbf44d271a55229
|
||||
Subproject commit f677dec0b34d3f9fe8fce2bc8ff5c508c3f3bb9a
|
|
@ -1 +1 @@
|
|||
Subproject commit cdccef0e8dc10b7fe703b5bb9b41b59b25177e83
|
||||
Subproject commit 9cd241b5ea142e21c01dd7639b42603281c43287
|
|
@ -1 +1 @@
|
|||
Subproject commit c920c09df5e415bba4bbe95dd50e1f0085f040e6
|
||||
Subproject commit e48952185556a10f182184fd572bcb04365f5831
|
|
@ -46,7 +46,7 @@ class EthTokenTxExtraDTO {
|
|||
),
|
||||
gas: _amountFromJsonNum(map['gas']),
|
||||
gasPrice: _amountFromJsonNum(map['gasPrice']),
|
||||
nonce: map['nonce'] as int,
|
||||
nonce: map['nonce'] as int?,
|
||||
input: map['input'] as String,
|
||||
gasCost: _amountFromJsonNum(map['gasCost']),
|
||||
gasUsed: _amountFromJsonNum(map['gasUsed']),
|
||||
|
@ -63,7 +63,7 @@ class EthTokenTxExtraDTO {
|
|||
final Amount gas;
|
||||
final Amount gasPrice;
|
||||
final String input;
|
||||
final int nonce;
|
||||
final int? nonce;
|
||||
final Amount gasCost;
|
||||
final Amount gasUsed;
|
||||
|
||||
|
|
|
@ -127,16 +127,16 @@ class EthTxDTO {
|
|||
map['timestamp'] = timestamp;
|
||||
map['from'] = from;
|
||||
map['to'] = to;
|
||||
map['value'] = value;
|
||||
map['gas'] = gas;
|
||||
map['gasPrice'] = gasPrice;
|
||||
map['maxFeePerGas'] = maxFeePerGas;
|
||||
map['maxPriorityFeePerGas'] = maxPriorityFeePerGas;
|
||||
map['value'] = value.toString();
|
||||
map['gas'] = gas.toString();
|
||||
map['gasPrice'] = gasPrice.toString();
|
||||
map['maxFeePerGas'] = maxFeePerGas.toString();
|
||||
map['maxPriorityFeePerGas'] = maxPriorityFeePerGas.toString();
|
||||
map['isError'] = isError;
|
||||
map['hasToken'] = hasToken;
|
||||
map['compressedTx'] = compressedTx;
|
||||
map['gasCost'] = gasCost;
|
||||
map['gasUsed'] = gasUsed;
|
||||
map['gasCost'] = gasCost.toString();
|
||||
map['gasUsed'] = gasUsed.toString();
|
||||
return map;
|
||||
}
|
||||
|
||||
|
|
|
@ -2341,8 +2341,6 @@ class ThemeAssetsV3 implements IThemeAssets {
|
|||
|
||||
// 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")
|
||||
|
@ -2388,6 +2386,19 @@ class ThemeAssetsV3 implements IThemeAssets {
|
|||
Map<Coin, String>? _coinCardImages;
|
||||
late final String? coinCardImagesString;
|
||||
|
||||
@ignore
|
||||
Map<Coin, String>? get coinCardFavoritesImages =>
|
||||
_coinCardFavoritesImages ??= coinCardFavoritesImagesString == null
|
||||
? null
|
||||
: parseCoinAssetsString(
|
||||
coinCardFavoritesImagesString!,
|
||||
placeHolder: coinPlaceholder,
|
||||
);
|
||||
@ignore
|
||||
Map<Coin, String>? _coinCardFavoritesImages;
|
||||
@Name("otherStringParam1")
|
||||
late final String? coinCardFavoritesImagesString;
|
||||
|
||||
ThemeAssetsV3();
|
||||
|
||||
factory ThemeAssetsV3.fromJson({
|
||||
|
@ -2443,13 +2454,18 @@ class ThemeAssetsV3 implements IThemeAssets {
|
|||
Map<String, dynamic>.from(json["coins"]["cards"] as Map),
|
||||
)
|
||||
: null
|
||||
..coinCardFavoritesImagesString = json["coins"]["favoriteCards"] is Map
|
||||
? createCoinAssetsString(
|
||||
"$themeId/assets",
|
||||
Map<String, dynamic>.from(json["coins"]["favoriteCards"] as Map),
|
||||
)
|
||||
: null
|
||||
..loadingGifRelative = json["loading_gif"] is String
|
||||
? "$themeId/assets/${json["loading_gif"] as String}"
|
||||
: null
|
||||
..backgroundRelative = json["background"] is String
|
||||
? "$themeId/assets/${json["background"] as String}"
|
||||
: null
|
||||
..dummy1 = null
|
||||
..dummy2 = null
|
||||
..dummy3 = null;
|
||||
}
|
||||
|
@ -2528,6 +2544,7 @@ class ThemeAssetsV3 implements IThemeAssets {
|
|||
'coinImages: $coinImages, '
|
||||
'coinSecondaryImages: $coinSecondaryImages, '
|
||||
'coinCardImages: $coinCardImages'
|
||||
'coinCardFavoritesImages: $coinCardFavoritesImages'
|
||||
')';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29626,7 +29626,7 @@ int _themeAssetsV3EstimateSize(
|
|||
}
|
||||
}
|
||||
{
|
||||
final value = object.dummy1;
|
||||
final value = object.coinCardFavoritesImagesString;
|
||||
if (value != null) {
|
||||
bytesCount += 3 + value.length * 3;
|
||||
}
|
||||
|
@ -29677,7 +29677,7 @@ void _themeAssetsV3Serialize(
|
|||
writer.writeString(offsets[7], object.coinSecondaryImagesString);
|
||||
writer.writeString(offsets[8], object.exchangeRelative);
|
||||
writer.writeString(offsets[9], object.loadingGifRelative);
|
||||
writer.writeString(offsets[10], object.dummy1);
|
||||
writer.writeString(offsets[10], object.coinCardFavoritesImagesString);
|
||||
writer.writeString(offsets[11], object.dummy2);
|
||||
writer.writeString(offsets[12], object.dummy3);
|
||||
writer.writeString(offsets[13], object.personaEasyRelative);
|
||||
|
@ -29714,7 +29714,7 @@ ThemeAssetsV3 _themeAssetsV3Deserialize(
|
|||
object.coinSecondaryImagesString = reader.readString(offsets[7]);
|
||||
object.exchangeRelative = reader.readString(offsets[8]);
|
||||
object.loadingGifRelative = reader.readStringOrNull(offsets[9]);
|
||||
object.dummy1 = reader.readStringOrNull(offsets[10]);
|
||||
object.coinCardFavoritesImagesString = reader.readStringOrNull(offsets[10]);
|
||||
object.dummy2 = reader.readStringOrNull(offsets[11]);
|
||||
object.dummy3 = reader.readStringOrNull(offsets[12]);
|
||||
object.personaEasyRelative = reader.readString(offsets[13]);
|
||||
|
@ -31224,7 +31224,7 @@ extension ThemeAssetsV3QueryFilter
|
|||
}
|
||||
|
||||
QueryBuilder<ThemeAssetsV3, ThemeAssetsV3, QAfterFilterCondition>
|
||||
dummy1IsNull() {
|
||||
coinCardFavoritesImagesStringIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
property: r'otherStringParam1',
|
||||
|
@ -31233,7 +31233,7 @@ extension ThemeAssetsV3QueryFilter
|
|||
}
|
||||
|
||||
QueryBuilder<ThemeAssetsV3, ThemeAssetsV3, QAfterFilterCondition>
|
||||
dummy1IsNotNull() {
|
||||
coinCardFavoritesImagesStringIsNotNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNotNull(
|
||||
property: r'otherStringParam1',
|
||||
|
@ -31242,7 +31242,7 @@ extension ThemeAssetsV3QueryFilter
|
|||
}
|
||||
|
||||
QueryBuilder<ThemeAssetsV3, ThemeAssetsV3, QAfterFilterCondition>
|
||||
dummy1EqualTo(
|
||||
coinCardFavoritesImagesStringEqualTo(
|
||||
String? value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
|
@ -31256,7 +31256,7 @@ extension ThemeAssetsV3QueryFilter
|
|||
}
|
||||
|
||||
QueryBuilder<ThemeAssetsV3, ThemeAssetsV3, QAfterFilterCondition>
|
||||
dummy1GreaterThan(
|
||||
coinCardFavoritesImagesStringGreaterThan(
|
||||
String? value, {
|
||||
bool include = false,
|
||||
bool caseSensitive = true,
|
||||
|
@ -31272,7 +31272,7 @@ extension ThemeAssetsV3QueryFilter
|
|||
}
|
||||
|
||||
QueryBuilder<ThemeAssetsV3, ThemeAssetsV3, QAfterFilterCondition>
|
||||
dummy1LessThan(
|
||||
coinCardFavoritesImagesStringLessThan(
|
||||
String? value, {
|
||||
bool include = false,
|
||||
bool caseSensitive = true,
|
||||
|
@ -31288,7 +31288,7 @@ extension ThemeAssetsV3QueryFilter
|
|||
}
|
||||
|
||||
QueryBuilder<ThemeAssetsV3, ThemeAssetsV3, QAfterFilterCondition>
|
||||
dummy1Between(
|
||||
coinCardFavoritesImagesStringBetween(
|
||||
String? lower,
|
||||
String? upper, {
|
||||
bool includeLower = true,
|
||||
|
@ -31308,7 +31308,7 @@ extension ThemeAssetsV3QueryFilter
|
|||
}
|
||||
|
||||
QueryBuilder<ThemeAssetsV3, ThemeAssetsV3, QAfterFilterCondition>
|
||||
dummy1StartsWith(
|
||||
coinCardFavoritesImagesStringStartsWith(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
|
@ -31322,7 +31322,7 @@ extension ThemeAssetsV3QueryFilter
|
|||
}
|
||||
|
||||
QueryBuilder<ThemeAssetsV3, ThemeAssetsV3, QAfterFilterCondition>
|
||||
dummy1EndsWith(
|
||||
coinCardFavoritesImagesStringEndsWith(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
|
@ -31336,7 +31336,8 @@ extension ThemeAssetsV3QueryFilter
|
|||
}
|
||||
|
||||
QueryBuilder<ThemeAssetsV3, ThemeAssetsV3, QAfterFilterCondition>
|
||||
dummy1Contains(String value, {bool caseSensitive = true}) {
|
||||
coinCardFavoritesImagesStringContains(String value,
|
||||
{bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.contains(
|
||||
property: r'otherStringParam1',
|
||||
|
@ -31347,7 +31348,8 @@ extension ThemeAssetsV3QueryFilter
|
|||
}
|
||||
|
||||
QueryBuilder<ThemeAssetsV3, ThemeAssetsV3, QAfterFilterCondition>
|
||||
dummy1Matches(String pattern, {bool caseSensitive = true}) {
|
||||
coinCardFavoritesImagesStringMatches(String pattern,
|
||||
{bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.matches(
|
||||
property: r'otherStringParam1',
|
||||
|
@ -31358,7 +31360,7 @@ extension ThemeAssetsV3QueryFilter
|
|||
}
|
||||
|
||||
QueryBuilder<ThemeAssetsV3, ThemeAssetsV3, QAfterFilterCondition>
|
||||
dummy1IsEmpty() {
|
||||
coinCardFavoritesImagesStringIsEmpty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'otherStringParam1',
|
||||
|
@ -31368,7 +31370,7 @@ extension ThemeAssetsV3QueryFilter
|
|||
}
|
||||
|
||||
QueryBuilder<ThemeAssetsV3, ThemeAssetsV3, QAfterFilterCondition>
|
||||
dummy1IsNotEmpty() {
|
||||
coinCardFavoritesImagesStringIsNotEmpty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.greaterThan(
|
||||
property: r'otherStringParam1',
|
||||
|
|
|
@ -142,7 +142,7 @@ class _AddCustomTokenViewState extends ConsumerState<AddCustomTokenView> {
|
|||
context: context,
|
||||
message: "Looking up contract",
|
||||
);
|
||||
currentToken = response.value;
|
||||
currentToken = response!.value;
|
||||
if (currentToken != null) {
|
||||
nameController.text = currentToken!.name;
|
||||
symbolController.text = currentToken!.symbol;
|
||||
|
@ -157,7 +157,7 @@ class _AddCustomTokenViewState extends ConsumerState<AddCustomTokenView> {
|
|||
context: context,
|
||||
builder: (context) => StackOkDialog(
|
||||
title: "Failed to look up token",
|
||||
message: response.exception?.message,
|
||||
message: response!.exception?.message,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -493,51 +493,54 @@ class _ConfirmTransactionViewState
|
|||
],
|
||||
),
|
||||
),
|
||||
if (coin == Coin.epicCash)
|
||||
if (coin == Coin.epicCash &&
|
||||
(transactionInfo["onChainNote"] as String).isNotEmpty)
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
if (coin == Coin.epicCash)
|
||||
if (coin == Coin.epicCash &&
|
||||
(transactionInfo["onChainNote"] as String).isNotEmpty)
|
||||
RoundedWhiteContainer(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(
|
||||
"On chain note",
|
||||
style: STextStyles.smallMed12(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
Text(
|
||||
transactionInfo["onChainNote"] as String,
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
),
|
||||
],
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(
|
||||
"On chain note",
|
||||
style: STextStyles.smallMed12(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
Text(
|
||||
transactionInfo["onChainNote"] as String,
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
RoundedWhiteContainer(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(
|
||||
(coin == Coin.epicCash) ? "Local Note" :
|
||||
"Note",
|
||||
style: STextStyles.smallMed12(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
Text(
|
||||
transactionInfo["note"] as String,
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
),
|
||||
],
|
||||
if ((transactionInfo["note"] as String).isNotEmpty)
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
if ((transactionInfo["note"] as String).isNotEmpty)
|
||||
RoundedWhiteContainer(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(
|
||||
(coin == Coin.epicCash) ? "Local Note" : "Note",
|
||||
style: STextStyles.smallMed12(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
Text(
|
||||
transactionInfo["note"] as String,
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (isDesktop)
|
||||
|
|
|
@ -164,7 +164,7 @@ class _InstallThemeFromFileDialogState
|
|||
);
|
||||
if (mounted) {
|
||||
Navigator.of(context).pop();
|
||||
if (!result) {
|
||||
if (!result!) {
|
||||
unawaited(
|
||||
showDialog(
|
||||
context: context,
|
||||
|
|
|
@ -72,11 +72,11 @@ class _StackThemeCardState extends ConsumerState<StackThemeCard> {
|
|||
}
|
||||
|
||||
Future<void> _downloadPressed() async {
|
||||
final result = await showLoading(
|
||||
final result = (await showLoading(
|
||||
whileFuture: _downloadAndInstall(),
|
||||
context: context,
|
||||
message: "Downloading and installing theme...",
|
||||
);
|
||||
))!;
|
||||
|
||||
if (mounted) {
|
||||
final message = result
|
||||
|
|
|
@ -20,11 +20,12 @@ import 'package:stackwallet/pages/home_view/home_view.dart';
|
|||
import 'package:stackwallet/pages/pinpad_views/lock_screen_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/advanced_views/debug_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/syncing_preferences_views/syncing_preferences_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/xpub_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/sub_widgets/settings_list_button.dart';
|
||||
import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_backup_views/wallet_backup_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/change_representative_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/wallet_settings_wallet_settings_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/xpub_view.dart';
|
||||
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||
import 'package:stackwallet/providers/ui/transaction_filter_provider.dart';
|
||||
import 'package:stackwallet/route_generator.dart';
|
||||
|
@ -231,7 +232,7 @@ class _WalletSettingsViewState extends ConsumerState<WalletSettingsView> {
|
|||
.mnemonic;
|
||||
|
||||
if (mounted) {
|
||||
Navigator.push(
|
||||
await Navigator.push(
|
||||
context,
|
||||
RouteGenerator.getRoute(
|
||||
shouldUseMaterialRoute:
|
||||
|
@ -305,6 +306,25 @@ class _WalletSettingsViewState extends ConsumerState<WalletSettingsView> {
|
|||
);
|
||||
},
|
||||
),
|
||||
if (coin == Coin.nano || coin == Coin.banano)
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
if (coin == Coin.nano || coin == Coin.banano)
|
||||
Consumer(
|
||||
builder: (_, ref, __) {
|
||||
return SettingsListButton(
|
||||
iconAssetName: Assets.svg.eye,
|
||||
title: "Change representative",
|
||||
onPressed: () {
|
||||
Navigator.of(context).pushNamed(
|
||||
ChangeRepresentativeView.routeName,
|
||||
arguments: widget.walletId,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
|
@ -434,18 +454,20 @@ class _EpiBoxInfoFormState extends ConsumerState<EpicBoxInfoForm> {
|
|||
TextButton(
|
||||
onPressed: () async {
|
||||
try {
|
||||
wallet.updateEpicboxConfig(
|
||||
await wallet.updateEpicboxConfig(
|
||||
hostController.text,
|
||||
int.parse(portController.text),
|
||||
);
|
||||
showFloatingFlushBar(
|
||||
context: context,
|
||||
message: "Epicbox info saved!",
|
||||
type: FlushBarType.success,
|
||||
);
|
||||
wallet.refresh();
|
||||
if (mounted) {
|
||||
await showFloatingFlushBar(
|
||||
context: context,
|
||||
message: "Epicbox info saved!",
|
||||
type: FlushBarType.success,
|
||||
);
|
||||
}
|
||||
unawaited(wallet.refresh());
|
||||
} catch (e) {
|
||||
showFloatingFlushBar(
|
||||
await showFloatingFlushBar(
|
||||
context: context,
|
||||
message: "Failed to save epicbox info: $e",
|
||||
type: FlushBarType.warning,
|
||||
|
|
|
@ -0,0 +1,402 @@
|
|||
/*
|
||||
* 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:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||
import 'package:stackwallet/services/coins/banano/banano_wallet.dart';
|
||||
import 'package:stackwallet/services/coins/nano/nano_wallet.dart';
|
||||
import 'package:stackwallet/themes/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/clipboard_interface.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/show_loading.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.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/desktop/desktop_dialog.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/primary_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 ChangeRepresentativeView extends ConsumerStatefulWidget {
|
||||
const ChangeRepresentativeView({
|
||||
Key? key,
|
||||
required this.walletId,
|
||||
this.clipboardInterface = const ClipboardWrapper(),
|
||||
}) : super(key: key);
|
||||
|
||||
final String walletId;
|
||||
final ClipboardInterface clipboardInterface;
|
||||
|
||||
static const String routeName = "/changeRepresentative";
|
||||
|
||||
@override
|
||||
ConsumerState<ChangeRepresentativeView> createState() => _XPubViewState();
|
||||
}
|
||||
|
||||
class _XPubViewState extends ConsumerState<ChangeRepresentativeView> {
|
||||
final _textController = TextEditingController();
|
||||
final _textFocusNode = FocusNode();
|
||||
final bool isDesktop = Util.isDesktop;
|
||||
|
||||
late ClipboardInterface _clipboardInterface;
|
||||
|
||||
String? representative;
|
||||
|
||||
Future<String> loadRepresentative() async {
|
||||
final manager =
|
||||
ref.read(walletsChangeNotifierProvider).getManager(widget.walletId);
|
||||
|
||||
if (manager.coin == Coin.nano) {
|
||||
return (manager.wallet as NanoWallet).getCurrentRepresentative();
|
||||
} else if (manager.coin == Coin.banano) {
|
||||
return (manager.wallet as BananoWallet).getCurrentRepresentative();
|
||||
}
|
||||
throw Exception("Unsupported wallet attempted to show representative!");
|
||||
}
|
||||
|
||||
Future<void> _save() async {
|
||||
final manager =
|
||||
ref.read(walletsChangeNotifierProvider).getManager(widget.walletId);
|
||||
|
||||
final changeFuture = manager.coin == Coin.nano
|
||||
? (manager.wallet as NanoWallet).changeRepresentative
|
||||
: (manager.wallet as BananoWallet).changeRepresentative;
|
||||
|
||||
final result = await showLoading(
|
||||
whileFuture: changeFuture(_textController.text),
|
||||
context: context,
|
||||
message: "Updating representative...",
|
||||
isDesktop: Util.isDesktop,
|
||||
onException: (ex) {
|
||||
String msg = ex.toString();
|
||||
while (msg.isNotEmpty && msg.startsWith("Exception:")) {
|
||||
msg = msg.substring(10).trim();
|
||||
}
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: msg,
|
||||
context: context,
|
||||
);
|
||||
});
|
||||
|
||||
if (mounted) {
|
||||
if (result != null && result) {
|
||||
setState(() {
|
||||
representative = _textController.text;
|
||||
_textController.text = "";
|
||||
});
|
||||
await showFloatingFlushBar(
|
||||
type: FlushBarType.success,
|
||||
message: "Representative changed",
|
||||
context: context,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_clipboardInterface = widget.clipboardInterface;
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_textController.dispose();
|
||||
_textFocusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _copy() async {
|
||||
await _clipboardInterface
|
||||
.setData(ClipboardData(text: representative ?? ""));
|
||||
if (mounted) {
|
||||
unawaited(showFloatingFlushBar(
|
||||
type: FlushBarType.info,
|
||||
message: "Copied to clipboard",
|
||||
iconAsset: Assets.svg.copy,
|
||||
context: context,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ConditionalParent(
|
||||
condition: !isDesktop,
|
||||
builder: (child) => Background(
|
||||
child: SafeArea(
|
||||
child: Scaffold(
|
||||
backgroundColor:
|
||||
Theme.of(context).extension<StackColors>()!.background,
|
||||
appBar: AppBar(
|
||||
leading: AppBarBackButton(
|
||||
onPressed: () async {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
title: Text(
|
||||
"Wallet representative",
|
||||
style: STextStyles.navBarTitle(context),
|
||||
),
|
||||
actions: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: AppBarIconButton(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.background,
|
||||
shadows: const [],
|
||||
icon: SvgPicture.asset(
|
||||
Assets.svg.copy,
|
||||
width: 24,
|
||||
height: 24,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.topNavIconPrimary,
|
||||
),
|
||||
onPressed: () {
|
||||
if (representative != null) {
|
||||
_copy();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 12,
|
||||
left: 16,
|
||||
right: 16,
|
||||
),
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
child: ConditionalParent(
|
||||
condition: isDesktop,
|
||||
builder: (child) => DesktopDialog(
|
||||
maxWidth: 600,
|
||||
maxHeight: double.infinity,
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 32,
|
||||
),
|
||||
child: Text(
|
||||
"Change representative",
|
||||
style: STextStyles.desktopH2(context),
|
||||
),
|
||||
),
|
||||
DesktopDialogCloseButton(
|
||||
onPressedOverride: Navigator.of(
|
||||
context,
|
||||
rootNavigator: true,
|
||||
).pop,
|
||||
),
|
||||
],
|
||||
),
|
||||
AnimatedSize(
|
||||
duration: const Duration(
|
||||
milliseconds: 150,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(32, 0, 32, 32),
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
if (isDesktop) const SizedBox(height: 24),
|
||||
ConditionalParent(
|
||||
condition: !isDesktop,
|
||||
builder: (child) => Expanded(
|
||||
child: child,
|
||||
),
|
||||
child: FutureBuilder(
|
||||
future: loadRepresentative(),
|
||||
builder: (context, AsyncSnapshot<String> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
representative = snapshot.data!;
|
||||
}
|
||||
|
||||
const height = 600.0;
|
||||
Widget child;
|
||||
if (representative == null) {
|
||||
child = const SizedBox(
|
||||
key: Key("loadingRepresentative"),
|
||||
height: height,
|
||||
child: Center(
|
||||
child: LoadingIndicator(
|
||||
width: 100,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
child = Column(
|
||||
children: [
|
||||
ConditionalParent(
|
||||
condition: !isDesktop,
|
||||
builder: (child) => RoundedWhiteContainer(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
child,
|
||||
],
|
||||
),
|
||||
),
|
||||
child: ConditionalParent(
|
||||
condition: isDesktop,
|
||||
builder: (child) => Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Current representative",
|
||||
style: STextStyles.desktopTextExtraExtraSmall(
|
||||
context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
child,
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
child: SelectableText(
|
||||
representative!,
|
||||
style: isDesktop
|
||||
? STextStyles.desktopTextExtraExtraSmall(
|
||||
context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark,
|
||||
)
|
||||
: STextStyles.itemSubtitle12(context),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
child: TextField(
|
||||
autocorrect: Util.isDesktop ? false : true,
|
||||
enableSuggestions: Util.isDesktop ? false : true,
|
||||
controller: _textController,
|
||||
style: isDesktop
|
||||
? STextStyles.desktopTextExtraSmall(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldActiveText,
|
||||
height: 1.8,
|
||||
)
|
||||
: STextStyles.field(context),
|
||||
focusNode: _textFocusNode,
|
||||
decoration: standardInputDecoration(
|
||||
"Enter new representative",
|
||||
_textFocusNode,
|
||||
context,
|
||||
desktopMed: isDesktop,
|
||||
).copyWith(
|
||||
contentPadding: isDesktop
|
||||
? const EdgeInsets.only(
|
||||
left: 16,
|
||||
top: 11,
|
||||
bottom: 12,
|
||||
right: 5,
|
||||
)
|
||||
: null,
|
||||
suffixIcon: _textController.text.isNotEmpty
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(right: 0),
|
||||
child: UnconstrainedBox(
|
||||
child: Row(
|
||||
children: [
|
||||
TextFieldIconButton(
|
||||
child: const XIcon(),
|
||||
onTap: () async {
|
||||
setState(() {
|
||||
_textController.text = "";
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (isDesktop) const SizedBox(height: 60),
|
||||
if (!isDesktop) const Spacer(),
|
||||
PrimaryButton(
|
||||
label: "Save",
|
||||
onPressed: _save,
|
||||
),
|
||||
if (!isDesktop)
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return AnimatedSwitcher(
|
||||
duration: const Duration(
|
||||
milliseconds: 200,
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -100,7 +100,7 @@ class _MyTokenSelectItemState extends ConsumerState<MyTokenSelectItem> {
|
|||
message: "Loading ${widget.token.name}",
|
||||
);
|
||||
|
||||
if (!success) {
|
||||
if (!success!) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ class WalletSummary extends StatelessWidget {
|
|||
walletId: walletId,
|
||||
width: constraints.maxWidth,
|
||||
height: constraints.maxHeight,
|
||||
isFavorite: false,
|
||||
),
|
||||
Positioned.fill(
|
||||
child: Padding(
|
||||
|
|
|
@ -358,7 +358,6 @@ class _TransactionDetailsViewState
|
|||
final currentHeight = ref.watch(walletsChangeNotifierProvider
|
||||
.select((value) => value.getManager(walletId).currentHeight));
|
||||
|
||||
|
||||
print("THIS TRANSACTION IS $_transaction");
|
||||
|
||||
return ConditionalParent(
|
||||
|
@ -474,7 +473,9 @@ class _TransactionDetailsViewState
|
|||
),
|
||||
SelectableText(
|
||||
_transaction.isCancelled
|
||||
? "Cancelled"
|
||||
? coin == Coin.ethereum
|
||||
? "Failed"
|
||||
: "Cancelled"
|
||||
: whatIsIt(
|
||||
_transaction,
|
||||
currentHeight,
|
||||
|
@ -585,7 +586,9 @@ class _TransactionDetailsViewState
|
|||
// child:
|
||||
SelectableText(
|
||||
_transaction.isCancelled
|
||||
? "Cancelled"
|
||||
? coin == Coin.ethereum
|
||||
? "Failed"
|
||||
: "Cancelled"
|
||||
: whatIsIt(
|
||||
_transaction,
|
||||
currentHeight,
|
||||
|
@ -781,8 +784,8 @@ class _TransactionDetailsViewState
|
|||
isDesktop
|
||||
? const _Divider()
|
||||
: const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
height: 12,
|
||||
),
|
||||
if (coin == Coin.epicCash)
|
||||
RoundedWhiteContainer(
|
||||
padding: isDesktop
|
||||
|
@ -790,22 +793,22 @@ class _TransactionDetailsViewState
|
|||
: const EdgeInsets.all(12),
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"On chain note",
|
||||
style: isDesktop
|
||||
? STextStyles
|
||||
.desktopTextExtraExtraSmall(
|
||||
context)
|
||||
.desktopTextExtraExtraSmall(
|
||||
context)
|
||||
: STextStyles.itemSubtitle(
|
||||
context),
|
||||
context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
|
@ -814,18 +817,16 @@ class _TransactionDetailsViewState
|
|||
_transaction.otherData ?? "",
|
||||
style: isDesktop
|
||||
? STextStyles
|
||||
.desktopTextExtraExtraSmall(
|
||||
context)
|
||||
.copyWith(
|
||||
color: Theme.of(
|
||||
context)
|
||||
.extension<
|
||||
StackColors>()!
|
||||
.textDark,
|
||||
)
|
||||
: STextStyles
|
||||
.itemSubtitle12(
|
||||
context),
|
||||
.desktopTextExtraExtraSmall(
|
||||
context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<
|
||||
StackColors>()!
|
||||
.textDark,
|
||||
)
|
||||
: STextStyles.itemSubtitle12(
|
||||
context),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -854,7 +855,9 @@ class _TransactionDetailsViewState
|
|||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
(coin == Coin.epicCash) ? "Local Note" : "Note ",
|
||||
(coin == Coin.epicCash)
|
||||
? "Local Note"
|
||||
: "Note ",
|
||||
style: isDesktop
|
||||
? STextStyles
|
||||
.desktopTextExtraExtraSmall(
|
||||
|
@ -923,7 +926,9 @@ class _TransactionDetailsViewState
|
|||
notesServiceChangeNotifierProvider(
|
||||
walletId)
|
||||
.select((value) => value.getNoteFor(
|
||||
txid: (coin == Coin.epicCash)? _transaction.slateId! : _transaction.txid ))),
|
||||
txid: (coin == Coin.epicCash)
|
||||
? _transaction.slateId!
|
||||
: _transaction.txid))),
|
||||
builder: (builderContext,
|
||||
AsyncSnapshot<String> snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
|
|
|
@ -149,6 +149,7 @@ class _FavoriteCardState extends ConsumerState<FavoriteCard> {
|
|||
walletId: widget.walletId,
|
||||
width: widget.width,
|
||||
height: widget.height,
|
||||
isFavorite: true,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
|
|
|
@ -13,7 +13,8 @@ import 'dart:async';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/xpub_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/change_representative_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/xpub_view.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/addresses/desktop_wallet_addresses_view.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_delete_wallet_dialog.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
|
@ -21,11 +22,13 @@ import 'package:stackwallet/route_generator.dart';
|
|||
import 'package:stackwallet/themes/stack_colors.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';
|
||||
|
||||
enum _WalletOptions {
|
||||
addressList,
|
||||
deleteWallet,
|
||||
changeRepresentative,
|
||||
showXpub;
|
||||
|
||||
String get prettyName {
|
||||
|
@ -34,6 +37,8 @@ enum _WalletOptions {
|
|||
return "Address list";
|
||||
case _WalletOptions.deleteWallet:
|
||||
return "Delete wallet";
|
||||
case _WalletOptions.changeRepresentative:
|
||||
return "Change representative";
|
||||
case _WalletOptions.showXpub:
|
||||
return "Show xPub";
|
||||
}
|
||||
|
@ -70,6 +75,9 @@ class WalletOptionsButton extends StatelessWidget {
|
|||
onAddressListPressed: () async {
|
||||
Navigator.of(context).pop(_WalletOptions.addressList);
|
||||
},
|
||||
onChangeRepPressed: () async {
|
||||
Navigator.of(context).pop(_WalletOptions.changeRepresentative);
|
||||
},
|
||||
onShowXpubPressed: () async {
|
||||
Navigator.of(context).pop(_WalletOptions.showXpub);
|
||||
},
|
||||
|
@ -134,6 +142,32 @@ class WalletOptionsButton extends StatelessWidget {
|
|||
),
|
||||
);
|
||||
|
||||
if (result == true) {
|
||||
if (context.mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case _WalletOptions.changeRepresentative:
|
||||
final result = await showDialog<bool?>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => Navigator(
|
||||
initialRoute: ChangeRepresentativeView.routeName,
|
||||
onGenerateRoute: RouteGenerator.generateRoute,
|
||||
onGenerateInitialRoutes: (_, __) {
|
||||
return [
|
||||
RouteGenerator.generateRoute(
|
||||
RouteSettings(
|
||||
name: ChangeRepresentativeView.routeName,
|
||||
arguments: walletId,
|
||||
),
|
||||
),
|
||||
];
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
if (result == true) {
|
||||
if (context.mounted) {
|
||||
Navigator.of(context).pop();
|
||||
|
@ -171,18 +205,24 @@ class WalletOptionsPopupMenu extends ConsumerWidget {
|
|||
required this.onDeletePressed,
|
||||
required this.onAddressListPressed,
|
||||
required this.onShowXpubPressed,
|
||||
required this.onChangeRepPressed,
|
||||
required this.walletId,
|
||||
}) : super(key: key);
|
||||
|
||||
final VoidCallback onDeletePressed;
|
||||
final VoidCallback onAddressListPressed;
|
||||
final VoidCallback onShowXpubPressed;
|
||||
final VoidCallback onChangeRepPressed;
|
||||
final String walletId;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final bool xpubEnabled = ref.watch(walletsChangeNotifierProvider
|
||||
.select((value) => value.getManager(walletId).hasXPub));
|
||||
final manager = ref.watch(walletsChangeNotifierProvider
|
||||
.select((value) => value.getManager(walletId)));
|
||||
final bool xpubEnabled = manager.hasXPub;
|
||||
|
||||
final bool canChangeRep =
|
||||
manager.coin == Coin.nano || manager.coin == Coin.banano;
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
|
@ -237,6 +277,43 @@ class WalletOptionsPopupMenu extends ConsumerWidget {
|
|||
),
|
||||
),
|
||||
),
|
||||
if (canChangeRep)
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
if (canChangeRep)
|
||||
TransparentButton(
|
||||
onPressed: onChangeRepPressed,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
Assets.svg.eye,
|
||||
width: 20,
|
||||
height: 20,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldActiveSearchIconLeft,
|
||||
),
|
||||
const SizedBox(width: 14),
|
||||
Expanded(
|
||||
child: Text(
|
||||
_WalletOptions.changeRepresentative.prettyName,
|
||||
style: STextStyles.desktopTextExtraExtraSmall(
|
||||
context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
if (xpubEnabled)
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
|
|
|
@ -125,7 +125,7 @@ class _CreatePasswordViewState extends ConsumerState<CreatePasswordView> {
|
|||
}
|
||||
}
|
||||
|
||||
if (!widget.restoreFromSWB) {
|
||||
if (!widget.restoreFromSWB && mounted) {
|
||||
unawaited(showFloatingFlushBar(
|
||||
type: FlushBarType.success,
|
||||
message: "Your password is set up",
|
||||
|
|
|
@ -84,10 +84,10 @@ class _DesktopLoginViewState extends ConsumerState<DesktopLoginView> {
|
|||
unawaited(
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => Column(
|
||||
builder: (context) => const Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: const [
|
||||
children: [
|
||||
LoadingIndicator(
|
||||
width: 200,
|
||||
height: 200,
|
||||
|
|
|
@ -109,14 +109,15 @@ import 'package:stackwallet/pages/settings_views/global_settings_view/support_vi
|
|||
import 'package:stackwallet/pages/settings_views/global_settings_view/syncing_preferences_views/syncing_options_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/syncing_preferences_views/syncing_preferences_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/syncing_preferences_views/wallet_syncing_options_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/xpub_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_backup_views/wallet_backup_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_network_settings_view/wallet_network_settings_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_settings_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/change_representative_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/delete_wallet_recovery_phrase_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/delete_wallet_warning_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/rename_wallet_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/wallet_settings_wallet_settings_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/xpub_view.dart';
|
||||
import 'package:stackwallet/pages/stack_privacy_calls.dart';
|
||||
import 'package:stackwallet/pages/token_view/my_tokens_view.dart';
|
||||
import 'package:stackwallet/pages/token_view/token_contract_details_view.dart';
|
||||
|
@ -618,6 +619,20 @@ class RouteGenerator {
|
|||
}
|
||||
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
||||
|
||||
case ChangeRepresentativeView.routeName:
|
||||
if (args is String) {
|
||||
return getRoute(
|
||||
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||
builder: (_) => ChangeRepresentativeView(
|
||||
walletId: args,
|
||||
),
|
||||
settings: RouteSettings(
|
||||
name: settings.name,
|
||||
),
|
||||
);
|
||||
}
|
||||
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
||||
|
||||
case AppearanceSettingsView.routeName:
|
||||
return getRoute(
|
||||
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||
|
|
|
@ -14,9 +14,9 @@ import 'package:stackwallet/services/event_bus/events/global/node_connection_sta
|
|||
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';
|
||||
import 'package:stackwallet/services/mixins/wallet_cache.dart';
|
||||
import 'package:stackwallet/services/mixins/wallet_db.dart';
|
||||
import 'package:stackwallet/services/nano_api.dart';
|
||||
import 'package:stackwallet/services/node_service.dart';
|
||||
import 'package:stackwallet/services/transaction_notification_tracker.dart';
|
||||
import 'package:stackwallet/utilities/amount/amount.dart';
|
||||
|
@ -32,8 +32,7 @@ const int MINIMUM_CONFIRMATIONS = 1;
|
|||
const String DEFAULT_REPRESENTATIVE =
|
||||
"ban_1ka1ium4pfue3uxtntqsrib8mumxgazsjf58gidh1xeo5te3whsq8z476goo";
|
||||
|
||||
class BananoWallet extends CoinServiceAPI
|
||||
with WalletCache, WalletDB, CoinControlInterface {
|
||||
class BananoWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
||||
BananoWallet({
|
||||
required String walletId,
|
||||
required String walletName,
|
||||
|
@ -925,4 +924,51 @@ class BananoWallet extends CoinServiceAPI
|
|||
);
|
||||
await updateCachedChainHeight(height ?? 0);
|
||||
}
|
||||
|
||||
Future<String> getCurrentRepresentative() async {
|
||||
final serverURI = Uri.parse(getCurrentNode().host);
|
||||
final address = await currentReceivingAddress;
|
||||
|
||||
final response = await NanoAPI.getAccountInfo(
|
||||
server: serverURI,
|
||||
representative: true,
|
||||
account: address,
|
||||
);
|
||||
|
||||
return response.accountInfo?.representative ?? DEFAULT_REPRESENTATIVE;
|
||||
}
|
||||
|
||||
Future<bool> changeRepresentative(String newRepresentative) async {
|
||||
try {
|
||||
final serverURI = Uri.parse(getCurrentNode().host);
|
||||
final balance = this.balance.spendable.raw.toString();
|
||||
final String privateKey = await getPrivateKeyFromMnemonic();
|
||||
final address = await currentReceivingAddress;
|
||||
|
||||
final response = await NanoAPI.getAccountInfo(
|
||||
server: serverURI,
|
||||
representative: true,
|
||||
account: address,
|
||||
);
|
||||
|
||||
if (response.accountInfo == null) {
|
||||
throw response.exception ?? Exception("Failed to get account info");
|
||||
}
|
||||
|
||||
final work = await requestWork(response.accountInfo!.frontier);
|
||||
|
||||
return await NanoAPI.changeRepresentative(
|
||||
server: serverURI,
|
||||
accountType: NanoAccountType.BANANO,
|
||||
account: address,
|
||||
newRepresentative: newRepresentative,
|
||||
previousBlock: response.accountInfo!.frontier,
|
||||
balance: balance,
|
||||
privateKey: privateKey,
|
||||
work: work!,
|
||||
);
|
||||
} catch (_) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1023,6 +1023,7 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
final response = await EthereumAPI.getEthTransactions(
|
||||
address: thisAddress,
|
||||
firstBlock: isRescan ? 0 : firstBlock,
|
||||
includeTokens: true,
|
||||
);
|
||||
|
||||
if (response.value == null) {
|
||||
|
@ -1057,8 +1058,10 @@ class EthereumWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
txFailed = true;
|
||||
}
|
||||
isIncoming = false;
|
||||
} else {
|
||||
} else if (checksumEthereumAddress(element.to) == thisAddress) {
|
||||
isIncoming = true;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
//Calculate fees (GasLimit * gasPrice)
|
||||
|
|
|
@ -24,9 +24,9 @@ import 'package:stackwallet/services/event_bus/events/global/node_connection_sta
|
|||
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';
|
||||
import 'package:stackwallet/services/mixins/wallet_cache.dart';
|
||||
import 'package:stackwallet/services/mixins/wallet_db.dart';
|
||||
import 'package:stackwallet/services/nano_api.dart';
|
||||
import 'package:stackwallet/services/node_service.dart';
|
||||
import 'package:stackwallet/services/transaction_notification_tracker.dart';
|
||||
import 'package:stackwallet/utilities/amount/amount.dart';
|
||||
|
@ -42,8 +42,7 @@ const int MINIMUM_CONFIRMATIONS = 1;
|
|||
const String DEFAULT_REPRESENTATIVE =
|
||||
"nano_38713x95zyjsqzx6nm1dsom1jmm668owkeb9913ax6nfgj15az3nu8xkx579";
|
||||
|
||||
class NanoWallet extends CoinServiceAPI
|
||||
with WalletCache, WalletDB, CoinControlInterface {
|
||||
class NanoWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
||||
NanoWallet({
|
||||
required String walletId,
|
||||
required String walletName,
|
||||
|
@ -937,4 +936,51 @@ class NanoWallet extends CoinServiceAPI
|
|||
);
|
||||
await updateCachedChainHeight(height ?? 0);
|
||||
}
|
||||
|
||||
Future<String> getCurrentRepresentative() async {
|
||||
final serverURI = Uri.parse(getCurrentNode().host);
|
||||
final address = await currentReceivingAddress;
|
||||
|
||||
final response = await NanoAPI.getAccountInfo(
|
||||
server: serverURI,
|
||||
representative: true,
|
||||
account: address,
|
||||
);
|
||||
|
||||
return response.accountInfo?.representative ?? DEFAULT_REPRESENTATIVE;
|
||||
}
|
||||
|
||||
Future<bool> changeRepresentative(String newRepresentative) async {
|
||||
try {
|
||||
final serverURI = Uri.parse(getCurrentNode().host);
|
||||
final balance = this.balance.spendable.raw.toString();
|
||||
final String privateKey = await getPrivateKeyFromMnemonic();
|
||||
final address = await currentReceivingAddress;
|
||||
|
||||
final response = await NanoAPI.getAccountInfo(
|
||||
server: serverURI,
|
||||
representative: true,
|
||||
account: address,
|
||||
);
|
||||
|
||||
if (response.accountInfo == null) {
|
||||
throw response.exception ?? Exception("Failed to get account info");
|
||||
}
|
||||
|
||||
final work = await requestWork(response.accountInfo!.frontier);
|
||||
|
||||
return await NanoAPI.changeRepresentative(
|
||||
server: serverURI,
|
||||
accountType: NanoAccountType.NANO,
|
||||
account: address,
|
||||
newRepresentative: newRepresentative,
|
||||
previousBlock: response.accountInfo!.frontier,
|
||||
balance: balance,
|
||||
privateKey: privateKey,
|
||||
work: work!,
|
||||
);
|
||||
} catch (_) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:decimal/decimal.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:stackwallet/dto/ethereum/eth_token_tx_dto.dart';
|
||||
import 'package:stackwallet/dto/ethereum/eth_token_tx_extra_dto.dart';
|
||||
|
@ -50,6 +49,7 @@ abstract class EthereumAPI {
|
|||
static Future<EthereumResponse<List<EthTxDTO>>> getEthTransactions({
|
||||
required String address,
|
||||
int firstBlock = 0,
|
||||
bool includeTokens = false,
|
||||
}) async {
|
||||
try {
|
||||
final response = await get(
|
||||
|
@ -67,7 +67,7 @@ abstract class EthereumAPI {
|
|||
for (final map in list!) {
|
||||
final txn = EthTxDTO.fromMap(Map<String, dynamic>.from(map as Map));
|
||||
|
||||
if (txn.hasToken == 0) {
|
||||
if (txn.hasToken == 0 || includeTokens) {
|
||||
txns.add(txn);
|
||||
}
|
||||
}
|
||||
|
@ -76,9 +76,11 @@ abstract class EthereumAPI {
|
|||
null,
|
||||
);
|
||||
} else {
|
||||
throw EthApiException(
|
||||
"getEthTransactions($address) response is empty but status code is "
|
||||
"${response.statusCode}",
|
||||
// nice that the api returns an empty body instead of being
|
||||
// consistent and returning a json object with no transactions
|
||||
return EthereumResponse(
|
||||
[],
|
||||
null,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
@ -196,9 +198,11 @@ abstract class EthereumAPI {
|
|||
null,
|
||||
);
|
||||
} else {
|
||||
throw EthApiException(
|
||||
"getEthTransactionNonces($txns) response is empty but status code is "
|
||||
"${response.statusCode}",
|
||||
// nice that the api returns an empty body instead of being
|
||||
// consistent and returning a json object with no transactions
|
||||
return EthereumResponse(
|
||||
[],
|
||||
null,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
@ -252,13 +256,13 @@ abstract class EthereumAPI {
|
|||
);
|
||||
} else {
|
||||
throw EthApiException(
|
||||
"getEthTransaction($txids) response is empty but status code is "
|
||||
"getEthTokenTransactionsByTxids($txids) response is empty but status code is "
|
||||
"${response.statusCode}",
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw EthApiException(
|
||||
"getEthTransaction($txids) failed with status code: "
|
||||
"getEthTokenTransactionsByTxids($txids) failed with status code: "
|
||||
"${response.statusCode}",
|
||||
);
|
||||
}
|
||||
|
@ -269,7 +273,7 @@ abstract class EthereumAPI {
|
|||
);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"getEthTransaction($txids): $e\n$s",
|
||||
"getEthTokenTransactionsByTxids($txids): $e\n$s",
|
||||
level: LogLevel.Error,
|
||||
);
|
||||
return EthereumResponse(
|
||||
|
@ -307,9 +311,11 @@ abstract class EthereumAPI {
|
|||
null,
|
||||
);
|
||||
} else {
|
||||
throw EthApiException(
|
||||
"getTokenTransactions($address, $tokenContractAddress) response is empty but status code is "
|
||||
"${response.statusCode}",
|
||||
// nice that the api returns an empty body instead of being
|
||||
// consistent and returning a json object with no transactions
|
||||
return EthereumResponse(
|
||||
[],
|
||||
null,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
@ -424,10 +430,10 @@ abstract class EthereumAPI {
|
|||
final map = json["data"].first as Map;
|
||||
|
||||
final balance =
|
||||
Decimal.tryParse(map["balance"].toString()) ?? Decimal.zero;
|
||||
BigInt.tryParse(map["units"].toString()) ?? BigInt.zero;
|
||||
|
||||
return EthereumResponse(
|
||||
Amount.fromDecimal(balance, fractionDigits: map["decimals"] as int),
|
||||
Amount(rawValue: balance, fractionDigits: map["decimals"] as int),
|
||||
null,
|
||||
);
|
||||
} else {
|
||||
|
|
130
lib/services/nano_api.dart
Normal file
|
@ -0,0 +1,130 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:nanodart/nanodart.dart';
|
||||
|
||||
class NanoAPI {
|
||||
static Future<
|
||||
({
|
||||
NAccountInfo? accountInfo,
|
||||
Exception? exception,
|
||||
})> getAccountInfo({
|
||||
required Uri server,
|
||||
required bool representative,
|
||||
required String account,
|
||||
}) async {
|
||||
NAccountInfo? accountInfo;
|
||||
Exception? exception;
|
||||
|
||||
try {
|
||||
final response = await http.post(
|
||||
server,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: jsonEncode({
|
||||
"action": "account_info",
|
||||
"representative": "true",
|
||||
"account": account,
|
||||
}),
|
||||
);
|
||||
|
||||
final map = jsonDecode(response.body);
|
||||
|
||||
if (map is Map && map["error"] != null) {
|
||||
throw Exception(map["error"].toString());
|
||||
}
|
||||
|
||||
accountInfo = NAccountInfo(
|
||||
frontier: map["frontier"] as String,
|
||||
representative: map["representative"] as String,
|
||||
);
|
||||
} on Exception catch (e) {
|
||||
exception = e;
|
||||
} catch (e) {
|
||||
exception = Exception(e.toString());
|
||||
}
|
||||
|
||||
return (accountInfo: accountInfo, exception: exception);
|
||||
}
|
||||
|
||||
static Future<bool> changeRepresentative({
|
||||
required Uri server,
|
||||
required int accountType,
|
||||
required String account,
|
||||
required String newRepresentative,
|
||||
required String previousBlock,
|
||||
required String balance,
|
||||
required String privateKey,
|
||||
required String work,
|
||||
}) async {
|
||||
Map<String, String> block = {
|
||||
"type": "state",
|
||||
"account": account,
|
||||
"previous": previousBlock,
|
||||
"representative": newRepresentative,
|
||||
"balance": balance,
|
||||
"link":
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"work": work,
|
||||
};
|
||||
|
||||
final String hash;
|
||||
|
||||
try {
|
||||
hash = NanoBlocks.computeStateHash(
|
||||
accountType,
|
||||
account,
|
||||
previousBlock,
|
||||
newRepresentative,
|
||||
BigInt.parse(balance),
|
||||
block["link"] as String,
|
||||
);
|
||||
} catch (e) {
|
||||
if (e is RangeError) {
|
||||
throw Exception("Invalid representative format");
|
||||
}
|
||||
rethrow;
|
||||
}
|
||||
|
||||
final signature = NanoSignatures.signBlock(hash, privateKey);
|
||||
|
||||
block["signature"] = signature;
|
||||
|
||||
final map = await postBlock(server: server, block: block);
|
||||
|
||||
if (map is Map && map["error"] != null) {
|
||||
throw Exception(map["error"].toString());
|
||||
}
|
||||
|
||||
return map["error"] == null;
|
||||
}
|
||||
|
||||
// TODO: GET RID OF DYNAMIC AND USED TYPED DATA
|
||||
static Future<dynamic> postBlock({
|
||||
required Uri server,
|
||||
required Map<String, dynamic> block,
|
||||
}) async {
|
||||
final response = await http.post(
|
||||
server,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: jsonEncode({
|
||||
"action": "process",
|
||||
"json_block": "true",
|
||||
"subtype": "change",
|
||||
"block": block,
|
||||
}),
|
||||
);
|
||||
|
||||
return jsonDecode(response.body);
|
||||
}
|
||||
}
|
||||
|
||||
class NAccountInfo {
|
||||
final String frontier;
|
||||
final String representative;
|
||||
|
||||
NAccountInfo({required this.frontier, required this.representative});
|
||||
}
|
|
@ -22,3 +22,14 @@ final coinCardProvider = Provider.family<String?, Coin>((ref, coin) {
|
|||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
final coinCardFavoritesProvider = Provider.family<String?, Coin>((ref, coin) {
|
||||
final assets = ref.watch(themeAssetsProvider);
|
||||
|
||||
if (assets is ThemeAssetsV3) {
|
||||
return assets.coinCardFavoritesImages?[coin.mainNetVersion] ??
|
||||
assets.coinCardImages?[coin.mainNetVersion];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -70,6 +70,11 @@ class AmountFormatter {
|
|||
String string, {
|
||||
EthContract? ethContract,
|
||||
}) {
|
||||
return unit.tryParse(string, locale: locale, coin: coin);
|
||||
return unit.tryParse(
|
||||
string,
|
||||
locale: locale,
|
||||
coin: coin,
|
||||
tokenContract: ethContract,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,15 +12,17 @@ import 'dart:async';
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stackwallet/themes/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/widgets/custom_loading_overlay.dart';
|
||||
|
||||
Future<T> showLoading<T>({
|
||||
Future<T?> showLoading<T>({
|
||||
required Future<T> whileFuture,
|
||||
required BuildContext context,
|
||||
required String message,
|
||||
String? subMessage,
|
||||
bool isDesktop = false,
|
||||
bool opaqueBG = false,
|
||||
void Function(Exception)? onException,
|
||||
}) async {
|
||||
unawaited(
|
||||
showDialog<void>(
|
||||
|
@ -43,10 +45,24 @@ Future<T> showLoading<T>({
|
|||
),
|
||||
);
|
||||
|
||||
final result = await whileFuture;
|
||||
Exception? ex;
|
||||
T? result;
|
||||
|
||||
try {
|
||||
result = await whileFuture;
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"showLoading caught: $e\n$s",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
ex = e is Exception ? e : Exception(e.toString());
|
||||
}
|
||||
|
||||
if (context.mounted) {
|
||||
Navigator.of(context, rootNavigator: isDesktop).pop();
|
||||
if (ex != null) {
|
||||
onException?.call(ex);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -25,11 +25,13 @@ class CoinCard extends ConsumerWidget {
|
|||
required this.walletId,
|
||||
required this.width,
|
||||
required this.height,
|
||||
required this.isFavorite,
|
||||
});
|
||||
|
||||
final String walletId;
|
||||
final double width;
|
||||
final double height;
|
||||
final bool isFavorite;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
@ -38,7 +40,7 @@ class CoinCard extends ConsumerWidget {
|
|||
.select((value) => value.getManager(walletId).coin),
|
||||
);
|
||||
|
||||
final bool hasCardImageBg = ref.watch(coinCardProvider(coin)) != null;
|
||||
final bool hasCardImageBg = (isFavorite) ? ref.watch(coinCardFavoritesProvider(coin)) != null : ref.watch(coinCardProvider(coin)) != null;
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
|
@ -54,7 +56,9 @@ class CoinCard extends ConsumerWidget {
|
|||
fit: BoxFit.cover,
|
||||
image: FileImage(
|
||||
File(
|
||||
ref.watch(coinCardProvider(coin))!,
|
||||
(isFavorite)
|
||||
? ref.watch(coinCardFavoritesProvider(coin))!
|
||||
: ref.watch(coinCardProvider(coin))!,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -230,7 +230,9 @@ class _TransactionCardState extends ConsumerState<TransactionCard> {
|
|||
fit: BoxFit.scaleDown,
|
||||
child: Text(
|
||||
_transaction.isCancelled
|
||||
? "Cancelled"
|
||||
? coin == Coin.ethereum
|
||||
? "Failed"
|
||||
: "Cancelled"
|
||||
: whatIsIt(
|
||||
_transaction.type,
|
||||
coin,
|
||||
|
|
|
@ -140,7 +140,7 @@ class SimpleWalletCard extends ConsumerWidget {
|
|||
isDesktop: Util.isDesktop,
|
||||
);
|
||||
|
||||
if (!success) {
|
||||
if (!success!) {
|
||||
// TODO: show error dialog here?
|
||||
Logging.instance.log(
|
||||
"Failed to load token wallet for $contract",
|
||||
|
|
|
@ -564,6 +564,7 @@
|
|||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx;
|
||||
STRIP_INSTALLED_PRODUCT = NO;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
|
@ -716,6 +717,7 @@
|
|||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx;
|
||||
STRIP_INSTALLED_PRODUCT = NO;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
|
|
|
@ -1,68 +1,68 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"size" : "16x16",
|
||||
"idiom" : "mac",
|
||||
"filename" : "app_icon_16.png",
|
||||
"scale" : "1x"
|
||||
"info": {
|
||||
"version": 1,
|
||||
"author": "xcode"
|
||||
},
|
||||
{
|
||||
"size" : "16x16",
|
||||
"idiom" : "mac",
|
||||
"filename" : "app_icon_32.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "32x32",
|
||||
"idiom" : "mac",
|
||||
"filename" : "app_icon_32.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "32x32",
|
||||
"idiom" : "mac",
|
||||
"filename" : "app_icon_64.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "128x128",
|
||||
"idiom" : "mac",
|
||||
"filename" : "app_icon_128.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "128x128",
|
||||
"idiom" : "mac",
|
||||
"filename" : "app_icon_256.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "256x256",
|
||||
"idiom" : "mac",
|
||||
"filename" : "app_icon_256.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "256x256",
|
||||
"idiom" : "mac",
|
||||
"filename" : "app_icon_512.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "512x512",
|
||||
"idiom" : "mac",
|
||||
"filename" : "app_icon_512.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "512x512",
|
||||
"idiom" : "mac",
|
||||
"filename" : "app_icon_1024.png",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
"images": [
|
||||
{
|
||||
"size": "16x16",
|
||||
"idiom": "mac",
|
||||
"filename": "app_icon_16.png",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"size": "16x16",
|
||||
"idiom": "mac",
|
||||
"filename": "app_icon_32.png",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "32x32",
|
||||
"idiom": "mac",
|
||||
"filename": "app_icon_32.png",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"size": "32x32",
|
||||
"idiom": "mac",
|
||||
"filename": "app_icon_64.png",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "128x128",
|
||||
"idiom": "mac",
|
||||
"filename": "app_icon_128.png",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"size": "128x128",
|
||||
"idiom": "mac",
|
||||
"filename": "app_icon_256.png",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "256x256",
|
||||
"idiom": "mac",
|
||||
"filename": "app_icon_256.png",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"size": "256x256",
|
||||
"idiom": "mac",
|
||||
"filename": "app_icon_512.png",
|
||||
"scale": "2x"
|
||||
},
|
||||
{
|
||||
"size": "512x512",
|
||||
"idiom": "mac",
|
||||
"filename": "app_icon_512.png",
|
||||
"scale": "1x"
|
||||
},
|
||||
{
|
||||
"size": "512x512",
|
||||
"idiom": "mac",
|
||||
"filename": "app_icon_1024.png",
|
||||
"scale": "2x"
|
||||
}
|
||||
]
|
||||
}
|
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 520 B After Width: | Height: | Size: 577 B |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
20
pubspec.lock
|
@ -226,10 +226,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: cli_util
|
||||
sha256: "66f86e916d285c1a93d3b79587d94bd71984a66aac4ff74e524cfa7877f1395c"
|
||||
sha256: b8db3080e59b2503ca9e7922c3df2072cf13992354d5e944074ffa836fba43b7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.5"
|
||||
version: "0.4.0"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -584,10 +584,10 @@ packages:
|
|||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_launcher_icons
|
||||
sha256: ce0e501cfc258907842238e4ca605e74b7fd1cdf04b3b43e86c43f3e40a1592c
|
||||
sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.11.0"
|
||||
version: "0.13.1"
|
||||
flutter_libepiccash:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -646,10 +646,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_native_splash
|
||||
sha256: "6777a3abb974021a39b5fdd2d46a03ca390e03903b6351f21d10e7ecc969f12d"
|
||||
sha256: ba45d8cfbd778478a74696b012f33ffb6b1760c9bc531b21e2964444a4870dae
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.16"
|
||||
version: "2.3.1"
|
||||
flutter_plugin_android_lifecycle:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -853,10 +853,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: image
|
||||
sha256: "8e9d133755c3e84c73288363e6343157c383a0c6c56fc51afcc5d4d7180306d6"
|
||||
sha256: a72242c9a0ffb65d03de1b7113bc4e189686fc07c7147b8b41811d0dd0e0d9bf
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.3.0"
|
||||
version: "4.0.17"
|
||||
import_sorter:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
|
@ -1575,10 +1575,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: universal_io
|
||||
sha256: "06866290206d196064fd61df4c7aea1ffe9a4e7c4ccaa8fcded42dd41948005d"
|
||||
sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
version: "2.2.2"
|
||||
url_launcher:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
|
@ -11,7 +11,7 @@ description: Stack Wallet
|
|||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
version: 1.7.15+181
|
||||
version: 1.7.16+182
|
||||
|
||||
environment:
|
||||
sdk: ">=3.0.2 <4.0.0"
|
||||
|
@ -145,7 +145,7 @@ dev_dependencies:
|
|||
integration_test:
|
||||
sdk: flutter
|
||||
build_runner: ^2.1.7
|
||||
flutter_launcher_icons: ^0.11.0
|
||||
flutter_launcher_icons: ^0.13.1
|
||||
hive_generator: ^2.0.0
|
||||
dependency_validator: ^3.1.2
|
||||
hive_test: ^1.0.1
|
||||
|
@ -157,7 +157,7 @@ dev_dependencies:
|
|||
flutter_lints: ^2.0.1
|
||||
isar_generator: 3.0.5
|
||||
|
||||
flutter_icons:
|
||||
flutter_launcher_icons:
|
||||
android: true
|
||||
ios: true
|
||||
image_path: assets/icon/icon.png
|
||||
|
@ -170,7 +170,7 @@ flutter_icons:
|
|||
icon_size: 48 # min:48, max:256, default: 48
|
||||
macos:
|
||||
generate: true
|
||||
image_path: assets/icon/icon.png
|
||||
image_path: assets/icon/macos-icon.png
|
||||
|
||||
flutter_native_splash:
|
||||
image: assets/images/splash.png
|
||||
|
|