mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-12-23 11:59:30 +00:00
Merge branch 'staging' into add-onchain-notes-for-epic
This commit is contained in:
commit
ebf67df3a9
17 changed files with 55 additions and 93 deletions
|
@ -29,13 +29,6 @@ Then in `File > Settings > Plugins`, install the **Flutter** and **Dart** plugin
|
||||||
|
|
||||||
Make a Pixel 4 (API 30) x86_64 emulator with 2GB of storage space for emulation
|
Make a Pixel 4 (API 30) x86_64 emulator with 2GB of storage space for emulation
|
||||||
|
|
||||||
### Scripted setup
|
|
||||||
|
|
||||||
[`scripts/setup.sh`](./../scripts/setup.sh) is provided as a tool to set up installation for building: download the script and run it anywhere. This script should skip the entire [Manual setup](#manual-setup) section below and prepare you to [run the prebuild script](#run-prebuild-script), [build the plugins](#Build-plugins), and [run](#Running).
|
|
||||||
|
|
||||||
### Manual setup
|
|
||||||
> If you used the `setup.sh` script, skip to [running](#Running)
|
|
||||||
|
|
||||||
Install basic dependencies
|
Install basic dependencies
|
||||||
```
|
```
|
||||||
sudo apt-get install libssl-dev curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake libgit2-dev clang libncurses5-dev libncursesw5-dev zlib1g-dev llvm python3-distutils
|
sudo apt-get install libssl-dev curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake libgit2-dev clang libncurses5-dev libncursesw5-dev zlib1g-dev llvm python3-distutils
|
||||||
|
|
|
@ -66,7 +66,7 @@ class MainDB {
|
||||||
|
|
||||||
// contact entries
|
// contact entries
|
||||||
List<ContactEntry> getContactEntries() {
|
List<ContactEntry> getContactEntries() {
|
||||||
return isar.contactEntrys.where().findAllSync();
|
return isar.contactEntrys.where().sortByName().findAllSync();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> deleteContactEntry({required String id}) {
|
Future<bool> deleteContactEntry({required String id}) {
|
||||||
|
|
|
@ -146,7 +146,7 @@ class ElectrumX {
|
||||||
throw response.exception!;
|
throw response.exception!;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.data["error"] != null) {
|
if (response.data is Map && response.data["error"] != null) {
|
||||||
if (response.data["error"]
|
if (response.data["error"]
|
||||||
.toString()
|
.toString()
|
||||||
.contains("No such mempool or blockchain transaction")) {
|
.contains("No such mempool or blockchain transaction")) {
|
||||||
|
|
|
@ -33,6 +33,22 @@ class ContactEntry {
|
||||||
@Index(unique: true, replace: true)
|
@Index(unique: true, replace: true)
|
||||||
late final String customId;
|
late final String customId;
|
||||||
|
|
||||||
|
@ignore
|
||||||
|
List<ContactAddressEntry> get addressesSorted {
|
||||||
|
final List<ContactAddressEntry> sorted = [];
|
||||||
|
for (final coin in Coin.values) {
|
||||||
|
final slice = addresses.where((e) => e.coin == coin).toList();
|
||||||
|
if (slice.isNotEmpty) {
|
||||||
|
slice.sort(
|
||||||
|
(a, b) => (a.other ?? a.label).compareTo(b.other ?? b.label),
|
||||||
|
);
|
||||||
|
sorted.addAll(slice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sorted;
|
||||||
|
}
|
||||||
|
|
||||||
ContactEntry copyWith({
|
ContactEntry copyWith({
|
||||||
bool shouldCopyEmojiWithNull = false,
|
bool shouldCopyEmojiWithNull = false,
|
||||||
String? emojiChar,
|
String? emojiChar,
|
||||||
|
|
|
@ -302,7 +302,7 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
...contacts
|
...contacts
|
||||||
.where((element) => element.addresses
|
.where((element) => element.addressesSorted
|
||||||
.where((e) => ref.watch(addressBookFilterProvider
|
.where((e) => ref.watch(addressBookFilterProvider
|
||||||
.select((value) => value.coins.contains(e.coin))))
|
.select((value) => value.coins.contains(e.coin))))
|
||||||
.isNotEmpty)
|
.isNotEmpty)
|
||||||
|
@ -350,7 +350,7 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
...contacts
|
...contacts
|
||||||
.where((element) => element.addresses
|
.where((element) => element.addressesSorted
|
||||||
.where((e) => ref.watch(
|
.where((e) => ref.watch(
|
||||||
addressBookFilterProvider.select((value) =>
|
addressBookFilterProvider.select((value) =>
|
||||||
value.coins.contains(e.coin))))
|
value.coins.contains(e.coin))))
|
||||||
|
|
|
@ -211,7 +211,8 @@ class _AddNewContactAddressViewState
|
||||||
const Duration(milliseconds: 75),
|
const Duration(milliseconds: 75),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
List<ContactAddressEntry> entries = contact.addresses;
|
List<ContactAddressEntry> entries =
|
||||||
|
contact.addresses.toList();
|
||||||
|
|
||||||
entries.add(ref
|
entries.add(ref
|
||||||
.read(addressEntryDataProvider(0))
|
.read(addressEntryDataProvider(0))
|
||||||
|
|
|
@ -341,7 +341,7 @@ class _ContactDetailsViewState extends ConsumerState<ContactDetailsView> {
|
||||||
padding: const EdgeInsets.all(0),
|
padding: const EdgeInsets.all(0),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
..._contact.addresses.map(
|
..._contact.addressesSorted.map(
|
||||||
(e) => Padding(
|
(e) => Padding(
|
||||||
padding: const EdgeInsets.all(12),
|
padding: const EdgeInsets.all(12),
|
||||||
child: Row(
|
child: Row(
|
||||||
|
|
|
@ -63,7 +63,7 @@ class ContactPopUp extends ConsumerWidget {
|
||||||
bool isExchangeFlow =
|
bool isExchangeFlow =
|
||||||
ref.watch(exchangeFlowIsActiveStateProvider.state).state;
|
ref.watch(exchangeFlowIsActiveStateProvider.state).state;
|
||||||
|
|
||||||
final addresses = contact.addresses.where((e) {
|
final addresses = contact.addressesSorted.where((e) {
|
||||||
if (hasActiveWallet && !isExchangeFlow) {
|
if (hasActiveWallet && !isExchangeFlow) {
|
||||||
return e.coin == active[0].coin;
|
return e.coin == active[0].coin;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -2127,6 +2127,7 @@ class _SendViewState extends ConsumerState<SendView> {
|
||||||
top: 16,
|
top: 16,
|
||||||
),
|
),
|
||||||
child: FeeSlider(
|
child: FeeSlider(
|
||||||
|
coin: coin,
|
||||||
onSatVByteChanged: (rate) {
|
onSatVByteChanged: (rate) {
|
||||||
customFeeRate = rate;
|
customFeeRate = rate;
|
||||||
},
|
},
|
||||||
|
|
|
@ -53,15 +53,6 @@ class DesktopContactDetails extends ConsumerStatefulWidget {
|
||||||
class _DesktopContactDetailsState extends ConsumerState<DesktopContactDetails> {
|
class _DesktopContactDetailsState extends ConsumerState<DesktopContactDetails> {
|
||||||
List<Tuple2<String, Transaction>> _cachedTransactions = [];
|
List<Tuple2<String, Transaction>> _cachedTransactions = [];
|
||||||
|
|
||||||
bool _contactHasAddress(String address, ContactEntry contact) {
|
|
||||||
for (final entry in contact.addresses) {
|
|
||||||
if (entry.address == address) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<List<Tuple2<String, Transaction>>> _filteredTransactionsByContact(
|
Future<List<Tuple2<String, Transaction>>> _filteredTransactionsByContact(
|
||||||
List<Manager> managers,
|
List<Manager> managers,
|
||||||
) async {
|
) async {
|
||||||
|
@ -259,7 +250,9 @@ class _DesktopContactDetailsState extends ConsumerState<DesktopContactDetails> {
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
for (int i = 0; i < contact.addresses.length; i++)
|
for (int i = 0;
|
||||||
|
i < contact.addressesSorted.length;
|
||||||
|
i++)
|
||||||
Column(
|
Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
|
@ -273,7 +266,7 @@ class _DesktopContactDetailsState extends ConsumerState<DesktopContactDetails> {
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(18),
|
padding: const EdgeInsets.all(18),
|
||||||
child: DesktopAddressCard(
|
child: DesktopAddressCard(
|
||||||
entry: contact.addresses[i],
|
entry: contact.addressesSorted[i],
|
||||||
contactId: contact.customId,
|
contactId: contact.customId,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -69,8 +69,8 @@ class _AddressBookAddressChooserState extends State<AddressBookAddressChooser> {
|
||||||
|
|
||||||
List<ContactEntry> filter(List<ContactEntry> contacts, String searchTerm) {
|
List<ContactEntry> filter(List<ContactEntry> contacts, String searchTerm) {
|
||||||
if (widget.coin != null) {
|
if (widget.coin != null) {
|
||||||
contacts.removeWhere(
|
contacts.removeWhere((e) =>
|
||||||
(e) => e.addresses.where((a) => a.coin == widget.coin!).isEmpty);
|
e.addressesSorted.where((a) => a.coin == widget.coin!).isEmpty);
|
||||||
}
|
}
|
||||||
|
|
||||||
contacts.retainWhere((e) => _matches(searchTerm, e));
|
contacts.retainWhere((e) => _matches(searchTerm, e));
|
||||||
|
|
|
@ -78,7 +78,7 @@ class _ContactListItemState extends ConsumerState<ContactListItem> {
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
// filter addresses by coin is provided before building address list
|
// filter addresses by coin is provided before building address list
|
||||||
...contact.addresses
|
...contact.addressesSorted
|
||||||
.where((e) =>
|
.where((e) =>
|
||||||
filterByCoin != null ? e.coin == filterByCoin! : true)
|
filterByCoin != null ? e.coin == filterByCoin! : true)
|
||||||
.map(
|
.map(
|
||||||
|
|
|
@ -1564,6 +1564,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
||||||
top: 16,
|
top: 16,
|
||||||
),
|
),
|
||||||
child: FeeSlider(
|
child: FeeSlider(
|
||||||
|
coin: coin,
|
||||||
onSatVByteChanged: (rate) {
|
onSatVByteChanged: (rate) {
|
||||||
customFeeRate = rate;
|
customFeeRate = rate;
|
||||||
},
|
},
|
||||||
|
|
|
@ -2665,7 +2665,10 @@ class DogecoinWallet extends CoinServiceAPI
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log("Starting buildTransaction ----------", level: LogLevel.Info);
|
.log("Starting buildTransaction ----------", level: LogLevel.Info);
|
||||||
|
|
||||||
final txb = TransactionBuilder(network: network);
|
final txb = TransactionBuilder(
|
||||||
|
network: network,
|
||||||
|
maximumFeeRate: 2500000, // 1000x default value in bitcoindart lib
|
||||||
|
);
|
||||||
txb.setVersion(1);
|
txb.setVersion(1);
|
||||||
|
|
||||||
// Add transaction inputs
|
// Add transaction inputs
|
||||||
|
|
|
@ -70,9 +70,10 @@ class _AddressBookCardState extends ConsumerState<AddressBookCard> {
|
||||||
final contact = _contact!;
|
final contact = _contact!;
|
||||||
|
|
||||||
final List<Coin> coins = [];
|
final List<Coin> coins = [];
|
||||||
for (var element in contact.addresses) {
|
|
||||||
if (!coins.contains(element.coin)) {
|
for (final coin in Coin.values) {
|
||||||
coins.add(element.coin);
|
if (contact.addresses.where((e) => e.coin == coin).isNotEmpty) {
|
||||||
|
coins.add(coin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
import 'package:stackwallet/utilities/text_styles.dart';
|
import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
|
|
||||||
class FeeSlider extends StatefulWidget {
|
class FeeSlider extends StatefulWidget {
|
||||||
const FeeSlider({
|
const FeeSlider({
|
||||||
super.key,
|
super.key,
|
||||||
required this.onSatVByteChanged,
|
required this.onSatVByteChanged,
|
||||||
|
required this.coin,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final Coin coin;
|
||||||
final void Function(int) onSatVByteChanged;
|
final void Function(int) onSatVByteChanged;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -16,12 +19,12 @@ class FeeSlider extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _FeeSliderState extends State<FeeSlider> {
|
class _FeeSliderState extends State<FeeSlider> {
|
||||||
static const int min = 1;
|
static const double min = 1;
|
||||||
static const int max = 4;
|
static const double max = 4;
|
||||||
|
|
||||||
double sliderValue = 0;
|
double sliderValue = 0;
|
||||||
|
|
||||||
int rate = min;
|
int rate = min.toInt();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -45,7 +48,14 @@ class _FeeSliderState extends State<FeeSlider> {
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
sliderValue = value;
|
sliderValue = value;
|
||||||
rate = pow(sliderValue * (max - min) + min, 4).toInt();
|
final number = pow(sliderValue * (max - min) + min, 4).toDouble();
|
||||||
|
switch (widget.coin) {
|
||||||
|
case Coin.dogecoin:
|
||||||
|
case Coin.dogecoinTestNet:
|
||||||
|
rate = (number * 1000).toInt();
|
||||||
|
default:
|
||||||
|
rate = number.toInt();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
widget.onSatVByteChanged(rate);
|
widget.onSatVByteChanged(rate);
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
export SCRIPTS=$(pwd)
|
|
||||||
|
|
||||||
sudo apt update && sudo apt upgrade -y && sudo apt dist-upgrade -y
|
|
||||||
mkdir "$HOME/development"
|
|
||||||
mkdir "$HOME/projects"
|
|
||||||
sudo apt install -y git build-essential curl
|
|
||||||
export DEVELOPMENT=$HOME/development
|
|
||||||
export PROJECTS=$HOME/projects
|
|
||||||
|
|
||||||
# setup flutter
|
|
||||||
sudo apt install -y unzip pkg-config clang cmake ninja-build libgtk-3-dev
|
|
||||||
cd $DEVELOPMENT
|
|
||||||
git clone https://github.com/flutter/flutter.git
|
|
||||||
cd flutter
|
|
||||||
git checkout 3.10.5
|
|
||||||
export FLUTTER_DIR=$(pwd)/bin
|
|
||||||
echo 'export PATH="$PATH:'${FLUTTER_DIR}'"' >> ~/.bashrc
|
|
||||||
source ~/.bashrc
|
|
||||||
flutter doctor
|
|
||||||
|
|
||||||
# install stack wallet dependencies
|
|
||||||
sudo apt-get install -y 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 -y debhelper libclang-dev cargo rustc opencl-headers libssl-dev ocl-icd-opencl-dev
|
|
||||||
|
|
||||||
sudo apt-get install -y unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake openjdk-8-jre-headless
|
|
||||||
|
|
||||||
sudo apt install -y libc6-dev-i386
|
|
||||||
|
|
||||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
|
|
||||||
source "$HOME/.cargo/env"
|
|
||||||
cargo install cargo-ndk
|
|
||||||
rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android
|
|
||||||
|
|
||||||
# # setup stack_wallet github
|
|
||||||
# cd $PROJECTS
|
|
||||||
# git clone https://github.com/cypherstack/stack_wallet.git
|
|
||||||
# cd stack_wallet
|
|
||||||
# export STACK_WALLET=$(pwd)
|
|
||||||
# git submodule update --init --recursive
|
|
||||||
|
|
||||||
# # create template lib/external_api_keys.dart file if it doesn't already exist
|
|
||||||
# KEYS="$HOME/projects/stack_wallet/lib/external_api_keys.dart"
|
|
||||||
# if ! test -f "$KEYS"; then
|
|
||||||
# echo 'prebuild.sh: creating template lib/external_api_keys.dart file'
|
|
||||||
# printf 'const kChangeNowApiKey = "";\nconst kSimpleSwapApiKey = "";' > $KEYS
|
|
||||||
# fi
|
|
||||||
|
|
||||||
# build stack wallet plugins
|
|
||||||
cd $SCRIPTS
|
|
||||||
./prebuild.sh
|
|
||||||
cd android
|
|
||||||
./build_all.sh
|
|
||||||
cd ../linux
|
|
||||||
./build_all.sh
|
|
Loading…
Reference in a new issue