Merge pull request #122 from cypherstack/staging

namecoin fix and other small ui fixes
This commit is contained in:
Rylee Davis 2022-10-05 21:53:43 -06:00 committed by GitHub
commit 1de599caa8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
45 changed files with 6124 additions and 5260 deletions

View file

@ -32,7 +32,10 @@ cd stack_wallet
git submodule update --init --recursive git submodule update --init --recursive
``` ```
You will need to install all dependencies listed in each of the plugins in the crypto_plugins folder. (eg. [Monero](https://github.com/cypherstack/flutter_libmonero), [Epic Cash](https://github.com/cypherstack/flutter_libepiccash) ) as of Sep 8th 2022 that is: Install all dependencies listed in each of the plugins in the crypto_plugins folder (eg. [flutter_libmonero](https://github.com/cypherstack/flutter_libmonero/blob/main/howto-build-android.md), [flutter_libepiccash](https://github.com/cypherstack/flutter_libepiccash) ) as of Oct 3rd 2022 that is:
```
sudo apt-get install unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake openjdk-8-jre-headless libgit2-dev clang libncurses5-dev libncursesw5-dev zlib1g-dev llvm sudo apt-get install debhelper libclang-dev cargo rustc opencl-headers libssl-dev ocl-icd-opencl-dev
```
Install [Rust](https://www.rust-lang.org/tools/install) Install [Rust](https://www.rust-lang.org/tools/install)
``` ```
@ -45,6 +48,26 @@ sudo apt install build-essential debhelper cmake libclang-dev libncurses5-dev cl
sudo apt install unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake openjdk-8-jre-headless sudo apt install unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake openjdk-8-jre-headless
``` ```
Run prebuild script
```
cd scripts
./prebuild.sh
// when finished go back to the root directory
cd ..
```
Remove pre-installed system libraries for the following packages built by cryptography plugins in the crypto_plugins folder: `boost iconv libjson-dev libsecret openssl sodium unbound zmq`. You can use
```
sudo apt list --installed | grep boost
```
for example to find which pre-installed packages you may need to remove with `sudo apt remove`. Be careful, as some packages (especially boost) are linked to GNOME (GUI) packages: when in doubt, remove `-dev` packages first like with
```
sudo apt-get remove '^libboost.*-dev.*'
```
<!-- TODO: configure compiler to prefer built over system libraries -->
Building plugins for Android Building plugins for Android
``` ```
cd scripts/android/ cd scripts/android/

3
assets/svg/Polygon.svg Normal file
View file

@ -0,0 +1,3 @@
<svg width="8" height="11" viewBox="0 0 8 11" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.83473 4.89146C7.24557 5.21575 7.24557 5.78425 6.83473 6.10854L1.53567 10.2914C0.941523 10.7604 -3.48066e-08 10.3873 0 9.68284L4.13348e-07 1.31716C4.48155e-07 0.612725 0.941523 0.239629 1.53567 0.708624L6.83473 4.89146Z" fill="#0056D2"/>
</svg>

After

Width:  |  Height:  |  Size: 350 B

11
assets/svg/box-auto.svg Normal file
View file

@ -0,0 +1,11 @@
<svg width="26" height="22" viewBox="0 0 26 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_5432_15256)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.1875 1.8125H1.8125C1.08693 1.8125 0.5 2.39943 0.5 3.125V5.09375C0.5 5.45469 0.79482 5.75 1.15625 5.75H20.8438C21.2047 5.75 21.5 5.45469 21.5 5.09375V3.125C21.5 2.39943 20.9135 1.8125 20.1875 1.8125ZM1.8125 18.2188C1.8125 19.3057 2.69393 20.1875 3.78125 20.1875H14.145C13.1157 18.9035 12.5 17.2737 12.5 15.5C12.5 11.3579 15.8579 8 20 8C20.0627 8 20.1252 8.00077 20.1875 8.0023V7.0625H1.8125V18.2188ZM7.0625 10.1797C7.0625 9.90899 7.28398 9.6875 7.55469 9.6875H12.9C13.0933 9.6875 13.25 9.8442 13.25 10.0375V10.65C13.25 10.8433 13.0933 11 12.9 11H7.55469C7.28398 11 7.0625 10.7785 7.0625 10.5078V10.1797Z" fill="black"/>
<path d="M14 15.5C14 12.1859 16.6859 9.5 20 9.5C23.3141 9.5 26 12.1859 26 15.5C26 18.8141 23.3141 21.5 20 21.5C16.6859 21.5 14 18.8141 14 15.5ZM22.7141 14.4641C22.9695 14.2086 22.9695 13.7914 22.7141 13.5359C22.4586 13.2805 22.0414 13.2805 21.7859 13.5359L19.25 16.0719L18.2141 15.0359C17.9586 14.7805 17.5414 14.7805 17.2859 15.0359C17.0305 15.2914 17.0305 15.7086 17.2859 15.9641L18.7859 17.4641C19.0414 17.7195 19.4586 17.7195 19.7141 17.4641L22.7141 14.4641Z" fill="black"/>
</g>
<defs>
<clipPath id="clip0_5432_15256">
<rect width="25.5" height="21" fill="white" transform="translate(0.5 0.5)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

@ -1 +1 @@
Subproject commit 8e3afd002968d21a3de788569356587a70818022 Subproject commit f74f31e2f3b4a7c11907ae5df6cd38505cd25897

View file

@ -42,6 +42,25 @@ PODS:
- Flutter - Flutter
- cw_shared_external/Sodium (0.0.1): - cw_shared_external/Sodium (0.0.1):
- Flutter - Flutter
- cw_wownero (0.0.2):
- cw_shared_external
- cw_wownero/Boost (= 0.0.2)
- cw_wownero/OpenSSL (= 0.0.2)
- cw_wownero/Sodium (= 0.0.2)
- cw_wownero/Wownero (= 0.0.2)
- Flutter
- cw_wownero/Boost (0.0.2):
- cw_shared_external
- Flutter
- cw_wownero/OpenSSL (0.0.2):
- cw_shared_external
- Flutter
- cw_wownero/Sodium (0.0.2):
- cw_shared_external
- Flutter
- cw_wownero/Wownero (0.0.2):
- cw_shared_external
- Flutter
- devicelocale (0.0.1): - devicelocale (0.0.1):
- Flutter - Flutter
- DKImagePickerController/Core (4.3.4): - DKImagePickerController/Core (4.3.4):
@ -127,6 +146,7 @@ DEPENDENCIES:
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
- cw_monero (from `.symlinks/plugins/cw_monero/ios`) - cw_monero (from `.symlinks/plugins/cw_monero/ios`)
- cw_shared_external (from `.symlinks/plugins/cw_shared_external/ios`) - cw_shared_external (from `.symlinks/plugins/cw_shared_external/ios`)
- cw_wownero (from `.symlinks/plugins/cw_wownero/ios`)
- devicelocale (from `.symlinks/plugins/devicelocale/ios`) - devicelocale (from `.symlinks/plugins/devicelocale/ios`)
- file_picker (from `.symlinks/plugins/file_picker/ios`) - file_picker (from `.symlinks/plugins/file_picker/ios`)
- Flutter (from `Flutter`) - Flutter (from `Flutter`)
@ -169,6 +189,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/cw_monero/ios" :path: ".symlinks/plugins/cw_monero/ios"
cw_shared_external: cw_shared_external:
:path: ".symlinks/plugins/cw_shared_external/ios" :path: ".symlinks/plugins/cw_shared_external/ios"
cw_wownero:
:path: ".symlinks/plugins/cw_wownero/ios"
devicelocale: devicelocale:
:path: ".symlinks/plugins/devicelocale/ios" :path: ".symlinks/plugins/devicelocale/ios"
file_picker: file_picker:
@ -216,6 +238,7 @@ SPEC CHECKSUMS:
connectivity_plus: 413a8857dd5d9f1c399a39130850d02fe0feaf7e connectivity_plus: 413a8857dd5d9f1c399a39130850d02fe0feaf7e
cw_monero: 9816991daff0e3ad0a8be140e31933b5526babd4 cw_monero: 9816991daff0e3ad0a8be140e31933b5526babd4
cw_shared_external: 2972d872b8917603478117c9957dfca611845a92 cw_shared_external: 2972d872b8917603478117c9957dfca611845a92
cw_wownero: 08e5713fe311a3be95efd7f3c1bf9d47d9cfafde
devicelocale: b22617f40038496deffba44747101255cee005b0 devicelocale: b22617f40038496deffba44747101255cee005b0
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179

View file

@ -3,7 +3,7 @@
archiveVersion = 1; archiveVersion = 1;
classes = { classes = {
}; };
objectVersion = 46; objectVersion = 50;
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
@ -253,6 +253,7 @@
"${BUILT_PRODUCTS_DIR}/connectivity_plus/connectivity_plus.framework", "${BUILT_PRODUCTS_DIR}/connectivity_plus/connectivity_plus.framework",
"${BUILT_PRODUCTS_DIR}/cw_monero/cw_monero.framework", "${BUILT_PRODUCTS_DIR}/cw_monero/cw_monero.framework",
"${BUILT_PRODUCTS_DIR}/cw_shared_external/cw_shared_external.framework", "${BUILT_PRODUCTS_DIR}/cw_shared_external/cw_shared_external.framework",
"${BUILT_PRODUCTS_DIR}/cw_wownero/cw_wownero.framework",
"${BUILT_PRODUCTS_DIR}/devicelocale/devicelocale.framework", "${BUILT_PRODUCTS_DIR}/devicelocale/devicelocale.framework",
"${BUILT_PRODUCTS_DIR}/file_picker/file_picker.framework", "${BUILT_PRODUCTS_DIR}/file_picker/file_picker.framework",
"${BUILT_PRODUCTS_DIR}/flutter_libmonero/flutter_libmonero.framework", "${BUILT_PRODUCTS_DIR}/flutter_libmonero/flutter_libmonero.framework",
@ -285,6 +286,7 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/connectivity_plus.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/connectivity_plus.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/cw_monero.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/cw_monero.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/cw_shared_external.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/cw_shared_external.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/cw_wownero.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/devicelocale.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/devicelocale.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_picker.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_picker.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_libmonero.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_libmonero.framework",

View file

@ -84,6 +84,10 @@ void main() async {
if (Platform.isIOS) { if (Platform.isIOS) {
appDirectory = (await getLibraryDirectory()); appDirectory = (await getLibraryDirectory());
} }
if (Platform.isLinux || Logging.isArmLinux) {
appDirectory = Directory("${appDirectory.path}/.stackwallet");
await appDirectory.create();
}
// FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding); // FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
if (!(Logging.isArmLinux || Logging.isTestEnv)) { if (!(Logging.isArmLinux || Logging.isTestEnv)) {
final isar = await Isar.open( final isar = await Isar.open(

View file

@ -42,6 +42,11 @@ class _RestoreFromDatePickerState extends State<RestoreFromDatePicker> {
style: STextStyles.field(context), style: STextStyles.field(context),
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Restore from...", hintText: "Restore from...",
hintStyle: STextStyles.fieldLabel(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldDefaultSearchIconLeft,
),
suffixIcon: UnconstrainedBox( suffixIcon: UnconstrainedBox(
child: Row( child: Row(
children: [ children: [

View file

@ -393,13 +393,15 @@ class _ContactDetailsViewState extends ConsumerState<ContactDetailsView> {
color: Theme.of(context) color: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.textFieldDefaultBG, .textFieldDefaultBG,
padding: const EdgeInsets.all(4), padding: const EdgeInsets.all(6),
child: SvgPicture.asset(Assets.svg.pencil, child: SvgPicture.asset(
width: 12, Assets.svg.pencil,
height: 12, width: 14,
color: Theme.of(context) height: 14,
.extension<StackColors>()! color: Theme.of(context)
.accentColorDark), .extension<StackColors>()!
.accentColorDark,
),
), ),
), ),
const SizedBox( const SizedBox(
@ -421,13 +423,15 @@ class _ContactDetailsViewState extends ConsumerState<ContactDetailsView> {
color: Theme.of(context) color: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.textFieldDefaultBG, .textFieldDefaultBG,
padding: const EdgeInsets.all(4), padding: const EdgeInsets.all(6),
child: SvgPicture.asset(Assets.svg.copy, child: SvgPicture.asset(
width: 12, Assets.svg.copy,
height: 12, width: 16,
color: Theme.of(context) height: 16,
.extension<StackColors>()! color: Theme.of(context)
.accentColorDark), .extension<StackColors>()!
.accentColorDark,
),
), ),
), ),
], ],

View file

@ -5,6 +5,7 @@ import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/models/send_view_auto_fill_data.dart'; import 'package:stackwallet/models/send_view_auto_fill_data.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/address_book_views/subviews/contact_details_view.dart'; import 'package:stackwallet/pages/address_book_views/subviews/contact_details_view.dart';
import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_2_view.dart';
import 'package:stackwallet/pages/send_view/send_view.dart'; import 'package:stackwallet/pages/send_view/send_view.dart';
import 'package:stackwallet/providers/exchange/exchange_flow_is_active_state_provider.dart'; import 'package:stackwallet/providers/exchange/exchange_flow_is_active_state_provider.dart';
import 'package:stackwallet/providers/global/address_book_service_provider.dart'; import 'package:stackwallet/providers/global/address_book_service_provider.dart';
@ -19,6 +20,9 @@ import 'package:stackwallet/widgets/rounded_container.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
final exchangeFromAddressBookAddressStateProvider =
StateProvider<String>((ref) => "");
class ContactPopUp extends ConsumerWidget { class ContactPopUp extends ConsumerWidget {
const ContactPopUp({ const ContactPopUp({
Key? key, Key? key,
@ -268,11 +272,11 @@ class ContactPopUp extends ConsumerWidget {
color: Theme.of(context) color: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.textFieldDefaultBG, .textFieldDefaultBG,
padding: const EdgeInsets.all(4), padding: const EdgeInsets.all(6),
child: SvgPicture.asset( child: SvgPicture.asset(
Assets.svg.copy, Assets.svg.copy,
width: 12, width: 16,
height: 12, height: 16,
color: Theme.of(context) color: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.accentColorDark), .accentColorDark),
@ -280,6 +284,45 @@ class ContactPopUp extends ConsumerWidget {
), ),
], ],
), ),
if (isExchangeFlow)
const SizedBox(
width: 6,
),
if (isExchangeFlow)
Column(
children: [
const SizedBox(
height: 2,
),
GestureDetector(
onTap: () {
ref
.read(
exchangeFromAddressBookAddressStateProvider
.state)
.state = e.address;
Navigator.of(context).popUntil(
ModalRoute.withName(
Step2View.routeName));
},
child: RoundedContainer(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldDefaultBG,
padding:
const EdgeInsets.all(6),
child: SvgPicture.asset(
Assets.svg.chevronRight,
width: 16,
height: 16,
color: Theme.of(context)
.extension<
StackColors>()!
.accentColorDark),
),
),
],
),
if (contact.id != "default" && if (contact.id != "default" &&
hasActiveWallet && hasActiveWallet &&
!isExchangeFlow) !isExchangeFlow)

View file

@ -0,0 +1,128 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_balance_future.dart';
import 'package:stackwallet/widgets/wallet_info_row/sub_widgets/wallet_info_row_coin_icon.dart';
class ChooseFromStackView extends ConsumerStatefulWidget {
const ChooseFromStackView({
Key? key,
required this.coin,
}) : super(key: key);
final Coin coin;
static const String routeName = "/chooseFromStack";
@override
ConsumerState<ChooseFromStackView> createState() =>
_ChooseFromStackViewState();
}
class _ChooseFromStackViewState extends ConsumerState<ChooseFromStackView> {
late final Coin coin;
@override
void initState() {
coin = widget.coin;
super.initState();
}
@override
Widget build(BuildContext context) {
final walletIds = ref.watch(walletsChangeNotifierProvider
.select((value) => value.getWalletIdsFor(coin: coin)));
return Scaffold(
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar(
leading: const AppBarBackButton(),
title: Text(
"Choose your ${coin.ticker.toUpperCase()} wallet",
style: STextStyles.navBarTitle(context),
),
),
body: Padding(
padding: const EdgeInsets.all(16),
child: walletIds.isEmpty
? Column(
children: [
RoundedWhiteContainer(
child: Center(
child: Text(
"No ${coin.ticker.toUpperCase()} wallets",
style: STextStyles.itemSubtitle(context),
),
),
),
],
)
: ListView.builder(
itemCount: walletIds.length,
itemBuilder: (context, index) {
final manager = ref.watch(walletsChangeNotifierProvider
.select((value) => value.getManager(walletIds[index])));
return Padding(
padding: const EdgeInsets.symmetric(vertical: 5.0),
child: RawMaterialButton(
splashColor:
Theme.of(context).extension<StackColors>()!.highlight,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
padding: const EdgeInsets.all(0),
// color: Theme.of(context).extension<StackColors>()!.popupBG,
elevation: 0,
onPressed: () async {
if (mounted) {
Navigator.of(context).pop(manager.walletId);
}
},
child: RoundedWhiteContainer(
// color: Colors.transparent,
child: Row(
children: [
WalletInfoCoinIcon(coin: coin),
const SizedBox(
width: 12,
),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
manager.walletName,
style: STextStyles.titleBold12(context),
overflow: TextOverflow.ellipsis,
),
const SizedBox(
height: 2,
),
WalletInfoRowBalanceFuture(
walletId: walletIds[index],
),
],
),
)
],
),
),
),
);
},
),
),
);
}
}

View file

@ -132,6 +132,7 @@ class _ConfirmChangeNowSendViewState
final managerProvider = ref.watch(walletsChangeNotifierProvider final managerProvider = ref.watch(walletsChangeNotifierProvider
.select((value) => value.getManagerProvider(walletId))); .select((value) => value.getManagerProvider(walletId)));
return Scaffold( return Scaffold(
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar( appBar: AppBar(
backgroundColor: Theme.of(context).extension<StackColors>()!.background, backgroundColor: Theme.of(context).extension<StackColors>()!.background,
leading: AppBarBackButton( leading: AppBarBackButton(
@ -327,7 +328,12 @@ class _ConfirmChangeNowSendViewState
children: [ children: [
Text( Text(
"Total amount", "Total amount",
style: STextStyles.titleBold12(context), style:
STextStyles.titleBold12(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textConfirmTotalAmount,
),
), ),
Text( Text(
"${Format.satoshiAmountToPrettyString( "${Format.satoshiAmountToPrettyString(
@ -341,7 +347,12 @@ class _ConfirmChangeNowSendViewState
managerProvider managerProvider
.select((value) => value.coin), .select((value) => value.coin),
).ticker}", ).ticker}",
style: STextStyles.itemSubtitle12(context), style: STextStyles.itemSubtitle12(context)
.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textConfirmTotalAmount,
),
textAlign: TextAlign.right, textAlign: TextAlign.right,
), ),
], ],

View file

@ -3,6 +3,8 @@ import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/models/exchange/incomplete_exchange.dart'; import 'package:stackwallet/models/exchange/incomplete_exchange.dart';
import 'package:stackwallet/pages/address_book_views/address_book_view.dart'; import 'package:stackwallet/pages/address_book_views/address_book_view.dart';
import 'package:stackwallet/pages/address_book_views/subviews/contact_popup.dart';
import 'package:stackwallet/pages/exchange_view/choose_from_stack_view.dart';
import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_3_view.dart'; import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_3_view.dart';
import 'package:stackwallet/pages/exchange_view/sub_widgets/step_row.dart'; import 'package:stackwallet/pages/exchange_view/sub_widgets/step_row.dart';
import 'package:stackwallet/providers/exchange/exchange_flow_is_active_state_provider.dart'; import 'package:stackwallet/providers/exchange/exchange_flow_is_active_state_provider.dart';
@ -17,6 +19,7 @@ import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
import 'package:stackwallet/widgets/icon_widgets/addressbook_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/addressbook_icon.dart';
import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart';
import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
@ -54,6 +57,15 @@ class _Step2ViewState extends ConsumerState<Step2View> {
late final FocusNode _toFocusNode; late final FocusNode _toFocusNode;
late final FocusNode _refundFocusNode; late final FocusNode _refundFocusNode;
bool isStackCoin(String ticker) {
try {
coinFromTickerCaseInsensitive(ticker);
return true;
} on ArgumentError catch (_) {
return false;
}
}
@override @override
void initState() { void initState() {
model = widget.model; model = widget.model;
@ -74,7 +86,22 @@ class _Step2ViewState extends ConsumerState<Step2View> {
.read(walletsChangeNotifierProvider) .read(walletsChangeNotifierProvider)
.getManager(tuple.item1) .getManager(tuple.item1)
.currentReceivingAddress .currentReceivingAddress
.then((value) => _toController.text = value); .then((value) {
_toController.text = value;
model.recipientAddress = _toController.text;
});
} else {
if (model.sendTicker.toUpperCase() ==
tuple.item2.ticker.toUpperCase()) {
ref
.read(walletsChangeNotifierProvider)
.getManager(tuple.item1)
.currentReceivingAddress
.then((value) {
_refundController.text = value;
model.refundAddress = _refundController.text;
});
}
} }
} }
@ -158,15 +185,36 @@ class _Step2ViewState extends ConsumerState<Step2View> {
"Recipient Wallet", "Recipient Wallet",
style: STextStyles.smallMed12(context), style: STextStyles.smallMed12(context),
), ),
// GestureDetector( if (isStackCoin(model.receiveTicker))
// onTap: () { BlueTextButton(
// // TODO: choose from stack? text: "Choose from stack",
// }, onTap: () {
// child: Text( try {
// "Choose from Stack", final coin = coinFromTickerCaseInsensitive(
// style: STextStyles.link2(context), model.receiveTicker,
// ), );
// ), Navigator.of(context)
.pushNamed(
ChooseFromStackView.routeName,
arguments: coin,
)
.then((value) async {
if (value is String) {
final manager = ref
.read(walletsChangeNotifierProvider)
.getManager(value);
_toController.text = manager.walletName;
model.recipientAddress = await manager
.currentReceivingAddress;
}
});
} catch (e, s) {
Logging.instance
.log("$e\n$s", level: LogLevel.Info);
}
},
),
], ],
), ),
const SizedBox( const SizedBox(
@ -195,6 +243,9 @@ class _Step2ViewState extends ConsumerState<Step2View> {
), ),
focusNode: _toFocusNode, focusNode: _toFocusNode,
style: STextStyles.field(context), style: STextStyles.field(context),
onChanged: (value) {
setState(() {});
},
decoration: standardInputDecoration( decoration: standardInputDecoration(
"Enter the ${model.receiveTicker.toUpperCase()} payout address", "Enter the ${model.receiveTicker.toUpperCase()} payout address",
_toFocusNode, _toFocusNode,
@ -221,6 +272,8 @@ class _Step2ViewState extends ConsumerState<Step2View> {
"sendViewClearAddressFieldButtonKey"), "sendViewClearAddressFieldButtonKey"),
onTap: () { onTap: () {
_toController.text = ""; _toController.text = "";
model.recipientAddress =
_toController.text;
setState(() {}); setState(() {});
}, },
@ -239,6 +292,8 @@ class _Step2ViewState extends ConsumerState<Step2View> {
data.text!.trim(); data.text!.trim();
_toController.text = content; _toController.text = content;
model.recipientAddress =
_toController.text;
setState(() {}); setState(() {});
} }
@ -259,13 +314,31 @@ class _Step2ViewState extends ConsumerState<Step2View> {
.state = true; .state = true;
Navigator.of(context) Navigator.of(context)
.pushNamed( .pushNamed(
AddressBookView.routeName, AddressBookView.routeName,
) )
.then((_) => ref .then((_) {
ref
.read(
exchangeFlowIsActiveStateProvider
.state)
.state = false;
final address = ref
.read(
exchangeFromAddressBookAddressStateProvider
.state)
.state;
if (address.isNotEmpty) {
_toController.text = address;
model.recipientAddress =
_toController.text;
ref
.read( .read(
exchangeFlowIsActiveStateProvider exchangeFromAddressBookAddressStateProvider
.state) .state)
.state = false); .state = "";
}
});
}, },
child: const AddressBookIcon(), child: const AddressBookIcon(),
), ),
@ -299,11 +372,15 @@ class _Step2ViewState extends ConsumerState<Step2View> {
// auto fill address // auto fill address
_toController.text = _toController.text =
results["address"] ?? ""; results["address"] ?? "";
model.recipientAddress =
_toController.text;
setState(() {}); setState(() {});
} else { } else {
_toController.text = _toController.text =
qrResult.rawContent; qrResult.rawContent;
model.recipientAddress =
_toController.text;
setState(() {}); setState(() {});
} }
@ -348,15 +425,37 @@ class _Step2ViewState extends ConsumerState<Step2View> {
"Refund Wallet (required)", "Refund Wallet (required)",
style: STextStyles.smallMed12(context), style: STextStyles.smallMed12(context),
), ),
// GestureDetector( if (isStackCoin(model.sendTicker))
// onTap: () { BlueTextButton(
// // TODO: choose from stack? text: "Choose from stack",
// }, onTap: () {
// child: Text( try {
// "Choose from Stack", final coin = coinFromTickerCaseInsensitive(
// style: STextStyles.link2(context), model.sendTicker,
// ), );
// ), Navigator.of(context)
.pushNamed(
ChooseFromStackView.routeName,
arguments: coin,
)
.then((value) async {
if (value is String) {
final manager = ref
.read(walletsChangeNotifierProvider)
.getManager(value);
_refundController.text =
manager.walletName;
model.refundAddress = await manager
.currentReceivingAddress;
}
});
} catch (e, s) {
Logging.instance
.log("$e\n$s", level: LogLevel.Info);
}
},
),
], ],
), ),
const SizedBox( const SizedBox(
@ -384,6 +483,9 @@ class _Step2ViewState extends ConsumerState<Step2View> {
), ),
focusNode: _refundFocusNode, focusNode: _refundFocusNode,
style: STextStyles.field(context), style: STextStyles.field(context),
onChanged: (value) {
setState(() {});
},
decoration: standardInputDecoration( decoration: standardInputDecoration(
"Enter ${model.sendTicker.toUpperCase()} refund address", "Enter ${model.sendTicker.toUpperCase()} refund address",
_refundFocusNode, _refundFocusNode,
@ -410,6 +512,8 @@ class _Step2ViewState extends ConsumerState<Step2View> {
"sendViewClearAddressFieldButtonKey"), "sendViewClearAddressFieldButtonKey"),
onTap: () { onTap: () {
_refundController.text = ""; _refundController.text = "";
model.refundAddress =
_refundController.text;
setState(() {}); setState(() {});
}, },
@ -429,6 +533,8 @@ class _Step2ViewState extends ConsumerState<Step2View> {
_refundController.text = _refundController.text =
content; content;
model.refundAddress =
_refundController.text;
setState(() {}); setState(() {});
} }
@ -450,13 +556,26 @@ class _Step2ViewState extends ConsumerState<Step2View> {
.state = true; .state = true;
Navigator.of(context) Navigator.of(context)
.pushNamed( .pushNamed(
AddressBookView.routeName, AddressBookView.routeName,
) )
.then((_) => ref .then((_) {
.read( ref
exchangeFlowIsActiveStateProvider .read(
.state) exchangeFlowIsActiveStateProvider
.state = false); .state)
.state = false;
final address = ref
.read(
exchangeFromAddressBookAddressStateProvider
.state)
.state;
if (address.isNotEmpty) {
_refundController.text =
address;
model.refundAddress =
_refundController.text;
}
});
}, },
child: const AddressBookIcon(), child: const AddressBookIcon(),
), ),
@ -490,11 +609,15 @@ class _Step2ViewState extends ConsumerState<Step2View> {
// auto fill address // auto fill address
_refundController.text = _refundController.text =
results["address"] ?? ""; results["address"] ?? "";
model.refundAddress =
_refundController.text;
setState(() {}); setState(() {});
} else { } else {
_refundController.text = _refundController.text =
qrResult.rawContent; qrResult.rawContent;
model.refundAddress =
_refundController.text;
setState(() {}); setState(() {});
} }
@ -556,9 +679,6 @@ class _Step2ViewState extends ConsumerState<Step2View> {
Expanded( Expanded(
child: TextButton( child: TextButton(
onPressed: () { onPressed: () {
model.recipientAddress = _toController.text;
model.refundAddress = _refundController.text;
Navigator.of(context).pushNamed( Navigator.of(context).pushNamed(
Step3View.routeName, Step3View.routeName,
arguments: model); arguments: model);

View file

@ -16,6 +16,7 @@ import 'package:stackwallet/utilities/clipboard_interface.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/custom_loading_overlay.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/stack_dialog.dart'; import 'package:stackwallet/widgets/stack_dialog.dart';
@ -222,6 +223,26 @@ class _Step3ViewState extends ConsumerState<Step3View> {
Expanded( Expanded(
child: TextButton( child: TextButton(
onPressed: () async { onPressed: () async {
unawaited(
showDialog<void>(
context: context,
barrierDismissible: false,
builder: (_) => WillPopScope(
onWillPop: () async => false,
child: Container(
color: Theme.of(context)
.extension<StackColors>()!
.overlay
.withOpacity(0.6),
child: const CustomLoadingOverlay(
message: "Creating a trade",
eventBus: null,
),
),
),
),
);
ChangeNowResponse<ExchangeTransaction> ChangeNowResponse<ExchangeTransaction>
response; response;
if (model.rateType == if (model.rateType ==
@ -251,6 +272,10 @@ class _Step3ViewState extends ConsumerState<Step3View> {
} }
if (response.value == null) { if (response.value == null) {
if (mounted) {
Navigator.of(context).pop();
}
unawaited(showDialog<void>( unawaited(showDialog<void>(
context: context, context: context,
barrierDismissible: true, barrierDismissible: true,
@ -273,8 +298,6 @@ class _Step3ViewState extends ConsumerState<Step3View> {
.getTransactionStatus( .getTransactionStatus(
id: response.value!.id); id: response.value!.id);
debugPrint("WTF: $statusResponse");
String status = "Waiting"; String status = "Waiting";
if (statusResponse.value != null) { if (statusResponse.value != null) {
status = statusResponse.value!.status.name; status = statusResponse.value!.status.name;
@ -290,6 +313,10 @@ class _Step3ViewState extends ConsumerState<Step3View> {
status += " for deposit"; status += " for deposit";
} }
if (mounted) {
Navigator.of(context).pop();
}
unawaited(NotificationApi.showNotification( unawaited(NotificationApi.showNotification(
changeNowId: model.trade!.id, changeNowId: model.trade!.id,
title: status, title: status,

View file

@ -232,7 +232,7 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
? ref.read(estimatedRateExchangeFormProvider).fromAmountString ? ref.read(estimatedRateExchangeFormProvider).fromAmountString
: ref.read(fixedRateExchangeFormProvider).fromAmountString; : ref.read(fixedRateExchangeFormProvider).fromAmountString;
_receiveController.text = isEstimated _receiveController.text = isEstimated
? ref.read(estimatedRateExchangeFormProvider).toAmountString ? "-" //ref.read(estimatedRateExchangeFormProvider).toAmountString
: ref.read(fixedRateExchangeFormProvider).toAmountString; : ref.read(fixedRateExchangeFormProvider).toAmountString;
_sendFocusNode.addListener(() async { _sendFocusNode.addListener(() async {
@ -260,7 +260,11 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
.read(fixedRateExchangeFormProvider) .read(fixedRateExchangeFormProvider)
.setFromAmountAndCalculateToAmount(Decimal.zero, true); .setFromAmountAndCalculateToAmount(Decimal.zero, true);
} }
_receiveController.text = ""; _receiveController.text =
ref.read(prefsChangeNotifierProvider).exchangeRateType ==
ExchangeRateType.estimated
? "-"
: "";
} }
} }
}); });
@ -325,7 +329,7 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
: fixedRateExchangeFormProvider.select( : fixedRateExchangeFormProvider.select(
(value) => value.toAmountString), (previous, String next) { (value) => value.toAmountString), (previous, String next) {
if (!_receiveFocusNode.hasFocus) { if (!_receiveFocusNode.hasFocus) {
_receiveController.text = next; _receiveController.text = isEstimated && next.isEmpty ? "-" : next;
debugPrint("RECEIVE AMOUNT LISTENER ACTIVATED"); debugPrint("RECEIVE AMOUNT LISTENER ACTIVATED");
if (_swapLock) { if (_swapLock) {
_sendController.text = isEstimated _sendController.text = isEstimated
@ -345,7 +349,12 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
debugPrint("SEND AMOUNT LISTENER ACTIVATED"); debugPrint("SEND AMOUNT LISTENER ACTIVATED");
if (_swapLock) { if (_swapLock) {
_receiveController.text = isEstimated _receiveController.text = isEstimated
? ref.read(estimatedRateExchangeFormProvider).toAmountString ? ref
.read(estimatedRateExchangeFormProvider)
.toAmountString
.isEmpty
? "-"
: ref.read(estimatedRateExchangeFormProvider).toAmountString
: ref.read(fixedRateExchangeFormProvider).toAmountString; : ref.read(fixedRateExchangeFormProvider).toAmountString;
} }
} }
@ -424,7 +433,7 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
.setFromAmountAndCalculateToAmount( .setFromAmountAndCalculateToAmount(
Decimal.zero, false); Decimal.zero, false);
} }
_receiveController.text = ""; _receiveController.text = isEstimated ? "-" : "";
} }
}, },
keyboardType: const TextInputType.numberWithOptions( keyboardType: const TextInputType.numberWithOptions(
@ -737,7 +746,7 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
.exchangeRateType == .exchangeRateType ==
ExchangeRateType.estimated, ExchangeRateType.estimated,
onTap: () { onTap: () {
if (_receiveController.text == "-") { if (!isEstimated && _receiveController.text == "-") {
_receiveController.text = ""; _receiveController.text = "";
} }
}, },

View file

@ -48,6 +48,26 @@ class _SendFromViewState extends ConsumerState<SendFromView> {
late final String address; late final String address;
late final ExchangeTransaction trade; late final ExchangeTransaction trade;
String formatAmount(Decimal amount, Coin coin) {
switch (coin) {
case Coin.bitcoin:
case Coin.bitcoincash:
case Coin.dogecoin:
case Coin.epicCash:
case Coin.firo:
case Coin.namecoin:
case Coin.bitcoinTestNet:
case Coin.bitcoincashTestnet:
case Coin.dogecoinTestNet:
case Coin.firoTestNet:
return amount.toStringAsFixed(Constants.decimalPlaces);
case Coin.monero:
return amount.toStringAsFixed(Constants.decimalPlacesMonero);
case Coin.wownero:
return amount.toStringAsFixed(Constants.decimalPlacesWownero);
}
}
@override @override
void initState() { void initState() {
coin = widget.coin; coin = widget.coin;
@ -59,6 +79,11 @@ class _SendFromViewState extends ConsumerState<SendFromView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType");
final walletIds = ref.watch(walletsChangeNotifierProvider
.select((value) => value.getWalletIdsFor(coin: coin)));
return Scaffold( return Scaffold(
backgroundColor: Theme.of(context).extension<StackColors>()!.background, backgroundColor: Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar( appBar: AppBar(
@ -68,44 +93,41 @@ class _SendFromViewState extends ConsumerState<SendFromView> {
}, },
), ),
title: Text( title: Text(
"Send ", "Send from",
style: STextStyles.navBarTitle(context), style: STextStyles.navBarTitle(context),
), ),
), ),
body: Padding( body: Padding(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
child: Wrap( child: Column(
// crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
Text( Row(
"Choose your ${coin.ticker} wallet", children: [
style: STextStyles.pageTitleH1(context), Text(
), "You need to send ${formatAmount(amount, coin)} ${coin.ticker}",
const SizedBox( style: STextStyles.itemSubtitle(context),
height: 8, ),
), ],
Text(
"You need to send ${amount.toStringAsFixed(coin == Coin.monero ? Constants.satsPerCoinMonero : coin == Coin.wownero ? Constants.satsPerCoinWownero : Constants.satsPerCoin)} ${coin.ticker}",
style: STextStyles.itemSubtitle(context),
), ),
const SizedBox( const SizedBox(
height: 16, height: 16,
), ),
ListView( Expanded(
shrinkWrap: true, child: ListView.builder(
children: [ itemCount: walletIds.length,
...ref itemBuilder: (context, index) {
.watch(walletsChangeNotifierProvider return Padding(
.select((value) => value.managers)) padding: const EdgeInsets.symmetric(vertical: 4),
.where((element) => element.coin == coin) child: SendFromCard(
.map((e) => SendFromCard( walletId: walletIds[index],
walletId: e.walletId, amount: amount,
amount: amount, address: address,
address: address, trade: trade,
trade: trade, ),
)) );
.toList(growable: false) },
], ),
), ),
], ],
), ),
@ -163,7 +185,7 @@ class _SendFromCardState extends ConsumerState<SendFromCard> {
child: MaterialButton( child: MaterialButton(
splashColor: Theme.of(context).extension<StackColors>()!.highlight, splashColor: Theme.of(context).extension<StackColors>()!.highlight,
key: Key("walletsSheetItemButtonKey_$walletId"), key: Key("walletsSheetItemButtonKey_$walletId"),
padding: const EdgeInsets.all(5), padding: const EdgeInsets.all(8),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
@ -276,59 +298,61 @@ class _SendFromCardState extends ConsumerState<SendFromCard> {
), ),
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.all(4), padding: const EdgeInsets.all(6),
child: SvgPicture.asset( child: SvgPicture.asset(
Assets.svg.iconFor(coin: coin), Assets.svg.iconFor(coin: coin),
width: 20, width: 24,
height: 20, height: 24,
), ),
), ),
), ),
const SizedBox( const SizedBox(
width: 12, width: 12,
), ),
Column( Expanded(
mainAxisAlignment: MainAxisAlignment.spaceBetween, child: Column(
crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ crossAxisAlignment: CrossAxisAlignment.start,
Text( children: [
manager.walletName, Text(
style: STextStyles.titleBold12(context), manager.walletName,
), style: STextStyles.titleBold12(context),
const SizedBox( ),
height: 2, const SizedBox(
), height: 2,
FutureBuilder( ),
future: manager.totalBalance, FutureBuilder(
builder: (builderContext, AsyncSnapshot<Decimal> snapshot) { future: manager.totalBalance,
if (snapshot.connectionState == ConnectionState.done && builder: (builderContext, AsyncSnapshot<Decimal> snapshot) {
snapshot.hasData) { if (snapshot.connectionState == ConnectionState.done &&
return Text( snapshot.hasData) {
"${Format.localizedStringAsFixed( return Text(
value: snapshot.data!, "${Format.localizedStringAsFixed(
locale: locale, value: snapshot.data!,
decimalPlaces: coin == Coin.monero locale: locale,
? Constants.satsPerCoinMonero decimalPlaces: coin == Coin.monero
: coin == Coin.wownero ? Constants.decimalPlacesMonero
? Constants.satsPerCoinWownero : coin == Coin.wownero
: Constants.satsPerCoin, ? Constants.decimalPlacesWownero
)} ${coin.ticker}", : Constants.decimalPlaces,
style: STextStyles.itemSubtitle(context), )} ${coin.ticker}",
); style: STextStyles.itemSubtitle(context),
} else { );
return AnimatedText( } else {
stringsToLoopThrough: const [ return AnimatedText(
"Loading balance", stringsToLoopThrough: const [
"Loading balance.", "Loading balance",
"Loading balance..", "Loading balance.",
"Loading balance..." "Loading balance..",
], "Loading balance..."
style: STextStyles.itemSubtitle(context), ],
); style: STextStyles.itemSubtitle(context),
} );
}, }
), },
], ),
],
),
), ),
], ],
), ),

View file

@ -10,6 +10,7 @@ import 'package:stackwallet/models/exchange/change_now/exchange_transaction_stat
import 'package:stackwallet/models/paymint/transactions_model.dart'; import 'package:stackwallet/models/paymint/transactions_model.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/exchange_view/edit_trade_note_view.dart'; import 'package:stackwallet/pages/exchange_view/edit_trade_note_view.dart';
import 'package:stackwallet/pages/exchange_view/send_from_view.dart';
import 'package:stackwallet/pages/wallet_view/transaction_views/edit_note_view.dart'; import 'package:stackwallet/pages/wallet_view/transaction_views/edit_note_view.dart';
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart'; import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
import 'package:stackwallet/providers/exchange/change_now_provider.dart'; import 'package:stackwallet/providers/exchange/change_now_provider.dart';
@ -24,6 +25,7 @@ import 'package:stackwallet/utilities/format.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
import 'package:stackwallet/widgets/rounded_container.dart'; import 'package:stackwallet/widgets/rounded_container.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/stack_dialog.dart'; import 'package:stackwallet/widgets/stack_dialog.dart';
@ -60,6 +62,15 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
String _note = ""; String _note = "";
bool isStackCoin(String ticker) {
try {
coinFromTickerCaseInsensitive(ticker);
return true;
} on ArgumentError catch (_) {
return false;
}
}
@override @override
initState() { initState() {
tradeId = widget.tradeId; tradeId = widget.tradeId;
@ -345,9 +356,48 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Row(
"Send ${trade.fromCurrency.toUpperCase()} to this address", mainAxisAlignment: MainAxisAlignment.spaceBetween,
style: STextStyles.itemSubtitle(context), children: [
Text(
"Send ${trade.fromCurrency.toUpperCase()} to this address",
style: STextStyles.itemSubtitle(context),
),
GestureDetector(
onTap: () async {
final address = trade.payinAddress;
await Clipboard.setData(
ClipboardData(
text: address,
),
);
unawaited(showFloatingFlushBar(
type: FlushBarType.info,
message: "Copied to clipboard",
context: context,
));
},
child: Row(
children: [
SvgPicture.asset(
Assets.svg.copy,
width: 12,
height: 12,
color: Theme.of(context)
.extension<StackColors>()!
.infoItemIcons,
),
const SizedBox(
width: 4,
),
Text(
"Copy",
style: STextStyles.link2(context),
),
],
),
),
],
), ),
const SizedBox( const SizedBox(
height: 4, height: 4,
@ -717,6 +767,32 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
const SizedBox( const SizedBox(
height: 12, height: 12,
), ),
if (isStackCoin(trade.fromCurrency) &&
trade.statusObject != null &&
(trade.statusObject!.status ==
ChangeNowTransactionStatus.New ||
trade.statusObject!.status ==
ChangeNowTransactionStatus.Waiting))
SecondaryButton(
label: "Send from Stack",
onPressed: () {
final amount = sendAmount;
final address = trade.payinAddress;
final coin =
coinFromTickerCaseInsensitive(trade.fromCurrency);
Navigator.of(context).pushNamed(
SendFromView.routeName,
arguments: Tuple4(
coin,
amount,
address,
trade,
),
);
},
),
], ],
), ),
), ),

View file

@ -83,8 +83,8 @@ class _WalletInitiatedExchangeViewState
child: Container( child: Container(
color: Theme.of(context) color: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.accentColorDark .overlay
.withOpacity(0.8), .withOpacity(0.6),
child: const CustomLoadingOverlay( child: const CustomLoadingOverlay(
message: "Updating exchange rate", message: "Updating exchange rate",
eventBus: null, eventBus: null,
@ -271,7 +271,11 @@ class _WalletInitiatedExchangeViewState
.read(fixedRateExchangeFormProvider) .read(fixedRateExchangeFormProvider)
.setFromAmountAndCalculateToAmount(Decimal.zero, true); .setFromAmountAndCalculateToAmount(Decimal.zero, true);
} }
_receiveController.text = ""; _receiveController.text =
ref.read(prefsChangeNotifierProvider).exchangeRateType ==
ExchangeRateType.estimated
? "-"
: "";
} }
} }
}); });
@ -329,7 +333,7 @@ class _WalletInitiatedExchangeViewState
: fixedRateExchangeFormProvider.select( : fixedRateExchangeFormProvider.select(
(value) => value.toAmountString), (previous, String next) { (value) => value.toAmountString), (previous, String next) {
if (!_receiveFocusNode.hasFocus) { if (!_receiveFocusNode.hasFocus) {
_receiveController.text = next; _receiveController.text = isEstimated && next.isEmpty ? "-" : next;
debugPrint("RECEIVE AMOUNT LISTENER ACTIVATED"); debugPrint("RECEIVE AMOUNT LISTENER ACTIVATED");
if (_swapLock) { if (_swapLock) {
_sendController.text = isEstimated _sendController.text = isEstimated
@ -349,7 +353,12 @@ class _WalletInitiatedExchangeViewState
debugPrint("SEND AMOUNT LISTENER ACTIVATED"); debugPrint("SEND AMOUNT LISTENER ACTIVATED");
if (_swapLock) { if (_swapLock) {
_receiveController.text = isEstimated _receiveController.text = isEstimated
? ref.read(estimatedRateExchangeFormProvider).toAmountString ? ref
.read(estimatedRateExchangeFormProvider)
.toAmountString
.isEmpty
? "-"
: ref.read(estimatedRateExchangeFormProvider).toAmountString
: ref.read(fixedRateExchangeFormProvider).toAmountString; : ref.read(fixedRateExchangeFormProvider).toAmountString;
} }
} }
@ -469,7 +478,7 @@ class _WalletInitiatedExchangeViewState
.setFromAmountAndCalculateToAmount( .setFromAmountAndCalculateToAmount(
Decimal.zero, false); Decimal.zero, false);
} }
_receiveController.text = ""; _receiveController.text = isEstimated ? "-" : "";
} }
}, },
keyboardType: const TextInputType.numberWithOptions( keyboardType: const TextInputType.numberWithOptions(
@ -808,7 +817,8 @@ class _WalletInitiatedExchangeViewState
.exchangeRateType == .exchangeRateType ==
ExchangeRateType.estimated, ExchangeRateType.estimated,
onTap: () { onTap: () {
if (_receiveController.text == "-") { if (!isEstimated &&
_receiveController.text == "-") {
_receiveController.text = ""; _receiveController.text = "";
} }
}, },
@ -1280,23 +1290,23 @@ class _WalletInitiatedExchangeViewState
.exchangeRateType == .exchangeRateType ==
ExchangeRateType.estimated; ExchangeRateType.estimated;
final ft = isEstimated // final ft = isEstimated
? ref // ? ref
.read( // .read(
estimatedRateExchangeFormProvider) // estimatedRateExchangeFormProvider)
.from // .from
?.ticker ?? // ?.ticker ??
"" // ""
: ref // : ref
.read( // .read(
fixedRateExchangeFormProvider) // fixedRateExchangeFormProvider)
.market // .market
?.from ?? // ?.from ??
""; // "";
//
final manager = ref // final manager = ref
.read(walletsChangeNotifierProvider) // .read(walletsChangeNotifierProvider)
.getManager(walletId); // .getManager(walletId);
final sendAmount = Decimal.parse(ref final sendAmount = Decimal.parse(ref
.read(estimatedRateExchangeFormProvider) .read(estimatedRateExchangeFormProvider)
.fromAmountString); .fromAmountString);

View file

@ -303,13 +303,17 @@ class _DebugViewState extends ConsumerState<DebugView> {
Logging.instance Logging.instance
.log("$e\n$s", level: LogLevel.Error); .log("$e\n$s", level: LogLevel.Error);
} }
String? path;
final String? path = if (Platform.isAndroid) {
await FilePicker.platform.getDirectoryPath( path = dir.path;
dialogTitle: "Choose Backup location", } else {
initialDirectory: dir.path, path = await FilePicker.platform
lockParentWindow: true, .getDirectoryPath(
); dialogTitle: "Choose Backup location",
initialDirectory: dir.path,
lockParentWindow: true,
);
}
if (path != null) { if (path != null) {
final eventBus = EventBus(); final eventBus = EventBus();
@ -328,7 +332,7 @@ class _DebugViewState extends ConsumerState<DebugView> {
), ),
)); ));
await ref final filename = await ref
.read(debugServiceProvider) .read(debugServiceProvider)
.exportToFile(path, eventBus); .exportToFile(path, eventBus);
@ -336,10 +340,26 @@ class _DebugViewState extends ConsumerState<DebugView> {
if (mounted) { if (mounted) {
Navigator.pop(context); Navigator.pop(context);
unawaited(showFloatingFlushBar(
type: FlushBarType.info, if (Platform.isAndroid) {
context: context, unawaited(
message: 'Logs file saved')); showDialog(
context: context,
builder: (context) => StackOkDialog(
title: "Logs saved to",
message: "${path!}/$filename",
),
),
);
} else {
unawaited(
showFloatingFlushBar(
type: FlushBarType.info,
context: context,
message: 'Logs file saved',
),
);
}
} }
} }
}, },

View file

@ -82,6 +82,17 @@ class _EnableAutoBackupViewState extends ConsumerState<CreateAutoBackupView> {
passwordFocusNode = FocusNode(); passwordFocusNode = FocusNode();
passwordRepeatFocusNode = FocusNode(); passwordRepeatFocusNode = FocusNode();
if (Platform.isAndroid) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
final dir = await stackFileSystem.prepareStorage();
if (mounted) {
setState(() {
fileLocationController.text = dir.path;
});
}
});
}
super.initState(); super.initState();
} }
@ -133,64 +144,70 @@ class _EnableAutoBackupViewState extends ConsumerState<CreateAutoBackupView> {
const SizedBox( const SizedBox(
height: 10, height: 10,
), ),
TextField( if (!Platform.isAndroid)
onTap: () async { TextField(
try { onTap: Platform.isAndroid
await stackFileSystem.prepareStorage(); ? null
: () async {
try {
await stackFileSystem.prepareStorage();
if (mounted) { if (mounted) {
await stackFileSystem.pickDir(context); await stackFileSystem.pickDir(context);
} }
if (mounted) { if (mounted) {
setState(() { setState(() {
fileLocationController.text = fileLocationController.text =
stackFileSystem.dirPath ?? ""; stackFileSystem.dirPath ?? "";
}); });
} }
} catch (e, s) { } catch (e, s) {
Logging.instance.log("$e\n$s", level: LogLevel.Error); Logging.instance
} .log("$e\n$s", level: LogLevel.Error);
}, }
controller: fileLocationController, },
style: STextStyles.field(context), controller: fileLocationController,
decoration: InputDecoration( style: STextStyles.field(context),
hintText: "Save to...", decoration: InputDecoration(
suffixIcon: UnconstrainedBox( hintText: "Save to...",
child: Row( hintStyle: STextStyles.fieldLabel(context),
children: [ suffixIcon: UnconstrainedBox(
const SizedBox( child: Row(
width: 16, children: [
), const SizedBox(
SvgPicture.asset( width: 16,
Assets.svg.folder, ),
color: Theme.of(context) SvgPicture.asset(
.extension<StackColors>()! Assets.svg.folder,
.textDark3, color: Theme.of(context)
width: 16, .extension<StackColors>()!
height: 16, .textDark3,
), width: 16,
const SizedBox( height: 16,
width: 12, ),
), const SizedBox(
], width: 12,
),
],
),
), ),
), ),
key: const Key(
"createBackupSaveToFileLocationTextFieldKey"),
readOnly: true,
toolbarOptions: const ToolbarOptions(
copy: true,
cut: false,
paste: false,
selectAll: false,
),
onChanged: (newValue) {},
), ),
key: const Key( if (!Platform.isAndroid)
"createBackupSaveToFileLocationTextFieldKey"), const SizedBox(
readOnly: true, height: 10,
toolbarOptions: const ToolbarOptions(
copy: true,
cut: false,
paste: false,
selectAll: false,
), ),
onChanged: (newValue) {},
),
const SizedBox(
height: 10,
),
ClipRRect( ClipRRect(
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius, Constants.size.circularBorderRadius,
@ -593,8 +610,15 @@ class _EnableAutoBackupViewState extends ConsumerState<CreateAutoBackupView> {
await showDialog<dynamic>( await showDialog<dynamic>(
context: context, context: context,
barrierDismissible: false, barrierDismissible: false,
builder: (_) => const StackOkDialog( builder: (_) => Platform.isAndroid
title: "Stack Auto Backup enabled!"), ? StackOkDialog(
title:
"Stack Auto Backup enabled and saved to:",
message: fileToSave,
)
: const StackOkDialog(
title:
"Stack Auto Backup enabled!"),
); );
if (mounted) { if (mounted) {
passwordController.text = ""; passwordController.text = "";

View file

@ -64,6 +64,17 @@ class _RestoreFromFileViewState extends State<CreateBackupView> {
passwordFocusNode = FocusNode(); passwordFocusNode = FocusNode();
passwordRepeatFocusNode = FocusNode(); passwordRepeatFocusNode = FocusNode();
if (Platform.isAndroid) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
final dir = await stackFileSystem.prepareStorage();
if (mounted) {
setState(() {
fileLocationController.text = dir.path;
});
}
});
}
super.initState(); super.initState();
} }
@ -113,88 +124,78 @@ class _RestoreFromFileViewState extends State<CreateBackupView> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
Consumer(builder: (context, ref, __) { if (!Platform.isAndroid)
return Container( Consumer(builder: (context, ref, __) {
color: Colors.transparent, return Container(
child: TextField( color: Colors.transparent,
onTap: () async { child: TextField(
try { onTap: Platform.isAndroid
await stackFileSystem.prepareStorage(); ? null
// ref : () async {
// .read( try {
// shouldShowLockscreenOnResumeStateProvider await stackFileSystem.prepareStorage();
// .state)
// .state = false;
if (mounted) {
await stackFileSystem.pickDir(context);
}
// Future<void>.delayed( if (mounted) {
// const Duration(seconds: 2), await stackFileSystem
// () => ref .pickDir(context);
// .read( }
// shouldShowLockscreenOnResumeStateProvider
// .state)
// .state = true,
// );
setState(() { if (mounted) {
fileLocationController.text = setState(() {
stackFileSystem.dirPath ?? ""; fileLocationController.text =
}); stackFileSystem.dirPath ?? "";
} catch (e, s) { });
// ref }
// .read( } catch (e, s) {
// shouldShowLockscreenOnResumeStateProvider Logging.instance.log("$e\n$s",
// .state) level: LogLevel.Error);
// .state = true; }
Logging.instance },
.log("$e\n$s", level: LogLevel.Error); controller: fileLocationController,
} style: STextStyles.field(context),
}, decoration: InputDecoration(
controller: fileLocationController, hintText: "Save to...",
style: STextStyles.field(context), hintStyle: STextStyles.fieldLabel(context),
decoration: InputDecoration( suffixIcon: UnconstrainedBox(
hintText: "Save to...", child: Row(
suffixIcon: UnconstrainedBox( children: [
child: Row( const SizedBox(
children: [ width: 16,
const SizedBox( ),
width: 16, SvgPicture.asset(
), Assets.svg.folder,
SvgPicture.asset( color: Theme.of(context)
Assets.svg.folder, .extension<StackColors>()!
color: Theme.of(context) .textDark3,
.extension<StackColors>()! width: 16,
.textDark3, height: 16,
width: 16, ),
height: 16, const SizedBox(
), width: 12,
const SizedBox( ),
width: 12, ],
), ),
],
), ),
), ),
key: const Key(
"createBackupSaveToFileLocationTextFieldKey"),
readOnly: true,
toolbarOptions: const ToolbarOptions(
copy: true,
cut: false,
paste: false,
selectAll: false,
),
onChanged: (newValue) {
// ref.read(addressEntryDataProvider(widget.id)).address = newValue;
},
), ),
key: const Key( );
"createBackupSaveToFileLocationTextFieldKey"), }),
readOnly: true, if (!Platform.isAndroid)
toolbarOptions: const ToolbarOptions( const SizedBox(
copy: true, height: 8,
cut: false, ),
paste: false,
selectAll: false,
),
onChanged: (newValue) {
// ref.read(addressEntryDataProvider(widget.id)).address = newValue;
},
),
);
}),
const SizedBox(
height: 8,
),
ClipRRect( ClipRRect(
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius, Constants.size.circularBorderRadius,
@ -315,8 +316,12 @@ class _RestoreFromFileViewState extends State<CreateBackupView> {
.extension<StackColors>()! .extension<StackColors>()!
.accentColorRed .accentColorRed
: passwordStrength < 1 : passwordStrength < 1
? Theme.of(context).extension<StackColors>()!.accentColorYellow ? Theme.of(context)
: Theme.of(context).extension<StackColors>()!.accentColorGreen, .extension<StackColors>()!
.accentColorYellow
: Theme.of(context)
.extension<StackColors>()!
.accentColorGreen,
backgroundColor: Theme.of(context) backgroundColor: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.buttonBackSecondary, .buttonBackSecondary,
@ -389,8 +394,12 @@ class _RestoreFromFileViewState extends State<CreateBackupView> {
const Spacer(), const Spacer(),
TextButton( TextButton(
style: shouldEnableCreate style: shouldEnableCreate
? Theme.of(context) .extension<StackColors>()!.getPrimaryEnabledButtonColor(context) ? Theme.of(context)
: Theme.of(context) .extension<StackColors>()!.getPrimaryDisabledButtonColor(context), .extension<StackColors>()!
.getPrimaryEnabledButtonColor(context)
: Theme.of(context)
.extension<StackColors>()!
.getPrimaryDisabledButtonColor(context),
onPressed: !shouldEnableCreate onPressed: !shouldEnableCreate
? null ? null
: () async { : () async {
@ -468,8 +477,14 @@ class _RestoreFromFileViewState extends State<CreateBackupView> {
await showDialog<dynamic>( await showDialog<dynamic>(
context: context, context: context,
barrierDismissible: false, barrierDismissible: false,
builder: (_) => const StackOkDialog( builder: (_) => Platform.isAndroid
title: "Backup creation succeeded"), ? StackOkDialog(
title: "Backup saved to:",
message: fileToSave,
)
: const StackOkDialog(
title:
"Backup creation succeeded"),
); );
passwordController.text = ""; passwordController.text = "";
passwordRepeatController.text = ""; passwordRepeatController.text = "";

View file

@ -84,6 +84,17 @@ class _EditAutoBackupViewState extends ConsumerState<EditAutoBackupView> {
passwordFocusNode = FocusNode(); passwordFocusNode = FocusNode();
passwordRepeatFocusNode = FocusNode(); passwordRepeatFocusNode = FocusNode();
if (Platform.isAndroid) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
final dir = await stackFileSystem.prepareStorage();
if (mounted) {
setState(() {
fileLocationController.text = dir.path;
});
}
});
}
super.initState(); super.initState();
} }
@ -135,64 +146,70 @@ class _EditAutoBackupViewState extends ConsumerState<EditAutoBackupView> {
const SizedBox( const SizedBox(
height: 10, height: 10,
), ),
TextField( if (!Platform.isAndroid)
onTap: () async { TextField(
try { onTap: Platform.isAndroid
await stackFileSystem.prepareStorage(); ? null
: () async {
try {
await stackFileSystem.prepareStorage();
if (mounted) { if (mounted) {
await stackFileSystem.pickDir(context); await stackFileSystem.pickDir(context);
} }
if (mounted) { if (mounted) {
setState(() { setState(() {
fileLocationController.text = fileLocationController.text =
stackFileSystem.dirPath ?? ""; stackFileSystem.dirPath ?? "";
}); });
} }
} catch (e, s) { } catch (e, s) {
Logging.instance.log("$e\n$s", level: LogLevel.Error); Logging.instance
} .log("$e\n$s", level: LogLevel.Error);
}, }
controller: fileLocationController, },
style: STextStyles.field(context), controller: fileLocationController,
decoration: InputDecoration( style: STextStyles.field(context),
hintText: "Save to...", decoration: InputDecoration(
suffixIcon: UnconstrainedBox( hintText: "Save to...",
child: Row( hintStyle: STextStyles.fieldLabel(context),
children: [ suffixIcon: UnconstrainedBox(
const SizedBox( child: Row(
width: 16, children: [
), const SizedBox(
SvgPicture.asset( width: 16,
Assets.svg.folder, ),
color: Theme.of(context) SvgPicture.asset(
.extension<StackColors>()! Assets.svg.folder,
.textDark3, color: Theme.of(context)
width: 16, .extension<StackColors>()!
height: 16, .textDark3,
), width: 16,
const SizedBox( height: 16,
width: 12, ),
), const SizedBox(
], width: 12,
),
],
),
), ),
), ),
key: const Key(
"createBackupSaveToFileLocationTextFieldKey"),
readOnly: true,
toolbarOptions: const ToolbarOptions(
copy: true,
cut: false,
paste: false,
selectAll: false,
),
onChanged: (newValue) {},
), ),
key: const Key( if (!Platform.isAndroid)
"createBackupSaveToFileLocationTextFieldKey"), const SizedBox(
readOnly: true, height: 10,
toolbarOptions: const ToolbarOptions(
copy: true,
cut: false,
paste: false,
selectAll: false,
), ),
onChanged: (newValue) {},
),
const SizedBox(
height: 10,
),
ClipRRect( ClipRRect(
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius, Constants.size.circularBorderRadius,
@ -594,8 +611,14 @@ class _EditAutoBackupViewState extends ConsumerState<EditAutoBackupView> {
await showDialog<dynamic>( await showDialog<dynamic>(
context: context, context: context,
barrierDismissible: false, barrierDismissible: false,
builder: (_) => const StackOkDialog( builder: (_) => Platform.isAndroid
title: "Stack Auto Backup saved"), ? StackOkDialog(
title:
"Stack Auto Backup saved to:",
message: fileToSave,
)
: const StackOkDialog(
title: "Stack Auto Backup saved"),
); );
if (mounted) { if (mounted) {
passwordController.text = ""; passwordController.text = "";

View file

@ -209,6 +209,10 @@ abstract class SWB {
Logging.instance.log( Logging.instance.log(
"...createStackWalletJSON DB.instance.mutex acquired", "...createStackWalletJSON DB.instance.mutex acquired",
level: LogLevel.Info); level: LogLevel.Info);
Logging.instance.log(
"SWB backing up nodes",
level: LogLevel.Warning,
);
try { try {
var primaryNodes = nodeService.primaryNodes.map((e) async { var primaryNodes = nodeService.primaryNodes.map((e) async {
final map = e.toMap(); final map = e.toMap();
@ -231,6 +235,11 @@ abstract class SWB {
Logging.instance.log("$e $s", level: LogLevel.Error); Logging.instance.log("$e $s", level: LogLevel.Error);
} }
Logging.instance.log(
"SWB backing up prefs",
level: LogLevel.Warning,
);
Map<String, dynamic> prefs = {}; Map<String, dynamic> prefs = {};
final _prefs = Prefs.instance; final _prefs = Prefs.instance;
await _prefs.init(); await _prefs.init();
@ -251,11 +260,21 @@ abstract class SWB {
backupJson['prefs'] = prefs; backupJson['prefs'] = prefs;
Logging.instance.log(
"SWB backing up addressbook",
level: LogLevel.Warning,
);
AddressBookService addressBookService = AddressBookService(); AddressBookService addressBookService = AddressBookService();
var addresses = await addressBookService.addressBookEntries; var addresses = await addressBookService.addressBookEntries;
backupJson['addressBookEntries'] = backupJson['addressBookEntries'] =
addresses.map((e) => e.toMap()).toList(); addresses.map((e) => e.toMap()).toList();
Logging.instance.log(
"SWB backing up wallets",
level: LogLevel.Warning,
);
List<dynamic> backupWallets = []; List<dynamic> backupWallets = [];
for (var manager in _wallets.managers) { for (var manager in _wallets.managers) {
Map<String, dynamic> backupWallet = {}; Map<String, dynamic> backupWallet = {};
@ -283,6 +302,11 @@ abstract class SWB {
} }
backupJson['wallets'] = backupWallets; backupJson['wallets'] = backupWallets;
Logging.instance.log(
"SWB backing up trades",
level: LogLevel.Warning,
);
// back up trade history // back up trade history
final tradesService = TradesService(); final tradesService = TradesService();
final trades = final trades =
@ -295,6 +319,11 @@ abstract class SWB {
tradeTxidLookupDataService.all.map((e) => e.toMap()).toList(); tradeTxidLookupDataService.all.map((e) => e.toMap()).toList();
backupJson["tradeTxidLookupData"] = lookupData; backupJson["tradeTxidLookupData"] = lookupData;
Logging.instance.log(
"SWB backing up trade notes",
level: LogLevel.Warning,
);
// back up trade notes // back up trade notes
final tradeNotesService = TradeNotesService(); final tradeNotesService = TradeNotesService();
final tradeNotes = tradeNotesService.all; final tradeNotes = tradeNotesService.all;
@ -357,7 +386,7 @@ abstract class SWB {
final notes = walletbackup["notes"] as Map?; final notes = walletbackup["notes"] as Map?;
if (notes != null) { if (notes != null) {
for (final note in notes.entries) { for (final note in notes.entries) {
notesService.editOrAddNote( await notesService.editOrAddNote(
txid: note.key as String, note: note.value as String); txid: note.key as String, note: note.value as String);
} }
} }
@ -432,11 +461,19 @@ abstract class SWB {
uiState?.preferences = StackRestoringStatus.restoring; uiState?.preferences = StackRestoringStatus.restoring;
Logging.instance.log(
"SWB restoring prefs",
level: LogLevel.Warning,
);
await _restorePrefs(prefs); await _restorePrefs(prefs);
uiState?.preferences = StackRestoringStatus.success; uiState?.preferences = StackRestoringStatus.success;
uiState?.addressBook = StackRestoringStatus.restoring; uiState?.addressBook = StackRestoringStatus.restoring;
Logging.instance.log(
"SWB restoring addressbook",
level: LogLevel.Warning,
);
if (addressBookEntries != null) { if (addressBookEntries != null) {
await _restoreAddressBook(addressBookEntries); await _restoreAddressBook(addressBookEntries);
} }
@ -444,6 +481,10 @@ abstract class SWB {
uiState?.addressBook = StackRestoringStatus.success; uiState?.addressBook = StackRestoringStatus.success;
uiState?.nodes = StackRestoringStatus.restoring; uiState?.nodes = StackRestoringStatus.restoring;
Logging.instance.log(
"SWB restoring nodes",
level: LogLevel.Warning,
);
await _restoreNodes(nodes, primaryNodes); await _restoreNodes(nodes, primaryNodes);
uiState?.nodes = StackRestoringStatus.success; uiState?.nodes = StackRestoringStatus.success;
@ -451,17 +492,29 @@ abstract class SWB {
// restore trade history // restore trade history
if (trades != null) { if (trades != null) {
Logging.instance.log(
"SWB restoring trades",
level: LogLevel.Warning,
);
await _restoreTrades(trades); await _restoreTrades(trades);
} }
// restore trade history lookup data for trades send from stack wallet // restore trade history lookup data for trades send from stack wallet
if (tradeTxidLookupData != null) { if (tradeTxidLookupData != null) {
Logging.instance.log(
"SWB restoring trade look up data",
level: LogLevel.Warning,
);
await _restoreTradesLookUpData(tradeTxidLookupData, oldToNewWalletIdMap); await _restoreTradesLookUpData(tradeTxidLookupData, oldToNewWalletIdMap);
} }
// restore trade notes // restore trade notes
if (tradeNotes != null) { if (tradeNotes != null) {
Logging.instance.log(
"SWB restoring trade notes",
level: LogLevel.Warning,
);
await _restoreTradesNotes(tradeNotes); await _restoreTradesNotes(tradeNotes);
} }
@ -490,9 +543,17 @@ abstract class SWB {
String jsonBackup, String jsonBackup,
StackRestoringUIState? uiState, StackRestoringUIState? uiState,
) async { ) async {
if (!Platform.isLinux) Wakelock.enable(); if (!Platform.isLinux) await Wakelock.enable();
Logging.instance.log(
"SWB creating temp backup",
level: LogLevel.Warning,
);
final preRestoreJSON = await createStackWalletJSON(); final preRestoreJSON = await createStackWalletJSON();
Logging.instance.log(
"SWB temp backup created",
level: LogLevel.Warning,
);
List<String> _currentWalletIds = Map<String, dynamic>.from(DB.instance List<String> _currentWalletIds = Map<String, dynamic>.from(DB.instance
.get<dynamic>( .get<dynamic>(
@ -814,13 +875,13 @@ abstract class SWB {
} }
await asyncRestore(epicCashWallets[i], uiState, walletsService); await asyncRestore(epicCashWallets[i], uiState, walletsService);
} }
if (!Platform.isLinux) Wakelock.disable(); if (!Platform.isLinux) await Wakelock.disable();
// check if cancel was requested and restore previous state // check if cancel was requested and restore previous state
if (_checkShouldCancel(preRestoreState)) { if (_checkShouldCancel(preRestoreState)) {
return false; return false;
} }
Logging.instance.log("done with SWB restore", level: LogLevel.Info); Logging.instance.log("done with SWB restore", level: LogLevel.Warning);
return true; return true;
} }
@ -849,7 +910,7 @@ abstract class SWB {
// if no contacts were present before attempted restore then delete any that // if no contacts were present before attempted restore then delete any that
// could have been added before the restore was cancelled // could have been added before the restore was cancelled
for (final String idToDelete in allContactIds) { for (final String idToDelete in allContactIds) {
addressBookService.removeContact(idToDelete); await addressBookService.removeContact(idToDelete);
} }
} else { } else {
final Map<String, dynamic> preContactMap = {}; final Map<String, dynamic> preContactMap = {};
@ -886,7 +947,7 @@ abstract class SWB {
); );
} else { } else {
// otherwise remove it as it was not there before attempting SWB restore // otherwise remove it as it was not there before attempting SWB restore
addressBookService.removeContact(id); await addressBookService.removeContact(id);
} }
} }
} }
@ -898,7 +959,7 @@ abstract class SWB {
// no pre nodes found so we delete all but defaults // no pre nodes found so we delete all but defaults
for (final node in currentNodes) { for (final node in currentNodes) {
if (!node.isDefault) { if (!node.isDefault) {
nodeService.delete(node.id, true); await nodeService.delete(node.id, true);
} }
} }
} else { } else {
@ -912,7 +973,7 @@ abstract class SWB {
if (nodeData != null) { if (nodeData != null) {
// node existed before restore attempt // node existed before restore attempt
// revert to pre restore node // revert to pre restore node
nodeService.edit( await nodeService.edit(
node.copyWith( node.copyWith(
host: nodeData['host'] as String, host: nodeData['host'] as String,
port: nodeData['port'] as int, port: nodeData['port'] as int,
@ -927,7 +988,7 @@ abstract class SWB {
nodeData['password'] as String?, nodeData['password'] as String?,
true); true);
} else { } else {
nodeService.delete(node.id, true); await nodeService.delete(node.id, true);
} }
} }
} }
@ -951,7 +1012,7 @@ abstract class SWB {
// no trade history found pre restore attempt so we delete anything that // no trade history found pre restore attempt so we delete anything that
// was added during the restore attempt // was added during the restore attempt
for (final tradeTx in currentTrades) { for (final tradeTx in currentTrades) {
tradesService.delete(trade: tradeTx, shouldNotifyListeners: true); await tradesService.delete(trade: tradeTx, shouldNotifyListeners: true);
} }
} else { } else {
final Map<String, dynamic> preTradeMap = {}; final Map<String, dynamic> preTradeMap = {};
@ -964,13 +1025,14 @@ abstract class SWB {
if (tradeData != null) { if (tradeData != null) {
// trade existed before attempted restore so we don't delete it, only // trade existed before attempted restore so we don't delete it, only
// revert data to pre restore state // revert data to pre restore state
tradesService.edit( await tradesService.edit(
trade: ExchangeTransaction.fromJson( trade: ExchangeTransaction.fromJson(
tradeData as Map<String, dynamic>), tradeData as Map<String, dynamic>),
shouldNotifyListeners: true); shouldNotifyListeners: true);
} else { } else {
// trade did not exist before so we delete it // trade did not exist before so we delete it
tradesService.delete(trade: tradeTx, shouldNotifyListeners: true); await tradesService.delete(
trade: tradeTx, shouldNotifyListeners: true);
} }
} }
} }
@ -982,7 +1044,7 @@ abstract class SWB {
if (tradeNotes == null) { if (tradeNotes == null) {
for (final noteEntry in currentNotes.entries) { for (final noteEntry in currentNotes.entries) {
tradeNotesService.delete(tradeId: noteEntry.key); await tradeNotesService.delete(tradeId: noteEntry.key);
} }
} else { } else {
// grab all trade IDs of (reverted to pre state) trades // grab all trade IDs of (reverted to pre state) trades
@ -991,7 +1053,7 @@ abstract class SWB {
// delete all notes that don't correspond to an id that we have // delete all notes that don't correspond to an id that we have
for (final noteEntry in currentNotes.entries) { for (final noteEntry in currentNotes.entries) {
if (!idsToKeep.contains(noteEntry.key)) { if (!idsToKeep.contains(noteEntry.key)) {
tradeNotesService.delete(tradeId: noteEntry.key); await tradeNotesService.delete(tradeId: noteEntry.key);
} }
} }
} }
@ -1009,7 +1071,7 @@ abstract class SWB {
for (int i = 0; i < tradeTxidLookupData.length; i++) { for (int i = 0; i < tradeTxidLookupData.length; i++) {
final json = Map<String, dynamic>.from(tradeTxidLookupData[i] as Map); final json = Map<String, dynamic>.from(tradeTxidLookupData[i] as Map);
TradeWalletLookup lookup = TradeWalletLookup.fromJson(json); TradeWalletLookup lookup = TradeWalletLookup.fromJson(json);
tradeTxidLookupDataService.save(tradeWalletLookup: lookup); await tradeTxidLookupDataService.save(tradeWalletLookup: lookup);
} }
} }
@ -1127,14 +1189,14 @@ abstract class SWB {
) async { ) async {
final tradesService = TradesService(); final tradesService = TradesService();
for (int i = 0; i < trades.length - 1; i++) { for (int i = 0; i < trades.length - 1; i++) {
tradesService.add( await tradesService.add(
trade: ExchangeTransaction.fromJson(trades[i] as Map<String, dynamic>), trade: ExchangeTransaction.fromJson(trades[i] as Map<String, dynamic>),
shouldNotifyListeners: false, shouldNotifyListeners: false,
); );
} }
// only call notifyListeners on last one added // only call notifyListeners on last one added
if (trades.isNotEmpty) { if (trades.isNotEmpty) {
tradesService.add( await tradesService.add(
trade: trade:
ExchangeTransaction.fromJson(trades.last as Map<String, dynamic>), ExchangeTransaction.fromJson(trades.last as Map<String, dynamic>),
shouldNotifyListeners: true, shouldNotifyListeners: true,
@ -1177,7 +1239,7 @@ abstract class SWB {
} }
} }
tradeTxidLookupDataService.save(tradeWalletLookup: lookup); await tradeTxidLookupDataService.save(tradeWalletLookup: lookup);
} }
} }
@ -1186,7 +1248,8 @@ abstract class SWB {
) async { ) async {
final tradeNotesService = TradeNotesService(); final tradeNotesService = TradeNotesService();
for (final note in tradeNotes.entries) { for (final note in tradeNotes.entries) {
tradeNotesService.set(tradeId: note.key, note: note.value as String); await tradeNotesService.set(
tradeId: note.key, note: note.value as String);
} }
} }
} }

View file

@ -13,7 +13,7 @@ class StackFileSystem {
final bool isDesktop = !(Platform.isAndroid || Platform.isIOS); final bool isDesktop = !(Platform.isAndroid || Platform.isIOS);
Future<void> prepareStorage() async { Future<Directory> prepareStorage() async {
rootPath = (await getApplicationDocumentsDirectory()); rootPath = (await getApplicationDocumentsDirectory());
debugPrint(rootPath!.absolute.toString()); debugPrint(rootPath!.absolute.toString());
if (Platform.isAndroid) { if (Platform.isAndroid) {
@ -47,6 +47,7 @@ class StackFileSystem {
debugPrint("$e $s"); debugPrint("$e $s");
} }
startPath = sampleFolder; startPath = sampleFolder;
return sampleFolder;
} }
Future<void> pickDir(BuildContext context) async { Future<void> pickDir(BuildContext context) async {

View file

@ -99,29 +99,17 @@ class _RestoreFromFileViewState extends ConsumerState<RestoreFromFileView> {
onTap: () async { onTap: () async {
try { try {
await stackFileSystem.prepareStorage(); await stackFileSystem.prepareStorage();
// ref if (mounted) {
// .read(shouldShowLockscreenOnResumeStateProvider await stackFileSystem.openFile(context);
// .state) }
// .state = false;
await stackFileSystem.openFile(context);
// Future<void>.delayed( if (mounted) {
// const Duration(seconds: 2), setState(() {
// () => ref fileLocationController.text =
// .read( stackFileSystem.filePath ?? "";
// shouldShowLockscreenOnResumeStateProvider });
// .state) }
// .state = true,
// );
fileLocationController.text =
stackFileSystem.filePath ?? "";
setState(() {});
} catch (e, s) { } catch (e, s) {
// ref
// .read(shouldShowLockscreenOnResumeStateProvider
// .state)
// .state = true;
Logging.instance Logging.instance
.log("$e\n$s", level: LogLevel.Error); .log("$e\n$s", level: LogLevel.Error);
} }
@ -130,6 +118,7 @@ class _RestoreFromFileViewState extends ConsumerState<RestoreFromFileView> {
style: STextStyles.field(context), style: STextStyles.field(context),
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Choose file...", hintText: "Choose file...",
hintStyle: STextStyles.fieldLabel(context),
suffixIcon: UnconstrainedBox( suffixIcon: UnconstrainedBox(
child: Row( child: Row(
children: [ children: [

View file

@ -9,7 +9,12 @@ import 'package:stackwallet/services/coins/manager.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/loading_indicator.dart'; import 'package:stackwallet/widgets/loading_indicator.dart';
import 'package:stackwallet/widgets/trade_card.dart';
import 'package:stackwallet/widgets/transaction_card.dart'; import 'package:stackwallet/widgets/transaction_card.dart';
import 'package:tuple/tuple.dart';
import '../../../providers/global/trades_service_provider.dart';
import '../../exchange_view/trade_details_view.dart';
class TransactionsList extends ConsumerStatefulWidget { class TransactionsList extends ConsumerStatefulWidget {
const TransactionsList({ const TransactionsList({
@ -125,18 +130,67 @@ class _TransactionsListState extends ConsumerState<TransactionsList> {
radius = _borderRadiusFirst; radius = _borderRadiusFirst;
} }
final tx = list[index]; final tx = list[index];
return Container(
decoration: BoxDecoration( final matchingTrades = ref
color: Theme.of(context).extension<StackColors>()!.popupBG, .read(tradesServiceProvider)
borderRadius: radius, .trades
), .where((e) =>
child: TransactionCard( e.statusObject != null &&
// this may mess with combined firo transactions (e.statusObject!.payinHash == tx.txid ||
key: Key(tx.toString()), // e.statusObject!.payoutHash == tx.txid));
transaction: tx, if (tx.txType == "Sent" && matchingTrades.isNotEmpty) {
walletId: widget.walletId, final trade = matchingTrades.first;
), return Container(
); decoration: BoxDecoration(
color:
Theme.of(context).extension<StackColors>()!.popupBG,
borderRadius: radius,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TransactionCard(
// this may mess with combined firo transactions
key: Key(tx.toString()), //
transaction: tx,
walletId: widget.walletId,
),
TradeCard(
// this may mess with combined firo transactions
key: Key(tx.toString() + trade.uuid), //
trade: trade,
onTap: () {
unawaited(
Navigator.of(context).pushNamed(
TradeDetailsView.routeName,
arguments: Tuple4(
trade.id,
tx,
widget.walletId,
ref.read(managerProvider).walletName,
),
),
);
},
)
],
),
);
} else {
return Container(
decoration: BoxDecoration(
color:
Theme.of(context).extension<StackColors>()!.popupBG,
borderRadius: radius,
),
child: TransactionCard(
// this may mess with combined firo transactions
key: Key(tx.toString()), //
transaction: tx,
walletId: widget.walletId,
),
);
}
}, },
), ),
); );

View file

@ -96,7 +96,14 @@ class AddWalletButton extends StatelessWidget {
.extension<StackColors>()! .extension<StackColors>()!
.getPrimaryEnabledButtonColor(context), .getPrimaryEnabledButtonColor(context),
onPressed: () { onPressed: () {
Navigator.of(context).pushNamed(AddWalletView.routeName); if (isDesktop) {
Navigator.of(
context,
rootNavigator: true,
).pushNamed(AddWalletView.routeName);
} else {
Navigator.of(context).pushNamed(AddWalletView.routeName);
}
}, },
child: Center( child: Center(
child: Container( child: Container(

View file

@ -0,0 +1,20 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class SettingsView extends ConsumerStatefulWidget {
const SettingsView({Key? key}) : super(key: key);
static const String routeName = "/settingsView";
@override
ConsumerState<SettingsView> createState() => _SettingsView();
}
class _SettingsView extends ConsumerState<SettingsView> {
@override
Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType");
// TODO: implement build
throw UnimplementedError();
}
}

View file

@ -1,7 +1,9 @@
import 'package:decimal/decimal.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/models/contact_address_entry.dart'; import 'package:stackwallet/models/contact_address_entry.dart';
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart';
import 'package:stackwallet/models/exchange/incomplete_exchange.dart'; import 'package:stackwallet/models/exchange/incomplete_exchange.dart';
import 'package:stackwallet/models/paymint/transactions_model.dart'; import 'package:stackwallet/models/paymint/transactions_model.dart';
import 'package:stackwallet/models/send_view_auto_fill_data.dart'; import 'package:stackwallet/models/send_view_auto_fill_data.dart';
@ -20,12 +22,14 @@ import 'package:stackwallet/pages/address_book_views/subviews/address_book_filte
import 'package:stackwallet/pages/address_book_views/subviews/contact_details_view.dart'; import 'package:stackwallet/pages/address_book_views/subviews/contact_details_view.dart';
import 'package:stackwallet/pages/address_book_views/subviews/edit_contact_address_view.dart'; import 'package:stackwallet/pages/address_book_views/subviews/edit_contact_address_view.dart';
import 'package:stackwallet/pages/address_book_views/subviews/edit_contact_name_emoji_view.dart'; import 'package:stackwallet/pages/address_book_views/subviews/edit_contact_name_emoji_view.dart';
import 'package:stackwallet/pages/exchange_view/choose_from_stack_view.dart';
import 'package:stackwallet/pages/exchange_view/edit_trade_note_view.dart'; import 'package:stackwallet/pages/exchange_view/edit_trade_note_view.dart';
import 'package:stackwallet/pages/exchange_view/exchange_loading_overlay.dart'; import 'package:stackwallet/pages/exchange_view/exchange_loading_overlay.dart';
import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_1_view.dart'; import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_1_view.dart';
import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_2_view.dart'; import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_2_view.dart';
import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_3_view.dart'; import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_3_view.dart';
import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_4_view.dart'; import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_4_view.dart';
import 'package:stackwallet/pages/exchange_view/send_from_view.dart';
import 'package:stackwallet/pages/exchange_view/trade_details_view.dart'; import 'package:stackwallet/pages/exchange_view/trade_details_view.dart';
import 'package:stackwallet/pages/exchange_view/wallet_initiated_exchange_view.dart'; import 'package:stackwallet/pages/exchange_view/wallet_initiated_exchange_view.dart';
import 'package:stackwallet/pages/home_view/home_view.dart'; import 'package:stackwallet/pages/home_view/home_view.dart';
@ -879,6 +883,37 @@ class RouteGenerator {
} }
return _routeError("${settings.name} invalid args: ${args.toString()}"); return _routeError("${settings.name} invalid args: ${args.toString()}");
case ChooseFromStackView.routeName:
if (args is Coin) {
return getRoute(
shouldUseMaterialRoute: useMaterialPageRoute,
builder: (_) => ChooseFromStackView(
coin: args,
),
settings: RouteSettings(
name: settings.name,
),
);
}
return _routeError("${settings.name} invalid args: ${args.toString()}");
case SendFromView.routeName:
if (args is Tuple4<Coin, Decimal, String, ExchangeTransaction>) {
return getRoute(
shouldUseMaterialRoute: useMaterialPageRoute,
builder: (_) => SendFromView(
coin: args.item1,
amount: args.item2,
trade: args.item4,
address: args.item3,
),
settings: RouteSettings(
name: settings.name,
),
);
}
return _routeError("${settings.name} invalid args: ${args.toString()}");
// == Desktop specific routes ============================================ // == Desktop specific routes ============================================
case CreatePasswordView.routeName: case CreatePasswordView.routeName:
return getRoute( return getRoute(

View file

@ -259,6 +259,9 @@ Future<String> deleteEpicWallet({
if (Platform.isIOS) { if (Platform.isIOS) {
appDir = (await getLibraryDirectory()); appDir = (await getLibraryDirectory());
} }
if (Platform.isLinux) {
appDir = Directory("${appDir.path}/.stackwallet");
}
final path = "${appDir.path}/epiccash"; final path = "${appDir.path}/epiccash";
final String name = walletId; final String name = walletId;
@ -1232,6 +1235,9 @@ class EpicCashWallet extends CoinServiceAPI {
if (Platform.isIOS) { if (Platform.isIOS) {
appDir = (await getLibraryDirectory()); appDir = (await getLibraryDirectory());
} }
if (Platform.isLinux) {
appDir = Directory("${appDir.path}/.stackwallet");
}
final path = "${appDir.path}/epiccash"; final path = "${appDir.path}/epiccash";
final String name = _walletId.trim(); final String name = _walletId.trim();
return '$path/$name'; return '$path/$name';

View file

@ -910,6 +910,10 @@ class MoneroWallet extends CoinServiceAPI {
if (Platform.isIOS) { if (Platform.isIOS) {
root = (await getLibraryDirectory()); root = (await getLibraryDirectory());
} }
//
if (Platform.isLinux) {
root = Directory("${root.path}/.stackwallet");
}
final prefix = walletTypeToString(type).toLowerCase(); final prefix = walletTypeToString(type).toLowerCase();
final walletsDir = Directory('${root.path}/wallets'); final walletsDir = Directory('${root.path}/wallets');
final walletDire = Directory('${walletsDir.path}/$prefix/$name'); final walletDire = Directory('${walletsDir.path}/$prefix/$name');

View file

@ -2501,7 +2501,8 @@ class NamecoinWallet extends CoinServiceAPI {
int totalOutput = 0; int totalOutput = 0;
for (final output in txObject["vout"] as List) { for (final output in txObject["vout"] as List) {
final address = output["scriptPubKey"]["addresses"][0]; Logging.instance.log(output, level: LogLevel.Info);
final address = output["scriptPubKey"]["address"];
final value = output["value"]; final value = output["value"];
final _value = (Decimal.parse(value.toString()) * final _value = (Decimal.parse(value.toString()) *
Decimal.fromInt(Constants.satsPerCoin)) Decimal.fromInt(Constants.satsPerCoin))

View file

@ -913,6 +913,9 @@ class WowneroWallet extends CoinServiceAPI {
if (Platform.isIOS) { if (Platform.isIOS) {
root = (await getLibraryDirectory()); root = (await getLibraryDirectory());
} }
if (Platform.isLinux) {
root = Directory("${root.path}/.stackwallet");
}
final prefix = walletTypeToString(type).toLowerCase(); final prefix = walletTypeToString(type).toLowerCase();
final walletsDir = Directory('${root.path}/wallets'); final walletsDir = Directory('${root.path}/wallets');
final walletDire = Directory('${walletsDir.path}/$prefix/$name'); final walletDire = Directory('${walletsDir.path}/$prefix/$name');

View file

@ -75,7 +75,8 @@ class DebugService extends ChangeNotifier {
level: LogLevel.Info); level: LogLevel.Info);
} }
Future<void> exportToFile(String directory, EventBus eventBus) async { /// returns the filename of the saved logs file
Future<String> exportToFile(String directory, EventBus eventBus) async {
final now = DateTime.now(); final now = DateTime.now();
final filename = final filename =
"Stack_Wallet_logs_${now.year}_${now.month}_${now.day}_${now.hour}_${now.minute}_${now.second}.txt"; "Stack_Wallet_logs_${now.year}_${now.month}_${now.day}_${now.hour}_${now.minute}_${now.second}.txt";
@ -99,5 +100,6 @@ class DebugService extends ChangeNotifier {
await sink.close(); await sink.close();
eventBus.fire(1.0); eventBus.fire(1.0);
return filename;
} }
} }

View file

@ -51,7 +51,9 @@ class _SVG {
String txExchangeFailed(BuildContext context) => String txExchangeFailed(BuildContext context) =>
"assets/svg/${Theme.of(context).extension<StackColors>()!.themeType.name}/tx-exchange-icon-failed.svg"; "assets/svg/${Theme.of(context).extension<StackColors>()!.themeType.name}/tx-exchange-icon-failed.svg";
String get polygon => "assets/svg/Polygon.svg";
String get drd => "assets/svg/drd-icon.svg"; String get drd => "assets/svg/drd-icon.svg";
String get boxAuto => "assets/svg/box-auto.svg";
String get plus => "assets/svg/plus.svg"; String get plus => "assets/svg/plus.svg";
String get gear => "assets/svg/gear.svg"; String get gear => "assets/svg/gear.svg";
String get bell => "assets/svg/bell.svg"; String get bell => "assets/svg/bell.svg";

View file

@ -21,6 +21,8 @@ abstract class Constants {
static const int satsPerCoinWownero = 100000000000; static const int satsPerCoinWownero = 100000000000;
static const int satsPerCoin = 100000000; static const int satsPerCoin = 100000000;
static const int decimalPlaces = 8; static const int decimalPlaces = 8;
static const int decimalPlacesWownero = 11;
static const int decimalPlacesMonero = 12;
static const int notificationsMax = 0xFFFFFFFF; static const int notificationsMax = 0xFFFFFFFF;
static const Duration networkAliveTimerDuration = Duration(seconds: 10); static const Duration networkAliveTimerDuration = Duration(seconds: 10);

View file

@ -698,6 +698,25 @@ class STextStyles {
} }
} }
static TextStyle desktopTextExtraExtraSmall(BuildContext context) {
switch (_theme(context).themeType) {
case ThemeType.light:
return GoogleFonts.inter(
color: _theme(context).textSubtitle1,
fontWeight: FontWeight.w500,
fontSize: 14,
height: 21 / 14,
);
case ThemeType.dark:
return GoogleFonts.inter(
color: _theme(context).textSubtitle1,
fontWeight: FontWeight.w500,
fontSize: 14,
height: 21 / 14,
);
}
}
static TextStyle desktopButtonSmallSecondaryEnabled(BuildContext context) { static TextStyle desktopButtonSmallSecondaryEnabled(BuildContext context) {
switch (_theme(context).themeType) { switch (_theme(context).themeType) {
case ThemeType.light: case ThemeType.light:

View file

@ -137,6 +137,9 @@ install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_libmonero/scripts/linux/build/libcw_monero.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_libmonero/scripts/linux/build/libcw_monero.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime) COMPONENT Runtime)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_libmonero/scripts/linux/build/libcw_wownero.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_libepiccash/scripts/linux/build/rust/target/x86_64-unknown-linux-gnu/release/libepic_cash_wallet.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto_plugins/flutter_libepiccash/scripts/linux/build/rust/target/x86_64-unknown-linux-gnu/release/libepic_cash_wallet.so" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime) COMPONENT Runtime)

View file

@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig"

View file

@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "ephemeral/Flutter-Generated.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig"

40
macos/Podfile Normal file
View file

@ -0,0 +1,40 @@
platform :osx, '10.11'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\""
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_macos_podfile_setup
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_macos_build_settings(target)
end
end

View file

@ -11,7 +11,7 @@ description: Stack Wallet
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at # Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.4.52+68 version: 1.5.0+70
environment: environment:
sdk: ">=2.17.0 <3.0.0" sdk: ">=2.17.0 <3.0.0"
@ -289,6 +289,7 @@ flutter:
- assets/svg/tx-icon-anonymize.svg - assets/svg/tx-icon-anonymize.svg
- assets/svg/tx-icon-anonymize-pending.svg - assets/svg/tx-icon-anonymize-pending.svg
- assets/svg/tx-icon-anonymize-failed.svg - assets/svg/tx-icon-anonymize-failed.svg
- assets/svg/Polygon.svg
# coin icons # coin icons
- assets/svg/coin_icons/Bitcoin.svg - assets/svg/coin_icons/Bitcoin.svg
- assets/svg/coin_icons/Bitcoincash.svg - assets/svg/coin_icons/Bitcoincash.svg
@ -312,6 +313,7 @@ flutter:
- assets/svg/exchange-3.svg - assets/svg/exchange-3.svg
- assets/svg/message-question-1.svg - assets/svg/message-question-1.svg
- assets/svg/drd-icon.svg - assets/svg/drd-icon.svg
- assets/svg/box-auto.svg
# An image asset can refer to one or more resolution-specific "variants", see # An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware. # https://flutter.dev/assets-and-images/#resolution-aware.

6
scripts/prebuild.sh Normal file
View file

@ -0,0 +1,6 @@
# Create template lib/external_api_keys.dart file if it doesn't already exist
KEYS=../lib/external_api_keys.dart
if ! test -f "$KEYS"; then
echo 'prebuild.sh: creating template lib/external_api_keys.dart file'
echo 'const kChangeNowApiKey = "";' > $KEYS
fi

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff