mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-03-12 09:32:33 +00:00
Merge branch 'main' of https://github.com/cake-tech/cake_wallet into CW-78-Ethereum
Conflicts: lib/main.dart
This commit is contained in:
commit
ef7fde9de7
102 changed files with 3408 additions and 742 deletions
3
.github/workflows/pr_test_build.yml
vendored
3
.github/workflows/pr_test_build.yml
vendored
|
@ -113,6 +113,9 @@ jobs:
|
|||
echo "const twitterBearerToken = '${{ secrets.TWITTER_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
|
||||
echo "const trocadorApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const trocadorExchangeMarkup = '${{ secrets.TROCADOR_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
|
||||
echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> lib/.secrets.g.dart
|
||||
echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const payfuraApiKey = '${{ secrets.PAYFURA_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
|
||||
- name: Rename app
|
||||
run: echo -e "id=com.cakewallet.test\nname=$GITHUB_HEAD_REF" > /opt/android/cake_wallet/android/app.properties
|
||||
|
|
|
@ -13,9 +13,6 @@
|
|||
-
|
||||
uri: node.c3pool.com:18081
|
||||
is_default: false
|
||||
-
|
||||
uri: node.supportxmr.com:18081
|
||||
is_default: false
|
||||
-
|
||||
uri: node.community.rino.io:18081
|
||||
is_default: false
|
||||
|
|
|
@ -40,7 +40,7 @@ class ElectrumClient {
|
|||
unterminatedString = '';
|
||||
|
||||
static const connectionTimeout = Duration(seconds: 5);
|
||||
static const aliveTimerDuration = Duration(seconds: 2);
|
||||
static const aliveTimerDuration = Duration(seconds: 4);
|
||||
|
||||
bool get isConnected => _isConnected;
|
||||
Socket? socket;
|
||||
|
@ -358,7 +358,7 @@ class ElectrumClient {
|
|||
Future<dynamic> callWithTimeout(
|
||||
{required String method,
|
||||
List<Object> params = const [],
|
||||
int timeout = 2000}) async {
|
||||
int timeout = 4000}) async {
|
||||
try {
|
||||
final completer = Completer<dynamic>();
|
||||
_id += 1;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:cw_core/currency.dart';
|
||||
import 'package:cw_core/enumerable_item.dart';
|
||||
|
||||
class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
|
||||
class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implements Currency {
|
||||
const CryptoCurrency({
|
||||
String title = '',
|
||||
int raw = -1,
|
||||
|
@ -162,6 +163,14 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
|
|||
return acc;
|
||||
});
|
||||
|
||||
static final Map<String, CryptoCurrency> _fullNameCurrencyMap =
|
||||
[...all, ...havenCurrencies].fold<Map<String, CryptoCurrency>>(<String, CryptoCurrency>{}, (acc, item) {
|
||||
if(item.fullName != null){
|
||||
acc.addAll({item.fullName!.toLowerCase(): item});
|
||||
}
|
||||
return acc;
|
||||
});
|
||||
|
||||
static CryptoCurrency deserialize({required int raw}) {
|
||||
|
||||
if (CryptoCurrency._rawCurrencyMap[raw] == null) {
|
||||
|
@ -180,6 +189,16 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
|
|||
return CryptoCurrency._nameCurrencyMap[name.toLowerCase()]!;
|
||||
}
|
||||
|
||||
static CryptoCurrency fromFullName(String name) {
|
||||
|
||||
if (CryptoCurrency._fullNameCurrencyMap[name.toLowerCase()] == null) {
|
||||
final s = 'Unexpected token: $name for CryptoCurrency fromFullName';
|
||||
throw ArgumentError.value(name, 'Fullname', s);
|
||||
}
|
||||
return CryptoCurrency._fullNameCurrencyMap[name.toLowerCase()]!;
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
String toString() => title;
|
||||
}
|
||||
|
|
6
cw_core/lib/currency.dart
Normal file
6
cw_core/lib/currency.dart
Normal file
|
@ -0,0 +1,6 @@
|
|||
abstract class Currency {
|
||||
String get name;
|
||||
String? get tag;
|
||||
String? get fullName;
|
||||
String? get iconPath;
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
import 'package:intl/intl.dart';
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
// FIXME: Hardcoded values; Works only for monero
|
||||
|
||||
|
@ -93,7 +95,7 @@ int getMoneroHeigthByDate({required DateTime date}) {
|
|||
int height = 0;
|
||||
|
||||
try {
|
||||
if ((dates[raw] == null)||(dates[raw] == lastHeight)) {
|
||||
if ((dates[raw] == null) || (dates[raw] == lastHeight)) {
|
||||
startHeight = dates.values.toList()[dates.length - 2];
|
||||
endHeight = dates.values.toList()[dates.length - 1];
|
||||
final heightPerDay = (endHeight - startHeight) / 31;
|
||||
|
@ -118,3 +120,86 @@ int getMoneroHeigthByDate({required DateTime date}) {
|
|||
|
||||
return height;
|
||||
}
|
||||
|
||||
const havenDates = {
|
||||
"2023-03": 1309180,
|
||||
"2023-01": 1266810,
|
||||
"2022-12": 1244510,
|
||||
"2022-11": 1222970,
|
||||
"2022-10": 1200700,
|
||||
"2022-09": 1179140,
|
||||
"2022-08": 1156870,
|
||||
"2022-07": 1134600,
|
||||
"2022-06": 1113030,
|
||||
"2022-05": 1090800,
|
||||
"2022-04": 1069250,
|
||||
"2022-03": 1047000,
|
||||
"2022-02": 1026960,
|
||||
"2022-01": 1004700,
|
||||
"2021-12": 982400,
|
||||
"2021-11": 961000,
|
||||
"2021-10": 938600,
|
||||
"2021-09": 917000,
|
||||
"2021-08": 894800,
|
||||
"2021-07": 886000,
|
||||
"2021-06": 867300,
|
||||
"2021-05": 845000,
|
||||
"2021-04": 823500,
|
||||
"2021-03": 801500,
|
||||
"2021-02": 781000,
|
||||
"2021-01": 759000,
|
||||
"2020-12": 736500,
|
||||
"2020-11": 715000,
|
||||
"2020-10": 693000,
|
||||
"2020-09": 671000,
|
||||
"2020-08": 649000,
|
||||
"2020-07": 626600,
|
||||
"2020-06": 605000,
|
||||
"2020-05": 582700,
|
||||
"2020-04": 561100,
|
||||
"2020-03": 539000,
|
||||
"2020-02": 518000,
|
||||
"2020-01": 496000,
|
||||
"2019-12": 473400,
|
||||
"2019-11": 451900,
|
||||
"2019-10": 429600,
|
||||
"2019-09": 408000,
|
||||
"2019-08": 385700,
|
||||
"2019-07": 363800,
|
||||
"2019-06": 342200,
|
||||
"2019-05": 320000,
|
||||
"2019-04": 298400,
|
||||
"2019-03": 276000,
|
||||
"2019-02": 256000,
|
||||
"2019-01": 233700,
|
||||
"2018-12": 211400,
|
||||
"2018-11": 189800,
|
||||
"2018-10": 167500,
|
||||
"2018-09": 145900,
|
||||
"2018-08": 123700,
|
||||
"2018-07": 101400,
|
||||
"2018-06": 80000,
|
||||
"2018-05": 57550,
|
||||
"2018-04": 32000,
|
||||
"2018-03": 8500
|
||||
};
|
||||
|
||||
DateTime formatMapKey(String key) => dateFormat.parse(key);
|
||||
|
||||
int getHavenHeightByDate({required DateTime date}) {
|
||||
String closestKey =
|
||||
havenDates.keys.firstWhere((key) => formatMapKey(key).isBefore(date), orElse: () => '');
|
||||
|
||||
return havenDates[closestKey] ?? 0;
|
||||
}
|
||||
|
||||
Future<int> getHavenCurrentHeight() async {
|
||||
final response = await http.get(Uri.parse('https://explorer.havenprotocol.org/api/networkinfo'));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final info = jsonDecode(response.body);
|
||||
return info['data']['height'] as int;
|
||||
} else {
|
||||
throw Exception('Failed to load current blockchain height');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ PODS:
|
|||
- connectivity (0.0.1):
|
||||
- Flutter
|
||||
- Reachability
|
||||
- CryptoSwift (1.3.2)
|
||||
- CryptoSwift (1.6.0)
|
||||
- cw_haven (0.0.1):
|
||||
- cw_haven/Boost (= 0.0.1)
|
||||
- cw_haven/Haven (= 0.0.1)
|
||||
|
@ -65,16 +65,18 @@ PODS:
|
|||
- Flutter
|
||||
- device_info (0.0.1):
|
||||
- Flutter
|
||||
- device_info_plus (0.0.1):
|
||||
- Flutter
|
||||
- devicelocale (0.0.1):
|
||||
- Flutter
|
||||
- DKImagePickerController/Core (4.3.2):
|
||||
- DKImagePickerController/Core (4.3.4):
|
||||
- DKImagePickerController/ImageDataManager
|
||||
- DKImagePickerController/Resource
|
||||
- DKImagePickerController/ImageDataManager (4.3.2)
|
||||
- DKImagePickerController/PhotoGallery (4.3.2):
|
||||
- DKImagePickerController/ImageDataManager (4.3.4)
|
||||
- DKImagePickerController/PhotoGallery (4.3.4):
|
||||
- DKImagePickerController/Core
|
||||
- DKPhotoGallery
|
||||
- DKImagePickerController/Resource (4.3.2)
|
||||
- DKImagePickerController/Resource (4.3.4)
|
||||
- DKPhotoGallery (0.0.17):
|
||||
- DKPhotoGallery/Core (= 0.0.17)
|
||||
- DKPhotoGallery/Model (= 0.0.17)
|
||||
|
@ -102,29 +104,41 @@ PODS:
|
|||
- DKImagePickerController/PhotoGallery
|
||||
- Flutter
|
||||
- Flutter (1.0.0)
|
||||
- flutter_inappwebview (0.0.1):
|
||||
- Flutter
|
||||
- flutter_inappwebview/Core (= 0.0.1)
|
||||
- OrderedSet (~> 5.0)
|
||||
- flutter_inappwebview/Core (0.0.1):
|
||||
- Flutter
|
||||
- OrderedSet (~> 5.0)
|
||||
- flutter_mailer (0.0.1):
|
||||
- Flutter
|
||||
- flutter_secure_storage (3.3.1):
|
||||
- Flutter
|
||||
- local_auth_ios (0.0.1):
|
||||
- Flutter
|
||||
- MTBBarcodeScanner (5.0.11)
|
||||
- OrderedSet (5.0.0)
|
||||
- package_info (0.0.1):
|
||||
- Flutter
|
||||
- path_provider_ios (0.0.1):
|
||||
- path_provider_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- permission_handler_apple (9.0.4):
|
||||
- Flutter
|
||||
- platform_device_id (0.0.1):
|
||||
- Flutter
|
||||
- Reachability (3.2)
|
||||
- SDWebImage (5.9.1):
|
||||
- SDWebImage/Core (= 5.9.1)
|
||||
- SDWebImage/Core (5.9.1)
|
||||
- SDWebImage (5.15.5):
|
||||
- SDWebImage/Core (= 5.15.5)
|
||||
- SDWebImage/Core (5.15.5)
|
||||
- share_plus (0.0.1):
|
||||
- Flutter
|
||||
- shared_preferences_ios (0.0.1):
|
||||
- shared_preferences_foundation (0.0.1):
|
||||
- Flutter
|
||||
- SwiftProtobuf (1.18.0)
|
||||
- SwiftyGif (5.3.0)
|
||||
- FlutterMacOS
|
||||
- SwiftProtobuf (1.21.0)
|
||||
- SwiftyGif (5.4.4)
|
||||
- uni_links (0.0.1):
|
||||
- Flutter
|
||||
- UnstoppableDomainsResolution (4.0.0):
|
||||
|
@ -132,8 +146,6 @@ PODS:
|
|||
- CryptoSwift
|
||||
- url_launcher_ios (0.0.1):
|
||||
- Flutter
|
||||
- webview_flutter_wkwebview (0.0.1):
|
||||
- Flutter
|
||||
|
||||
DEPENDENCIES:
|
||||
- barcode_scan2 (from `.symlinks/plugins/barcode_scan2/ios`)
|
||||
|
@ -144,21 +156,23 @@ DEPENDENCIES:
|
|||
- cw_shared_external (from `.symlinks/plugins/cw_shared_external/ios`)
|
||||
- device_display_brightness (from `.symlinks/plugins/device_display_brightness/ios`)
|
||||
- device_info (from `.symlinks/plugins/device_info/ios`)
|
||||
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||
- devicelocale (from `.symlinks/plugins/devicelocale/ios`)
|
||||
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||
- Flutter (from `Flutter`)
|
||||
- flutter_inappwebview (from `.symlinks/plugins/flutter_inappwebview/ios`)
|
||||
- flutter_mailer (from `.symlinks/plugins/flutter_mailer/ios`)
|
||||
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
|
||||
- local_auth_ios (from `.symlinks/plugins/local_auth_ios/ios`)
|
||||
- package_info (from `.symlinks/plugins/package_info/ios`)
|
||||
- path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
|
||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`)
|
||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||
- platform_device_id (from `.symlinks/plugins/platform_device_id/ios`)
|
||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||
- shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`)
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/ios`)
|
||||
- uni_links (from `.symlinks/plugins/uni_links/ios`)
|
||||
- UnstoppableDomainsResolution (~> 4.0.0)
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
- webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`)
|
||||
|
||||
SPEC REPOS:
|
||||
https://github.com/CocoaPods/Specs.git:
|
||||
|
@ -167,6 +181,7 @@ SPEC REPOS:
|
|||
- DKImagePickerController
|
||||
- DKPhotoGallery
|
||||
- MTBBarcodeScanner
|
||||
- OrderedSet
|
||||
- Reachability
|
||||
- SDWebImage
|
||||
- SwiftProtobuf
|
||||
|
@ -188,67 +203,74 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/device_display_brightness/ios"
|
||||
device_info:
|
||||
:path: ".symlinks/plugins/device_info/ios"
|
||||
device_info_plus:
|
||||
:path: ".symlinks/plugins/device_info_plus/ios"
|
||||
devicelocale:
|
||||
:path: ".symlinks/plugins/devicelocale/ios"
|
||||
file_picker:
|
||||
:path: ".symlinks/plugins/file_picker/ios"
|
||||
Flutter:
|
||||
:path: Flutter
|
||||
flutter_inappwebview:
|
||||
:path: ".symlinks/plugins/flutter_inappwebview/ios"
|
||||
flutter_mailer:
|
||||
:path: ".symlinks/plugins/flutter_mailer/ios"
|
||||
flutter_secure_storage:
|
||||
:path: ".symlinks/plugins/flutter_secure_storage/ios"
|
||||
local_auth_ios:
|
||||
:path: ".symlinks/plugins/local_auth_ios/ios"
|
||||
package_info:
|
||||
:path: ".symlinks/plugins/package_info/ios"
|
||||
path_provider_ios:
|
||||
:path: ".symlinks/plugins/path_provider_ios/ios"
|
||||
path_provider_foundation:
|
||||
:path: ".symlinks/plugins/path_provider_foundation/ios"
|
||||
permission_handler_apple:
|
||||
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
||||
platform_device_id:
|
||||
:path: ".symlinks/plugins/platform_device_id/ios"
|
||||
share_plus:
|
||||
:path: ".symlinks/plugins/share_plus/ios"
|
||||
shared_preferences_ios:
|
||||
:path: ".symlinks/plugins/shared_preferences_ios/ios"
|
||||
shared_preferences_foundation:
|
||||
:path: ".symlinks/plugins/shared_preferences_foundation/ios"
|
||||
uni_links:
|
||||
:path: ".symlinks/plugins/uni_links/ios"
|
||||
url_launcher_ios:
|
||||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||
webview_flutter_wkwebview:
|
||||
:path: ".symlinks/plugins/webview_flutter_wkwebview/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
barcode_scan2: 0af2bb63c81b4565aab6cd78278e4c0fa136dbb0
|
||||
BigInt: f668a80089607f521586bbe29513d708491ef2f7
|
||||
connectivity: c4130b2985d4ef6fd26f9702e886bd5260681467
|
||||
CryptoSwift: 093499be1a94b0cae36e6c26b70870668cb56060
|
||||
CryptoSwift: 562f8eceb40e80796fffc668b0cad9313284cfa6
|
||||
cw_haven: b3e54e1fbe7b8e6fda57a93206bc38f8e89b898a
|
||||
cw_monero: 4cf3b96f2da8e95e2ef7d6703dd4d2c509127b7d
|
||||
cw_shared_external: 2972d872b8917603478117c9957dfca611845a92
|
||||
device_display_brightness: 1510e72c567a1f6ce6ffe393dcd9afd1426034f7
|
||||
device_info: d7d233b645a32c40dfdc212de5cf646ca482f175
|
||||
device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed
|
||||
devicelocale: b22617f40038496deffba44747101255cee005b0
|
||||
DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d
|
||||
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
|
||||
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
|
||||
file_picker: 817ab1d8cd2da9d2da412a417162deee3500fc95
|
||||
file_picker: ce3938a0df3cc1ef404671531facef740d03f920
|
||||
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
|
||||
flutter_inappwebview: bfd58618f49dc62f2676de690fc6dcda1d6c3721
|
||||
flutter_mailer: 2ef5a67087bc8c6c4cefd04a178bf1ae2c94cd83
|
||||
flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec
|
||||
local_auth_ios: 0d333dde7780f669e66f19d2ff6005f3ea84008d
|
||||
local_auth_ios: c6cf091ded637a88f24f86a8875d8b0f526e2605
|
||||
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
|
||||
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
|
||||
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
|
||||
path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02
|
||||
path_provider_foundation: c68054786f1b4f3343858c1e1d0caaded73f0be9
|
||||
permission_handler_apple: 44366e37eaf29454a1e7b1b7d736c2cceaeb17ce
|
||||
platform_device_id: 81b3e2993881f87d0c82ef151dc274df4869aef5
|
||||
Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
|
||||
SDWebImage: a990c053fff71e388a10f3357edb0be17929c9c5
|
||||
SDWebImage: fd7e1a22f00303e058058278639bf6196ee431fe
|
||||
share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
|
||||
shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad
|
||||
SwiftProtobuf: c3c12645230d9b09c72267e0de89468c5543bd86
|
||||
SwiftyGif: e466e86c660d343357ab944a819a101c4127cb40
|
||||
shared_preferences_foundation: 986fc17f3d3251412d18b0265f9c64113a8c2472
|
||||
SwiftProtobuf: afced68785854575756db965e9da52bbf3dc45e7
|
||||
SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f
|
||||
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
|
||||
UnstoppableDomainsResolution: c3c67f4d0a5e2437cb00d4bd50c2e00d6e743841
|
||||
url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de
|
||||
webview_flutter_wkwebview: b7e70ef1ddded7e69c796c7390ee74180182971f
|
||||
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
|
||||
|
||||
PODFILE CHECKSUM: ae71bdf0eb731a1ffc399c122f6aa4dea0cb5f6f
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 51;
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
|
@ -228,6 +228,7 @@
|
|||
};
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
|
@ -242,6 +243,7 @@
|
|||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
|
|
211
lib/anonpay/anonpay_api.dart
Normal file
211
lib/anonpay/anonpay_api.dart
Normal file
|
@ -0,0 +1,211 @@
|
|||
import 'dart:convert';
|
||||
import 'package:cake_wallet/anonpay/anonpay_donation_link_info.dart';
|
||||
import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
|
||||
import 'package:cake_wallet/anonpay/anonpay_request.dart';
|
||||
import 'package:cake_wallet/anonpay/anonpay_status_response.dart';
|
||||
import 'package:cake_wallet/core/fiat_conversion_service.dart';
|
||||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||
import 'package:cake_wallet/exchange/limits.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
|
||||
class AnonPayApi {
|
||||
const AnonPayApi({
|
||||
this.useTorOnly = false,
|
||||
required this.wallet,
|
||||
});
|
||||
final bool useTorOnly;
|
||||
final WalletBase wallet;
|
||||
|
||||
static const anonpayRef = secrets.anonPayReferralCode;
|
||||
static const onionApiAuthority = 'trocadorfyhlu27aefre5u7zri66gudtzdyelymftvr4yjwcxhfaqsid.onion';
|
||||
static const clearNetAuthority = 'trocador.app';
|
||||
static const markup = secrets.trocadorExchangeMarkup;
|
||||
static const anonPayPath = '/anonpay';
|
||||
static const anonPayStatus = '/anonpay/status';
|
||||
static const coinPath = 'api/coin';
|
||||
static const apiKey = secrets.trocadorApiKey;
|
||||
|
||||
Future<AnonpayStatusResponse> paymentStatus(String id) async {
|
||||
final authority = await _getAuthority();
|
||||
final response = await get(Uri.https(authority, "$anonPayStatus/$id"));
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final status = responseJSON['Status'] as String;
|
||||
final fiatAmount = responseJSON['Fiat_Amount'] as double?;
|
||||
final fiatEquiv = responseJSON['Fiat_Equiv'] as String?;
|
||||
final amountTo = responseJSON['AmountTo'] as double?;
|
||||
final coinTo = responseJSON['CoinTo'] as String;
|
||||
final address = responseJSON['Address'] as String;
|
||||
|
||||
return AnonpayStatusResponse(
|
||||
status: status,
|
||||
fiatAmount: fiatAmount,
|
||||
amountTo: amountTo,
|
||||
coinTo: coinTo,
|
||||
address: address,
|
||||
fiatEquiv: fiatEquiv,
|
||||
);
|
||||
}
|
||||
|
||||
Future<AnonpayInvoiceInfo> createInvoice(AnonPayRequest request) async {
|
||||
final description = Uri.encodeComponent(request.description);
|
||||
final body = <String, dynamic>{
|
||||
'ticker_to': request.cryptoCurrency.title.toLowerCase(),
|
||||
'network_to': _networkFor(request.cryptoCurrency),
|
||||
'address': request.address,
|
||||
'name': request.name,
|
||||
'description': description,
|
||||
'email': request.email,
|
||||
'ref': anonpayRef,
|
||||
'markup': markup,
|
||||
'direct': 'False',
|
||||
};
|
||||
|
||||
if (request.amount != null) {
|
||||
body['amount'] = request.amount;
|
||||
}
|
||||
if (request.fiatEquivalent != null) {
|
||||
body['fiat_equiv'] = request.fiatEquivalent;
|
||||
}
|
||||
final authority = await _getAuthority();
|
||||
|
||||
final response = await get(Uri.https(authority, anonPayPath, body));
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final id = responseJSON['ID'] as String;
|
||||
final url = responseJSON['url'] as String;
|
||||
final urlOnion = responseJSON['url_onion'] as String;
|
||||
final statusUrl = responseJSON['status_url'] as String;
|
||||
final statusUrlOnion = responseJSON['status_url_onion'] as String;
|
||||
|
||||
final statusInfo = await paymentStatus(id);
|
||||
|
||||
return AnonpayInvoiceInfo(
|
||||
invoiceId: id,
|
||||
clearnetUrl: url,
|
||||
onionUrl: urlOnion,
|
||||
status: statusInfo.status,
|
||||
fiatAmount: statusInfo.fiatAmount,
|
||||
fiatEquiv: statusInfo.fiatEquiv,
|
||||
amountTo: statusInfo.amountTo,
|
||||
coinTo: statusInfo.coinTo,
|
||||
address: statusInfo.address,
|
||||
clearnetStatusUrl: statusUrl,
|
||||
onionStatusUrl: statusUrlOnion,
|
||||
walletId: wallet.id,
|
||||
createdAt: DateTime.now(),
|
||||
provider: 'Trocador AnonPay invoice',
|
||||
);
|
||||
}
|
||||
|
||||
Future<AnonpayDonationLinkInfo> generateDonationLink(AnonPayRequest request) async {
|
||||
final body = <String, dynamic>{
|
||||
'ticker_to': request.cryptoCurrency.title.toLowerCase(),
|
||||
'network_to': _networkFor(request.cryptoCurrency),
|
||||
'address': request.address,
|
||||
'ref': anonpayRef,
|
||||
'direct': 'True',
|
||||
};
|
||||
if (request.name.isNotEmpty) {
|
||||
body['name'] = request.name;
|
||||
}
|
||||
if (request.description.isNotEmpty) {
|
||||
body['description'] = request.description;
|
||||
}
|
||||
if (request.email.isNotEmpty) {
|
||||
body['email'] = request.email;
|
||||
}
|
||||
|
||||
final clearnetUrl = Uri.https(clearNetAuthority, anonPayPath, body);
|
||||
final onionUrl = Uri.https(onionApiAuthority, anonPayPath, body);
|
||||
return AnonpayDonationLinkInfo(
|
||||
clearnetUrl: clearnetUrl.toString(),
|
||||
onionUrl: onionUrl.toString(),
|
||||
address: request.address,
|
||||
);
|
||||
}
|
||||
|
||||
Future<Limits> fetchLimits({
|
||||
FiatCurrency? fiatCurrency,
|
||||
required CryptoCurrency cryptoCurrency,
|
||||
}) async {
|
||||
double fiatRate = 0.0;
|
||||
if (fiatCurrency != null) {
|
||||
fiatRate = await FiatConversionService.fetchPrice(
|
||||
crypto: cryptoCurrency,
|
||||
fiat: fiatCurrency,
|
||||
torOnly: useTorOnly,
|
||||
);
|
||||
}
|
||||
|
||||
final params = <String, String>{
|
||||
'api_key': apiKey,
|
||||
'ticker': cryptoCurrency.title.toLowerCase(),
|
||||
'name': cryptoCurrency.name,
|
||||
};
|
||||
|
||||
final String apiAuthority = await _getAuthority();
|
||||
final uri = Uri.https(apiAuthority, coinPath, params);
|
||||
|
||||
final response = await get(uri);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as List<dynamic>;
|
||||
|
||||
if (responseJSON.isEmpty) {
|
||||
throw Exception('No data');
|
||||
}
|
||||
|
||||
final coinJson = responseJSON.first as Map<String, dynamic>;
|
||||
final minimum = coinJson['minimum'] as double;
|
||||
final maximum = coinJson['maximum'] as double;
|
||||
|
||||
if (fiatCurrency != null) {
|
||||
return Limits(
|
||||
min: double.tryParse((minimum * fiatRate).toStringAsFixed(2)),
|
||||
max: double.tryParse((maximum * fiatRate).toStringAsFixed(2)),
|
||||
);
|
||||
}
|
||||
|
||||
return Limits(
|
||||
min: minimum,
|
||||
max: maximum,
|
||||
);
|
||||
}
|
||||
|
||||
String _networkFor(CryptoCurrency currency) {
|
||||
switch (currency) {
|
||||
case CryptoCurrency.usdt:
|
||||
return CryptoCurrency.btc.title.toLowerCase();
|
||||
default:
|
||||
return currency.tag != null ? _normalizeTag(currency.tag!) : 'Mainnet';
|
||||
}
|
||||
}
|
||||
|
||||
String _normalizeTag(String tag) {
|
||||
switch (tag) {
|
||||
case 'ETH':
|
||||
return 'ERC20';
|
||||
default:
|
||||
return tag.toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> _getAuthority() async {
|
||||
try {
|
||||
if (useTorOnly) {
|
||||
return onionApiAuthority;
|
||||
}
|
||||
final uri = Uri.https(onionApiAuthority, '/anonpay');
|
||||
await get(uri);
|
||||
return onionApiAuthority;
|
||||
} catch (e) {
|
||||
return clearNetAuthority;
|
||||
}
|
||||
}
|
||||
}
|
13
lib/anonpay/anonpay_donation_link_info.dart
Normal file
13
lib/anonpay/anonpay_donation_link_info.dart
Normal file
|
@ -0,0 +1,13 @@
|
|||
import 'package:cake_wallet/anonpay/anonpay_info_base.dart';
|
||||
|
||||
class AnonpayDonationLinkInfo implements AnonpayInfoBase{
|
||||
final String clearnetUrl;
|
||||
final String onionUrl;
|
||||
final String address;
|
||||
|
||||
AnonpayDonationLinkInfo({
|
||||
required this.clearnetUrl,
|
||||
required this.onionUrl,
|
||||
required this.address,
|
||||
});
|
||||
}
|
5
lib/anonpay/anonpay_info_base.dart
Normal file
5
lib/anonpay/anonpay_info_base.dart
Normal file
|
@ -0,0 +1,5 @@
|
|||
abstract class AnonpayInfoBase {
|
||||
String get clearnetUrl;
|
||||
String get onionUrl;
|
||||
String get address;
|
||||
}
|
57
lib/anonpay/anonpay_invoice_info.dart
Normal file
57
lib/anonpay/anonpay_invoice_info.dart
Normal file
|
@ -0,0 +1,57 @@
|
|||
import 'package:cake_wallet/anonpay/anonpay_info_base.dart';
|
||||
import 'package:cw_core/keyable.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
|
||||
part 'anonpay_invoice_info.g.dart';
|
||||
|
||||
@HiveType(typeId: AnonpayInvoiceInfo.typeId)
|
||||
class AnonpayInvoiceInfo extends HiveObject with Keyable implements AnonpayInfoBase {
|
||||
@HiveField(0)
|
||||
final String invoiceId;
|
||||
@HiveField(1)
|
||||
String status;
|
||||
@HiveField(2)
|
||||
final double? fiatAmount;
|
||||
@HiveField(3)
|
||||
final String? fiatEquiv;
|
||||
@HiveField(4)
|
||||
final double? amountTo;
|
||||
@HiveField(5)
|
||||
final String coinTo;
|
||||
@HiveField(6)
|
||||
final String address;
|
||||
@HiveField(7)
|
||||
final String clearnetUrl;
|
||||
@HiveField(8)
|
||||
final String onionUrl;
|
||||
@HiveField(9)
|
||||
final String clearnetStatusUrl;
|
||||
@HiveField(10)
|
||||
final String onionStatusUrl;
|
||||
@HiveField(11)
|
||||
final DateTime createdAt;
|
||||
@HiveField(12)
|
||||
final String walletId;
|
||||
@HiveField(13)
|
||||
final String provider;
|
||||
|
||||
static const typeId = 10;
|
||||
static const boxName = 'AnonpayInvoiceInfo';
|
||||
|
||||
AnonpayInvoiceInfo({
|
||||
required this.invoiceId,
|
||||
required this.clearnetUrl,
|
||||
required this.onionUrl,
|
||||
required this.clearnetStatusUrl,
|
||||
required this.onionStatusUrl,
|
||||
required this.status,
|
||||
this.fiatAmount,
|
||||
this.fiatEquiv,
|
||||
this.amountTo,
|
||||
required this.coinTo,
|
||||
required this.address,
|
||||
required this.createdAt,
|
||||
required this.walletId,
|
||||
required this.provider,
|
||||
});
|
||||
}
|
21
lib/anonpay/anonpay_request.dart
Normal file
21
lib/anonpay/anonpay_request.dart
Normal file
|
@ -0,0 +1,21 @@
|
|||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
||||
class AnonPayRequest {
|
||||
CryptoCurrency cryptoCurrency;
|
||||
String address;
|
||||
String name;
|
||||
String? amount;
|
||||
String email;
|
||||
String description;
|
||||
String? fiatEquivalent;
|
||||
|
||||
AnonPayRequest({
|
||||
required this.cryptoCurrency,
|
||||
required this.address,
|
||||
required this.name,
|
||||
required this.email,
|
||||
this.amount,
|
||||
required this.description,
|
||||
this.fiatEquivalent,
|
||||
});
|
||||
}
|
17
lib/anonpay/anonpay_status_response.dart
Normal file
17
lib/anonpay/anonpay_status_response.dart
Normal file
|
@ -0,0 +1,17 @@
|
|||
class AnonpayStatusResponse {
|
||||
final String status;
|
||||
final double? fiatAmount;
|
||||
final String? fiatEquiv;
|
||||
final double? amountTo;
|
||||
final String coinTo;
|
||||
final String address;
|
||||
|
||||
const AnonpayStatusResponse({
|
||||
required this.status,
|
||||
this.fiatAmount,
|
||||
this.fiatEquiv,
|
||||
this.amountTo,
|
||||
required this.coinTo,
|
||||
required this.address,
|
||||
});
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:convert';
|
||||
import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart';
|
||||
import 'package:cake_wallet/utils/exception_handler.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
@ -55,6 +56,7 @@ class AnyPayApi {
|
|||
final response = await post(url, headers: headers, body: utf8.encode(json.encode(body)));
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
ExceptionHandler.onError(FlutterErrorDetails(exception: response));
|
||||
throw Exception('Unexpected response http code: ${response.statusCode}');
|
||||
}
|
||||
|
||||
|
|
|
@ -1,32 +1,59 @@
|
|||
import 'package:cake_wallet/core/validator.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
||||
class AmountValidator extends TextValidator {
|
||||
AmountValidator({required WalletType type, bool isAutovalidate = false})
|
||||
AmountValidator({required CryptoCurrency currency, bool isAutovalidate = false}) {
|
||||
symbolsAmountValidator =
|
||||
SymbolsAmountValidator(isAutovalidate: isAutovalidate);
|
||||
decimalAmountValidator = DecimalAmountValidator(currency: currency,isAutovalidate: isAutovalidate);
|
||||
}
|
||||
|
||||
late final SymbolsAmountValidator symbolsAmountValidator;
|
||||
|
||||
late final DecimalAmountValidator decimalAmountValidator;
|
||||
|
||||
String? call(String? value) => symbolsAmountValidator(value) ?? decimalAmountValidator(value);
|
||||
}
|
||||
|
||||
class SymbolsAmountValidator extends TextValidator {
|
||||
SymbolsAmountValidator({required bool isAutovalidate})
|
||||
: super(
|
||||
errorMessage: S.current.error_text_amount,
|
||||
pattern: _pattern(type),
|
||||
errorMessage: S.current.error_text_amount,
|
||||
pattern: _pattern(),
|
||||
isAutovalidate: isAutovalidate,
|
||||
minLength: 0,
|
||||
maxLength: 0);
|
||||
|
||||
static String _pattern() => '^([0-9]+([.\,][0-9]+)?|[.\,][0-9]+)\$';
|
||||
}
|
||||
|
||||
class DecimalAmountValidator extends TextValidator {
|
||||
DecimalAmountValidator({required CryptoCurrency currency, required bool isAutovalidate })
|
||||
: super(
|
||||
errorMessage: S.current.decimal_places_error,
|
||||
pattern: _pattern(currency),
|
||||
isAutovalidate: isAutovalidate,
|
||||
minLength: 0,
|
||||
maxLength: 0);
|
||||
|
||||
static String _pattern(WalletType type) {
|
||||
switch (type) {
|
||||
case WalletType.monero:
|
||||
return '^([0-9]+([.\,][0-9]{0,12})?|[.\,][0-9]{1,12})\$';
|
||||
case WalletType.bitcoin:
|
||||
return '^([0-9]+([.\,][0-9]{0,8})?|[.\,][0-9]{1,8})\$';
|
||||
static String _pattern(CryptoCurrency currency) {
|
||||
switch (currency) {
|
||||
case CryptoCurrency.xmr:
|
||||
return '^([0-9]+([.\,][0-9]{1,12})?|[.\,][0-9]{1,12})\$';
|
||||
case CryptoCurrency.btc:
|
||||
return '^([0-9]+([.\,][0-9]{1,8})?|[.\,][0-9]{1,8})\$';
|
||||
default:
|
||||
return '';
|
||||
return '^([0-9]+([.\,][0-9]{1,12})?|[.\,][0-9]{1,12})\$';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AllAmountValidator extends TextValidator {
|
||||
AllAmountValidator() : super(
|
||||
errorMessage: S.current.error_text_amount,
|
||||
pattern: S.current.all,
|
||||
minLength: 0,
|
||||
maxLength: 0);
|
||||
AllAmountValidator()
|
||||
: super(
|
||||
errorMessage: S.current.error_text_amount,
|
||||
pattern: S.current.all,
|
||||
minLength: 0,
|
||||
maxLength: 0);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ import 'package:cake_wallet/entities/fiat_currency.dart';
|
|||
import 'dart:convert';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
|
||||
|
||||
const _fiatApiClearNetAuthority = 'fiat-api.cakewallet.com';
|
||||
const _fiatApiOnionAuthority = 'n4z7bdcmwk2oyddxvzaap3x2peqcplh3pzdy7tpkk5ejz5n4mhfvoxqd.onion';
|
||||
|
@ -17,6 +19,7 @@ Future<double> _fetchPrice(Map<String, dynamic> args) async {
|
|||
'interval_count': '1',
|
||||
'base': crypto.toString(),
|
||||
'quote': fiat.toString(),
|
||||
'key' : secrets.fiatApiKey,
|
||||
};
|
||||
|
||||
double price = 0.0;
|
||||
|
|
91
lib/di.dart
91
lib/di.dart
|
@ -1,11 +1,20 @@
|
|||
import 'package:cake_wallet/anonpay/anonpay_api.dart';
|
||||
import 'package:cake_wallet/anonpay/anonpay_info_base.dart';
|
||||
import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
|
||||
import 'package:cake_wallet/core/yat_service.dart';
|
||||
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||
import 'package:cake_wallet/entities/parse_address_from_domain.dart';
|
||||
import 'package:cake_wallet/entities/receive_page_option.dart';
|
||||
import 'package:cake_wallet/entities/wake_lock.dart';
|
||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_anypay.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_gift_card.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_tip.dart';
|
||||
import 'package:cake_wallet/src/screens/anonpay_details/anonpay_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/onramper_page.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/payfura_page.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/anonpay_invoice_page.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/anonpay_receive_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/display_settings_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/other_settings_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/privacy_page.dart';
|
||||
|
@ -14,7 +23,11 @@ import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_redeem_page.dar
|
|||
import 'package:cake_wallet/src/screens/ionia/cards/ionia_gift_card_detail_page.dart';
|
||||
import 'package:cake_wallet/src/screens/ionia/cards/ionia_more_options_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/connection_sync_page.dart';
|
||||
import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart';
|
||||
import 'package:cake_wallet/utils/payment_request.dart';
|
||||
import 'package:cake_wallet/view_model/anon_invoice_page_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/anonpay_details_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/ionia/ionia_auth_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/ionia/ionia_buy_card_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/ionia/ionia_custom_tip_view_model.dart';
|
||||
|
@ -177,6 +190,7 @@ late Box<ExchangeTemplate> _exchangeTemplates;
|
|||
late Box<TransactionDescription> _transactionDescriptionBox;
|
||||
late Box<Order> _ordersSource;
|
||||
late Box<UnspentCoinsInfo>? _unspentCoinsInfoSource;
|
||||
late Box<AnonpayInvoiceInfo> _anonpayInvoiceInfoSource;
|
||||
|
||||
Future setup(
|
||||
{required Box<WalletInfo> walletInfoSource,
|
||||
|
@ -187,7 +201,9 @@ Future setup(
|
|||
required Box<ExchangeTemplate> exchangeTemplates,
|
||||
required Box<TransactionDescription> transactionDescriptionBox,
|
||||
required Box<Order> ordersSource,
|
||||
Box<UnspentCoinsInfo>? unspentCoinsInfoSource}) async {
|
||||
Box<UnspentCoinsInfo>? unspentCoinsInfoSource,
|
||||
required Box<AnonpayInvoiceInfo> anonpayInvoiceInfoSource
|
||||
}) async {
|
||||
_walletInfoSource = walletInfoSource;
|
||||
_nodeSource = nodeSource;
|
||||
_contactSource = contactSource;
|
||||
|
@ -197,6 +213,7 @@ Future setup(
|
|||
_transactionDescriptionBox = transactionDescriptionBox;
|
||||
_ordersSource = ordersSource;
|
||||
_unspentCoinsInfoSource = unspentCoinsInfoSource;
|
||||
_anonpayInvoiceInfoSource = anonpayInvoiceInfoSource;
|
||||
|
||||
if (!_isSetupFinished) {
|
||||
getIt.registerSingletonAsync<SharedPreferences>(
|
||||
|
@ -241,6 +258,8 @@ Future setup(
|
|||
appStore: getIt.get<AppStore>(),
|
||||
secureStorage: getIt.get<FlutterSecureStorage>())
|
||||
..init());
|
||||
getIt.registerSingleton<AnonpayTransactionsStore>(AnonpayTransactionsStore(
|
||||
anonpayInvoiceInfoSource: _anonpayInvoiceInfoSource));
|
||||
|
||||
final secretStore =
|
||||
await SecretStoreBase.load(getIt.get<FlutterSecureStorage>());
|
||||
|
@ -307,7 +326,9 @@ Future setup(
|
|||
transactionFilterStore: getIt.get<TransactionFilterStore>(),
|
||||
settingsStore: settingsStore,
|
||||
yatStore: getIt.get<YatStore>(),
|
||||
ordersStore: getIt.get<OrdersStore>()));
|
||||
ordersStore: getIt.get<OrdersStore>(),
|
||||
anonpayTransactionsStore: getIt.get<AnonpayTransactionsStore>())
|
||||
);
|
||||
|
||||
getIt.registerFactory<AuthService>(() => AuthService(
|
||||
secureStorage: getIt.get<FlutterSecureStorage>(),
|
||||
|
@ -361,11 +382,37 @@ Future setup(
|
|||
BalancePage(dashboardViewModel: getIt.get<DashboardViewModel>(), settingsStore: getIt.get<SettingsStore>()));
|
||||
|
||||
getIt.registerFactory<DashboardPage>(() => DashboardPage( balancePage: getIt.get<BalancePage>(), walletViewModel: getIt.get<DashboardViewModel>(), addressListViewModel: getIt.get<WalletAddressListViewModel>()));
|
||||
|
||||
getIt.registerFactoryParam<ReceiveOptionViewModel, ReceivePageOption?, void>((pageOption, _) => ReceiveOptionViewModel(
|
||||
getIt.get<AppStore>().wallet!, pageOption));
|
||||
|
||||
getIt.registerFactoryParam<AnonInvoicePageViewModel, List<dynamic>, void>((args, _) {
|
||||
final address = args.first as String;
|
||||
final pageOption = args.last as ReceivePageOption;
|
||||
return AnonInvoicePageViewModel(
|
||||
getIt.get<AnonPayApi>(),
|
||||
address,
|
||||
getIt.get<SettingsStore>(),
|
||||
getIt.get<AppStore>().wallet!,
|
||||
_anonpayInvoiceInfoSource,
|
||||
getIt.get<SharedPreferences>(),
|
||||
pageOption,
|
||||
);
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<AnonPayInvoicePage, List<dynamic>, void>((List<dynamic> args, _) {
|
||||
final pageOption = args.last as ReceivePageOption;
|
||||
return AnonPayInvoicePage(
|
||||
getIt.get<AnonInvoicePageViewModel>(param1: args),
|
||||
getIt.get<ReceiveOptionViewModel>(param1: pageOption));
|
||||
});
|
||||
|
||||
getIt.registerFactory<ReceivePage>(() => ReceivePage(
|
||||
addressListViewModel: getIt.get<WalletAddressListViewModel>()));
|
||||
getIt.registerFactory<AddressPage>(() => AddressPage(
|
||||
addressListViewModel: getIt.get<WalletAddressListViewModel>(),
|
||||
walletViewModel: getIt.get<DashboardViewModel>()));
|
||||
walletViewModel: getIt.get<DashboardViewModel>(),
|
||||
receiveOptionViewModel: getIt.get<ReceiveOptionViewModel>()));
|
||||
|
||||
getIt.registerFactoryParam<WalletAddressEditOrCreateViewModel, WalletAddressListItem?, void>(
|
||||
(WalletAddressListItem? item, _) => WalletAddressEditOrCreateViewModel(
|
||||
|
@ -515,16 +562,23 @@ Future setup(
|
|||
(WalletType? type, _) => NodeCreateOrEditViewModel(
|
||||
_nodeSource,
|
||||
type ?? getIt.get<AppStore>().wallet!.type,
|
||||
getIt.get<SettingsStore>(),
|
||||
getIt.get<SettingsStore>()
|
||||
));
|
||||
|
||||
getIt.registerFactory(
|
||||
() => NodeCreateOrEditPage(getIt.get<NodeCreateOrEditViewModel>()));
|
||||
getIt.registerFactoryParam<NodeCreateOrEditPage, Node?, bool?>(
|
||||
(Node? editingNode, bool? isSelected) => NodeCreateOrEditPage(
|
||||
nodeCreateOrEditViewModel: getIt.get<NodeCreateOrEditViewModel>(),
|
||||
editingNode: editingNode,
|
||||
isSelected: isSelected));
|
||||
|
||||
getIt.registerFactory(() => OnRamperPage(
|
||||
settingsStore: getIt.get<AppStore>().settingsStore,
|
||||
wallet: getIt.get<AppStore>().wallet!));
|
||||
|
||||
getIt.registerFactory(() => PayFuraPage(
|
||||
settingsStore: getIt.get<AppStore>().settingsStore,
|
||||
wallet: getIt.get<AppStore>().wallet!));
|
||||
|
||||
getIt.registerFactory(() => ExchangeViewModel(
|
||||
getIt.get<AppStore>().wallet!,
|
||||
_tradesSource,
|
||||
|
@ -715,8 +769,8 @@ Future setup(
|
|||
getIt.registerFactory(() => AddressResolver(yatService: getIt.get<YatService>(),
|
||||
walletType: getIt.get<AppStore>().wallet!.type));
|
||||
|
||||
getIt.registerFactoryParam<FullscreenQRPage, String, bool>(
|
||||
(String qrData, bool isLight) => FullscreenQRPage(qrData: qrData, isLight: isLight,));
|
||||
getIt.registerFactoryParam<FullscreenQRPage, String, int?>(
|
||||
(String qrData, int? version) => FullscreenQRPage(qrData: qrData, version: version,));
|
||||
|
||||
getIt.registerFactory(() => IoniaApi());
|
||||
|
||||
|
@ -799,7 +853,7 @@ Future setup(
|
|||
return IoniaMoreOptionsPage(giftCard);
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<IoniaCustomRedeemViewModel, IoniaGiftCard, void>((IoniaGiftCard giftCard, _)
|
||||
getIt.registerFactoryParam<IoniaCustomRedeemViewModel, IoniaGiftCard, void>((IoniaGiftCard giftCard, _)
|
||||
=> IoniaCustomRedeemViewModel(giftCard: giftCard, ioniaService: getIt.get<IoniaService>()));
|
||||
|
||||
getIt.registerFactoryParam<IoniaCustomRedeemPage, List, void>((List args, _){
|
||||
|
@ -822,6 +876,25 @@ Future setup(
|
|||
getIt.registerFactory(() => IoniaAccountPage(getIt.get<IoniaAccountViewModel>()));
|
||||
|
||||
getIt.registerFactory(() => IoniaAccountCardsPage(getIt.get<IoniaAccountViewModel>()));
|
||||
|
||||
getIt.registerFactory(() => AnonPayApi(useTorOnly: getIt.get<SettingsStore>().exchangeStatus == ExchangeApiMode.torOnly,
|
||||
wallet: getIt.get<AppStore>().wallet!)
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<AnonpayDetailsViewModel, AnonpayInvoiceInfo, void>(
|
||||
(AnonpayInvoiceInfo anonpayInvoiceInfo, _)
|
||||
=> AnonpayDetailsViewModel(
|
||||
anonPayApi: getIt.get<AnonPayApi>(),
|
||||
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
||||
settingsStore: getIt.get<SettingsStore>(),
|
||||
));
|
||||
|
||||
getIt.registerFactoryParam<AnonPayReceivePage, AnonpayInfoBase, void>(
|
||||
(AnonpayInfoBase anonpayInvoiceInfo, _) => AnonPayReceivePage(invoiceInfo: anonpayInvoiceInfo));
|
||||
|
||||
getIt.registerFactoryParam<AnonpayDetailsPage, AnonpayInvoiceInfo, void>(
|
||||
(AnonpayInvoiceInfo anonpayInvoiceInfo, _)
|
||||
=> AnonpayDetailsPage(anonpayDetailsViewModel: getIt.get<AnonpayDetailsViewModel>(param1: anonpayInvoiceInfo)));
|
||||
|
||||
getIt.registerFactoryParam<IoniaPaymentStatusViewModel, IoniaAnyPayPaymentInfo, AnyPayPaymentCommittedInfo>(
|
||||
(IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo)
|
||||
|
|
|
@ -40,6 +40,9 @@ Future defaultSettingsMigration(
|
|||
await ios_migrate_v1(walletInfoSource, tradeSource, contactSource);
|
||||
}
|
||||
|
||||
// check current nodes for nullability regardless of the version
|
||||
await checkCurrentNodes(nodes, sharedPreferences);
|
||||
|
||||
final currentVersion = sharedPreferences
|
||||
.getInt(PreferencesKey.currentDefaultSettingsMigrationVersion) ??
|
||||
0;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:cw_core/currency.dart';
|
||||
import 'package:cw_core/enumerable_item.dart';
|
||||
|
||||
class FiatCurrency extends EnumerableItem<String> with Serializable<String> {
|
||||
class FiatCurrency extends EnumerableItem<String> with Serializable<String> implements Currency {
|
||||
const FiatCurrency({required String symbol, required this.countryCode, required this.fullName}) : super(title: symbol, raw: symbol);
|
||||
|
||||
final String countryCode;
|
||||
|
@ -118,4 +119,13 @@ class FiatCurrency extends EnumerableItem<String> with Serializable<String> {
|
|||
|
||||
@override
|
||||
int get hashCode => raw.hashCode ^ title.hashCode;
|
||||
|
||||
@override
|
||||
String get name => raw;
|
||||
|
||||
@override
|
||||
String? get tag => null;
|
||||
|
||||
@override
|
||||
String get iconPath => "assets/images/flags/$countryCode.png";
|
||||
}
|
||||
|
|
|
@ -25,7 +25,8 @@ class AddressResolver {
|
|||
'888',
|
||||
'nft',
|
||||
'dao',
|
||||
'blockchain'
|
||||
'blockchain',
|
||||
'polygon'
|
||||
];
|
||||
|
||||
static String? extractAddressByType({required String raw, required CryptoCurrency type}) {
|
||||
|
|
|
@ -39,4 +39,6 @@ class PreferencesKey {
|
|||
=> '${PreferencesKey.moneroWalletPasswordUpdateV1Base}_${name}';
|
||||
|
||||
static const exchangeProvidersSelection = 'exchange-providers-selection';
|
||||
static const clearnetDonationLink = 'clearnet_donation_link';
|
||||
static const onionDonationLink = 'onion_donation_link';
|
||||
}
|
||||
|
|
23
lib/entities/receive_page_option.dart
Normal file
23
lib/entities/receive_page_option.dart
Normal file
|
@ -0,0 +1,23 @@
|
|||
|
||||
enum ReceivePageOption {
|
||||
mainnet,
|
||||
anonPayInvoice,
|
||||
anonPayDonationLink;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
String label = '';
|
||||
switch (this) {
|
||||
case ReceivePageOption.mainnet:
|
||||
label = 'Mainnet';
|
||||
break;
|
||||
case ReceivePageOption.anonPayInvoice:
|
||||
label = 'Trocador AnonPay Invoice';
|
||||
break;
|
||||
case ReceivePageOption.anonPayDonationLink:
|
||||
label = 'Trocador AnonPay Donation Link';
|
||||
break;
|
||||
}
|
||||
return label;
|
||||
}
|
||||
}
|
|
@ -219,9 +219,9 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
|
||||
final responseJSON = responseListJson.first;
|
||||
final id = responseJSON['trade_id'] as String;
|
||||
final inputAddress = responseJSON['address_user'] as String;
|
||||
final payoutAddress = responseJSON['address_user'] as String;
|
||||
final refundAddress = responseJSON['refund_address'] as String;
|
||||
final payoutAddress = responseJSON['address_provider'] as String;
|
||||
final inputAddress = responseJSON['address_provider'] as String;
|
||||
final fromAmount = responseJSON['amount_from']?.toString() ?? '0';
|
||||
final from = CryptoCurrency.fromString(responseJSON['ticker_from'] as String);
|
||||
final to = CryptoCurrency.fromString(responseJSON['ticker_to'] as String);
|
||||
|
|
|
@ -1,346 +1,331 @@
|
|||
part of 'haven.dart';
|
||||
|
||||
class CWHavenAccountList extends HavenAccountList {
|
||||
CWHavenAccountList(this._wallet);
|
||||
final Object _wallet;
|
||||
CWHavenAccountList(this._wallet);
|
||||
|
||||
@override
|
||||
@computed
|
||||
final Object _wallet;
|
||||
|
||||
@override
|
||||
@computed
|
||||
ObservableList<Account> get accounts {
|
||||
final havenWallet = _wallet as HavenWallet;
|
||||
final accounts = havenWallet.walletAddresses.accountList
|
||||
.accounts
|
||||
.map((acc) => Account(id: acc.id, label: acc.label))
|
||||
.toList();
|
||||
return ObservableList<Account>.of(accounts);
|
||||
final havenWallet = _wallet as HavenWallet;
|
||||
final accounts = havenWallet.walletAddresses.accountList.accounts
|
||||
.map((acc) => Account(id: acc.id, label: acc.label))
|
||||
.toList();
|
||||
return ObservableList<Account>.of(accounts);
|
||||
}
|
||||
|
||||
@override
|
||||
void update(Object wallet) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
havenWallet.walletAddresses.accountList.update();
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
havenWallet.walletAddresses.accountList.update();
|
||||
}
|
||||
|
||||
@override
|
||||
void refresh(Object wallet) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
havenWallet.walletAddresses.accountList.refresh();
|
||||
}
|
||||
void refresh(Object wallet) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
havenWallet.walletAddresses.accountList.refresh();
|
||||
}
|
||||
|
||||
@override
|
||||
@override
|
||||
List<Account> getAll(Object wallet) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
return havenWallet.walletAddresses.accountList
|
||||
.getAll()
|
||||
.map((acc) => Account(id: acc.id, label: acc.label))
|
||||
.toList();
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
return havenWallet.walletAddresses.accountList
|
||||
.getAll()
|
||||
.map((acc) => Account(id: acc.id, label: acc.label))
|
||||
.toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> addAccount(Object wallet, {required String label}) async {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
await havenWallet.walletAddresses.accountList.addAccount(label: label);
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
await havenWallet.walletAddresses.accountList.addAccount(label: label);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setLabelAccount(Object wallet, {required int accountIndex, required String label}) async {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
await havenWallet.walletAddresses.accountList
|
||||
.setLabelAccount(
|
||||
accountIndex: accountIndex,
|
||||
label: label);
|
||||
Future<void> setLabelAccount(Object wallet,
|
||||
{required int accountIndex, required String label}) async {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
await havenWallet.walletAddresses.accountList
|
||||
.setLabelAccount(accountIndex: accountIndex, label: label);
|
||||
}
|
||||
}
|
||||
|
||||
class CWHavenSubaddressList extends MoneroSubaddressList {
|
||||
CWHavenSubaddressList(this._wallet);
|
||||
final Object _wallet;
|
||||
CWHavenSubaddressList(this._wallet);
|
||||
|
||||
@override
|
||||
@computed
|
||||
final Object _wallet;
|
||||
|
||||
@override
|
||||
@computed
|
||||
ObservableList<Subaddress> get subaddresses {
|
||||
final havenWallet = _wallet as HavenWallet;
|
||||
final subAddresses = havenWallet.walletAddresses.subaddressList
|
||||
.subaddresses
|
||||
.map((sub) => Subaddress(
|
||||
id: sub.id,
|
||||
address: sub.address,
|
||||
label: sub.label))
|
||||
.toList();
|
||||
return ObservableList<Subaddress>.of(subAddresses);
|
||||
final havenWallet = _wallet as HavenWallet;
|
||||
final subAddresses = havenWallet.walletAddresses.subaddressList.subaddresses
|
||||
.map((sub) => Subaddress(id: sub.id, address: sub.address, label: sub.label))
|
||||
.toList();
|
||||
return ObservableList<Subaddress>.of(subAddresses);
|
||||
}
|
||||
|
||||
@override
|
||||
void update(Object wallet, {required int accountIndex}) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
havenWallet.walletAddresses.subaddressList.update(accountIndex: accountIndex);
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
havenWallet.walletAddresses.subaddressList.update(accountIndex: accountIndex);
|
||||
}
|
||||
|
||||
@override
|
||||
void refresh(Object wallet, {required int accountIndex}) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
havenWallet.walletAddresses.subaddressList.refresh(accountIndex: accountIndex);
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
havenWallet.walletAddresses.subaddressList.refresh(accountIndex: accountIndex);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Subaddress> getAll(Object wallet) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
return havenWallet.walletAddresses
|
||||
.subaddressList
|
||||
.getAll()
|
||||
.map((sub) => Subaddress(id: sub.id, label: sub.label, address: sub.address))
|
||||
.toList();
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
return havenWallet.walletAddresses.subaddressList
|
||||
.getAll()
|
||||
.map((sub) => Subaddress(id: sub.id, label: sub.label, address: sub.address))
|
||||
.toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> addSubaddress(Object wallet, {required int accountIndex, required String label}) async {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
await havenWallet.walletAddresses.subaddressList
|
||||
.addSubaddress(
|
||||
accountIndex: accountIndex,
|
||||
label: label);
|
||||
Future<void> addSubaddress(Object wallet,
|
||||
{required int accountIndex, required String label}) async {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
await havenWallet.walletAddresses.subaddressList
|
||||
.addSubaddress(accountIndex: accountIndex, label: label);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setLabelSubaddress(Object wallet,
|
||||
{required int accountIndex, required int addressIndex, required String label}) async {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
await havenWallet.walletAddresses.subaddressList
|
||||
.setLabelSubaddress(
|
||||
accountIndex: accountIndex,
|
||||
addressIndex: addressIndex,
|
||||
label: label);
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
await havenWallet.walletAddresses.subaddressList
|
||||
.setLabelSubaddress(accountIndex: accountIndex, addressIndex: addressIndex, label: label);
|
||||
}
|
||||
}
|
||||
|
||||
class CWHavenWalletDetails extends HavenWalletDetails {
|
||||
CWHavenWalletDetails(this._wallet);
|
||||
final Object _wallet;
|
||||
CWHavenWalletDetails(this._wallet);
|
||||
|
||||
@computed
|
||||
final Object _wallet;
|
||||
|
||||
@computed
|
||||
@override
|
||||
Account get account {
|
||||
final havenWallet = _wallet as HavenWallet;
|
||||
final acc = havenWallet.walletAddresses.account as monero_account.Account;
|
||||
return Account(id: acc.id, label: acc.label);
|
||||
final havenWallet = _wallet as HavenWallet;
|
||||
final acc = havenWallet.walletAddresses.account as monero_account.Account;
|
||||
return Account(id: acc.id, label: acc.label);
|
||||
}
|
||||
|
||||
@computed
|
||||
@override
|
||||
HavenBalance get balance {
|
||||
final havenWallet = _wallet as HavenWallet;
|
||||
final balance = havenWallet.balance;
|
||||
throw Exception('Unimplemented');
|
||||
//return HavenBalance(
|
||||
// fullBalance: balance.fullBalance,
|
||||
// unlockedBalance: balance.unlockedBalance);
|
||||
}
|
||||
HavenBalance get balance {
|
||||
final havenWallet = _wallet as HavenWallet;
|
||||
final balance = havenWallet.balance;
|
||||
throw Exception('Unimplemented');
|
||||
//return HavenBalance(
|
||||
// fullBalance: balance.fullBalance,
|
||||
// unlockedBalance: balance.unlockedBalance);
|
||||
}
|
||||
}
|
||||
|
||||
class CWHaven extends Haven {
|
||||
@override
|
||||
HavenAccountList getAccountList(Object wallet) {
|
||||
return CWHavenAccountList(wallet);
|
||||
}
|
||||
|
||||
@override
|
||||
MoneroSubaddressList getSubaddressList(Object wallet) {
|
||||
return CWHavenSubaddressList(wallet);
|
||||
}
|
||||
return CWHavenAccountList(wallet);
|
||||
}
|
||||
|
||||
@override
|
||||
TransactionHistoryBase getTransactionHistory(Object wallet) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
return havenWallet.transactionHistory;
|
||||
}
|
||||
MoneroSubaddressList getSubaddressList(Object wallet) {
|
||||
return CWHavenSubaddressList(wallet);
|
||||
}
|
||||
|
||||
@override
|
||||
HavenWalletDetails getMoneroWalletDetails(Object wallet) {
|
||||
return CWHavenWalletDetails(wallet);
|
||||
}
|
||||
TransactionHistoryBase getTransactionHistory(Object wallet) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
return havenWallet.transactionHistory;
|
||||
}
|
||||
|
||||
@override
|
||||
int getHeigthByDate({required DateTime date}) {
|
||||
return getMoneroHeigthByDate(date: date);
|
||||
}
|
||||
|
||||
@override
|
||||
TransactionPriority getDefaultTransactionPriority() {
|
||||
return MoneroTransactionPriority.automatic;
|
||||
}
|
||||
HavenWalletDetails getMoneroWalletDetails(Object wallet) {
|
||||
return CWHavenWalletDetails(wallet);
|
||||
}
|
||||
|
||||
@override
|
||||
TransactionPriority deserializeMoneroTransactionPriority({required int raw}) {
|
||||
return MoneroTransactionPriority.deserialize(raw: raw);
|
||||
}
|
||||
int getHeightByDate({required DateTime date}) => getHavenHeightByDate(date: date);
|
||||
|
||||
@override
|
||||
List<TransactionPriority> getTransactionPriorities() {
|
||||
return MoneroTransactionPriority.all;
|
||||
}
|
||||
Future<int> getCurrentHeight() => getHavenCurrentHeight();
|
||||
|
||||
@override
|
||||
List<String> getMoneroWordList(String language) {
|
||||
switch (language.toLowerCase()) {
|
||||
case 'english':
|
||||
return EnglishMnemonics.words;
|
||||
case 'chinese (simplified)':
|
||||
return ChineseSimplifiedMnemonics.words;
|
||||
case 'dutch':
|
||||
return DutchMnemonics.words;
|
||||
case 'german':
|
||||
return GermanMnemonics.words;
|
||||
case 'japanese':
|
||||
return JapaneseMnemonics.words;
|
||||
case 'portuguese':
|
||||
return PortugueseMnemonics.words;
|
||||
case 'russian':
|
||||
return RussianMnemonics.words;
|
||||
case 'spanish':
|
||||
return SpanishMnemonics.words;
|
||||
case 'french':
|
||||
return FrenchMnemonics.words;
|
||||
case 'italian':
|
||||
return ItalianMnemonics.words;
|
||||
default:
|
||||
return EnglishMnemonics.words;
|
||||
}
|
||||
}
|
||||
TransactionPriority getDefaultTransactionPriority() {
|
||||
return MoneroTransactionPriority.automatic;
|
||||
}
|
||||
|
||||
@override
|
||||
WalletCredentials createHavenRestoreWalletFromKeysCredentials({
|
||||
required String name,
|
||||
TransactionPriority deserializeMoneroTransactionPriority({required int raw}) {
|
||||
return MoneroTransactionPriority.deserialize(raw: raw);
|
||||
}
|
||||
|
||||
@override
|
||||
List<TransactionPriority> getTransactionPriorities() {
|
||||
return MoneroTransactionPriority.all;
|
||||
}
|
||||
|
||||
@override
|
||||
List<String> getMoneroWordList(String language) {
|
||||
switch (language.toLowerCase()) {
|
||||
case 'english':
|
||||
return EnglishMnemonics.words;
|
||||
case 'chinese (simplified)':
|
||||
return ChineseSimplifiedMnemonics.words;
|
||||
case 'dutch':
|
||||
return DutchMnemonics.words;
|
||||
case 'german':
|
||||
return GermanMnemonics.words;
|
||||
case 'japanese':
|
||||
return JapaneseMnemonics.words;
|
||||
case 'portuguese':
|
||||
return PortugueseMnemonics.words;
|
||||
case 'russian':
|
||||
return RussianMnemonics.words;
|
||||
case 'spanish':
|
||||
return SpanishMnemonics.words;
|
||||
case 'french':
|
||||
return FrenchMnemonics.words;
|
||||
case 'italian':
|
||||
return ItalianMnemonics.words;
|
||||
default:
|
||||
return EnglishMnemonics.words;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
WalletCredentials createHavenRestoreWalletFromKeysCredentials(
|
||||
{required String name,
|
||||
required String spendKey,
|
||||
required String viewKey,
|
||||
required String address,
|
||||
required String password,
|
||||
required String language,
|
||||
required int height}) {
|
||||
return HavenRestoreWalletFromKeysCredentials(
|
||||
name: name,
|
||||
spendKey: spendKey,
|
||||
viewKey: viewKey,
|
||||
address: address,
|
||||
password: password,
|
||||
language: language,
|
||||
height: height);
|
||||
}
|
||||
|
||||
@override
|
||||
WalletCredentials createHavenRestoreWalletFromSeedCredentials({
|
||||
required String name,
|
||||
required String password,
|
||||
required int height,
|
||||
required String mnemonic}) {
|
||||
return HavenRestoreWalletFromSeedCredentials(
|
||||
name: name,
|
||||
password: password,
|
||||
height: height,
|
||||
mnemonic: mnemonic);
|
||||
}
|
||||
return HavenRestoreWalletFromKeysCredentials(
|
||||
name: name,
|
||||
spendKey: spendKey,
|
||||
viewKey: viewKey,
|
||||
address: address,
|
||||
password: password,
|
||||
language: language,
|
||||
height: height);
|
||||
}
|
||||
|
||||
@override
|
||||
WalletCredentials createHavenNewWalletCredentials({
|
||||
required String name,
|
||||
required String language,
|
||||
String? password}) {
|
||||
return HavenNewWalletCredentials(
|
||||
name: name,
|
||||
password: password,
|
||||
language: language);
|
||||
}
|
||||
WalletCredentials createHavenRestoreWalletFromSeedCredentials(
|
||||
{required String name,
|
||||
required String password,
|
||||
required int height,
|
||||
required String mnemonic}) {
|
||||
return HavenRestoreWalletFromSeedCredentials(
|
||||
name: name, password: password, height: height, mnemonic: mnemonic);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, String> getKeys(Object wallet) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
final keys = havenWallet.keys;
|
||||
return <String, String>{
|
||||
'privateSpendKey': keys.privateSpendKey,
|
||||
WalletCredentials createHavenNewWalletCredentials(
|
||||
{required String name, required String language, String? password}) {
|
||||
return HavenNewWalletCredentials(name: name, password: password, language: language);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, String> getKeys(Object wallet) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
final keys = havenWallet.keys;
|
||||
return <String, String>{
|
||||
'privateSpendKey': keys.privateSpendKey,
|
||||
'privateViewKey': keys.privateViewKey,
|
||||
'publicSpendKey': keys.publicSpendKey,
|
||||
'publicViewKey': keys.publicViewKey};
|
||||
}
|
||||
'publicViewKey': keys.publicViewKey
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
Object createHavenTransactionCreationCredentials({
|
||||
required List<Output> outputs,
|
||||
required TransactionPriority priority,
|
||||
required String assetType}) {
|
||||
return HavenTransactionCreationCredentials(
|
||||
outputs: outputs.map((out) => OutputInfo(
|
||||
fiatAmount: out.fiatAmount,
|
||||
cryptoAmount: out.cryptoAmount,
|
||||
address: out.address,
|
||||
note: out.note,
|
||||
sendAll: out.sendAll,
|
||||
extractedAddress: out.extractedAddress,
|
||||
isParsedAddress: out.isParsedAddress,
|
||||
formattedCryptoAmount: out.formattedCryptoAmount))
|
||||
.toList(),
|
||||
priority: priority as MoneroTransactionPriority,
|
||||
assetType: assetType);
|
||||
}
|
||||
Object createHavenTransactionCreationCredentials(
|
||||
{required List<Output> outputs,
|
||||
required TransactionPriority priority,
|
||||
required String assetType}) {
|
||||
return HavenTransactionCreationCredentials(
|
||||
outputs: outputs
|
||||
.map((out) => OutputInfo(
|
||||
fiatAmount: out.fiatAmount,
|
||||
cryptoAmount: out.cryptoAmount,
|
||||
address: out.address,
|
||||
note: out.note,
|
||||
sendAll: out.sendAll,
|
||||
extractedAddress: out.extractedAddress,
|
||||
isParsedAddress: out.isParsedAddress,
|
||||
formattedCryptoAmount: out.formattedCryptoAmount))
|
||||
.toList(),
|
||||
priority: priority as MoneroTransactionPriority,
|
||||
assetType: assetType);
|
||||
}
|
||||
|
||||
@override
|
||||
String formatterMoneroAmountToString({required int amount}) {
|
||||
return moneroAmountToString(amount: amount);
|
||||
}
|
||||
|
||||
@override
|
||||
double formatterMoneroAmountToDouble({required int amount}) {
|
||||
return moneroAmountToDouble(amount: amount);
|
||||
}
|
||||
String formatterMoneroAmountToString({required int amount}) {
|
||||
return moneroAmountToString(amount: amount);
|
||||
}
|
||||
|
||||
@override
|
||||
int formatterMoneroParseAmount({required String amount}) {
|
||||
return moneroParseAmount(amount: amount);
|
||||
}
|
||||
double formatterMoneroAmountToDouble({required int amount}) {
|
||||
return moneroAmountToDouble(amount: amount);
|
||||
}
|
||||
|
||||
@override
|
||||
Account getCurrentAccount(Object wallet) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
final acc = havenWallet.walletAddresses.account as monero_account.Account;
|
||||
return Account(id: acc.id, label: acc.label);
|
||||
}
|
||||
int formatterMoneroParseAmount({required String amount}) {
|
||||
return moneroParseAmount(amount: amount);
|
||||
}
|
||||
|
||||
@override
|
||||
void setCurrentAccount(Object wallet, int id, String label) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
havenWallet.walletAddresses.account = monero_account.Account(id: id, label: label);
|
||||
}
|
||||
Account getCurrentAccount(Object wallet) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
final acc = havenWallet.walletAddresses.account as monero_account.Account;
|
||||
return Account(id: acc.id, label: acc.label);
|
||||
}
|
||||
|
||||
@override
|
||||
void onStartup() {
|
||||
monero_wallet_api.onStartup();
|
||||
}
|
||||
void setCurrentAccount(Object wallet, int id, String label) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
havenWallet.walletAddresses.account = monero_account.Account(id: id, label: label);
|
||||
}
|
||||
|
||||
@override
|
||||
int getTransactionInfoAccountId(TransactionInfo tx) {
|
||||
final havenTransactionInfo = tx as HavenTransactionInfo;
|
||||
return havenTransactionInfo.accountIndex;
|
||||
}
|
||||
void onStartup() {
|
||||
monero_wallet_api.onStartup();
|
||||
}
|
||||
|
||||
@override
|
||||
WalletService createHavenWalletService(Box<WalletInfo> walletInfoSource) {
|
||||
return HavenWalletService(walletInfoSource);
|
||||
}
|
||||
int getTransactionInfoAccountId(TransactionInfo tx) {
|
||||
final havenTransactionInfo = tx as HavenTransactionInfo;
|
||||
return havenTransactionInfo.accountIndex;
|
||||
}
|
||||
|
||||
@override
|
||||
String getTransactionAddress(Object wallet, int accountIndex, int addressIndex) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
return havenWallet.getTransactionAddress(accountIndex, addressIndex);
|
||||
}
|
||||
WalletService createHavenWalletService(Box<WalletInfo> walletInfoSource) {
|
||||
return HavenWalletService(walletInfoSource);
|
||||
}
|
||||
|
||||
@override
|
||||
CryptoCurrency assetOfTransaction(TransactionInfo tx) {
|
||||
final transaction = tx as HavenTransactionInfo;
|
||||
final asset = CryptoCurrency.fromString(transaction.assetType);
|
||||
return asset;
|
||||
}
|
||||
String getTransactionAddress(Object wallet, int accountIndex, int addressIndex) {
|
||||
final havenWallet = wallet as HavenWallet;
|
||||
return havenWallet.getTransactionAddress(accountIndex, addressIndex);
|
||||
}
|
||||
|
||||
@override
|
||||
List<AssetRate> getAssetRate()
|
||||
=> getRate()
|
||||
.map((rate) => AssetRate(rate.getAssetType(), rate.getRate()))
|
||||
.toList();
|
||||
CryptoCurrency assetOfTransaction(TransactionInfo tx) {
|
||||
final transaction = tx as HavenTransactionInfo;
|
||||
final asset = CryptoCurrency.fromString(transaction.assetType);
|
||||
return asset;
|
||||
}
|
||||
|
||||
@override
|
||||
List<AssetRate> getAssetRate() =>
|
||||
getRate().map((rate) => AssetRate(rate.getAssetType(), rate.getRate())).toList();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'dart:async';
|
||||
import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
|
||||
import 'package:cake_wallet/core/auth_service.dart';
|
||||
import 'package:cake_wallet/entities/language_service.dart';
|
||||
import 'package:cake_wallet/buy/order.dart';
|
||||
|
@ -100,6 +101,10 @@ Future<void> main() async {
|
|||
Hive.registerAdapter(UnspentCoinsInfoAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(AnonpayInvoiceInfo.typeId)) {
|
||||
Hive.registerAdapter(AnonpayInvoiceInfoAdapter());
|
||||
}
|
||||
|
||||
final secureStorage = FlutterSecureStorage();
|
||||
final transactionDescriptionsBoxKey = await getEncryptionKey(
|
||||
secureStorage: secureStorage, forKey: TransactionDescription.boxKey);
|
||||
|
@ -120,6 +125,7 @@ Future<void> main() async {
|
|||
final templates = await Hive.openBox<Template>(Template.boxName);
|
||||
final exchangeTemplates =
|
||||
await Hive.openBox<ExchangeTemplate>(ExchangeTemplate.boxName);
|
||||
final anonpayInvoiceInfo = await Hive.openBox<AnonpayInvoiceInfo>(AnonpayInvoiceInfo.boxName);
|
||||
Box<UnspentCoinsInfo>? unspentCoinsInfoSource;
|
||||
|
||||
if (!isMoneroOnly) {
|
||||
|
@ -139,6 +145,7 @@ Future<void> main() async {
|
|||
exchangeTemplates: exchangeTemplates,
|
||||
transactionDescriptions: transactionDescriptions,
|
||||
secureStorage: secureStorage,
|
||||
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
||||
initialMigrationVersion: 21);
|
||||
runApp(App());
|
||||
}, (error, stackTrace) async {
|
||||
|
@ -158,6 +165,7 @@ Future<void> initialSetup(
|
|||
required Box<ExchangeTemplate> exchangeTemplates,
|
||||
required Box<TransactionDescription> transactionDescriptions,
|
||||
required FlutterSecureStorage secureStorage,
|
||||
required Box<AnonpayInvoiceInfo> anonpayInvoiceInfo,
|
||||
Box<UnspentCoinsInfo>? unspentCoinsInfoSource,
|
||||
int initialMigrationVersion = 15}) async {
|
||||
LanguageService.loadLocaleList();
|
||||
|
@ -178,6 +186,7 @@ Future<void> initialSetup(
|
|||
exchangeTemplates: exchangeTemplates,
|
||||
transactionDescriptionBox: transactionDescriptions,
|
||||
ordersSource: ordersSource,
|
||||
anonpayInvoiceInfoSource: anonpayInvoiceInfo,
|
||||
unspentCoinsInfoSource: unspentCoinsInfoSource,
|
||||
);
|
||||
await bootstrap(navigatorKey);
|
||||
|
|
|
@ -25,7 +25,7 @@ Future<void> bootstrap(GlobalKey<NavigatorState> navigatorKey) async {
|
|||
.get<SharedPreferences>()
|
||||
.getString(PreferencesKey.currentWalletName);
|
||||
if (currentWalletName != null) {
|
||||
authenticationStore.state = AuthenticationState.installed;
|
||||
authenticationStore.installed();
|
||||
}
|
||||
|
||||
startAuthenticationStateChange(authenticationStore, navigatorKey);
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
import 'package:cake_wallet/anonpay/anonpay_info_base.dart';
|
||||
import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
|
||||
import 'package:cake_wallet/entities/contact_record.dart';
|
||||
import 'package:cake_wallet/buy/order.dart';
|
||||
import 'package:cake_wallet/src/screens/anonpay_details/anonpay_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/backup/backup_page.dart';
|
||||
import 'package:cake_wallet/src/screens/backup/edit_backup_password_page.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/buy_webview_page.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/onramper_page.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/payfura_page.dart';
|
||||
import 'package:cake_wallet/src/screens/buy/pre_order_page.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/anonpay_invoice_page.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/anonpay_receive_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/display_settings_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/other_settings_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/privacy_page.dart';
|
||||
|
@ -82,6 +88,7 @@ import 'package:cake_wallet/src/screens/ionia/cards/ionia_payment_status_page.da
|
|||
import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
|
||||
late RouteSettings currentRouteSettings;
|
||||
|
||||
|
@ -307,8 +314,11 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
builder: (_) => getIt.get<OtherSettingsPage>());
|
||||
|
||||
case Routes.newNode:
|
||||
final args = settings.arguments as Map<String, dynamic>?;
|
||||
return CupertinoPageRoute<void>(
|
||||
builder: (_) => getIt.get<NodeCreateOrEditPage>());
|
||||
builder: (_) => getIt.get<NodeCreateOrEditPage>(
|
||||
param1: args?['editingNode'] as Node?,
|
||||
param2: args?['isSelected'] as bool?));
|
||||
|
||||
case Routes.login:
|
||||
return CupertinoPageRoute<void>(
|
||||
|
@ -436,7 +446,8 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
builder: (_) =>
|
||||
getIt.get<FullscreenQRPage>(
|
||||
param1: args['qrData'] as String,
|
||||
param2: args['isLight'] as bool,
|
||||
param2: args['version'] as int?,
|
||||
|
||||
));
|
||||
|
||||
case Routes.ioniaWelcomePage:
|
||||
|
@ -502,6 +513,9 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
case Routes.onramperPage:
|
||||
return CupertinoPageRoute<void>(builder: (_) => getIt.get<OnRamperPage>());
|
||||
|
||||
case Routes.payfuraPage:
|
||||
return CupertinoPageRoute<void>(builder: (_) => getIt.get<PayFuraPage>());
|
||||
|
||||
case Routes.advancedPrivacySettings:
|
||||
final type = settings.arguments as WalletType;
|
||||
|
||||
|
@ -510,7 +524,19 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
getIt.get<AdvancedPrivacySettingsViewModel>(param1: type),
|
||||
getIt.get<NodeCreateOrEditViewModel>(param1: type),
|
||||
));
|
||||
|
||||
|
||||
case Routes.anonPayInvoicePage:
|
||||
final args = settings.arguments as List;
|
||||
return CupertinoPageRoute<void>(builder: (_) => getIt.get<AnonPayInvoicePage>(param1: args));
|
||||
|
||||
case Routes.anonPayReceivePage:
|
||||
final anonInvoiceViewData = settings.arguments as AnonpayInfoBase;
|
||||
return CupertinoPageRoute<void>(builder: (_) => getIt.get<AnonPayReceivePage>(param1: anonInvoiceViewData));
|
||||
|
||||
case Routes.anonPayDetailsPage:
|
||||
final anonInvoiceViewData = settings.arguments as AnonpayInvoiceInfo;
|
||||
return CupertinoPageRoute<void>(builder: (_) => getIt.get<AnonpayDetailsPage>(param1: anonInvoiceViewData));
|
||||
|
||||
default:
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) => Scaffold(
|
||||
|
|
|
@ -82,4 +82,8 @@ class Routes {
|
|||
static const displaySettingsPage = '/display_settings_page';
|
||||
static const otherSettingsPage = '/other_settings_page';
|
||||
static const advancedPrivacySettings = '/advanced_privacy_settings';
|
||||
static const anonPayInvoicePage = '/anon_pay_invoice_page';
|
||||
static const anonPayReceivePage = '/anon_pay_receive_page';
|
||||
static const anonPayDetailsPage = '/anon_pay_details_page';
|
||||
static const payfuraPage = '/pay_fura_page';
|
||||
}
|
||||
|
|
56
lib/src/screens/anonpay_details/anonpay_details_page.dart
Normal file
56
lib/src/screens/anonpay_details/anonpay_details_page.dart
Normal file
|
@ -0,0 +1,56 @@
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/trade_details/trade_details_list_card.dart';
|
||||
import 'package:cake_wallet/src/screens/trade_details/trade_details_status_item.dart';
|
||||
import 'package:cake_wallet/src/widgets/list_row.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_list_card.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_list_status_row.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:cake_wallet/view_model/anonpay_details_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class AnonpayDetailsPage extends BasePage {
|
||||
AnonpayDetailsPage({required this.anonpayDetailsViewModel});
|
||||
|
||||
@override
|
||||
String get title => S.current.invoice_details;
|
||||
|
||||
final AnonpayDetailsViewModel anonpayDetailsViewModel;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return SectionStandardList(
|
||||
context: context,
|
||||
sectionCount: 1,
|
||||
itemCounter: (int _) => anonpayDetailsViewModel.items.length,
|
||||
itemBuilder: (_, __, index) {
|
||||
final item = anonpayDetailsViewModel.items[index];
|
||||
|
||||
if (item is DetailsListStatusItem) {
|
||||
return StandardListStatusRow(title: item.title, value: item.value);
|
||||
}
|
||||
|
||||
if (item is TradeDetailsListCardItem) {
|
||||
return TradeDetailsStandardListCard(
|
||||
id: item.id,
|
||||
create: item.createdAt,
|
||||
pair: item.pair,
|
||||
currentTheme: anonpayDetailsViewModel.settingsStore.currentTheme.type,
|
||||
onTap: item.onTap,
|
||||
);
|
||||
}
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Clipboard.setData(ClipboardData(text: item.value));
|
||||
showBar<void>(context, S.of(context).transaction_details_copied(item.title));
|
||||
},
|
||||
child: ListRow(title: '${item.title}:', value: item.value),
|
||||
);
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
}
|
73
lib/src/screens/buy/payfura_page.dart
Normal file
73
lib/src/screens/buy/payfura_page.dart
Normal file
|
@ -0,0 +1,73 @@
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
class PayFuraPage extends BasePage {
|
||||
PayFuraPage({required this.settingsStore, required this.wallet});
|
||||
|
||||
final SettingsStore settingsStore;
|
||||
final WalletBase wallet;
|
||||
|
||||
@override
|
||||
String get title => S.current.buy;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return PayFuraPageBody(
|
||||
settingsStore: settingsStore,
|
||||
wallet: wallet);
|
||||
}
|
||||
}
|
||||
|
||||
class PayFuraPageBody extends StatefulWidget {
|
||||
PayFuraPageBody(
|
||||
{required this.settingsStore,
|
||||
required this.wallet});
|
||||
|
||||
static const baseUrl = 'exchange.payfura.com';
|
||||
final SettingsStore settingsStore;
|
||||
final WalletBase wallet;
|
||||
|
||||
Uri get uri => Uri.https(baseUrl, '', <String, dynamic>{
|
||||
'apiKey': secrets.payfuraApiKey,
|
||||
'to': wallet.currency.title,
|
||||
'from': settingsStore.fiatCurrency.title,
|
||||
'walletAddress': '${wallet.currency.title}:${wallet.walletAddresses.address}',
|
||||
'mode': 'buy'
|
||||
});
|
||||
|
||||
@override
|
||||
PayFuraPageBodyState createState() => PayFuraPageBodyState();
|
||||
}
|
||||
|
||||
class PayFuraPageBodyState extends State<PayFuraPageBody> {
|
||||
PayFuraPageBodyState();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InAppWebView(
|
||||
initialOptions: InAppWebViewGroupOptions(
|
||||
crossPlatform: InAppWebViewOptions(transparentBackground: true),
|
||||
),
|
||||
initialUrlRequest: URLRequest(url: widget.uri),
|
||||
androidOnPermissionRequest: (_, __, resources) async {
|
||||
bool permissionGranted = await Permission.camera.status == PermissionStatus.granted;
|
||||
if (!permissionGranted) {
|
||||
permissionGranted = await Permission.camera.request().isGranted;
|
||||
}
|
||||
|
||||
return PermissionRequestResponse(
|
||||
resources: resources,
|
||||
action: permissionGranted
|
||||
? PermissionRequestResponseAction.GRANT
|
||||
: PermissionRequestResponseAction.DENY,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:cake_wallet/core/validator.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cw_core/currency.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
@ -153,8 +154,8 @@ class ContactPage extends BasePage {
|
|||
items: contactViewModel.currencies,
|
||||
title: S.of(context).please_select,
|
||||
hintText: S.of(context).search_currency,
|
||||
onItemSelected: (CryptoCurrency item) =>
|
||||
contactViewModel.currency = item),
|
||||
onItemSelected: (Currency item) =>
|
||||
contactViewModel.currency = item as CryptoCurrency),
|
||||
context: context);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:async';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/market_place_page.dart';
|
||||
import 'package:cake_wallet/wallet_type_utils.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
|
@ -277,6 +278,9 @@ class DashboardPage extends BasePage {
|
|||
case WalletType.litecoin:
|
||||
Navigator.of(context).pushNamed(Routes.onramperPage);
|
||||
break;
|
||||
case WalletType.monero:
|
||||
Navigator.of(context).pushNamed(Routes.payfuraPage);
|
||||
break;
|
||||
default:
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
|
@ -308,7 +312,8 @@ class DashboardPage extends BasePage {
|
|||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.of(context).sell,
|
||||
alertContent: S.of(context).sell_alert_content,
|
||||
alertContent: isMoneroOnly ? S.of(context).sell_monero_com_alert_content
|
||||
: S.of(context).sell_alert_content,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
});
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
import 'package:cake_wallet/anonpay/anonpay_donation_link_info.dart';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cake_wallet/entities/receive_page_option.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/present_receive_option_picker.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:cake_wallet/utils/share_util.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart';
|
||||
|
@ -13,24 +18,25 @@ import 'package:cake_wallet/generated/i18n.dart';
|
|||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:keyboard_actions/keyboard_actions.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
|
||||
class AddressPage extends BasePage {
|
||||
AddressPage({
|
||||
required this.addressListViewModel,
|
||||
required this.walletViewModel})
|
||||
: _cryptoAmountFocus = FocusNode();
|
||||
required this.walletViewModel,
|
||||
required this.receiveOptionViewModel,
|
||||
}) : _cryptoAmountFocus = FocusNode();
|
||||
|
||||
final WalletAddressListViewModel addressListViewModel;
|
||||
final DashboardViewModel walletViewModel;
|
||||
final ReceiveOptionViewModel receiveOptionViewModel;
|
||||
|
||||
final FocusNode _cryptoAmountFocus;
|
||||
|
||||
@override
|
||||
String get title => S.current.receive;
|
||||
|
||||
@override
|
||||
Color get backgroundLightColor => currentTheme.type == ThemeType.bright
|
||||
? Colors.transparent : Colors.white;
|
||||
Color get backgroundLightColor =>
|
||||
currentTheme.type == ThemeType.bright ? Colors.transparent : Colors.white;
|
||||
|
||||
@override
|
||||
Color get backgroundDarkColor => Colors.transparent;
|
||||
|
@ -38,11 +44,15 @@ class AddressPage extends BasePage {
|
|||
@override
|
||||
bool get resizeToAvoidBottomInset => false;
|
||||
|
||||
bool effectsInstalled = false;
|
||||
|
||||
@override
|
||||
Widget leading(BuildContext context) {
|
||||
final _backButton = Icon(Icons.arrow_back_ios,
|
||||
color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!,
|
||||
size: 16,);
|
||||
final _backButton = Icon(
|
||||
Icons.arrow_back_ios,
|
||||
color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!,
|
||||
size: 16,
|
||||
);
|
||||
|
||||
return SizedBox(
|
||||
height: 37,
|
||||
|
@ -61,16 +71,8 @@ class AddressPage extends BasePage {
|
|||
}
|
||||
|
||||
@override
|
||||
Widget middle(BuildContext context) {
|
||||
return Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 18.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Lato',
|
||||
color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!),
|
||||
);
|
||||
}
|
||||
Widget middle(BuildContext context) =>
|
||||
PresentReceiveOptionPicker(receiveOptionViewModel: receiveOptionViewModel);
|
||||
|
||||
@override
|
||||
Widget Function(BuildContext, Widget) get rootWrapper =>
|
||||
|
@ -85,53 +87,56 @@ class AddressPage extends BasePage {
|
|||
|
||||
@override
|
||||
Widget? trailing(BuildContext context) {
|
||||
final shareImage =
|
||||
Image.asset('assets/images/share.png',
|
||||
final shareImage = Image.asset('assets/images/share.png',
|
||||
color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!);
|
||||
|
||||
return !addressListViewModel.hasAddressList ? Material(
|
||||
color: Colors.transparent,
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: BoxConstraints(),
|
||||
highlightColor: Colors.transparent,
|
||||
splashColor: Colors.transparent,
|
||||
iconSize: 25,
|
||||
onPressed: () {
|
||||
ShareUtil.share(
|
||||
text: addressListViewModel.address.address,
|
||||
context: context,
|
||||
);
|
||||
},
|
||||
icon: shareImage,
|
||||
),
|
||||
) : null;
|
||||
return !addressListViewModel.hasAddressList
|
||||
? Material(
|
||||
color: Colors.transparent,
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: BoxConstraints(),
|
||||
highlightColor: Colors.transparent,
|
||||
splashColor: Colors.transparent,
|
||||
iconSize: 25,
|
||||
onPressed: () {
|
||||
ShareUtil.share(
|
||||
text: addressListViewModel.address.address,
|
||||
context: context,
|
||||
);
|
||||
},
|
||||
icon: shareImage,
|
||||
),
|
||||
)
|
||||
: null;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
_setEffects(context);
|
||||
|
||||
autorun((_) async {
|
||||
if (!walletViewModel.isOutdatedElectrumWallet
|
||||
|| !walletViewModel.settingsStore.shouldShowReceiveWarning) {
|
||||
if (!walletViewModel.isOutdatedElectrumWallet ||
|
||||
!walletViewModel.settingsStore.shouldShowReceiveWarning) {
|
||||
return;
|
||||
}
|
||||
|
||||
await Future<void>.delayed(Duration(seconds: 1));
|
||||
if (context.mounted) {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).pre_seed_title,
|
||||
alertContent: S.of(context).outdated_electrum_wallet_receive_warning,
|
||||
leftButtonText: S.of(context).understand,
|
||||
actionLeftButton: () => Navigator.of(context).pop(),
|
||||
rightButtonText: S.of(context).do_not_show_me,
|
||||
actionRightButton: () {
|
||||
walletViewModel.settingsStore.setShouldShowReceiveWarning(false);
|
||||
Navigator.of(context).pop();
|
||||
});
|
||||
});
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).pre_seed_title,
|
||||
alertContent: S.of(context).outdated_electrum_wallet_receive_warning,
|
||||
leftButtonText: S.of(context).understand,
|
||||
actionLeftButton: () => Navigator.of(context).pop(),
|
||||
rightButtonText: S.of(context).do_not_show_me,
|
||||
actionRightButton: () {
|
||||
walletViewModel.settingsStore.setShouldShowReceiveWarning(false);
|
||||
Navigator.of(context).pop();
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -141,8 +146,7 @@ class AddressPage extends BasePage {
|
|||
tapOutsideToDismiss: true,
|
||||
config: KeyboardActionsConfig(
|
||||
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
|
||||
keyboardBarColor:
|
||||
Theme.of(context).accentTextTheme!.bodyText1!.backgroundColor!,
|
||||
keyboardBarColor: Theme.of(context).accentTextTheme.bodyText1!.backgroundColor!,
|
||||
nextFocus: false,
|
||||
actions: [
|
||||
KeyboardActionsItem(
|
||||
|
@ -154,29 +158,25 @@ class AddressPage extends BasePage {
|
|||
padding: EdgeInsets.fromLTRB(24, 24, 24, 32),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Observer(builder: (_) => QRWidget(
|
||||
addressListViewModel: addressListViewModel,
|
||||
amountTextFieldFocusNode: _cryptoAmountFocus,
|
||||
isAmountFieldShow: !addressListViewModel.hasAccounts,
|
||||
isLight: walletViewModel.settingsStore.currentTheme.type == ThemeType.light))
|
||||
Expanded(
|
||||
child: Observer(builder: (_) => QRWidget(
|
||||
addressListViewModel: addressListViewModel,
|
||||
amountTextFieldFocusNode: _cryptoAmountFocus,
|
||||
isAmountFieldShow: !addressListViewModel.hasAccounts,
|
||||
isLight: walletViewModel.settingsStore.currentTheme.type == ThemeType.light))
|
||||
),
|
||||
Observer(builder: (_) {
|
||||
return addressListViewModel.hasAddressList
|
||||
? GestureDetector(
|
||||
onTap: () =>
|
||||
Navigator.of(context).pushNamed(Routes.receive),
|
||||
onTap: () => Navigator.of(context).pushNamed(Routes.receive),
|
||||
child: Container(
|
||||
height: 50,
|
||||
padding: EdgeInsets.only(left: 24, right: 12),
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(25)),
|
||||
borderRadius: BorderRadius.all(Radius.circular(25)),
|
||||
border: Border.all(
|
||||
color:
|
||||
Theme.of(context).textTheme!.subtitle1!.color!,
|
||||
width: 1),
|
||||
color: Theme.of(context).textTheme.subtitle1!.color!, width: 1),
|
||||
color: Theme.of(context).buttonColor),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
|
@ -185,42 +185,79 @@ class AddressPage extends BasePage {
|
|||
Observer(
|
||||
builder: (_) => Text(
|
||||
addressListViewModel.hasAccounts
|
||||
? S
|
||||
.of(context)
|
||||
.accounts_subaddresses
|
||||
? S.of(context).accounts_subaddresses
|
||||
: S.of(context).addresses,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.accentTextTheme
|
||||
.headline2!
|
||||
.backgroundColor!),
|
||||
)),
|
||||
Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
size: 14,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.headline2!
|
||||
.backgroundColor!,
|
||||
color:
|
||||
Theme.of(context).accentTextTheme.headline2!.backgroundColor!,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
: Text(
|
||||
S.of(context).electrum_address_disclaimer,
|
||||
: Text(S.of(context).electrum_address_disclaimer,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.headline3!
|
||||
.backgroundColor!));
|
||||
color: Theme.of(context).accentTextTheme.headline3!.backgroundColor!));
|
||||
})
|
||||
],
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
void _setEffects(BuildContext context) {
|
||||
if (effectsInstalled) {
|
||||
return;
|
||||
}
|
||||
|
||||
reaction((_) => receiveOptionViewModel.selectedReceiveOption, (ReceivePageOption option) {
|
||||
Navigator.pop(context);
|
||||
switch (option) {
|
||||
case ReceivePageOption.anonPayInvoice:
|
||||
Navigator.pushReplacementNamed(
|
||||
context,
|
||||
Routes.anonPayInvoicePage,
|
||||
arguments: [addressListViewModel.address.address, option],
|
||||
);
|
||||
break;
|
||||
case ReceivePageOption.anonPayDonationLink:
|
||||
final sharedPreferences = getIt.get<SharedPreferences>();
|
||||
final clearnetUrl = sharedPreferences.getString(PreferencesKey.clearnetDonationLink);
|
||||
final onionUrl = sharedPreferences.getString(PreferencesKey.onionDonationLink);
|
||||
|
||||
if (clearnetUrl != null && onionUrl != null) {
|
||||
Navigator.pushReplacementNamed(
|
||||
context,
|
||||
Routes.anonPayReceivePage,
|
||||
arguments: AnonpayDonationLinkInfo(
|
||||
clearnetUrl: clearnetUrl,
|
||||
onionUrl: onionUrl,
|
||||
address: addressListViewModel.address.address,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
Navigator.pushReplacementNamed(
|
||||
context,
|
||||
Routes.anonPayInvoicePage,
|
||||
arguments: [addressListViewModel.address.address, option],
|
||||
);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
|
||||
effectsInstalled = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class AnonpayTransactionRow extends StatelessWidget {
|
||||
AnonpayTransactionRow({
|
||||
required this.provider,
|
||||
required this.createdAt,
|
||||
required this.currency,
|
||||
required this.onTap,
|
||||
required this.amount,
|
||||
});
|
||||
|
||||
final VoidCallback? onTap;
|
||||
final String provider;
|
||||
final String createdAt;
|
||||
final String amount;
|
||||
final String currency;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
padding: EdgeInsets.fromLTRB(24, 8, 24, 8),
|
||||
color: Colors.transparent,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
_getImage(),
|
||||
SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[
|
||||
Text(provider,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!)),
|
||||
Text(amount + ' ' + currency,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!))
|
||||
]),
|
||||
SizedBox(height: 5),
|
||||
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[
|
||||
Text(createdAt,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).textTheme.overline!.backgroundColor!))
|
||||
])
|
||||
],
|
||||
))
|
||||
],
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
Widget _getImage() => ClipRRect(
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
child: Image.asset('assets/images/trocador.png', width: 36, height: 36));
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/screens/ionia/widgets/rounded_checkbox.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_background.dart';
|
||||
import 'package:cake_wallet/typography.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
class PresentReceiveOptionPicker extends StatelessWidget {
|
||||
PresentReceiveOptionPicker({required this.receiveOptionViewModel});
|
||||
|
||||
final ReceiveOptionViewModel receiveOptionViewModel;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final arrowBottom =
|
||||
Image.asset('assets/images/arrow_bottom_purple_icon.png', color: Colors.white, height: 6);
|
||||
|
||||
return TextButton(
|
||||
onPressed: () => _showPicker(context),
|
||||
style: ButtonStyle(
|
||||
padding: MaterialStateProperty.all(EdgeInsets.zero),
|
||||
splashFactory: NoSplash.splashFactory,
|
||||
foregroundColor: MaterialStateProperty.all(Colors.transparent),
|
||||
overlayColor: MaterialStateProperty.all(Colors.transparent),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.current.receive,
|
||||
style: TextStyle(
|
||||
fontSize: 18.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Lato',
|
||||
color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!),
|
||||
),
|
||||
Observer(
|
||||
builder: (_) => Text(receiveOptionViewModel.selectedReceiveOption.toString(),
|
||||
style: TextStyle(
|
||||
fontSize: 10.0,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).textTheme.headline5!.color!)))
|
||||
],
|
||||
),
|
||||
SizedBox(width: 5),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 12),
|
||||
child: arrowBottom,
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showPicker(BuildContext context) async {
|
||||
await showPopUp<void>(
|
||||
builder: (BuildContext popUpContext) => Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
backgroundColor: Colors.transparent,
|
||||
body: AlertBackground(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Spacer(),
|
||||
Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 24),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
color: Theme.of(context).backgroundColor,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 24, bottom: 24),
|
||||
child: (ListView.separated(
|
||||
padding: EdgeInsets.zero,
|
||||
shrinkWrap: true,
|
||||
itemCount: receiveOptionViewModel.options.length,
|
||||
itemBuilder: (_, index) {
|
||||
final option = receiveOptionViewModel.options[index];
|
||||
return InkWell(
|
||||
onTap: () => receiveOptionViewModel.selectReceiveOption(option),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 24, right: 24),
|
||||
child: Observer(builder: (_) {
|
||||
final value = receiveOptionViewModel.selectedReceiveOption;
|
||||
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(option.toString(),
|
||||
textAlign: TextAlign.left,
|
||||
style: textSmall(
|
||||
color: Theme.of(context).primaryTextTheme.headline6!.color!,
|
||||
).copyWith(
|
||||
fontWeight:
|
||||
value == option ? FontWeight.w800 : FontWeight.w500,
|
||||
)),
|
||||
RoundedCheckbox(
|
||||
value: value == option,
|
||||
)
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
},
|
||||
separatorBuilder: (_, index) => SizedBox(height: 30),
|
||||
)),
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
Container(
|
||||
margin: EdgeInsets.only(bottom: 40),
|
||||
child: InkWell(
|
||||
onTap: () => Navigator.pop(context),
|
||||
child: CircleAvatar(
|
||||
child: Icon(
|
||||
Icons.close,
|
||||
color: Palette.darkBlueCraiola,
|
||||
),
|
||||
backgroundColor: Colors.white,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
context: context,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
import 'package:cake_wallet/src/screens/dashboard/widgets/anonpay_transaction_row.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/order_row.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/anonpay_transaction_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/order_list_item.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
@ -22,102 +25,104 @@ class TransactionsPage extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(
|
||||
top: 24,
|
||||
bottom: 24
|
||||
),
|
||||
padding: EdgeInsets.only(top: 24, bottom: 24),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
HeaderRow(dashboardViewModel: dashboardViewModel),
|
||||
Expanded(
|
||||
child: Observer(
|
||||
builder: (_) {
|
||||
final items = dashboardViewModel.items;
|
||||
Expanded(child: Observer(builder: (_) {
|
||||
final items = dashboardViewModel.items;
|
||||
|
||||
return items?.isNotEmpty ?? false
|
||||
? ListView.builder(
|
||||
itemCount: items.length,
|
||||
itemBuilder: (context, index) {
|
||||
return items.isNotEmpty
|
||||
? ListView.builder(
|
||||
itemCount: items.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = items[index];
|
||||
|
||||
final item = items[index];
|
||||
|
||||
if (item is DateSectionItem) {
|
||||
return DateSectionRaw(date: item.date);
|
||||
}
|
||||
|
||||
if (item is TransactionListItem) {
|
||||
final transaction = item.transaction;
|
||||
|
||||
return Observer(
|
||||
builder: (_) => TransactionRow(
|
||||
onTap: () => Navigator.of(context).pushNamed(
|
||||
Routes.transactionDetails,
|
||||
arguments: transaction),
|
||||
direction: transaction.direction,
|
||||
formattedDate: DateFormat('HH:mm')
|
||||
.format(transaction.date),
|
||||
formattedAmount: item.formattedCryptoAmount,
|
||||
formattedFiatAmount:
|
||||
dashboardViewModel.balanceViewModel.isFiatDisabled
|
||||
? '' : item.formattedFiatAmount,
|
||||
isPending: transaction.isPending,
|
||||
title: item.formattedTitle + item.formattedStatus));
|
||||
}
|
||||
|
||||
if (item is TradeListItem) {
|
||||
final trade = item.trade;
|
||||
|
||||
return Observer(builder: (_) => TradeRow(
|
||||
onTap: () => Navigator.of(context).pushNamed(
|
||||
Routes.tradeDetails,
|
||||
arguments: trade),
|
||||
provider: trade.provider,
|
||||
from: trade.from,
|
||||
to: trade.to,
|
||||
createdAtFormattedDate:
|
||||
trade.createdAt != null
|
||||
? DateFormat('HH:mm').format(trade.createdAt!)
|
||||
: null,
|
||||
formattedAmount: item.tradeFormattedAmount
|
||||
));
|
||||
}
|
||||
|
||||
if (item is OrderListItem) {
|
||||
final order = item.order;
|
||||
|
||||
return Observer(builder: (_) => OrderRow(
|
||||
onTap: () => Navigator.of(context).pushNamed(
|
||||
Routes.orderDetails,
|
||||
arguments: order),
|
||||
provider: order.provider,
|
||||
from: order.from!,
|
||||
to: order.to!,
|
||||
createdAtFormattedDate:
|
||||
DateFormat('HH:mm').format(order.createdAt),
|
||||
formattedAmount: item.orderFormattedAmount,
|
||||
));
|
||||
}
|
||||
|
||||
return Container(
|
||||
color: Colors.transparent,
|
||||
height: 1);
|
||||
if (item is DateSectionItem) {
|
||||
return DateSectionRaw(date: item.date);
|
||||
}
|
||||
)
|
||||
: Center(
|
||||
|
||||
if (item is TransactionListItem) {
|
||||
final transaction = item.transaction;
|
||||
|
||||
return Observer(
|
||||
builder: (_) => TransactionRow(
|
||||
onTap: () => Navigator.of(context)
|
||||
.pushNamed(Routes.transactionDetails, arguments: transaction),
|
||||
direction: transaction.direction,
|
||||
formattedDate: DateFormat('HH:mm').format(transaction.date),
|
||||
formattedAmount: item.formattedCryptoAmount,
|
||||
formattedFiatAmount:
|
||||
dashboardViewModel.balanceViewModel.isFiatDisabled
|
||||
? ''
|
||||
: item.formattedFiatAmount,
|
||||
isPending: transaction.isPending,
|
||||
title: item.formattedTitle + item.formattedStatus));
|
||||
}
|
||||
|
||||
if (item is AnonpayTransactionListItem) {
|
||||
final transactionInfo = item.transaction;
|
||||
|
||||
return AnonpayTransactionRow(
|
||||
onTap: () => Navigator.of(context)
|
||||
.pushNamed(Routes.anonPayDetailsPage, arguments: transactionInfo),
|
||||
currency: transactionInfo.fiatAmount != null
|
||||
? transactionInfo.fiatEquiv ?? ''
|
||||
: CryptoCurrency.fromFullName(transactionInfo.coinTo)
|
||||
.name
|
||||
.toUpperCase(),
|
||||
provider: transactionInfo.provider,
|
||||
amount: transactionInfo.fiatAmount?.toString() ??
|
||||
(transactionInfo.amountTo?.toString() ?? ''),
|
||||
createdAt: DateFormat('HH:mm').format(transactionInfo.createdAt),
|
||||
);
|
||||
}
|
||||
|
||||
if (item is TradeListItem) {
|
||||
final trade = item.trade;
|
||||
|
||||
return Observer(
|
||||
builder: (_) => TradeRow(
|
||||
onTap: () => Navigator.of(context)
|
||||
.pushNamed(Routes.tradeDetails, arguments: trade),
|
||||
provider: trade.provider,
|
||||
from: trade.from,
|
||||
to: trade.to,
|
||||
createdAtFormattedDate: trade.createdAt != null
|
||||
? DateFormat('HH:mm').format(trade.createdAt!)
|
||||
: null,
|
||||
formattedAmount: item.tradeFormattedAmount));
|
||||
}
|
||||
|
||||
if (item is OrderListItem) {
|
||||
final order = item.order;
|
||||
|
||||
return Observer(
|
||||
builder: (_) => OrderRow(
|
||||
onTap: () => Navigator.of(context)
|
||||
.pushNamed(Routes.orderDetails, arguments: order),
|
||||
provider: order.provider,
|
||||
from: order.from!,
|
||||
to: order.to!,
|
||||
createdAtFormattedDate:
|
||||
DateFormat('HH:mm').format(order.createdAt),
|
||||
formattedAmount: item.orderFormattedAmount,
|
||||
));
|
||||
}
|
||||
|
||||
return Container(color: Colors.transparent, height: 1);
|
||||
})
|
||||
: Center(
|
||||
child: Text(
|
||||
S.of(context).placeholder_transactions,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).primaryTextTheme!
|
||||
.overline!.decorationColor!
|
||||
),
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).primaryTextTheme.overline!.decorationColor!),
|
||||
),
|
||||
);
|
||||
}
|
||||
)
|
||||
)
|
||||
}))
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -240,7 +240,7 @@ class ExchangePage extends BasePage {
|
|||
.bodyText1!
|
||||
.color!,
|
||||
currencyValueValidator: AmountValidator(
|
||||
type: exchangeViewModel.wallet.type),
|
||||
currency: exchangeViewModel.depositCurrency),
|
||||
addressTextFieldValidator: AddressValidator(
|
||||
type: exchangeViewModel.depositCurrency),
|
||||
onPushPasteButton: (context) async {
|
||||
|
@ -304,7 +304,7 @@ class ExchangePage extends BasePage {
|
|||
.bodyText1!
|
||||
.decorationColor!,
|
||||
currencyValueValidator: AmountValidator(
|
||||
type: exchangeViewModel.wallet.type),
|
||||
currency: exchangeViewModel.receiveCurrency),
|
||||
addressTextFieldValidator:
|
||||
AddressValidator(
|
||||
type: exchangeViewModel
|
||||
|
|
|
@ -165,7 +165,7 @@ class ExchangeTemplatePage extends BasePage {
|
|||
.bodyText1!
|
||||
.color!,
|
||||
currencyValueValidator: AmountValidator(
|
||||
type: exchangeViewModel.wallet.type),
|
||||
currency: exchangeViewModel.depositCurrency),
|
||||
//addressTextFieldValidator: AddressValidator(
|
||||
// type: exchangeViewModel.depositCurrency),
|
||||
),
|
||||
|
@ -206,7 +206,7 @@ class ExchangeTemplatePage extends BasePage {
|
|||
.bodyText1!
|
||||
.decorationColor!,
|
||||
currencyValueValidator: AmountValidator(
|
||||
type: exchangeViewModel.wallet.type),
|
||||
currency: exchangeViewModel.receiveCurrency),
|
||||
//addressTextFieldValidator: AddressValidator(
|
||||
// type: exchangeViewModel.receiveCurrency),
|
||||
)),
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:ui';
|
|||
import 'package:cake_wallet/src/screens/exchange/widgets/currency_picker_item_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/widgets/picker_item.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
|
||||
import 'package:cw_core/currency.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
@ -20,9 +21,9 @@ class CurrencyPicker extends StatefulWidget {
|
|||
this.isConvertFrom = false});
|
||||
|
||||
int selectedAtIndex;
|
||||
final List<CryptoCurrency> items;
|
||||
final List<Currency> items;
|
||||
final String? title;
|
||||
final Function(CryptoCurrency) onItemSelected;
|
||||
final Function(Currency) onItemSelected;
|
||||
final bool isMoneroWallet;
|
||||
final bool isConvertFrom;
|
||||
final String? hintText;
|
||||
|
@ -38,13 +39,13 @@ class CurrencyPickerState extends State<CurrencyPicker> {
|
|||
subPickerItemsList = items,
|
||||
appBarTextStyle =
|
||||
TextStyle(fontSize: 20, fontFamily: 'Lato', backgroundColor: Colors.transparent, color: Colors.white),
|
||||
pickerItemsList = <PickerItem<CryptoCurrency>>[];
|
||||
pickerItemsList = <PickerItem<Currency>>[];
|
||||
|
||||
List<PickerItem<CryptoCurrency>> pickerItemsList;
|
||||
List<CryptoCurrency> items;
|
||||
List<PickerItem<Currency>> pickerItemsList;
|
||||
List<Currency> items;
|
||||
bool isSearchBarActive;
|
||||
String textFieldValue;
|
||||
List<CryptoCurrency> subPickerItemsList;
|
||||
List<Currency> subPickerItemsList;
|
||||
TextStyle appBarTextStyle;
|
||||
|
||||
void cleanSubPickerItemsList() => subPickerItemsList = items;
|
||||
|
@ -54,7 +55,7 @@ class CurrencyPickerState extends State<CurrencyPicker> {
|
|||
if (subString.isNotEmpty) {
|
||||
subPickerItemsList = items
|
||||
.where((element) =>
|
||||
(element.title != null ? element.title.toLowerCase().contains(subString.toLowerCase()) : false) ||
|
||||
element.name.toLowerCase().contains(subString.toLowerCase()) ||
|
||||
(element.tag != null ? element.tag!.toLowerCase().contains(subString.toLowerCase()) : false) ||
|
||||
(element.fullName != null ? element.fullName!.toLowerCase().contains(subString.toLowerCase()) : false))
|
||||
.toList();
|
||||
|
@ -139,7 +140,7 @@ class CurrencyPickerState extends State<CurrencyPicker> {
|
|||
AspectRatio(
|
||||
aspectRatio: 6,
|
||||
child: PickerItemWidget(
|
||||
title: items[widget.selectedAtIndex].title,
|
||||
title: items[widget.selectedAtIndex].name,
|
||||
iconPath: items[widget.selectedAtIndex].iconPath,
|
||||
isSelected: true,
|
||||
tag: items[widget.selectedAtIndex].tag,
|
||||
|
|
|
@ -32,12 +32,12 @@ class PickerItemWidget extends StatelessWidget {
|
|||
width: 20.0,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
title.toUpperCase(),
|
||||
style: TextStyle(
|
||||
color: isSelected ? Palette.blueCraiola : Theme.of(context).primaryTextTheme!.headline6!.color!,
|
||||
fontSize: isSelected ? 16 : 14.0,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import 'package:cw_core/currency.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'picker_item.dart';
|
||||
import 'currency_picker_item_widget.dart';
|
||||
|
||||
class CurrencyPickerWidget extends StatelessWidget {
|
||||
|
@ -14,7 +13,7 @@ class CurrencyPickerWidget extends StatelessWidget {
|
|||
final int crossAxisCount;
|
||||
final int selectedAtIndex;
|
||||
final Function pickListItem;
|
||||
final List<CryptoCurrency> pickerItemsList;
|
||||
final List<Currency> pickerItemsList;
|
||||
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
|
||||
|
@ -39,8 +38,8 @@ class CurrencyPickerWidget extends StatelessWidget {
|
|||
onTap: () {
|
||||
pickListItem(index);
|
||||
},
|
||||
title: pickerItemsList[index].title,
|
||||
iconPath: pickerItemsList[index].iconPath,
|
||||
title: pickerItemsList[index].name,
|
||||
iconPath: pickerItemsList[index].iconPath,
|
||||
tag: pickerItemsList[index].tag,
|
||||
);
|
||||
}),
|
||||
|
|
|
@ -4,6 +4,7 @@ import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
|||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/utils/payment_request.dart';
|
||||
import 'package:cw_core/currency.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
@ -501,9 +502,9 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
hintText: S.of(context).search_currency,
|
||||
isMoneroWallet: _isMoneroWallet,
|
||||
isConvertFrom: widget.hasRefundAddress,
|
||||
onItemSelected: (CryptoCurrency item) =>
|
||||
onItemSelected: (Currency item) =>
|
||||
widget.onCurrencySelected != null
|
||||
? widget.onCurrencySelected(item)
|
||||
? widget.onCurrencySelected(item as CryptoCurrency)
|
||||
: null),
|
||||
context: context);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'package:cake_wallet/core/execution_state.dart';
|
|||
import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
@ -13,7 +14,7 @@ import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
|||
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
|
||||
|
||||
class NodeCreateOrEditPage extends BasePage {
|
||||
NodeCreateOrEditPage(this.nodeCreateOrEditViewModel)
|
||||
NodeCreateOrEditPage({required this.nodeCreateOrEditViewModel,this.editingNode, this.isSelected})
|
||||
: _formKey = GlobalKey<FormState>(),
|
||||
_addressController = TextEditingController(),
|
||||
_portController = TextEditingController(),
|
||||
|
@ -62,9 +63,11 @@ class NodeCreateOrEditPage extends BasePage {
|
|||
final TextEditingController _passwordController;
|
||||
|
||||
@override
|
||||
String get title => S.current.node_new;
|
||||
String get title => editingNode != null ? S.current.edit_node : S.current.node_new;
|
||||
|
||||
final NodeCreateOrEditViewModel nodeCreateOrEditViewModel;
|
||||
final Node? editingNode;
|
||||
final bool? isSelected;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
|
@ -108,6 +111,7 @@ class NodeCreateOrEditPage extends BasePage {
|
|||
content: NodeForm(
|
||||
formKey: _formKey,
|
||||
nodeViewModel: nodeCreateOrEditViewModel,
|
||||
editingNode: editingNode,
|
||||
),
|
||||
bottomSectionPadding: EdgeInsets.only(bottom: 24),
|
||||
bottomSection: Observer(
|
||||
|
@ -140,7 +144,8 @@ class NodeCreateOrEditPage extends BasePage {
|
|||
return;
|
||||
}
|
||||
|
||||
await nodeCreateOrEditViewModel.save();
|
||||
await nodeCreateOrEditViewModel.save(
|
||||
editingNode: editingNode, saveAsCurrent: isSelected ?? false);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
text: S.of(context).save,
|
||||
|
|
|
@ -3,6 +3,7 @@ import 'package:cake_wallet/core/node_port_validator.dart';
|
|||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
|
||||
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
@ -12,22 +13,20 @@ class NodeForm extends StatelessWidget {
|
|||
NodeForm({
|
||||
required this.nodeViewModel,
|
||||
required this.formKey,
|
||||
}) : _addressController = TextEditingController(),
|
||||
_portController = TextEditingController(),
|
||||
_loginController = TextEditingController(),
|
||||
_passwordController = TextEditingController() {
|
||||
reaction((_) => nodeViewModel.address, (String address) {
|
||||
if (address != _addressController.text) {
|
||||
_addressController.text = address;
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => nodeViewModel.port, (String port) {
|
||||
if (port != _portController.text) {
|
||||
_portController.text = port;
|
||||
}
|
||||
});
|
||||
|
||||
this.editingNode,
|
||||
}) : _addressController = TextEditingController(text: editingNode?.uri.host.toString()),
|
||||
_portController = TextEditingController(text: editingNode?.uri.port.toString()),
|
||||
_loginController = TextEditingController(text: editingNode?.login),
|
||||
_passwordController = TextEditingController(text: editingNode?.password) {
|
||||
if (editingNode != null) {
|
||||
nodeViewModel
|
||||
..setAddress((editingNode!.uri.host.toString()))
|
||||
..setPort((editingNode!.uri.port.toString()))
|
||||
..setPassword((editingNode!.password ?? ''))
|
||||
..setLogin((editingNode!.login ?? ''))
|
||||
..setSSL((editingNode!.isSSL))
|
||||
..setTrusted((editingNode!.trusted));
|
||||
}
|
||||
if (nodeViewModel.hasAuthCredentials) {
|
||||
reaction((_) => nodeViewModel.login, (String login) {
|
||||
if (login != _loginController.text) {
|
||||
|
@ -42,18 +41,15 @@ class NodeForm extends StatelessWidget {
|
|||
});
|
||||
}
|
||||
|
||||
_addressController
|
||||
.addListener(() => nodeViewModel.address = _addressController.text);
|
||||
_portController
|
||||
.addListener(() => nodeViewModel.port = _portController.text);
|
||||
_loginController
|
||||
.addListener(() => nodeViewModel.login = _loginController.text);
|
||||
_passwordController
|
||||
.addListener(() => nodeViewModel.password = _passwordController.text);
|
||||
_addressController.addListener(() => nodeViewModel.address = _addressController.text);
|
||||
_portController.addListener(() => nodeViewModel.port = _portController.text);
|
||||
_loginController.addListener(() => nodeViewModel.login = _loginController.text);
|
||||
_passwordController.addListener(() => nodeViewModel.password = _passwordController.text);
|
||||
}
|
||||
|
||||
final NodeCreateOrEditViewModel nodeViewModel;
|
||||
final GlobalKey<FormState> formKey;
|
||||
final Node? editingNode;
|
||||
|
||||
final TextEditingController _addressController;
|
||||
final TextEditingController _portController;
|
||||
|
@ -84,8 +80,7 @@ class NodeForm extends StatelessWidget {
|
|||
child: BaseTextFormField(
|
||||
controller: _portController,
|
||||
hintText: S.of(context).node_port,
|
||||
keyboardType: TextInputType.numberWithOptions(
|
||||
signed: false, decimal: false),
|
||||
keyboardType: TextInputType.numberWithOptions(signed: false, decimal: false),
|
||||
validator: NodePortValidator(),
|
||||
))
|
||||
],
|
||||
|
|
219
lib/src/screens/receive/anonpay_invoice_page.dart
Normal file
219
lib/src/screens/receive/anonpay_invoice_page.dart
Normal file
|
@ -0,0 +1,219 @@
|
|||
import 'package:cake_wallet/anonpay/anonpay_donation_link_info.dart';
|
||||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cake_wallet/entities/receive_page_option.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/present_receive_option_picker.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/widgets/anonpay_input_form.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||
import 'package:cake_wallet/view_model/anon_invoice_page_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:keyboard_actions/keyboard_actions.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/trail_button.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class AnonPayInvoicePage extends BasePage {
|
||||
AnonPayInvoicePage(
|
||||
this.anonInvoicePageViewModel,
|
||||
this.receiveOptionViewModel,
|
||||
) : _amountFocusNode = FocusNode() {
|
||||
}
|
||||
|
||||
final _nameController = TextEditingController();
|
||||
final _emailController = TextEditingController();
|
||||
final _descriptionController = TextEditingController();
|
||||
final _amountController = TextEditingController();
|
||||
final FocusNode _amountFocusNode;
|
||||
|
||||
final AnonInvoicePageViewModel anonInvoicePageViewModel;
|
||||
final ReceiveOptionViewModel receiveOptionViewModel;
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
|
||||
bool effectsInstalled = false;
|
||||
@override
|
||||
Color get titleColor => Colors.white;
|
||||
|
||||
@override
|
||||
bool get resizeToAvoidBottomInset => false;
|
||||
|
||||
@override
|
||||
bool get extendBodyBehindAppBar => true;
|
||||
|
||||
@override
|
||||
AppBarStyle get appBarStyle => AppBarStyle.transparent;
|
||||
|
||||
@override
|
||||
Widget middle(BuildContext context) =>
|
||||
PresentReceiveOptionPicker(receiveOptionViewModel: receiveOptionViewModel);
|
||||
|
||||
@override
|
||||
Widget trailing(BuildContext context) => TrailButton(
|
||||
caption: S.of(context).clear,
|
||||
onPressed: () {
|
||||
_formKey.currentState?.reset();
|
||||
anonInvoicePageViewModel.reset();
|
||||
});
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => _setReactions(context));
|
||||
|
||||
return KeyboardActions(
|
||||
disableScroll: true,
|
||||
config: KeyboardActionsConfig(
|
||||
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
|
||||
keyboardBarColor: Theme.of(context).accentTextTheme.bodyText1!.backgroundColor!,
|
||||
nextFocus: false,
|
||||
actions: [
|
||||
KeyboardActionsItem(
|
||||
focusNode: _amountFocusNode,
|
||||
toolbarButtons: [(_) => KeyboardDoneButton()],
|
||||
),
|
||||
]),
|
||||
child: Container(
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(bottom: 24),
|
||||
content: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
Theme.of(context).primaryTextTheme.subtitle2!.color!,
|
||||
Theme.of(context).primaryTextTheme.subtitle2!.decorationColor!,
|
||||
],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
),
|
||||
child: Observer(builder: (_) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.fromLTRB(24, 100, 24, 0),
|
||||
child: AnonInvoiceForm(
|
||||
nameController: _nameController,
|
||||
descriptionController: _descriptionController,
|
||||
amountController: _amountController,
|
||||
emailController: _emailController,
|
||||
depositAmountFocus: _amountFocusNode,
|
||||
formKey: _formKey,
|
||||
isInvoice: receiveOptionViewModel.selectedReceiveOption ==
|
||||
ReceivePageOption.anonPayInvoice,
|
||||
anonInvoicePageViewModel: anonInvoicePageViewModel,
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||
bottomSection: Observer(builder: (_) {
|
||||
final isInvoice =
|
||||
receiveOptionViewModel.selectedReceiveOption == ReceivePageOption.anonPayInvoice;
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(bottom: 15),
|
||||
child: Center(
|
||||
child: Text(
|
||||
isInvoice
|
||||
? S.of(context).anonpay_description("an invoice", "pay")
|
||||
: S.of(context).anonpay_description("a donation link", "donate"),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.headline1!.decorationColor!,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 12),
|
||||
),
|
||||
),
|
||||
),
|
||||
LoadingPrimaryButton(
|
||||
text:
|
||||
isInvoice ? S.of(context).create_invoice : S.of(context).create_donation_link,
|
||||
onPressed: () {
|
||||
anonInvoicePageViewModel.setRequestParams(
|
||||
inputAmount: _amountController.text,
|
||||
inputName: _nameController.text,
|
||||
inputEmail: _emailController.text,
|
||||
inputDescription: _descriptionController.text,
|
||||
);
|
||||
if (anonInvoicePageViewModel.receipientEmail.isNotEmpty &&
|
||||
_formKey.currentState != null &&
|
||||
!_formKey.currentState!.validate()) {
|
||||
return;
|
||||
}
|
||||
if (isInvoice) {
|
||||
anonInvoicePageViewModel.createInvoice();
|
||||
} else {
|
||||
anonInvoicePageViewModel.generateDonationLink();
|
||||
}
|
||||
},
|
||||
color: Theme.of(context).accentTextTheme.bodyText1!.color!,
|
||||
textColor: Colors.white,
|
||||
isLoading: anonInvoicePageViewModel.state is IsExecutingState,
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _setReactions(BuildContext context) {
|
||||
if (effectsInstalled) {
|
||||
return;
|
||||
}
|
||||
|
||||
reaction((_) => receiveOptionViewModel.selectedReceiveOption, (ReceivePageOption option) {
|
||||
Navigator.pop(context);
|
||||
switch (option) {
|
||||
case ReceivePageOption.mainnet:
|
||||
Navigator.popAndPushNamed(context, Routes.addressPage);
|
||||
break;
|
||||
case ReceivePageOption.anonPayDonationLink:
|
||||
final sharedPreferences = getIt.get<SharedPreferences>();
|
||||
final clearnetUrl = sharedPreferences.getString(PreferencesKey.clearnetDonationLink);
|
||||
final onionUrl = sharedPreferences.getString(PreferencesKey.onionDonationLink);
|
||||
|
||||
if (clearnetUrl != null && onionUrl != null) {
|
||||
Navigator.pushReplacementNamed(context, Routes.anonPayReceivePage,
|
||||
arguments: AnonpayDonationLinkInfo(
|
||||
clearnetUrl: clearnetUrl,
|
||||
onionUrl: onionUrl,
|
||||
address: anonInvoicePageViewModel.address,
|
||||
));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => anonInvoicePageViewModel.state, (ExecutionState state) {
|
||||
if (state is ExecutedSuccessfullyState) {
|
||||
Navigator.pushNamed(context, Routes.anonPayReceivePage, arguments: state.payload);
|
||||
}
|
||||
if (state is FailureState) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.of(context).error,
|
||||
alertContent: state.error.toString(),
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
effectsInstalled = true;
|
||||
}
|
||||
}
|
181
lib/src/screens/receive/anonpay_receive_page.dart
Normal file
181
lib/src/screens/receive/anonpay_receive_page.dart
Normal file
|
@ -0,0 +1,181 @@
|
|||
import 'package:cake_wallet/anonpay/anonpay_info_base.dart';
|
||||
import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
|
||||
import 'package:cake_wallet/entities/receive_page_option.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/widgets/anonpay_status_section.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/widgets/qr_image.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/widgets/copy_link_item.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:device_display_brightness/device_display_brightness.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:qr_flutter/qr_flutter.dart' as qr;
|
||||
|
||||
class AnonPayReceivePage extends BasePage {
|
||||
final AnonpayInfoBase invoiceInfo;
|
||||
|
||||
AnonPayReceivePage({required this.invoiceInfo});
|
||||
|
||||
@override
|
||||
String get title => S.current.receive;
|
||||
|
||||
@override
|
||||
Color get backgroundLightColor =>
|
||||
currentTheme.type == ThemeType.bright ? Colors.transparent : Colors.white;
|
||||
|
||||
@override
|
||||
Color get backgroundDarkColor => Colors.transparent;
|
||||
|
||||
@override
|
||||
bool get resizeToAvoidBottomInset => false;
|
||||
|
||||
@override
|
||||
Widget leading(BuildContext context) {
|
||||
final _backButton = Icon(
|
||||
Icons.arrow_back_ios,
|
||||
color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!,
|
||||
size: 16,
|
||||
);
|
||||
|
||||
return SizedBox(
|
||||
height: 37,
|
||||
width: 37,
|
||||
child: ButtonTheme(
|
||||
minWidth: double.minPositive,
|
||||
child: TextButton(
|
||||
onPressed: () =>
|
||||
Navigator.pushNamedAndRemoveUntil(context, Routes.dashboard, (route) => false),
|
||||
child: _backButton),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget middle(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 18.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Lato',
|
||||
color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!),
|
||||
),
|
||||
Text(
|
||||
invoiceInfo is AnonpayInvoiceInfo
|
||||
? ReceivePageOption.anonPayInvoice.toString()
|
||||
: ReceivePageOption.anonPayDonationLink.toString(),
|
||||
style: TextStyle(
|
||||
fontSize: 10.0,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).textTheme.headline5!.color!),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget? trailing(BuildContext context) {
|
||||
if (invoiceInfo is AnonpayInvoiceInfo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
child: IconButton(
|
||||
onPressed: () => Navigator.popAndPushNamed(
|
||||
context,
|
||||
Routes.anonPayInvoicePage,
|
||||
arguments: [invoiceInfo.address, ReceivePageOption.anonPayDonationLink],
|
||||
),
|
||||
icon: Icon(
|
||||
Icons.edit,
|
||||
color: Theme.of(context).accentTextTheme.caption!.color!,
|
||||
size: 22.0,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget Function(BuildContext, Widget) get rootWrapper =>
|
||||
(BuildContext context, Widget scaffold) => Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(colors: [
|
||||
Theme.of(context).accentColor,
|
||||
Theme.of(context).scaffoldBackgroundColor,
|
||||
Theme.of(context).primaryColor,
|
||||
], begin: Alignment.topRight, end: Alignment.bottomLeft)),
|
||||
child: scaffold);
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
SizedBox(height: 24),
|
||||
if (invoiceInfo is AnonpayInvoiceInfo)
|
||||
AnonInvoiceStatusSection(invoiceInfo: invoiceInfo as AnonpayInvoiceInfo),
|
||||
Padding(
|
||||
padding: EdgeInsets.fromLTRB(24, 50, 24, 24),
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: MediaQuery.of(context).size.width * 0.5,
|
||||
),
|
||||
child: GestureDetector(
|
||||
onTap: () async {
|
||||
final double brightness = await DeviceDisplayBrightness.getBrightness();
|
||||
|
||||
// ignore: unawaited_futures
|
||||
DeviceDisplayBrightness.setBrightness(1.0);
|
||||
await Navigator.pushNamed(
|
||||
context,
|
||||
Routes.fullscreenQR,
|
||||
arguments: {
|
||||
'qrData': invoiceInfo.clearnetUrl,
|
||||
'version': qr.QrVersions.auto,
|
||||
},
|
||||
);
|
||||
// ignore: unawaited_futures
|
||||
DeviceDisplayBrightness.setBrightness(brightness);
|
||||
},
|
||||
child: Hero(
|
||||
tag: Key(invoiceInfo.clearnetUrl),
|
||||
child: Center(
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1.0,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(5),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 3,
|
||||
color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!,
|
||||
),
|
||||
),
|
||||
child: QrImage(
|
||||
data: invoiceInfo.clearnetUrl,
|
||||
version: qr.QrVersions.auto,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 24),
|
||||
Column(
|
||||
children: [
|
||||
CopyLinkItem(url: invoiceInfo.clearnetUrl, title: S.of(context).clearnet_link),
|
||||
SizedBox(height: 16),
|
||||
CopyLinkItem(url: invoiceInfo.onionUrl, title: S.of(context).onion_link),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 100),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -4,10 +4,10 @@ import 'package:flutter/material.dart';
|
|||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
|
||||
class FullscreenQRPage extends BasePage {
|
||||
FullscreenQRPage({required this.qrData, required this.isLight});
|
||||
FullscreenQRPage({required this.qrData, int? this.version});
|
||||
|
||||
final bool isLight;
|
||||
final String qrData;
|
||||
final int? version;
|
||||
|
||||
@override
|
||||
Color get backgroundLightColor => currentTheme.type == ThemeType.bright ? Colors.transparent : Colors.white;
|
||||
|
@ -71,7 +71,7 @@ class FullscreenQRPage extends BasePage {
|
|||
padding: EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(width: 3, color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!)),
|
||||
child: QrImage(data: qrData),
|
||||
child: QrImage(data: qrData, version: version),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cw_core/currency.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class AnonpayCurrencyInputField extends StatelessWidget {
|
||||
const AnonpayCurrencyInputField(
|
||||
{super.key,
|
||||
required this.onTapPicker,
|
||||
required this.selectedCurrency,
|
||||
required this.focusNode,
|
||||
required this.controller,
|
||||
required this.minAmount,
|
||||
required this.maxAmount});
|
||||
final Function() onTapPicker;
|
||||
final Currency selectedCurrency;
|
||||
final FocusNode focusNode;
|
||||
final TextEditingController controller;
|
||||
final String minAmount;
|
||||
final String maxAmount;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final arrowBottomPurple = Image.asset(
|
||||
'assets/images/arrow_bottom_purple_icon.png',
|
||||
color: Colors.white,
|
||||
height: 8,
|
||||
);
|
||||
return Column(
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: Theme.of(context).accentTextTheme.headline6!.backgroundColor!,
|
||||
width: 1)),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.only(right: 8),
|
||||
height: 32,
|
||||
child: InkWell(
|
||||
onTap: onTapPicker,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(right: 5),
|
||||
child: arrowBottomPurple,
|
||||
),
|
||||
Text(selectedCurrency.name.toUpperCase(),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600, fontSize: 16, color: Colors.white))
|
||||
]),
|
||||
),
|
||||
),
|
||||
selectedCurrency.tag != null
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(right: 3.0),
|
||||
child: Container(
|
||||
height: 32,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).primaryTextTheme.headline4!.color!,
|
||||
borderRadius: BorderRadius.all(Radius.circular(6))),
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(6.0),
|
||||
child: Text(
|
||||
selectedCurrency.tag!,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.headline4!
|
||||
.decorationColor!,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: Container(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 4.0),
|
||||
child: Text(':',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600, fontSize: 16, color: Colors.white)),
|
||||
),
|
||||
Expanded(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Flexible(
|
||||
child: BaseTextFormField(
|
||||
focusNode: focusNode,
|
||||
controller: controller,
|
||||
textInputAction: TextInputAction.next,
|
||||
enabled: true,
|
||||
textAlign: TextAlign.left,
|
||||
keyboardType:
|
||||
TextInputType.numberWithOptions(signed: false, decimal: true),
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.deny(RegExp('[\\-|\\ ]'))
|
||||
],
|
||||
hintText: '0.0000',
|
||||
borderColor: Colors.transparent,
|
||||
//widget.borderColor,
|
||||
textStyle: TextStyle(
|
||||
fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
|
||||
placeholderTextStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).accentTextTheme.headline1!.decorationColor!,
|
||||
),
|
||||
validator: null,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)),
|
||||
Container(
|
||||
height: 15,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.of(context).min_value(minAmount, selectedCurrency.toString()),
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
height: 1.2,
|
||||
color: Theme.of(context).accentTextTheme.headline1!.decorationColor!),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Text(S.of(context).max_value(maxAmount, selectedCurrency.toString()),
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
height: 1.2,
|
||||
color: Theme.of(context).accentTextTheme.headline1!.decorationColor!)),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
137
lib/src/screens/receive/widgets/anonpay_input_form.dart
Normal file
137
lib/src/screens/receive/widgets/anonpay_input_form.dart
Normal file
|
@ -0,0 +1,137 @@
|
|||
import 'package:cake_wallet/core/email_validator.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/widgets/currency_picker.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/widgets/anonpay_currency_input_field.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/typography.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/anon_invoice_page_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
||||
class AnonInvoiceForm extends StatelessWidget {
|
||||
AnonInvoiceForm({
|
||||
super.key,
|
||||
required this.formKey,
|
||||
required this.anonInvoicePageViewModel,
|
||||
required this.isInvoice,
|
||||
required this.amountController,
|
||||
required this.nameController,
|
||||
required this.emailController,
|
||||
required this.descriptionController,
|
||||
required this.depositAmountFocus,
|
||||
}) : _nameFocusNode = FocusNode(),
|
||||
_emailFocusNode = FocusNode(),
|
||||
_descriptionFocusNode = FocusNode(){
|
||||
amountController.text = anonInvoicePageViewModel.amount;
|
||||
nameController.text = anonInvoicePageViewModel.receipientName;
|
||||
descriptionController.text = anonInvoicePageViewModel.description;
|
||||
emailController.text = anonInvoicePageViewModel.receipientEmail;
|
||||
}
|
||||
|
||||
final TextEditingController amountController;
|
||||
final TextEditingController nameController;
|
||||
final TextEditingController emailController;
|
||||
final TextEditingController descriptionController;
|
||||
final AnonInvoicePageViewModel anonInvoicePageViewModel;
|
||||
final FocusNode depositAmountFocus;
|
||||
final FocusNode _nameFocusNode;
|
||||
final FocusNode _emailFocusNode;
|
||||
final FocusNode _descriptionFocusNode;
|
||||
final GlobalKey<FormState> formKey;
|
||||
final bool isInvoice;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Form(
|
||||
key: formKey,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
isInvoice ? S.of(context).invoice_details : S.of(context).donation_link_details,
|
||||
style: textMediumSemiBold(),
|
||||
),
|
||||
if (isInvoice)
|
||||
Observer(builder: (_) {
|
||||
return AnonpayCurrencyInputField(
|
||||
onTapPicker: () => _presentPicker(context),
|
||||
controller: amountController,
|
||||
focusNode: depositAmountFocus,
|
||||
maxAmount: anonInvoicePageViewModel.maximum?.toString() ?? '...',
|
||||
minAmount: anonInvoicePageViewModel.minimum?.toString() ?? '...',
|
||||
selectedCurrency: anonInvoicePageViewModel.selectedCurrency,
|
||||
);
|
||||
}),
|
||||
SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
BaseTextFormField(
|
||||
controller: nameController,
|
||||
focusNode: _nameFocusNode,
|
||||
borderColor: Theme.of(context).accentTextTheme.headline6!.backgroundColor,
|
||||
suffixIcon: SizedBox(width: 36),
|
||||
hintText: S.of(context).optional_name,
|
||||
textInputAction: TextInputAction.next,
|
||||
placeholderTextStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).accentTextTheme.headline1!.decorationColor!,
|
||||
),
|
||||
textStyle: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
|
||||
validator: null,
|
||||
),
|
||||
SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
BaseTextFormField(
|
||||
controller: descriptionController,
|
||||
focusNode: _descriptionFocusNode,
|
||||
textInputAction: TextInputAction.next,
|
||||
borderColor: Theme.of(context).accentTextTheme.headline6!.backgroundColor,
|
||||
suffixIcon: SizedBox(width: 36),
|
||||
hintText: S.of(context).optional_description,
|
||||
placeholderTextStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).accentTextTheme.headline1!.decorationColor!,
|
||||
),
|
||||
textStyle: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
|
||||
validator: null,
|
||||
),
|
||||
SizedBox(height: 24),
|
||||
BaseTextFormField(
|
||||
controller: emailController,
|
||||
textInputAction: TextInputAction.next,
|
||||
focusNode: _emailFocusNode,
|
||||
borderColor: Theme.of(context).accentTextTheme.headline6!.backgroundColor,
|
||||
suffixIcon: SizedBox(width: 36),
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
hintText: S.of(context).optional_email_hint,
|
||||
placeholderTextStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).accentTextTheme.headline1!.decorationColor!,
|
||||
),
|
||||
textStyle: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
|
||||
validator: EmailValidator(),
|
||||
),
|
||||
SizedBox(
|
||||
height: 52,
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
|
||||
void _presentPicker(BuildContext context) {
|
||||
showPopUp<void>(
|
||||
builder: (_) => CurrencyPicker(
|
||||
selectedAtIndex: anonInvoicePageViewModel.selectedCurrencyIndex,
|
||||
items: anonInvoicePageViewModel.currencies,
|
||||
hintText: S.of(context).search_currency,
|
||||
onItemSelected: anonInvoicePageViewModel.selectCurrency,
|
||||
),
|
||||
context: context,
|
||||
);
|
||||
}
|
||||
}
|
87
lib/src/screens/receive/widgets/anonpay_status_section.dart
Normal file
87
lib/src/screens/receive/widgets/anonpay_status_section.dart
Normal file
|
@ -0,0 +1,87 @@
|
|||
import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator_icon.dart';
|
||||
import 'package:cake_wallet/typography.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AnonInvoiceStatusSection extends StatelessWidget {
|
||||
const AnonInvoiceStatusSection({
|
||||
super.key,
|
||||
required this.invoiceInfo,
|
||||
});
|
||||
|
||||
final AnonpayInvoiceInfo invoiceInfo;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: 200,
|
||||
padding: EdgeInsets.all(19),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).backgroundColor,
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
S.current.status,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).primaryTextTheme.headline1!.decorationColor!,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).accentTextTheme.headline3!.color!,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SyncIndicatorIcon(
|
||||
boolMode: false,
|
||||
value: invoiceInfo.status ?? '',
|
||||
size: 6,
|
||||
),
|
||||
SizedBox(width: 5),
|
||||
Text(
|
||||
invoiceInfo.status ?? '',
|
||||
style: textSmallSemiBold(
|
||||
color: Theme.of(context).primaryTextTheme.headline6!.color,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(height: 27),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'ID',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).primaryTextTheme.headline1!.decorationColor!,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
invoiceInfo.invoiceId ?? '',
|
||||
style: textSmallSemiBold(
|
||||
color: Theme.of(context).primaryTextTheme.headline6!.color,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
56
lib/src/screens/receive/widgets/copy_link_item.dart
Normal file
56
lib/src/screens/receive/widgets/copy_link_item.dart
Normal file
|
@ -0,0 +1,56 @@
|
|||
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/typography.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
|
||||
class CopyLinkItem extends StatelessWidget {
|
||||
const CopyLinkItem({super.key, required this.url, required this.title});
|
||||
final String url;
|
||||
final String title;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final copyImage = Image.asset('assets/images/copy_address.png',
|
||||
color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!);
|
||||
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: textMedium(
|
||||
color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!,
|
||||
),
|
||||
),
|
||||
SizedBox(width: 50),
|
||||
Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Clipboard.setData(ClipboardData(text: url));
|
||||
showBar<void>(context, S.of(context).copied_to_clipboard);
|
||||
},
|
||||
child: copyImage,
|
||||
),
|
||||
SizedBox(width: 20),
|
||||
IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: BoxConstraints(),
|
||||
highlightColor: Colors.transparent,
|
||||
splashColor: Colors.transparent,
|
||||
iconSize: 25,
|
||||
onPressed: () => Share.share(url),
|
||||
icon: Icon(
|
||||
Icons.share,
|
||||
color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!,
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -5,13 +5,13 @@ class QrImage extends StatelessWidget {
|
|||
QrImage({
|
||||
required this.data,
|
||||
this.size = 100.0,
|
||||
this.version = 9, // Previous value: 7 something happened after flutter upgrade monero wallets addresses are longer than ver. 7 ???
|
||||
this.version,
|
||||
this.errorCorrectionLevel = qr.QrErrorCorrectLevel.L,
|
||||
});
|
||||
|
||||
final double size;
|
||||
final String data;
|
||||
final int version;
|
||||
final int? version;
|
||||
final int errorCorrectionLevel;
|
||||
|
||||
@override
|
||||
|
@ -19,7 +19,7 @@ class QrImage extends StatelessWidget {
|
|||
return qr.QrImage(
|
||||
data: data,
|
||||
errorCorrectionLevel: errorCorrectionLevel,
|
||||
version: version,
|
||||
version: version ?? 9, // Previous value: 7 something happened after flutter upgrade monero wallets addresses are longer than ver. 7 ???
|
||||
size: size,
|
||||
foregroundColor: Colors.black,
|
||||
backgroundColor: Colors.white,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:device_display_brightness/device_display_brightness.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
@ -15,11 +15,12 @@ class QRWidget extends StatelessWidget {
|
|||
QRWidget(
|
||||
{required this.addressListViewModel,
|
||||
required this.isLight,
|
||||
this.qrVersion,
|
||||
this.isAmountFieldShow = false,
|
||||
this.amountTextFieldFocusNode})
|
||||
: amountController = TextEditingController(),
|
||||
_formKey = GlobalKey<FormState>() {
|
||||
amountController.addListener(() => addressListViewModel.amount =
|
||||
amountController.addListener(() => addressListViewModel?.amount =
|
||||
_formKey.currentState!.validate() ? amountController.text : '');
|
||||
}
|
||||
|
||||
|
@ -29,6 +30,7 @@ class QRWidget extends StatelessWidget {
|
|||
final FocusNode? amountTextFieldFocusNode;
|
||||
final GlobalKey<FormState> _formKey;
|
||||
final bool isLight;
|
||||
final int? qrVersion;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -56,46 +58,48 @@ class QRWidget extends StatelessWidget {
|
|||
children: <Widget>[
|
||||
Spacer(flex: 3),
|
||||
Observer(
|
||||
builder: (_) => Flexible(
|
||||
flex: 5,
|
||||
child: GestureDetector(
|
||||
onTap: () async {
|
||||
// Get the current brightness:
|
||||
final double brightness = await DeviceDisplayBrightness.getBrightness();
|
||||
builder: (_) {
|
||||
return Flexible(
|
||||
flex: 5,
|
||||
child: GestureDetector(
|
||||
onTap: () async {
|
||||
// Get the current brightness:
|
||||
final double brightness = await DeviceDisplayBrightness.getBrightness();
|
||||
|
||||
// ignore: unawaited_futures
|
||||
DeviceDisplayBrightness.setBrightness(1.0);
|
||||
await Navigator.pushNamed(
|
||||
context,
|
||||
Routes.fullscreenQR,
|
||||
arguments: {
|
||||
'qrData': addressListViewModel.uri.toString(),
|
||||
'isLight': isLight,
|
||||
},
|
||||
);
|
||||
// ignore: unawaited_futures
|
||||
DeviceDisplayBrightness.setBrightness(brightness);
|
||||
},
|
||||
child: Hero(
|
||||
tag: Key(addressListViewModel.uri.toString()),
|
||||
child: Center(
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1.0,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(5),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 3,
|
||||
color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!,
|
||||
// ignore: unawaited_futures
|
||||
DeviceDisplayBrightness.setBrightness(1.0);
|
||||
await Navigator.pushNamed(
|
||||
context,
|
||||
Routes.fullscreenQR,
|
||||
arguments: {
|
||||
'qrData': addressListViewModel.uri.toString(),
|
||||
},
|
||||
);
|
||||
// ignore: unawaited_futures
|
||||
DeviceDisplayBrightness.setBrightness(brightness);
|
||||
},
|
||||
child: Hero(
|
||||
tag: Key(addressListViewModel.uri.toString()),
|
||||
child: Center(
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1.0,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(5),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 3,
|
||||
color:
|
||||
Theme.of(context).accentTextTheme!.headline2!.backgroundColor!,
|
||||
),
|
||||
),
|
||||
child: QrImage(data: addressListViewModel.uri.toString(), version: qrVersion),
|
||||
),
|
||||
child: QrImage(data: addressListViewModel.uri.toString()),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
),
|
||||
Spacer(flex: 3)
|
||||
],
|
||||
|
@ -119,7 +123,9 @@ class QRWidget extends StatelessWidget {
|
|||
hintText: S.of(context).receive_amount,
|
||||
textColor: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!,
|
||||
borderColor: Theme.of(context).textTheme!.headline5!.decorationColor!,
|
||||
validator: AmountValidator(type: addressListViewModel.type, isAutovalidate: true),
|
||||
validator: AmountValidator(
|
||||
currency: walletTypeToCryptoCurrency(addressListViewModel!.type),
|
||||
isAutovalidate: true),
|
||||
// FIX-ME: Check does it equal to autovalidate: true,
|
||||
autovalidateMode: AutovalidateMode.always,
|
||||
placeholderTextStyle: TextStyle(
|
||||
|
@ -133,39 +139,40 @@ class QRWidget extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 8, bottom: 8),
|
||||
child: Builder(
|
||||
builder: (context) => Observer(
|
||||
builder: (context) => GestureDetector(
|
||||
onTap: () {
|
||||
Clipboard.setData(ClipboardData(text: addressListViewModel.address.address));
|
||||
showBar<void>(context, S.of(context).copied_to_clipboard);
|
||||
},
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
addressListViewModel.address.address,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 8, bottom: 8),
|
||||
child: Builder(
|
||||
builder: (context) => Observer(
|
||||
builder: (context) => GestureDetector(
|
||||
onTap: () {
|
||||
Clipboard.setData(ClipboardData(text: addressListViewModel!.address.address));
|
||||
showBar<void>(context, S.of(context).copied_to_clipboard);
|
||||
},
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
addressListViewModel!.address.address,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w500,
|
||||
color:
|
||||
Theme.of(context).accentTextTheme!.headline2!.backgroundColor!),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 12),
|
||||
child: copyImage,
|
||||
)
|
||||
],
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 12),
|
||||
child: copyImage,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arro
|
|||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
@ -90,12 +89,12 @@ class ConnectionSyncPage extends BasePage {
|
|||
|
||||
final dismissibleRow = Slidable(
|
||||
key: Key('${node.keyIndex}'),
|
||||
startActionPane: _actionPane(context, node),
|
||||
endActionPane: _actionPane(context, node),
|
||||
startActionPane: _actionPane(context, node, isSelected),
|
||||
endActionPane: _actionPane(context, node, isSelected),
|
||||
child: nodeListRow,
|
||||
);
|
||||
|
||||
return isSelected ? nodeListRow : dismissibleRow;
|
||||
return dismissibleRow;
|
||||
},
|
||||
),
|
||||
);
|
||||
|
@ -124,33 +123,42 @@ class ConnectionSyncPage extends BasePage {
|
|||
);
|
||||
}
|
||||
|
||||
ActionPane _actionPane(BuildContext context, Node node) => ActionPane(
|
||||
ActionPane _actionPane(BuildContext context, Node node, bool isSelected) => ActionPane(
|
||||
motion: const ScrollMotion(),
|
||||
extentRatio: 0.3,
|
||||
extentRatio: isSelected ? 0.3 : 0.6,
|
||||
children: [
|
||||
SlidableAction(
|
||||
onPressed: (context) async {
|
||||
final confirmed = await showPopUp<bool>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).remove_node,
|
||||
alertContent: S.of(context).remove_node_message,
|
||||
rightButtonText: S.of(context).remove,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
actionRightButton: () => Navigator.pop(context, true),
|
||||
actionLeftButton: () => Navigator.pop(context, false));
|
||||
}) ??
|
||||
false;
|
||||
if (!isSelected)
|
||||
SlidableAction(
|
||||
onPressed: (context) async {
|
||||
final confirmed = await showPopUp<bool>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).remove_node,
|
||||
alertContent: S.of(context).remove_node_message,
|
||||
rightButtonText: S.of(context).remove,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
actionRightButton: () => Navigator.pop(context, true),
|
||||
actionLeftButton: () => Navigator.pop(context, false));
|
||||
}) ??
|
||||
false;
|
||||
|
||||
if (confirmed) {
|
||||
await nodeListViewModel.delete(node);
|
||||
}
|
||||
},
|
||||
backgroundColor: Colors.red,
|
||||
if (confirmed) {
|
||||
await nodeListViewModel.delete(node);
|
||||
}
|
||||
},
|
||||
backgroundColor: Colors.red,
|
||||
foregroundColor: Colors.white,
|
||||
icon: CupertinoIcons.delete,
|
||||
label: S.of(context).delete,
|
||||
),
|
||||
SlidableAction(
|
||||
onPressed: (_) => Navigator.of(context).pushNamed(Routes.newNode,
|
||||
arguments: {'editingNode': node, 'isSelected': isSelected}),
|
||||
backgroundColor: Colors.blue,
|
||||
foregroundColor: Colors.white,
|
||||
icon: CupertinoIcons.delete,
|
||||
label: S.of(context).delete,
|
||||
icon: Icons.edit,
|
||||
label: S.of(context).edit,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
|
|
@ -27,26 +27,22 @@ class SecurityBackupPage extends BasePage {
|
|||
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.show_keys,
|
||||
handler: (_) => _securitySettingsViewModel.checkPinCodeRiquired()
|
||||
? Navigator.of(context).pushNamed(Routes.auth,
|
||||
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
|
||||
if (isAuthenticatedSuccessfully) {
|
||||
auth.close(route: Routes.showKeys);
|
||||
}
|
||||
})
|
||||
: Navigator.of(context).pushNamed(Routes.showKeys),
|
||||
handler: (_) => Navigator.of(context).pushNamed(Routes.auth,
|
||||
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
|
||||
if (isAuthenticatedSuccessfully) {
|
||||
auth.close(route: Routes.showKeys);
|
||||
}
|
||||
}),
|
||||
),
|
||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.create_backup,
|
||||
handler: (_) => _securitySettingsViewModel.checkPinCodeRiquired()
|
||||
? Navigator.of(context).pushNamed(Routes.auth,
|
||||
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
|
||||
if (isAuthenticatedSuccessfully) {
|
||||
auth.close(route: Routes.backup);
|
||||
}
|
||||
})
|
||||
: Navigator.of(context).pushNamed(Routes.backup),
|
||||
handler: (_) => Navigator.of(context).pushNamed(Routes.auth,
|
||||
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
|
||||
if (isAuthenticatedSuccessfully) {
|
||||
auth.close(route: Routes.backup);
|
||||
}
|
||||
}),
|
||||
),
|
||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
SettingsCellWithArrow(
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:auto_size_text/auto_size_text.dart';
|
||||
import 'package:cake_wallet/src/widgets/section_divider.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:device_display_brightness/device_display_brightness.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
@ -9,6 +10,7 @@ import 'package:cake_wallet/generated/i18n.dart';
|
|||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/list_row.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_keys_view_model.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
|
||||
class WalletKeysPage extends BasePage {
|
||||
WalletKeysPage(this.walletKeysViewModel);
|
||||
|
@ -18,6 +20,31 @@ class WalletKeysPage extends BasePage {
|
|||
|
||||
final WalletKeysViewModel walletKeysViewModel;
|
||||
|
||||
@override
|
||||
Widget trailing(BuildContext context) => IconButton(
|
||||
onPressed: () async {
|
||||
// Get the current brightness:
|
||||
final double brightness = await DeviceDisplayBrightness.getBrightness();
|
||||
|
||||
// ignore: unawaited_futures
|
||||
DeviceDisplayBrightness.setBrightness(1.0);
|
||||
await Navigator.pushNamed(
|
||||
context,
|
||||
Routes.fullscreenQR,
|
||||
arguments: {
|
||||
'qrData': (await walletKeysViewModel.url).toString(),
|
||||
},
|
||||
);
|
||||
// ignore: unawaited_futures
|
||||
DeviceDisplayBrightness.setBrightness(brightness);
|
||||
},
|
||||
splashColor: Colors.transparent,
|
||||
highlightColor: Colors.transparent,
|
||||
hoverColor: Colors.transparent,
|
||||
icon: Image.asset(
|
||||
'assets/images/qr_code_icon.png',
|
||||
));
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Column(
|
||||
|
|
|
@ -56,6 +56,8 @@ class AddressTextField extends StatelessWidget {
|
|||
return Stack(
|
||||
children: <Widget>[
|
||||
TextFormField(
|
||||
enableIMEPersonalizedLearning: false,
|
||||
keyboardType: TextInputType.visiblePassword,
|
||||
onFieldSubmitted: (_) => FocusScope.of(context).unfocus(),
|
||||
enabled: isActive,
|
||||
controller: controller,
|
||||
|
|
34
lib/store/anonpay/anonpay_transactions_store.dart
Normal file
34
lib/store/anonpay/anonpay_transactions_store.dart
Normal file
|
@ -0,0 +1,34 @@
|
|||
import 'dart:async';
|
||||
import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/anonpay_transaction_list_item.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
part 'anonpay_transactions_store.g.dart';
|
||||
|
||||
class AnonpayTransactionsStore = AnonpayTransactionsStoreBase with _$AnonpayTransactionsStore;
|
||||
|
||||
abstract class AnonpayTransactionsStoreBase with Store {
|
||||
AnonpayTransactionsStoreBase({
|
||||
required this.anonpayInvoiceInfoSource,
|
||||
}) : transactions = <AnonpayTransactionListItem>[] {
|
||||
anonpayInvoiceInfoSource.watch().listen(
|
||||
(_) async => await updateTransactionList(),
|
||||
);
|
||||
updateTransactionList();
|
||||
}
|
||||
|
||||
Box<AnonpayInvoiceInfo> anonpayInvoiceInfoSource;
|
||||
|
||||
@observable
|
||||
List<AnonpayTransactionListItem> transactions;
|
||||
|
||||
@action
|
||||
Future<void> updateTransactionList() async {
|
||||
transactions = anonpayInvoiceInfoSource.values
|
||||
.map(
|
||||
(transaction) => AnonpayTransactionListItem(transaction: transaction),
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/anonpay_transaction_list_item.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cw_core/transaction_direction.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/filter_item.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
part 'transaction_filter_store.g.dart';
|
||||
|
||||
|
@ -57,8 +57,8 @@ abstract class TransactionFilterStoreBase with Store {
|
|||
@action
|
||||
void changeEndDate(DateTime date) => endDate = date;
|
||||
|
||||
List<TransactionListItem> filtered({required List<TransactionListItem> transactions}) {
|
||||
var _transactions = <TransactionListItem>[];
|
||||
List<ActionListItem> filtered({required List<ActionListItem> transactions}) {
|
||||
var _transactions = <ActionListItem>[];
|
||||
final needToFilter = !displayAll ||
|
||||
(startDate != null && endDate != null);
|
||||
|
||||
|
@ -67,16 +67,26 @@ abstract class TransactionFilterStoreBase with Store {
|
|||
var allowed = true;
|
||||
|
||||
if (allowed && startDate != null && endDate != null) {
|
||||
if(item is TransactionListItem){
|
||||
allowed = (startDate?.isBefore(item.transaction.date) ?? false)
|
||||
&& (endDate?.isAfter(item.transaction.date) ?? false);
|
||||
}else if(item is AnonpayTransactionListItem){
|
||||
allowed = (startDate?.isBefore(item.transaction.createdAt) ?? false)
|
||||
&& (endDate?.isAfter(item.transaction.createdAt) ?? false);
|
||||
}
|
||||
}
|
||||
|
||||
if (allowed && (!displayAll)) {
|
||||
if(item is TransactionListItem){
|
||||
allowed = (displayOutgoing &&
|
||||
item.transaction.direction ==
|
||||
TransactionDirection.outgoing) ||
|
||||
(displayIncoming &&
|
||||
item.transaction.direction == TransactionDirection.incoming);
|
||||
} else if(item is AnonpayTransactionListItem){
|
||||
allowed = displayIncoming;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return allowed;
|
||||
|
|
|
@ -17,13 +17,14 @@ class ExceptionHandler {
|
|||
static bool _hasError = false;
|
||||
static const _coolDownDurationInDays = 7;
|
||||
|
||||
static void _saveException(String? error, StackTrace? stackTrace) async {
|
||||
static void _saveException(String? error, StackTrace? stackTrace, {String? library}) async {
|
||||
final appDocDir = await getApplicationDocumentsDirectory();
|
||||
|
||||
final file = File('${appDocDir.path}/error.txt');
|
||||
final exception = {
|
||||
"${DateTime.now()}": {
|
||||
"Error": error,
|
||||
"Error": "$error\n\n",
|
||||
"Library": "$library\n\n",
|
||||
"StackTrace": stackTrace.toString(),
|
||||
}
|
||||
};
|
||||
|
@ -31,7 +32,7 @@ class ExceptionHandler {
|
|||
const String separator = '''\n\n==========================================================
|
||||
==========================================================\n\n''';
|
||||
|
||||
await file.writeAsString(
|
||||
file.writeAsStringSync(
|
||||
"$exception $separator",
|
||||
mode: FileMode.append,
|
||||
);
|
||||
|
@ -75,7 +76,11 @@ class ExceptionHandler {
|
|||
return;
|
||||
}
|
||||
|
||||
_saveException(errorDetails.exception.toString(), errorDetails.stack);
|
||||
_saveException(
|
||||
errorDetails.exceptionAsString(),
|
||||
errorDetails.stack,
|
||||
library: errorDetails.library,
|
||||
);
|
||||
|
||||
final sharedPrefs = await SharedPreferences.getInstance();
|
||||
|
||||
|
@ -131,9 +136,13 @@ class ExceptionHandler {
|
|||
"errno = 54", // SocketException: Connection reset by peer
|
||||
"errno = 57", // SocketException: Read failed (OS Error: Socket is not connected)
|
||||
"errno = 60", // SocketException: Operation timed out
|
||||
"errno = 65", // SocketException: No route to host
|
||||
"errno = 103", // SocketException: Software caused connection abort
|
||||
"errno = 104", // SocketException: Connection reset by peer
|
||||
"errno = 110", // SocketException: Connection timed out
|
||||
"HttpException: Connection reset by peer",
|
||||
"HttpException: Connection closed before full header was received",
|
||||
"HandshakeException: Connection terminated during handshake",
|
||||
"PERMISSION_NOT_GRANTED",
|
||||
];
|
||||
|
||||
|
|
|
@ -3,8 +3,6 @@ import 'package:share_plus/share_plus.dart';
|
|||
import 'package:cross_file/cross_file.dart';
|
||||
|
||||
class ShareUtil {
|
||||
static const _mimeType = 'application/*';
|
||||
|
||||
static void share({required String text, required BuildContext context}) {
|
||||
Share.share(
|
||||
text,
|
||||
|
@ -17,7 +15,8 @@ class ShareUtil {
|
|||
required String fileName,
|
||||
required BuildContext context,
|
||||
}) async {
|
||||
Share.shareXFiles(
|
||||
const _mimeType = 'application/*';
|
||||
await Share.shareXFiles(
|
||||
<XFile>[
|
||||
XFile(
|
||||
filePath,
|
||||
|
@ -29,7 +28,11 @@ class ShareUtil {
|
|||
);
|
||||
}
|
||||
|
||||
static Rect? _sharePosition(BuildContext context) {
|
||||
static Rect _sharePosition(BuildContext context) {
|
||||
if (!context.mounted) {
|
||||
return Rect.zero;
|
||||
}
|
||||
|
||||
final box = context.findRenderObject() as RenderBox?;
|
||||
|
||||
return box!.localToGlobal(Offset.zero) & box.size;
|
||||
|
|
186
lib/view_model/anon_invoice_page_view_model.dart
Normal file
186
lib/view_model/anon_invoice_page_view_model.dart
Normal file
|
@ -0,0 +1,186 @@
|
|||
import 'package:cake_wallet/anonpay/anonpay_api.dart';
|
||||
import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
|
||||
import 'package:cake_wallet/anonpay/anonpay_request.dart';
|
||||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cake_wallet/entities/receive_page_option.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/currency.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
part 'anon_invoice_page_view_model.g.dart';
|
||||
|
||||
class AnonInvoicePageViewModel = AnonInvoicePageViewModelBase with _$AnonInvoicePageViewModel;
|
||||
|
||||
abstract class AnonInvoicePageViewModelBase with Store {
|
||||
AnonInvoicePageViewModelBase(
|
||||
this.anonPayApi,
|
||||
this.address,
|
||||
this.settingsStore,
|
||||
this._wallet,
|
||||
this._anonpayInvoiceInfoSource,
|
||||
this.sharedPreferences,
|
||||
this.pageOption,
|
||||
) : receipientEmail = '',
|
||||
receipientName = '',
|
||||
description = '',
|
||||
amount = '',
|
||||
state = InitialExecutionState(),
|
||||
selectedCurrency = walletTypeToCryptoCurrency(_wallet.type),
|
||||
cryptoCurrency = walletTypeToCryptoCurrency(_wallet.type) {
|
||||
_getPreviousDonationLink();
|
||||
_fetchLimits();
|
||||
}
|
||||
|
||||
List<Currency> get currencies => [walletTypeToCryptoCurrency(_wallet.type), ...FiatCurrency.all];
|
||||
final AnonPayApi anonPayApi;
|
||||
final String address;
|
||||
final SettingsStore settingsStore;
|
||||
final WalletBase _wallet;
|
||||
final Box<AnonpayInvoiceInfo> _anonpayInvoiceInfoSource;
|
||||
final SharedPreferences sharedPreferences;
|
||||
final ReceivePageOption pageOption;
|
||||
|
||||
@observable
|
||||
Currency selectedCurrency;
|
||||
|
||||
CryptoCurrency cryptoCurrency;
|
||||
|
||||
@observable
|
||||
String receipientEmail;
|
||||
|
||||
@observable
|
||||
String receipientName;
|
||||
|
||||
@observable
|
||||
String description;
|
||||
|
||||
@observable
|
||||
String amount;
|
||||
|
||||
@observable
|
||||
ExecutionState state;
|
||||
|
||||
@computed
|
||||
int get selectedCurrencyIndex => currencies.indexOf(selectedCurrency);
|
||||
|
||||
@observable
|
||||
double? minimum;
|
||||
|
||||
@observable
|
||||
double? maximum;
|
||||
|
||||
@action
|
||||
void selectCurrency(Currency currency) {
|
||||
selectedCurrency = currency;
|
||||
maximum = minimum = null;
|
||||
if (currency is CryptoCurrency) {
|
||||
cryptoCurrency = currency;
|
||||
} else {
|
||||
cryptoCurrency = walletTypeToCryptoCurrency(_wallet.type);
|
||||
}
|
||||
|
||||
_fetchLimits();
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> createInvoice() async {
|
||||
state = IsExecutingState();
|
||||
if (amount.isNotEmpty) {
|
||||
final amountInCrypto = double.parse(amount);
|
||||
if (minimum != null && amountInCrypto < minimum!) {
|
||||
state = FailureState('Amount is too small');
|
||||
return;
|
||||
}
|
||||
if (maximum != null && amountInCrypto > maximum!) {
|
||||
state = FailureState('Amount is too big');
|
||||
return;
|
||||
}
|
||||
}
|
||||
final result = await anonPayApi.createInvoice(AnonPayRequest(
|
||||
cryptoCurrency: cryptoCurrency,
|
||||
address: address,
|
||||
amount: amount.isEmpty ? null : amount,
|
||||
description: description,
|
||||
email: receipientEmail,
|
||||
name: receipientName,
|
||||
fiatEquivalent:
|
||||
selectedCurrency is FiatCurrency ? (selectedCurrency as FiatCurrency).raw : null,
|
||||
));
|
||||
|
||||
_anonpayInvoiceInfoSource.add(result);
|
||||
|
||||
state = ExecutedSuccessfullyState(payload: result);
|
||||
}
|
||||
|
||||
@action
|
||||
void setRequestParams({
|
||||
required String inputAmount,
|
||||
required String inputName,
|
||||
required String inputEmail,
|
||||
required String inputDescription,
|
||||
}) {
|
||||
receipientName = inputName;
|
||||
receipientEmail = inputEmail;
|
||||
description = inputDescription;
|
||||
amount = inputAmount;
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> generateDonationLink() async {
|
||||
state = IsExecutingState();
|
||||
|
||||
final result = await anonPayApi.generateDonationLink(AnonPayRequest(
|
||||
cryptoCurrency: cryptoCurrency,
|
||||
address: address,
|
||||
description: description,
|
||||
email: receipientEmail,
|
||||
name: receipientName,
|
||||
));
|
||||
|
||||
await sharedPreferences.setString(PreferencesKey.clearnetDonationLink, result.clearnetUrl);
|
||||
await sharedPreferences.setString(PreferencesKey.onionDonationLink, result.onionUrl);
|
||||
|
||||
state = ExecutedSuccessfullyState(payload: result);
|
||||
}
|
||||
|
||||
Future<void> _fetchLimits() async {
|
||||
final limit = await anonPayApi.fetchLimits(
|
||||
cryptoCurrency: cryptoCurrency,
|
||||
fiatCurrency: selectedCurrency is FiatCurrency ? selectedCurrency as FiatCurrency : null,
|
||||
);
|
||||
minimum = limit.min;
|
||||
maximum = limit.max != null ? limit.max! / 4 : null;
|
||||
}
|
||||
|
||||
@action
|
||||
void reset() {
|
||||
selectedCurrency = walletTypeToCryptoCurrency(_wallet.type);
|
||||
cryptoCurrency = walletTypeToCryptoCurrency(_wallet.type);
|
||||
receipientEmail = '';
|
||||
receipientName = '';
|
||||
description = '';
|
||||
amount = '';
|
||||
_fetchLimits();
|
||||
}
|
||||
|
||||
Future<void> _getPreviousDonationLink() async {
|
||||
if (pageOption == ReceivePageOption.anonPayDonationLink) {
|
||||
final donationLink = sharedPreferences.getString(PreferencesKey.clearnetDonationLink);
|
||||
if (donationLink != null) {
|
||||
final url = Uri.parse(donationLink);
|
||||
url.queryParameters.forEach((key, value) {
|
||||
if (key == 'name') receipientName = value;
|
||||
if (key == 'email') receipientEmail = value;
|
||||
if (key == 'description') description = Uri.decodeComponent(value);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
78
lib/view_model/anonpay_details_view_model.dart
Normal file
78
lib/view_model/anonpay_details_view_model.dart
Normal file
|
@ -0,0 +1,78 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:cake_wallet/anonpay/anonpay_api.dart';
|
||||
import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/trade_details/track_trade_list_item.dart';
|
||||
import 'package:cake_wallet/src/screens/trade_details/trade_details_list_card.dart';
|
||||
import 'package:cake_wallet/src/screens/trade_details/trade_details_status_item.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/utils/date_formatter.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
||||
part 'anonpay_details_view_model.g.dart';
|
||||
|
||||
class AnonpayDetailsViewModel = AnonpayDetailsViewModelBase with _$AnonpayDetailsViewModel;
|
||||
|
||||
abstract class AnonpayDetailsViewModelBase with Store {
|
||||
AnonpayDetailsViewModelBase(
|
||||
{required this.anonPayApi,
|
||||
required AnonpayInvoiceInfo anonpayInvoiceInfo,
|
||||
required this.settingsStore})
|
||||
: items = ObservableList<StandartListItem>(),
|
||||
invoiceDetail = anonpayInvoiceInfo {
|
||||
_updateItems();
|
||||
_updateInvoiceDetail();
|
||||
timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateInvoiceDetail());
|
||||
}
|
||||
|
||||
final AnonPayApi anonPayApi;
|
||||
final SettingsStore settingsStore;
|
||||
final AnonpayInvoiceInfo invoiceDetail;
|
||||
|
||||
final ObservableList<StandartListItem> items;
|
||||
|
||||
Timer? timer;
|
||||
|
||||
@action
|
||||
Future<void> _updateInvoiceDetail() async {
|
||||
try {
|
||||
final data = await anonPayApi.paymentStatus(invoiceDetail.invoiceId);
|
||||
invoiceDetail.status = data.status;
|
||||
_updateItems();
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
void _updateItems() {
|
||||
final dateFormat = DateFormatter.withCurrentLocal();
|
||||
items.clear();
|
||||
items.addAll([
|
||||
DetailsListStatusItem(title: S.current.status, value: invoiceDetail.status),
|
||||
TradeDetailsListCardItem(
|
||||
id: invoiceDetail.invoiceId,
|
||||
createdAt: dateFormat.format(invoiceDetail.createdAt).toString(),
|
||||
pair: (invoiceDetail.fiatAmount != null)
|
||||
? "→ ${invoiceDetail.fiatAmount} ${invoiceDetail.fiatEquiv ?? ''}"
|
||||
: '→ ${invoiceDetail.amountTo ?? ''} ${CryptoCurrency.fromFullName(invoiceDetail.coinTo).name.toUpperCase()}',
|
||||
onTap: (BuildContext context) {
|
||||
Clipboard.setData(ClipboardData(text: '${invoiceDetail.invoiceId}'));
|
||||
showBar<void>(context, S.of(context).copied_to_clipboard);
|
||||
},
|
||||
),
|
||||
StandartListItem(title: S.current.trade_details_provider, value: invoiceDetail.provider)
|
||||
]);
|
||||
|
||||
items.add(TrackTradeListItem(
|
||||
title: 'Track',
|
||||
value: invoiceDetail.clearnetStatusUrl,
|
||||
onTap: () => launchUrlString(invoiceDetail.clearnetStatusUrl)));
|
||||
}
|
||||
}
|
11
lib/view_model/dashboard/anonpay_transaction_list_item.dart
Normal file
11
lib/view_model/dashboard/anonpay_transaction_list_item.dart
Normal file
|
@ -0,0 +1,11 @@
|
|||
import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
|
||||
|
||||
class AnonpayTransactionListItem extends ActionListItem {
|
||||
AnonpayTransactionListItem({required this.transaction});
|
||||
|
||||
final AnonpayInvoiceInfo transaction;
|
||||
|
||||
@override
|
||||
DateTime get date => transaction.createdAt;
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||
import 'package:cake_wallet/entities/fiat_api_mode.dart';
|
||||
import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/anonpay_transaction_list_item.dart';
|
||||
import 'package:cake_wallet/wallet_type_utils.dart';
|
||||
import 'package:cw_core/transaction_history.dart';
|
||||
import 'package:cw_core/balance.dart';
|
||||
|
@ -48,7 +50,9 @@ abstract class DashboardViewModelBase with Store {
|
|||
required this.transactionFilterStore,
|
||||
required this.settingsStore,
|
||||
required this.yatStore,
|
||||
required this.ordersStore})
|
||||
required this.ordersStore,
|
||||
required this.anonpayTransactionsStore,
|
||||
})
|
||||
: isOutdatedElectrumWallet = false,
|
||||
hasSellAction = false,
|
||||
isEnabledSellAction = false,
|
||||
|
@ -227,6 +231,11 @@ abstract class DashboardViewModelBase with Store {
|
|||
List<OrderListItem> get orders => ordersStore.orders
|
||||
.where((item) => item.order.walletId == wallet.id)
|
||||
.toList();
|
||||
|
||||
@computed
|
||||
List<AnonpayTransactionListItem> get anonpayTransactons => anonpayTransactionsStore.transactions
|
||||
.where((item) => item.transaction.walletId == wallet.id)
|
||||
.toList();
|
||||
|
||||
@computed
|
||||
double get price => balanceViewModel.price;
|
||||
|
@ -235,7 +244,7 @@ abstract class DashboardViewModelBase with Store {
|
|||
List<ActionListItem> get items {
|
||||
final _items = <ActionListItem>[];
|
||||
|
||||
_items.addAll(transactionFilterStore.filtered(transactions: transactions));
|
||||
_items.addAll(transactionFilterStore.filtered(transactions: [...transactions, ...anonpayTransactons]));
|
||||
_items.addAll(tradeFilterStore.filtered(trades: trades, wallet: wallet));
|
||||
_items.addAll(orders);
|
||||
|
||||
|
@ -262,6 +271,8 @@ abstract class DashboardViewModelBase with Store {
|
|||
|
||||
TradeFilterStore tradeFilterStore;
|
||||
|
||||
AnonpayTransactionsStore anonpayTransactionsStore;
|
||||
|
||||
TransactionFilterStore transactionFilterStore;
|
||||
|
||||
Map<String, List<FilterItem>> filterItems;
|
||||
|
@ -391,12 +402,11 @@ abstract class DashboardViewModelBase with Store {
|
|||
|
||||
void updateActions() {
|
||||
hasExchangeAction = !isHaven;
|
||||
isEnabledBuyAction = wallet.type != WalletType.haven
|
||||
&& wallet.type != WalletType.monero;
|
||||
hasBuyAction = !isMoneroOnly && !isHaven;
|
||||
isEnabledBuyAction = wallet.type != WalletType.haven;
|
||||
hasBuyAction = !isHaven;
|
||||
isEnabledSellAction = wallet.type != WalletType.haven
|
||||
&& wallet.type != WalletType.monero
|
||||
&& wallet.type != WalletType.litecoin;
|
||||
hasSellAction = !isMoneroOnly && !isHaven;
|
||||
hasSellAction = !isHaven;
|
||||
}
|
||||
}
|
||||
|
|
34
lib/view_model/dashboard/receive_option_view_model.dart
Normal file
34
lib/view_model/dashboard/receive_option_view_model.dart
Normal file
|
@ -0,0 +1,34 @@
|
|||
import 'package:cake_wallet/entities/receive_page_option.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
part 'receive_option_view_model.g.dart';
|
||||
|
||||
class ReceiveOptionViewModel = ReceiveOptionViewModelBase with _$ReceiveOptionViewModel;
|
||||
|
||||
abstract class ReceiveOptionViewModelBase with Store {
|
||||
ReceiveOptionViewModelBase(this._wallet, this.initialPageOption)
|
||||
: selectedReceiveOption = initialPageOption ?? ReceivePageOption.mainnet,
|
||||
_options = [] {
|
||||
final walletType = _wallet.type;
|
||||
_options =
|
||||
walletType == WalletType.haven ? [ReceivePageOption.mainnet] : ReceivePageOption.values;
|
||||
}
|
||||
|
||||
final WalletBase _wallet;
|
||||
|
||||
final ReceivePageOption? initialPageOption;
|
||||
|
||||
List<ReceivePageOption> _options;
|
||||
|
||||
@observable
|
||||
ReceivePageOption selectedReceiveOption;
|
||||
|
||||
List<ReceivePageOption> get options => _options;
|
||||
|
||||
@action
|
||||
void selectReceiveOption(ReceivePageOption option) {
|
||||
selectedReceiveOption = option;
|
||||
}
|
||||
}
|
|
@ -97,7 +97,6 @@ abstract class ExchangeViewModelBase with Store {
|
|||
receiveAddress = '';
|
||||
depositAddress = depositCurrency == wallet.currency
|
||||
? wallet.walletAddresses.address : '';
|
||||
_cryptoNumberFormat = NumberFormat()..maximumFractionDigits = wallet.type == WalletType.bitcoin ? 8 : 12;
|
||||
provider = providersForCurrentPair().first;
|
||||
final initialProvider = provider;
|
||||
provider!.checkIsAvailable().then((bool isAvailable) {
|
||||
|
@ -287,6 +286,7 @@ abstract class ExchangeViewModelBase with Store {
|
|||
|
||||
await _calculateBestRate();
|
||||
}
|
||||
_cryptoNumberFormat.maximumFractionDigits = depositMaxDigits;
|
||||
|
||||
depositAmount = _cryptoNumberFormat
|
||||
.format(_enteredAmount / _bestRate)
|
||||
|
@ -312,6 +312,7 @@ abstract class ExchangeViewModelBase with Store {
|
|||
|
||||
await _calculateBestRate();
|
||||
}
|
||||
_cryptoNumberFormat.maximumFractionDigits = receiveMaxDigits;
|
||||
|
||||
receiveAmount = _cryptoNumberFormat
|
||||
.format(_bestRate * _enteredAmount)
|
||||
|
@ -713,4 +714,8 @@ abstract class ExchangeViewModelBase with Store {
|
|||
providerList = _allProviders;
|
||||
}
|
||||
}
|
||||
|
||||
int get depositMaxDigits => depositCurrency == CryptoCurrency.btc ? 8 : 12;
|
||||
|
||||
int get receiveMaxDigits => receiveCurrency == CryptoCurrency.btc ? 8 : 12;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ import 'package:mobx/mobx.dart';
|
|||
import 'package:cw_core/node.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
||||
import 'node_list_view_model.dart';
|
||||
|
||||
part 'node_create_or_edit_view_model.g.dart';
|
||||
|
||||
class NodeCreateOrEditViewModel = NodeCreateOrEditViewModelBase
|
||||
|
@ -77,14 +79,39 @@ abstract class NodeCreateOrEditViewModelBase with Store {
|
|||
}
|
||||
|
||||
@action
|
||||
Future<void> save({bool saveAsCurrent = false}) async {
|
||||
void setPort (String val) => port = val;
|
||||
|
||||
@action
|
||||
void setAddress (String val) => address = val;
|
||||
|
||||
@action
|
||||
void setLogin (String val) => login = val;
|
||||
|
||||
@action
|
||||
void setPassword (String val) => password = val;
|
||||
|
||||
@action
|
||||
void setSSL (bool val) => useSSL = val;
|
||||
|
||||
@action
|
||||
void setTrusted (bool val) => trusted = val;
|
||||
|
||||
@action
|
||||
Future<void> save({Node? editingNode, bool saveAsCurrent = false}) async {
|
||||
final node = Node(
|
||||
uri: uri,
|
||||
type: _walletType,
|
||||
login: login,
|
||||
password: password,
|
||||
useSSL: useSSL,
|
||||
trusted: trusted);
|
||||
try {
|
||||
state = IsExecutingState();
|
||||
final node =
|
||||
Node(uri: uri, type: _walletType, login: login, password: password,
|
||||
useSSL: useSSL, trusted: trusted);
|
||||
await _nodeSource.add(node);
|
||||
|
||||
if (editingNode != null) {
|
||||
await _nodeSource.put(editingNode.key, node);
|
||||
} else {
|
||||
await _nodeSource.add(node);
|
||||
}
|
||||
if (saveAsCurrent) {
|
||||
_settingsStore.nodes[_walletType] = node;
|
||||
}
|
||||
|
|
|
@ -81,21 +81,23 @@ abstract class OrderDetailsViewModelBase with Store {
|
|||
: S.current.trade_details_fetching),
|
||||
]);
|
||||
|
||||
if (order.provider != null) {
|
||||
items.add(
|
||||
StandartListItem(
|
||||
title: 'Buy provider',
|
||||
value: order.provider.title)
|
||||
);
|
||||
}
|
||||
items.add(
|
||||
StandartListItem(
|
||||
title: 'Buy provider',
|
||||
value: order.provider.title)
|
||||
);
|
||||
|
||||
if (_provider!.trackUrl?.isNotEmpty ?? false) {
|
||||
if (_provider?.trackUrl.isNotEmpty ?? false) {
|
||||
final buildURL = _provider!.trackUrl + '${order.transferId}';
|
||||
items.add(
|
||||
TrackTradeListItem(
|
||||
title: 'Track',
|
||||
value: buildURL,
|
||||
onTap: () => launch(buildURL)
|
||||
onTap: () {
|
||||
try {
|
||||
launch(buildURL);
|
||||
} catch (e) {}
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:cake_wallet/view_model/send/output.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/entities/template.dart';
|
||||
import 'package:cake_wallet/store/templates/send_template_store.dart';
|
||||
|
@ -26,7 +27,8 @@ abstract class SendTemplateViewModelBase with Store {
|
|||
|
||||
Output output;
|
||||
|
||||
Validator get amountValidator => AmountValidator(type: _wallet.type);
|
||||
Validator get amountValidator =>
|
||||
AmountValidator(currency: walletTypeToCryptoCurrency(_wallet.type));
|
||||
|
||||
Validator get addressValidator => AddressValidator(type: _wallet.currency);
|
||||
|
||||
|
|
|
@ -127,7 +127,8 @@ abstract class SendViewModelBase with Store {
|
|||
|
||||
CryptoCurrency get currency => _wallet.currency;
|
||||
|
||||
Validator get amountValidator => AmountValidator(type: _wallet.type);
|
||||
Validator get amountValidator =>
|
||||
AmountValidator(currency: walletTypeToCryptoCurrency(_wallet.type));
|
||||
|
||||
Validator get allAmountValidator => AllAmountValidator();
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import 'package:cake_wallet/src/screens/trade_details/track_trade_list_item.dart
|
|||
import 'package:cake_wallet/src/screens/trade_details/trade_details_list_card.dart';
|
||||
import 'package:cake_wallet/src/screens/trade_details/trade_details_status_item.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
part 'trade_details_view_model.g.dart';
|
||||
|
||||
class TradeDetailsViewModel = TradeDetailsViewModelBase with _$TradeDetailsViewModel;
|
||||
|
@ -121,23 +122,26 @@ abstract class TradeDetailsViewModelBase with Store {
|
|||
title: 'Track',
|
||||
value: buildURL,
|
||||
onTap: () {
|
||||
launch(buildURL);
|
||||
_launchUrl(buildURL);
|
||||
}));
|
||||
}
|
||||
|
||||
if (trade.provider == ExchangeProviderDescription.sideShift) {
|
||||
final buildURL = 'https://sideshift.ai/orders/${trade.id.toString()}';
|
||||
items.add(TrackTradeListItem(title: 'Track', value: buildURL, onTap: () => launch(buildURL)));
|
||||
items.add(
|
||||
TrackTradeListItem(title: 'Track', value: buildURL, onTap: () => _launchUrl(buildURL)));
|
||||
}
|
||||
|
||||
if (trade.provider == ExchangeProviderDescription.simpleSwap) {
|
||||
final buildURL = 'https://simpleswap.io/exchange?id=${trade.id.toString()}';
|
||||
items.add(TrackTradeListItem(title: 'Track', value: buildURL, onTap: () => launch(buildURL)));
|
||||
items.add(
|
||||
TrackTradeListItem(title: 'Track', value: buildURL, onTap: () => _launchUrl(buildURL)));
|
||||
}
|
||||
|
||||
if (trade.provider == ExchangeProviderDescription.trocador) {
|
||||
final buildURL = 'https://trocador.app/en/checkout/${trade.id.toString()}';
|
||||
items.add(TrackTradeListItem(title: 'Track', value: buildURL, onTap: () => launch(buildURL)));
|
||||
items.add(
|
||||
TrackTradeListItem(title: 'Track', value: buildURL, onTap: () => _launchUrl(buildURL)));
|
||||
|
||||
items.add(StandartListItem(
|
||||
title: '${trade.providerName} ${S.current.id.toUpperCase()}',
|
||||
|
@ -148,4 +152,10 @@ abstract class TradeDetailsViewModelBase with Store {
|
|||
title: '${trade.providerName} ${S.current.password}', value: trade.password ?? ''));
|
||||
}
|
||||
}
|
||||
|
||||
void _launchUrl(String url) {
|
||||
try {
|
||||
launch(url);
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@ import 'package:cake_wallet/store/settings_store.dart';
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:cake_wallet/monero/monero.dart';
|
||||
import 'package:cake_wallet/haven/haven.dart';
|
||||
|
||||
part 'transaction_details_view_model.g.dart';
|
||||
|
||||
|
@ -150,7 +149,11 @@ abstract class TransactionDetailsViewModelBase with Store {
|
|||
items.add(BlockExplorerListItem(
|
||||
title: S.current.view_in_block_explorer,
|
||||
value: _explorerDescription(type),
|
||||
onTap: () => launch(_explorerUrl(type, tx.id))));
|
||||
onTap: () {
|
||||
try {
|
||||
launch(_explorerUrl(type, tx.id));
|
||||
} catch (e) {}
|
||||
}));
|
||||
|
||||
final description = transactionDescriptionBox.values.firstWhere(
|
||||
(val) => val.id == transactionInfo.id,
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'package:cw_core/wallet_base.dart';
|
|||
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
|
||||
import 'package:cake_wallet/monero/monero.dart';
|
||||
import 'package:cake_wallet/haven/haven.dart';
|
||||
import 'package:cw_monero/api/wallet.dart' as monero_wallet;
|
||||
|
||||
part 'wallet_keys_view_model.g.dart';
|
||||
|
||||
|
@ -17,10 +18,11 @@ abstract class WalletKeysViewModelBase with Store {
|
|||
wallet.type == WalletType.ethereum
|
||||
? S.current.wallet_seed
|
||||
: S.current.wallet_keys,
|
||||
_wallet = wallet,
|
||||
_restoreHeight = wallet.walletInfo.restoreHeight,
|
||||
items = ObservableList<StandartListItem>() {
|
||||
if (wallet.type == WalletType.monero) {
|
||||
final keys = monero!.getKeys(wallet);
|
||||
|
||||
items.addAll([
|
||||
if (keys['publicSpendKey'] != null)
|
||||
StandartListItem(title: S.current.spend_key_public, value: keys['publicSpendKey']!),
|
||||
|
@ -36,7 +38,6 @@ abstract class WalletKeysViewModelBase with Store {
|
|||
|
||||
if (wallet.type == WalletType.haven) {
|
||||
final keys = haven!.getKeys(wallet);
|
||||
|
||||
items.addAll([
|
||||
if (keys['publicSpendKey'] != null)
|
||||
StandartListItem(title: S.current.spend_key_public, value: keys['publicSpendKey']!),
|
||||
|
@ -62,4 +63,59 @@ abstract class WalletKeysViewModelBase with Store {
|
|||
final ObservableList<StandartListItem> items;
|
||||
|
||||
final String title;
|
||||
|
||||
final WalletBase _wallet;
|
||||
|
||||
final int _restoreHeight;
|
||||
|
||||
Future<int?> currentHeight() async {
|
||||
if (_wallet.type == WalletType.haven) {
|
||||
return await haven!.getCurrentHeight();
|
||||
}
|
||||
if (_wallet.type == WalletType.monero) {
|
||||
return monero_wallet.getCurrentHeight();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String get _path {
|
||||
switch (_wallet.type) {
|
||||
case WalletType.monero:
|
||||
return 'monero_wallet:';
|
||||
case WalletType.bitcoin:
|
||||
return 'bitcoin_wallet:';
|
||||
case WalletType.litecoin:
|
||||
return 'litecoin_wallet:';
|
||||
case WalletType.haven:
|
||||
return 'haven_wallet:';
|
||||
default:
|
||||
throw Exception('Unexpected wallet type: ${_wallet.toString()}');
|
||||
}
|
||||
}
|
||||
|
||||
Future<String?> get restoreHeight async {
|
||||
if (_restoreHeight != 0) {
|
||||
return _restoreHeight.toString();
|
||||
}
|
||||
final _currentHeight = await currentHeight();
|
||||
if (_currentHeight == null) {
|
||||
return null;
|
||||
}
|
||||
return ((_currentHeight / 1000).floor() * 1000).toString();
|
||||
}
|
||||
|
||||
Future<Map<String, String>> get _queryParams async {
|
||||
final restoreHeightResult = await restoreHeight;
|
||||
return {
|
||||
'seed': _wallet.seed,
|
||||
if (restoreHeightResult != null) ...{'height': restoreHeightResult}
|
||||
};
|
||||
}
|
||||
|
||||
Future<Uri> get url async {
|
||||
return Uri(
|
||||
path: _path,
|
||||
queryParameters: await _queryParams,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -485,7 +485,7 @@
|
|||
|
||||
"submit_request":"تقديم طلب",
|
||||
|
||||
"buy_alert_content":"لا ندعم حاليًا سوى شراء Bitcoin و Litecoin. لشراء Bitcoin أو Litecoin ، يرجى إنشاء محفظة Bitcoin أو Litecoin أو التبديل إليها.",
|
||||
"buy_alert_content":"لا ندعم حاليًا سوى شراء Bitcoin و Litecoin و Monero. يرجى إنشاء محفظة Bitcoin أو Litecoin أو Monero أو التبديل إليها.",
|
||||
"sell_alert_content":"نحن ندعم حاليًا بيع البيتكوين فقط. لبيع Bitcoin ، يرجى إنشاء أو التبديل إلى محفظة Bitcoin الخاصة بك.",
|
||||
|
||||
"outdated_electrum_wallet_description":"محافظ Bitcoin الجديدة التي تم إنشاؤها في Cake الآن سييد مكونة من 24 كلمة. من الضروري أن تقوم بإنشاء محفظة Bitcoin جديدة وتحويل جميع أموالك إلى المحفظة الجديدة المكونة من 24 كلمة ، والتوقف عن استخدام محافظ سييد مكونة من 12 كلمة. يرجى القيام بذلك على الفور لتأمين أموالك.",
|
||||
|
@ -682,5 +682,18 @@
|
|||
"send_to_this_address" : "أرسل ${currency} ${tag}إلى هذا العنوان",
|
||||
"arrive_in_this_address" : "سيصل ${currency} ${tag}إلى هذا العنوان",
|
||||
"do_not_send": "لا ترسل",
|
||||
"error_dialog_content": "عفوًا ، لقد حصلنا على بعض الخطأ.\n\nيرجى إرسال تقرير التعطل إلى فريق الدعم لدينا لتحسين التطبيق."
|
||||
"error_dialog_content": "عفوًا ، لقد حصلنا على بعض الخطأ.\n\nيرجى إرسال تقرير التعطل إلى فريق الدعم لدينا لتحسين التطبيق.",
|
||||
"decimal_places_error": "عدد كبير جدًا من المنازل العشرية",
|
||||
"edit_node": "تحرير العقدة",
|
||||
"invoice_details": "تفاصيل الفاتورة",
|
||||
"donation_link_details": "تفاصيل رابط التبرع",
|
||||
"anonpay_description": "توليد ${type}. يمكن للمستلم ${method} بأي عملة مشفرة مدعومة ، وستتلقى أموالاً في هذه",
|
||||
"create_invoice": "إنشاء فاتورة",
|
||||
"create_donation_link": "إنشاء رابط التبرع",
|
||||
"optional_email_hint": "البريد الإلكتروني إخطار المدفوع لأمره الاختياري",
|
||||
"optional_description": "وصف اختياري",
|
||||
"optional_name": "اسم المستلم الاختياري",
|
||||
"clearnet_link": "رابط Clearnet",
|
||||
"onion_link": "رابط البصل",
|
||||
"sell_monero_com_alert_content": "بيع Monero غير مدعوم حتى الآن"
|
||||
}
|
||||
|
|
|
@ -485,7 +485,7 @@
|
|||
|
||||
"submit_request" : "изпращане на заявка",
|
||||
|
||||
"buy_alert_content" : "В момента поддържаме покупката само на Bitcoin и Litecoin. За да закупите Bitcoin или Litecoin, създайте или изберете своя Bitcoin или Litecoin портфейл.",
|
||||
"buy_alert_content" : "Понастоящем поддържаме само закупуване на Bitcoin, Litecoin и Monero. Моля, създайте или преминете към своя портфейл Bitcoin, Litecoin или Monero.",
|
||||
"sell_alert_content": "В момента поддържаме само продажбата на Bitcoin. За да продавате Bitcoin, създайте или изберете своя Bitcoin портфейл.",
|
||||
|
||||
"outdated_electrum_wallet_description" : "Нови Bitcoin портфейли, създадени в Cake, сега имат seed от 24 думи. Трябва да създадете нов Bitcoin адрес и да прехвърлите всичките си средства в него и веднага да спрете използването на стари портфейли. Моля, напревете това незабавно, за да подсигурите средствата си.",
|
||||
|
@ -684,5 +684,18 @@
|
|||
"send_to_this_address" : "Send ${currency} ${tag}to this address",
|
||||
"arrive_in_this_address" : "${currency} ${tag}ще отидат на този адрес",
|
||||
"do_not_send": "Не изпращай",
|
||||
"error_dialog_content": "Получихме грешка.\n\nМоля, изпратете доклада до нашия отдел поддръжка, за да подобрим приложението."
|
||||
"error_dialog_content": "Получихме грешка.\n\nМоля, изпратете доклада до нашия отдел поддръжка, за да подобрим приложението.",
|
||||
"decimal_places_error": "Твърде много знаци след десетичната запетая",
|
||||
"edit_node": "Редактиране на възел",
|
||||
"invoice_details": "IДанни за фактура",
|
||||
"donation_link_details": "Подробности за връзката за дарение",
|
||||
"anonpay_description": "Генерирайте ${type}. Получателят може да ${method} с всяка поддържана криптовалута и вие ще получите средства в този портфейл.",
|
||||
"create_invoice": "Създайте фактура",
|
||||
"create_donation_link": "Създайте връзка за дарение",
|
||||
"optional_email_hint": "Незадължителен имейл за уведомяване на получателя",
|
||||
"optional_description": "Описание по избор",
|
||||
"optional_name": "Незадължително име на получател",
|
||||
"clearnet_link": "Clearnet връзка",
|
||||
"onion_link": "Лукова връзка",
|
||||
"sell_monero_com_alert_content": "Продажбата на Monero все още не се поддържа"
|
||||
}
|
||||
|
|
|
@ -485,7 +485,7 @@
|
|||
|
||||
"submit_request" : "odeslat požadavek",
|
||||
|
||||
"buy_alert_content" : "V současné době podporujeme nákup pouze Bitcoinu a Litecoinu. Pro nákup Bitcoinu, nebo Litecoinu si prosím vytvořte Bitcoinovou, nebo Litecoinovou peněženku, nebo se do ní přepněte.",
|
||||
"buy_alert_content" : "V současné době podporujeme pouze nákup Bitcoinů, Litecoinů a Monero. Vytvořte nebo přepněte na svou peněženku Bitcoinů, Litecoinů nebo Monero.",
|
||||
"sell_alert_content": "V současné době podporujeme pouze prodej Bitcoinu. Pro prodej Bitcoinu si prosím vytvořte Bitcoinovou peněženku, nebo se do ní přepněte.",
|
||||
|
||||
"outdated_electrum_wallet_description" : "Nové Bitcoinové peněženky vytvořené v Cake mají nyní seed se 24 slovy. Je třeba si vytvořit novou Bitcoinovou peněženku se 24 slovy, převést na ni všechny prostředky a přestat používat seed se 12 slovy. Prosím udělejte to hned pro zabezpečení svých prostředků.",
|
||||
|
@ -684,5 +684,18 @@
|
|||
"send_to_this_address" : "Poslat ${currency} ${tag}na tuto adresu",
|
||||
"arrive_in_this_address" : "${currency} ${tag}přijde na tuto adresu",
|
||||
"do_not_send": "Neodesílat",
|
||||
"error_dialog_content": "Nastala chyba.\n\nProsím odešlete zprávu o chybě naší podpoře, aby mohli zajistit opravu."
|
||||
"error_dialog_content": "Nastala chyba.\n\nProsím odešlete zprávu o chybě naší podpoře, aby mohli zajistit opravu.",
|
||||
"decimal_places_error": "Příliš mnoho desetinných míst",
|
||||
"edit_node": "Upravit uzel",
|
||||
"invoice_details": "detaily faktury",
|
||||
"donation_link_details": "Podrobnosti odkazu na darování",
|
||||
"anonpay_description": "Vygenerujte ${type}. Příjemce může ${method} s jakoukoli podporovanou kryptoměnou a vy obdržíte prostředky v této peněžence.",
|
||||
"create_invoice": "Vytvořit fakturu",
|
||||
"create_donation_link": "Vytvořit odkaz na darování",
|
||||
"optional_email_hint": "Volitelný e-mail s upozorněním na příjemce platby",
|
||||
"optional_description": "Volitelný popis",
|
||||
"optional_name": "Volitelné jméno příjemce",
|
||||
"clearnet_link": "Odkaz na Clearnet",
|
||||
"onion_link": "Cibulový odkaz",
|
||||
"sell_monero_com_alert_content": "Prodej Monero zatím není podporován"
|
||||
}
|
||||
|
|
|
@ -485,7 +485,7 @@
|
|||
|
||||
"submit_request" : "Eine Anfrage stellen",
|
||||
|
||||
"buy_alert_content" : "Derzeit unterstützen wir nur den Kauf von Bitcoin und Litecoin. Um Bitcoin oder Litecoin zu kaufen, erstellen oder wechseln Sie bitte zu Ihrem Bitcoin- oder Litecoin-Wallet.",
|
||||
"buy_alert_content" : "Derzeit unterstützen wir nur den Kauf von Bitcoin, Litecoin und Monero. Bitte erstellen oder wechseln Sie zu Ihrer Bitcoin-, Litecoin- oder Monero-Wallet.",
|
||||
"sell_alert_content": "Wir unterstützen derzeit nur den Verkauf von Bitcoin. Um Bitcoin zu verkaufen, erstellen Sie bitte Ihre Bitcoin-Wallet oder wechseln Sie zu ihr.",
|
||||
|
||||
"outdated_electrum_wallet_description" : "Neue Bitcoin-Wallets, die in Cake erstellt wurden, haben jetzt einen 24-Wort-Seed. Sie müssen eine neue Bitcoin-Wallet erstellen, Ihr gesamtes Geld in die neue 24-Wort-Wallet überweisen und keine Wallet mit einem 12-Wort-Seed mehr verwenden. Bitte tun Sie dies sofort, um Ihr Geld zu sichern.",
|
||||
|
@ -684,5 +684,18 @@
|
|||
"send_to_this_address" : "Senden Sie ${currency} ${tag}an diese Adresse",
|
||||
"arrive_in_this_address" : "${currency} ${tag}wird an dieser Adresse ankommen",
|
||||
"do_not_send": "Nicht senden",
|
||||
"error_dialog_content": "Hoppla, wir haben einen Fehler.\n\nBitte senden Sie den Absturzbericht an unser Support-Team, um die Anwendung zu verbessern."
|
||||
"error_dialog_content": "Hoppla, wir haben einen Fehler.\n\nBitte senden Sie den Absturzbericht an unser Support-Team, um die Anwendung zu verbessern.",
|
||||
"decimal_places_error": "Zu viele Nachkommastellen",
|
||||
"edit_node": "Knoten bearbeiten",
|
||||
"invoice_details": "Rechnungs-Details",
|
||||
"donation_link_details": "Details zum Spendenlink",
|
||||
"anonpay_description": "Generieren Sie ${type}. Der Empfänger kann ${method} mit jeder unterstützten Kryptowährung verwenden, und Sie erhalten Geld in dieser Brieftasche.",
|
||||
"create_invoice": "Rechnung erstellen",
|
||||
"create_donation_link": "Spendenlink erstellen",
|
||||
"optional_email_hint": "Optionale Benachrichtigungs-E-Mail für den Zahlungsempfänger",
|
||||
"optional_description": "Optionale Beschreibung",
|
||||
"optional_name": "Optionaler Empfängername",
|
||||
"clearnet_link": "Clearnet-Link",
|
||||
"onion_link": "Zwiebel-Link",
|
||||
"sell_monero_com_alert_content": "Der Verkauf von Monero wird noch nicht unterstützt"
|
||||
}
|
||||
|
|
|
@ -485,7 +485,7 @@
|
|||
|
||||
"submit_request" : "submit a request",
|
||||
|
||||
"buy_alert_content" : "Currently we only support the purchase of Bitcoin and Litecoin. To buy Bitcoin or Litecoin, please create or switch to your Bitcoin or Litecoin wallet.",
|
||||
"buy_alert_content" : "Currently we only support the purchase of Bitcoin, Litecoin, and Monero. Please create or switch to your Bitcoin, Litecoin, or Monero wallet.",
|
||||
"sell_alert_content": "We currently only support the sale of Bitcoin. To sell Bitcoin, please create or switch to your Bitcoin wallet.",
|
||||
|
||||
"outdated_electrum_wallet_description" : "New Bitcoin wallets created in Cake now have a 24-word seed. It is mandatory that you create a new Bitcoin wallet and transfer all of your funds to the new 24-word wallet, and stop using wallets with a 12-word seed. Please do this immediately to secure your funds.",
|
||||
|
@ -684,5 +684,18 @@
|
|||
"send_to_this_address" : "Send ${currency} ${tag}to this address",
|
||||
"arrive_in_this_address" : "${currency} ${tag}will arrive in this address",
|
||||
"do_not_send": "Don't send",
|
||||
"error_dialog_content": "Oops, we got some error.\n\nPlease send the crash report to our support team to make the application better."
|
||||
"error_dialog_content": "Oops, we got some error.\n\nPlease send the crash report to our support team to make the application better.",
|
||||
"invoice_details": "Invoice details",
|
||||
"donation_link_details": "Donation link details",
|
||||
"anonpay_description": "Generate ${type}. The recipient can ${method} with any supported cryptocurrency, and you will receive funds in this wallet.",
|
||||
"create_invoice": "Create invoice",
|
||||
"create_donation_link": "Create donation link",
|
||||
"optional_email_hint": "Optional payee notification email",
|
||||
"optional_description": "Optional description",
|
||||
"optional_name": "Optional recipient name",
|
||||
"clearnet_link": "Clearnet link",
|
||||
"onion_link": "Onion link",
|
||||
"decimal_places_error": "Too many decimal places",
|
||||
"edit_node": "Edit Node",
|
||||
"sell_monero_com_alert_content": "Selling Monero is not supported yet"
|
||||
}
|
||||
|
|
|
@ -485,7 +485,7 @@
|
|||
|
||||
"submit_request" : "presentar una solicitud",
|
||||
|
||||
"buy_alert_content" : "Actualmente solo apoyamos la compra de Bitcoin y Litecoin. Para comprar Bitcoin o Litecoin, cree o cambie a su billetera Bitcoin o Litecoin.",
|
||||
"buy_alert_content" : "Actualmente solo admitimos la compra de Bitcoin, Litecoin y Monero. Cree o cambie a su billetera Bitcoin, Litecoin o Monero.",
|
||||
"sell_alert_content": "Actualmente solo admitimos la venta de Bitcoin. Para vender Bitcoin, cree o cambie a su billetera Bitcoin.",
|
||||
|
||||
"outdated_electrum_wallet_description" : "Las nuevas carteras de Bitcoin creadas en Cake ahora tienen una semilla de 24 palabras. Es obligatorio que cree una nueva billetera de Bitcoin y transfiera todos sus fondos a la nueva billetera de 24 palabras, y deje de usar billeteras con una semilla de 12 palabras. Haga esto de inmediato para asegurar sus fondos.",
|
||||
|
@ -684,5 +684,18 @@
|
|||
"send_to_this_address" : "Enviar ${currency} ${tag}a esta dirección",
|
||||
"arrive_in_this_address" : "${currency} ${tag}llegará a esta dirección",
|
||||
"do_not_send": "no enviar",
|
||||
"error_dialog_content": "Vaya, tenemos un error.\n\nEnvíe el informe de bloqueo a nuestro equipo de soporte para mejorar la aplicación."
|
||||
"error_dialog_content": "Vaya, tenemos un error.\n\nEnvíe el informe de bloqueo a nuestro equipo de soporte para mejorar la aplicación.",
|
||||
"decimal_places_error": "Demasiados lugares decimales",
|
||||
"edit_node": "Edit Node",
|
||||
"invoice_details": "Detalles de la factura",
|
||||
"donation_link_details": "Detalles del enlace de donación",
|
||||
"anonpay_description": "Genera ${type}. El destinatario puede ${method} con cualquier criptomoneda admitida, y recibirá fondos en esta billetera.",
|
||||
"create_invoice": "Crear factura",
|
||||
"create_donation_link": "Crear enlace de donación",
|
||||
"optional_email_hint": "Correo electrónico de notificación del beneficiario opcional",
|
||||
"optional_description": "Descripción opcional",
|
||||
"optional_name": "Nombre del destinatario opcional",
|
||||
"clearnet_link": "enlace Clearnet",
|
||||
"onion_link": "Enlace de cebolla",
|
||||
"sell_monero_com_alert_content": "Aún no se admite la venta de Monero"
|
||||
}
|
||||
|
|
|
@ -483,7 +483,7 @@
|
|||
|
||||
"submit_request" : "soumettre une requête",
|
||||
|
||||
"buy_alert_content" : "Pour le moment nous ne supportons que l'achat de Bitcoin et Litecoin. Pour acheter du Bitcoin ou du Litecoin, merci de créer ou de sélectionner votre portefeuille (wallet) Bitcoin ou Litecoin.",
|
||||
"buy_alert_content" : "Actuellement, nous ne prenons en charge que l'achat de Bitcoin, Litecoin et Monero. Veuillez créer ou basculer vers votre portefeuille Bitcoin, Litecoin ou Monero.",
|
||||
"sell_alert_content": "Pour le moment nous ne supportons que la vente de Bitcoin. Pour vendre du Bitcoin, merci de créer ou de sélectionner votre portefeuille (wallet) Bitcoin.",
|
||||
|
||||
"outdated_electrum_wallet_description" : "Les nouveaux portefeuilles (wallets) Bitcoin créés dans Cake ont dorénavant une phrase secrète (seed) de 24 mots. Il est impératif que vous créiez un nouveau portefeuille Bitcoin, que vous y transfériez tous vos fonds puis que vous cessiez d'utiliser le portefeuille avec une phrase secrète de 12 mots. Merci de faire cela immédiatement pour assurer la sécurité de vos avoirs.",
|
||||
|
@ -682,5 +682,18 @@
|
|||
"send_to_this_address" : "Envoyez ${currency} ${tag}à cette adresse",
|
||||
"arrive_in_this_address" : "${currency} ${tag}arrivera à cette adresse",
|
||||
"do_not_send": "N'envoyez pas",
|
||||
"error_dialog_content": "Oups, nous avons eu une erreur.\n\nVeuillez envoyer le rapport de plantage à notre équipe d'assistance pour améliorer l'application."
|
||||
"error_dialog_content": "Oups, nous avons eu une erreur.\n\nVeuillez envoyer le rapport de plantage à notre équipe d'assistance pour améliorer l'application.",
|
||||
"decimal_places_error": "Trop de décimales",
|
||||
"edit_node": "Modifier le nœud",
|
||||
"invoice_details": "Détails de la facture",
|
||||
"donation_link_details": "Détails du lien de don",
|
||||
"anonpay_description": "Générez ${type}. Le destinataire peut ${method} avec n'importe quelle crypto-monnaie prise en charge, et vous recevrez des fonds dans ce portefeuille.",
|
||||
"create_invoice": "Créer une facture",
|
||||
"create_donation_link": "Créer un lien de don",
|
||||
"optional_email_hint": "E-mail de notification du bénéficiaire facultatif",
|
||||
"optional_description": "Descriptif facultatif",
|
||||
"optional_name": "Nom du destinataire facultatif",
|
||||
"clearnet_link": "Lien Clearnet",
|
||||
"onion_link": "Lien d'oignon",
|
||||
"sell_monero_com_alert_content": "La vente de Monero n'est pas encore prise en charge"
|
||||
}
|
||||
|
|
|
@ -485,7 +485,7 @@
|
|||
|
||||
"submit_request" : "एक अनुरोध सबमिट करें",
|
||||
|
||||
"buy_alert_content" : "वर्तमान में हम केवल बिटकॉइन और लिटकोइन की खरीद का समर्थन करते हैं। बिटकॉइन या लाइटकोइन खरीदने के लिए, कृपया अपना बिटकॉइन या लाइटकोइन वॉलेट बनाएं या स्विच करें।",
|
||||
"buy_alert_content" : "वर्तमान में हम केवल बिटकॉइन, लाइटकॉइन और मोनेरो की खरीद का समर्थन करते हैं। कृपया अपना बिटकॉइन, लाइटकॉइन, या मोनेरो वॉलेट बनाएं या स्विच करें।",
|
||||
"sell_alert_content": "हम वर्तमान में केवल बिटकॉइन की बिक्री का समर्थन करते हैं। बिटकॉइन बेचने के लिए, कृपया अपना बिटकॉइन वॉलेट बनाएं या उसमें स्विच करें।",
|
||||
|
||||
"outdated_electrum_wallet_description" : "केक में बनाए गए नए बिटकॉइन वॉलेट में अब 24-शब्द का बीज है। यह अनिवार्य है कि आप एक नया बिटकॉइन वॉलेट बनाएं और अपने सभी फंड को नए 24-शब्द वाले वॉलेट में स्थानांतरित करें, और 12-शब्द बीज वाले वॉलेट का उपयोग करना बंद करें। कृपया अपने धन को सुरक्षित करने के लिए इसे तुरंत करें।",
|
||||
|
@ -684,5 +684,18 @@
|
|||
"send_to_this_address" : "इस पते पर ${currency} ${tag}भेजें",
|
||||
"arrive_in_this_address" : "${currency} ${tag}इस पते पर पहुंचेंगे",
|
||||
"do_not_send": "मत भेजो",
|
||||
"error_dialog_content": "ओह, हमसे कुछ गड़बड़ी हुई है.\n\nएप्लिकेशन को बेहतर बनाने के लिए कृपया क्रैश रिपोर्ट हमारी सहायता टीम को भेजें।"
|
||||
"error_dialog_content": "ओह, हमसे कुछ गड़बड़ी हुई है.\n\nएप्लिकेशन को बेहतर बनाने के लिए कृपया क्रैश रिपोर्ट हमारी सहायता टीम को भेजें।",
|
||||
"decimal_places_error": "बहुत अधिक दशमलव स्थान",
|
||||
"edit_node": "नोड संपादित करें",
|
||||
"invoice_details": "चालान विवरण",
|
||||
"donation_link_details": "दान लिंक विवरण",
|
||||
"anonpay_description": "${type} उत्पन्न करें। प्राप्तकर्ता किसी भी समर्थित क्रिप्टोकरेंसी के साथ ${method} कर सकता है, और आपको इस वॉलेट में धन प्राप्त होगा।",
|
||||
"create_invoice": "इनवॉयस बनाएँ",
|
||||
"create_donation_link": "दान लिंक बनाएं",
|
||||
"optional_email_hint": "वैकल्पिक प्राप्तकर्ता सूचना ईमेल",
|
||||
"optional_description": "वैकल्पिक विवरण",
|
||||
"optional_name": "वैकल्पिक प्राप्तकर्ता नाम",
|
||||
"clearnet_link": "क्लियरनेट लिंक",
|
||||
"onion_link": "प्याज का लिंक",
|
||||
"sell_monero_com_alert_content": "मोनेरो बेचना अभी तक समर्थित नहीं है"
|
||||
}
|
||||
|
|
|
@ -485,7 +485,7 @@
|
|||
|
||||
"submit_request" : "podnesi zahtjev",
|
||||
|
||||
"buy_alert_content" : "Trenutno podržavamo samo kupnju Bitcoina i Litecoina. Da biste kupili Bitcoin ili Litecoin, stvorite ili pređite na svoj Bitcoin ili Litecoin novčanik.",
|
||||
"buy_alert_content" : "Trenutno podržavamo samo kupnju Bitcoina, Litecoina i Monera. Izradite ili prijeđite na svoj Bitcoin, Litecoin ili Monero novčanik.",
|
||||
"sell_alert_content": "Trenutno podržavamo samo prodaju Bitcoina. Da biste prodali Bitcoin, stvorite ili prijeđite na svoj Bitcoin novčanik.",
|
||||
|
||||
"outdated_electrum_wallet_description" : "Novi Bitcoin novčanici stvoreni u Cakeu sada imaju sjeme od 24 riječi. Obavezno je stvoriti novi Bitcoin novčanik i prenijeti sva svoja sredstva u novi novčanik od 24 riječi te prestati koristiti novčanike s sjemenkom od 12 riječi. Učinite to odmah kako biste osigurali svoja sredstva.",
|
||||
|
@ -684,5 +684,18 @@
|
|||
"send_to_this_address" : "Pošaljite ${currency} ${tag}na ovu adresu",
|
||||
"arrive_in_this_address" : "${currency} ${tag}će stići na ovu adresu",
|
||||
"do_not_send": "Ne šalji",
|
||||
"error_dialog_content": "Ups, imamo grešku.\n\nPošaljite izvješće o padu našem timu za podršku kako bismo poboljšali aplikaciju."
|
||||
"error_dialog_content": "Ups, imamo grešku.\n\nPošaljite izvješće o padu našem timu za podršku kako bismo poboljšali aplikaciju.",
|
||||
"decimal_places_error": "Previše decimalnih mjesta",
|
||||
"edit_node": "Uredi čvor",
|
||||
"invoice_details": "Podaci o fakturi",
|
||||
"donation_link_details": "Detalji veza za donacije",
|
||||
"anonpay_description": "Generiraj ${type}. Primatelj može ${method} s bilo kojom podržanom kriptovalutom, a vi ćete primiti sredstva u ovaj novčanik.",
|
||||
"create_invoice": "Izradite fakturu",
|
||||
"create_donation_link": "Izradi poveznicu za donaciju",
|
||||
"optional_email_hint": "Neobavezna e-pošta za obavijest primatelja",
|
||||
"optional_description": "Opcijski opis",
|
||||
"optional_name": "Izborno ime primatelja",
|
||||
"clearnet_link": "Clearnet veza",
|
||||
"onion_link": "Poveznica luka",
|
||||
"sell_monero_com_alert_content": "Prodaja Monera još nije podržana"
|
||||
}
|
||||
|
|
|
@ -472,7 +472,7 @@
|
|||
|
||||
"submit_request" : "kirim permintaan",
|
||||
|
||||
"buy_alert_content" : "Saat ini kami hanya mendukung pembelian Bitcoin dan Litecoin. Untuk membeli Bitcoin atau Litecoin, silakan buat atau beralih ke dompet Bitcoin atau Litecoin Anda.",
|
||||
"buy_alert_content" : "Saat ini kami hanya mendukung pembelian Bitcoin, Litecoin, dan Monero. Harap buat atau alihkan ke dompet Bitcoin, Litecoin, atau Monero Anda.",
|
||||
"sell_alert_content": "Saat ini kami hanya mendukung penjualan Bitcoin. Untuk menjual Bitcoin, silakan buat atau beralih ke dompet Bitcoin Anda.",
|
||||
|
||||
"outdated_electrum_wallet_description" : "Dompet Bitcoin baru yang dibuat di Cake sekarang memiliki biji semai 24 kata. Wajib bagi Anda untuk membuat dompet Bitcoin baru dan mentransfer semua dana Anda ke dompet 24 kata baru, dan berhenti menggunakan dompet dengan biji semai 12 kata. Silakan lakukan ini segera untuk mengamankan dana Anda.",
|
||||
|
@ -666,5 +666,18 @@
|
|||
"unmatched_currencies": "Mata uang dompet Anda saat ini tidak cocok dengan yang ditandai QR",
|
||||
"orbot_running_alert": "Pastikan Orbot sedang berjalan sebelum menghubungkan ke node ini.",
|
||||
"contact_list_contacts": "Kontak",
|
||||
"contact_list_wallets": "Dompet Saya"
|
||||
"contact_list_wallets": "Dompet Saya",
|
||||
"decimal_places_error": "Terlalu banyak tempat desimal",
|
||||
"edit_node": "Sunting Node",
|
||||
"invoice_details": "Detail faktur",
|
||||
"donation_link_details": "Detail tautan donasi",
|
||||
"anonpay_description": "Hasilkan ${type}. Penerima dapat ${method} dengan cryptocurrency apa pun yang didukung, dan Anda akan menerima dana di dompet ini.",
|
||||
"create_invoice": "Buat faktur",
|
||||
"create_donation_link": "Buat tautan donasi",
|
||||
"optional_email_hint": "Email pemberitahuan penerima pembayaran opsional",
|
||||
"optional_description": "Deskripsi opsional",
|
||||
"optional_name": "Nama penerima opsional",
|
||||
"clearnet_link": "Tautan clearnet",
|
||||
"onion_link": "Tautan bawang",
|
||||
"sell_monero_com_alert_content": "Menjual Monero belum didukung"
|
||||
}
|
||||
|
|
|
@ -485,7 +485,7 @@
|
|||
|
||||
"submit_request" : "invia una richiesta",
|
||||
|
||||
"buy_alert_content" : "Attualmente supportiamo solo l'acquisto di Bitcoin e Litecoin. Per acquistare Bitcoin o Litecoin, crea o passa al tuo portafoglio Bitcoin o Litecoin.",
|
||||
"buy_alert_content" : "Attualmente supportiamo solo l'acquisto di Bitcoin, Litecoin e Monero. Crea o passa al tuo portafoglio Bitcoin, Litecoin o Monero.",
|
||||
"sell_alert_content": "Al momento supportiamo solo la vendita di Bitcoin. Per vendere Bitcoin, crea o passa al tuo portafoglio Bitcoin.",
|
||||
|
||||
"outdated_electrum_wallet_description" : "I nuovi portafogli Bitcoin creati in Cake ora hanno un seme di 24 parole. È obbligatorio creare un nuovo portafoglio Bitcoin e trasferire tutti i fondi nel nuovo portafoglio di 24 parole e smettere di usare portafogli con un seme di 12 parole. Ti preghiamo di farlo immediatamente per proteggere i tuoi fondi.",
|
||||
|
@ -684,5 +684,18 @@
|
|||
"send_to_this_address" : "Invia ${currency} ${tag}a questo indirizzo",
|
||||
"arrive_in_this_address" : "${currency} ${tag}arriverà a questo indirizzo",
|
||||
"do_not_send": "Non inviare",
|
||||
"error_dialog_content": "Ups, imamo grešku.\n\nPošaljite izvješće o padu našem timu za podršku kako bismo poboljšali aplikaciju."
|
||||
"error_dialog_content": "Spiacenti, abbiamo riscontrato un errore.\n\nSi prega di inviare il rapporto sull'arresto anomalo al nostro team di supporto per migliorare l'applicazione.",
|
||||
"decimal_places_error": "Troppe cifre decimali",
|
||||
"edit_node": "Modifica nodo",
|
||||
"invoice_details": "Dettagli della fattura",
|
||||
"donation_link_details": "Dettagli del collegamento alla donazione",
|
||||
"anonpay_description": "Genera ${type}. Il destinatario può ${method} con qualsiasi criptovaluta supportata e riceverai fondi in questo portafoglio.",
|
||||
"create_invoice": "Crea fattura",
|
||||
"create_donation_link": "Crea un link per la donazione",
|
||||
"optional_email_hint": "Email di notifica del beneficiario facoltativa",
|
||||
"optional_description": "Descrizione facoltativa",
|
||||
"optional_name": "Nome del destinatario facoltativo",
|
||||
"clearnet_link": "Collegamento Clearnet",
|
||||
"onion_link": "Collegamento a cipolla",
|
||||
"sell_monero_com_alert_content": "La vendita di Monero non è ancora supportata"
|
||||
}
|
||||
|
|
|
@ -485,7 +485,7 @@
|
|||
|
||||
"submit_request" : "リクエストを送信する",
|
||||
|
||||
"buy_alert_content" : "現在、ビットコインとライトコインの購入のみをサポートしています。 ビットコインまたはライトコインを購入するには、ビットコインまたはライトコインのウォレットを作成するか、ウォレットに切り替えてください。",
|
||||
"buy_alert_content" : "現在、ビットコイン、ライトコイン、モネロの購入のみをサポートしています。 Bitcoin、Litecoin、または Monero ウォレットを作成するか、切り替えてください。",
|
||||
"sell_alert_content": "現在、ビットコインの販売のみをサポートしています。ビットコインを販売するには、ビットコインウォレットを作成するか切り替えてください。",
|
||||
|
||||
"outdated_electrum_wallet_description" : "Cakeで作成された新しいビットコインウォレットには、24ワードのシードがあります。 新しいビットコインウォレットを作成し、すべての資金を新しい24ワードのウォレットに転送し、12ワードのシードを持つウォレットの使用を停止することが必須です。 あなたの資金を確保するためにこれをすぐに行ってください。",
|
||||
|
@ -684,5 +684,18 @@
|
|||
"send_to_this_address" : "${currency} ${tag}をこのアドレスに送金",
|
||||
"arrive_in_this_address" : "${currency} ${tag}はこの住所に到着します",
|
||||
"do_not_send": "送信しない",
|
||||
"error_dialog_content": "Spiacenti, abbiamo riscontrato un errore.\n\nSi prega di inviare il rapporto sull'arresto anomalo al nostro team di supporto per migliorare l'applicazione."
|
||||
"error_dialog_content": "エラーが発生しました。\n\nアプリケーションを改善するために、クラッシュ レポートをサポート チームに送信してください。",
|
||||
"decimal_places_error": "小数点以下の桁数が多すぎる",
|
||||
"edit_node": "ノードを編集",
|
||||
"invoice_details": "請求の詳細",
|
||||
"donation_link_details": "寄付リンクの詳細",
|
||||
"anonpay_description": "${type} を生成します。受取人はサポートされている任意の暗号通貨で ${method} でき、あなたはこのウォレットで資金を受け取ります。",
|
||||
"create_invoice": "請求書の作成",
|
||||
"create_donation_link": "寄付リンクを作成",
|
||||
"optional_email_hint": "オプションの受取人通知メール",
|
||||
"optional_description": "オプションの説明",
|
||||
"optional_name": "オプションの受信者名",
|
||||
"clearnet_link": "クリアネット リンク",
|
||||
"onion_link": "オニオンリンク",
|
||||
"sell_monero_com_alert_content": "モネロの販売はまだサポートされていません"
|
||||
}
|
||||
|
|
|
@ -485,7 +485,7 @@
|
|||
|
||||
"submit_request" : "요청을 제출",
|
||||
|
||||
"buy_alert_content" : "현재 우리는 비트 코인과 라이트 코인 구매 만 지원합니다. 비트 코인 또는 라이트 코인을 구매하려면 비트 코인 또는 라이트 코인 지갑을 생성하거나 전환하십시오.",
|
||||
"buy_alert_content" : "현재 우리는 Bitcoin, Litecoin 및 Monero 구매만 지원합니다. Bitcoin, Litecoin 또는 Monero 지갑을 생성하거나 전환하십시오.",
|
||||
"sell_alert_content": "현재 비트코인 판매만 지원합니다. 비트코인을 판매하려면 비트코인 지갑을 생성하거나 전환하세요.",
|
||||
|
||||
"outdated_electrum_wallet_description" : "Cake에서 생성 된 새로운 비트 코인 지갑에는 이제 24 단어 시드가 있습니다. 새로운 비트 코인 지갑을 생성하고 모든 자금을 새로운 24 단어 지갑으로 이체하고 12 단어 시드가있는 지갑 사용을 중지해야합니다. 자금을 확보하려면 즉시이 작업을 수행하십시오.",
|
||||
|
@ -684,5 +684,18 @@
|
|||
"send_to_this_address" : "이 주소로 ${currency} ${tag}송금",
|
||||
"arrive_in_this_address" : "${currency} ${tag}이(가) 이 주소로 도착합니다",
|
||||
"do_not_send": "보내지 마세요",
|
||||
"error_dialog_content": "죄송합니다. 오류가 발생했습니다.\n\n응용 프로그램을 개선하려면 지원 팀에 충돌 보고서를 보내주십시오."
|
||||
"error_dialog_content": "죄송합니다. 오류가 발생했습니다.\n\n응용 프로그램을 개선하려면 지원 팀에 충돌 보고서를 보내주십시오.",
|
||||
"decimal_places_error": "소수점 이하 자릿수가 너무 많습니다.",
|
||||
"edit_node": "노드 편집",
|
||||
"invoice_details": "인보이스 세부정보",
|
||||
"donation_link_details": "기부 링크 세부정보",
|
||||
"anonpay_description": "${type} 생성. 수신자는 지원되는 모든 암호화폐로 ${method}할 수 있으며 이 지갑에서 자금을 받게 됩니다.",
|
||||
"create_invoice": "인보이스 생성",
|
||||
"create_donation_link": "기부 링크 만들기",
|
||||
"optional_email_hint": "선택적 수취인 알림 이메일",
|
||||
"optional_description": "선택적 설명",
|
||||
"optional_name": "선택적 수신자 이름",
|
||||
"clearnet_link": "클리어넷 링크",
|
||||
"onion_link": "양파 링크",
|
||||
"sell_monero_com_alert_content": "지원되지 않습니다."
|
||||
}
|
||||
|
|
|
@ -485,7 +485,7 @@
|
|||
|
||||
"submit_request" : "တောင်းဆိုချက်တစ်ခုတင်ပြပါ။",
|
||||
|
||||
"buy_alert_content" : "လောလောဆယ် ကျွန်ုပ်တို့သည် Bitcoin နှင့် Litecoin ဝယ်ယူမှုကိုသာ ပံ့ပိုးပေးပါသည်။ Bitcoin သို့မဟုတ် Litecoin ဝယ်ယူရန်၊ သင်၏ Bitcoin သို့မဟုတ် Litecoin ပိုက်ဆံအိတ်ကို ဖန်တီးပါ သို့မဟုတ် ပြောင်းပါ။",
|
||||
"buy_alert_content" : "လောလောဆယ်တွင် ကျွန်ုပ်တို့သည် Bitcoin၊ Litecoin နှင့် Monero တို့ကိုသာ ဝယ်ယူမှုကို ပံ့ပိုးပေးပါသည်။ သင်၏ Bitcoin၊ Litecoin သို့မဟုတ် Monero ပိုက်ဆံအိတ်ကို ဖန်တီးပါ သို့မဟုတ် ပြောင်းပါ။",
|
||||
"sell_alert_content" : "ကျွန်ုပ်တို့သည် လက်ရှိတွင် Bitcoin ရောင်းချခြင်းကိုသာ ပံ့ပိုးပေးပါသည်။ Bitcoin ရောင်းချရန်၊ သင်၏ Bitcoin ပိုက်ဆံအိတ်ကို ဖန်တီးပါ သို့မဟုတ် ပြောင်းပါ။",
|
||||
|
||||
"outdated_electrum_wallet_description" : "ယခု Cake တွင်ဖန်တီးထားသော Bitcoin ပိုက်ဆံအိတ်အသစ်တွင် စကားလုံး 24 မျိုးရှိသည်။ Bitcoin ပိုက်ဆံအိတ်အသစ်တစ်ခုကို ဖန်တီးပြီး သင့်ငွေအားလုံးကို 24 စကားလုံးပိုက်ဆံအိတ်အသစ်သို့ လွှဲပြောင်းပြီး 12 စကားလုံးမျိုးစေ့ဖြင့် ပိုက်ဆံအိတ်များကို အသုံးပြုခြင်းကို ရပ်တန့်ရန် မဖြစ်မနေလိုအပ်ပါသည်။ သင့်ရန်ပုံငွေများကို လုံခြုံစေရန်အတွက် ၎င်းကိုချက်ချင်းလုပ်ဆောင်ပါ။",
|
||||
|
@ -684,5 +684,18 @@
|
|||
"send_to_this_address" : "ဤလိပ်စာသို့ ${currency} ${tag}သို့ ပို့ပါ။",
|
||||
"arrive_in_this_address" : "${currency} ${tag}ဤလိပ်စာသို့ ရောက်ရှိပါမည်။",
|
||||
"do_not_send": "မပို့ပါနှင့်",
|
||||
"error_dialog_content": "အိုး၊ ကျွန်ုပ်တို့တွင် အမှားအယွင်းအချို့ရှိသည်။\n\nအပလီကေးရှင်းကို ပိုမိုကောင်းမွန်စေရန်အတွက် ပျက်စီးမှုအစီရင်ခံစာကို ကျွန်ုပ်တို့၏ပံ့ပိုးကူညီရေးအဖွဲ့ထံ ပေးပို့ပါ။"
|
||||
"error_dialog_content": "အိုး၊ ကျွန်ုပ်တို့တွင် အမှားအယွင်းအချို့ရှိသည်။\n\nအပလီကေးရှင်းကို ပိုမိုကောင်းမွန်စေရန်အတွက် ပျက်စီးမှုအစီရင်ခံစာကို ကျွန်ုပ်တို့၏ပံ့ပိုးကူညီရေးအဖွဲ့ထံ ပေးပို့ပါ။",
|
||||
"decimal_places_error": "ဒဿမနေရာများ များလွန်းသည်။",
|
||||
"edit_node": "Node ကို တည်းဖြတ်ပါ။",
|
||||
"invoice_details": "ပြေစာအသေးစိတ်",
|
||||
"donation_link_details": "လှူဒါန်းရန်လင့်ခ်အသေးစိတ်",
|
||||
"anonpay_description": "${type} ကို ဖန်တီးပါ။ လက်ခံသူက ${method} ကို ပံ့ပိုးပေးထားသည့် cryptocurrency တစ်ခုခုဖြင့် လုပ်ဆောင်နိုင်ပြီး၊ သင်သည် ဤပိုက်ဆံအိတ်တွင် ရံပုံငွေများ ရရှိမည်ဖြစ်သည်။",
|
||||
"create_invoice": "ပြေစာဖန်တီးပါ။",
|
||||
"create_donation_link": "လှူဒါန်းမှုလင့်ခ်ကို ဖန်တီးပါ။",
|
||||
"optional_email_hint": "ရွေးချယ်နိုင်သော ငွေလက်ခံသူ အကြောင်းကြားချက် အီးမေးလ်",
|
||||
"optional_description": "ရွေးချယ်နိုင်သော ဖော်ပြချက်",
|
||||
"optional_name": "ရွေးချယ်နိုင်သော လက်ခံသူအမည်",
|
||||
"clearnet_link": "Clearnet လင့်ခ်",
|
||||
"onion_link": "ကြက်သွန်လင့်",
|
||||
"sell_monero_com_alert_content": "Monero ရောင်းချခြင်းကို မပံ့ပိုးရသေးပါ။"
|
||||
}
|
||||
|
|
|
@ -485,7 +485,7 @@
|
|||
|
||||
"submit_request" : "een verzoek indienen",
|
||||
|
||||
"buy_alert_content" : "Momenteel ondersteunen we alleen de aankoop van Bitcoin en Litecoin. Om Bitcoin of Litecoin te kopen, maakt u uw Bitcoin- of Litecoin-portemonnee aan of schakelt u over naar deze.",
|
||||
"buy_alert_content" : "Momenteel ondersteunen we alleen de aankoop van Bitcoin, Litecoin en Monero. Maak of schakel over naar uw Bitcoin-, Litecoin- of Monero-portemonnee.",
|
||||
"sell_alert_content": "We ondersteunen momenteel alleen de verkoop van Bitcoin. Om Bitcoin te verkopen, maakt u uw Bitcoin-portemonnee aan of schakelt u over naar deze.",
|
||||
|
||||
"outdated_electrum_wallet_description" : "Nieuwe Bitcoin-portefeuilles die in Cake zijn gemaakt, hebben nu een zaadje van 24 woorden. Het is verplicht dat u een nieuwe Bitcoin-portemonnee maakt en al uw geld overmaakt naar de nieuwe portemonnee van 24 woorden, en stopt met het gebruik van wallets met een seed van 12 woorden. Doe dit onmiddellijk om uw geld veilig te stellen.",
|
||||
|
@ -684,5 +684,18 @@
|
|||
"send_to_this_address" : "Stuur ${currency} ${tag}naar dit adres",
|
||||
"arrive_in_this_address" : "${currency} ${tag}komt aan op dit adres",
|
||||
"do_not_send": "Niet sturen",
|
||||
"error_dialog_content": "Oeps, er is een fout opgetreden.\n\nStuur het crashrapport naar ons ondersteuningsteam om de applicatie te verbeteren."
|
||||
"error_dialog_content": "Oeps, er is een fout opgetreden.\n\nStuur het crashrapport naar ons ondersteuningsteam om de applicatie te verbeteren.",
|
||||
"decimal_places_error": "Te veel decimalen",
|
||||
"edit_node": "Knooppunt bewerken",
|
||||
"invoice_details": "Factuurgegevens",
|
||||
"donation_link_details": "Details van de donatielink",
|
||||
"anonpay_description": "Genereer ${type}. De ontvanger kan ${method} gebruiken met elke ondersteunde cryptocurrency en u ontvangt geld in deze portemonnee",
|
||||
"create_invoice": "Factuur maken",
|
||||
"create_donation_link": "Maak een donatielink aan",
|
||||
"optional_email_hint": "Optionele kennisgeving per e-mail aan de begunstigde",
|
||||
"optional_description": "Optionele beschrijving",
|
||||
"optional_name": "Optionele naam ontvanger",
|
||||
"clearnet_link": "Clearnet-link",
|
||||
"onion_link": "Ui koppeling",
|
||||
"sell_monero_com_alert_content": "Het verkopen van Monero wordt nog niet ondersteund"
|
||||
}
|
||||
|
|
|
@ -485,7 +485,7 @@
|
|||
|
||||
"submit_request" : "Złóż wniosek",
|
||||
|
||||
"buy_alert_content" : "Obecnie obsługujemy tylko zakup Bitcoina i Litecoina. Aby kupić Bitcoin lub Litecoin, utwórz lub przełącz się na swój portfel Bitcoin lub Litecoin.",
|
||||
"buy_alert_content" : "Obecnie obsługujemy tylko zakup Bitcoin, Litecoin i Monero. Utwórz lub przełącz się na swój portfel Bitcoin, Litecoin lub Monero.",
|
||||
"sell_alert_content": "Obecnie obsługujemy tylko sprzedaż Bitcoina. Aby sprzedać Bitcoin, utwórz lub przełącz się na swój portfel Bitcoin.",
|
||||
|
||||
"outdated_electrum_wallet_description" : "Nowe portfele Bitcoin utworzone w Cake mają teraz fraze seed składające się z 24 słów. Konieczne jest utworzenie nowego portfela Bitcoin i przeniesienie wszystkich środków do nowego portfela na 24 słowa oraz zaprzestanie korzystania z portfeli z frazą seed na 12 słów. Zrób to natychmiast, aby zabezpieczyć swoje fundusze.",
|
||||
|
@ -684,5 +684,18 @@
|
|||
"send_to_this_address" : "Wyślij ${currency} ${tag}na ten adres",
|
||||
"arrive_in_this_address" : "${currency} ${tag}dotrze na ten adres",
|
||||
"do_not_send": "Nie wysyłaj",
|
||||
"error_dialog_content": "Ups, wystąpił błąd.\n\nPrześlij raport o awarii do naszego zespołu wsparcia, aby ulepszyć aplikację."
|
||||
"error_dialog_content": "Ups, wystąpił błąd.\n\nPrześlij raport o awarii do naszego zespołu wsparcia, aby ulepszyć aplikację.",
|
||||
"decimal_places_error": "Za dużo miejsc dziesiętnych",
|
||||
"edit_node": "Edytuj węzeł",
|
||||
"invoice_details": "Dane do faktury",
|
||||
"donation_link_details": "Szczegóły linku darowizny",
|
||||
"anonpay_description": "Wygeneruj ${type}. Odbiorca może ${method} z dowolną obsługiwaną kryptowalutą, a Ty otrzymasz środki w tym portfelu.",
|
||||
"create_invoice": "Wystaw fakturę",
|
||||
"create_donation_link": "Utwórz link do darowizny",
|
||||
"optional_email_hint": "Opcjonalny e-mail z powiadomieniem odbiorcy płatności",
|
||||
"optional_description": "Opcjonalny opis",
|
||||
"optional_name": "Opcjonalna nazwa odbiorcy",
|
||||
"clearnet_link": "łącze Clearnet",
|
||||
"onion_link": "Łącznik cebulowy",
|
||||
"sell_monero_com_alert_content": "Sprzedaż Monero nie jest jeszcze obsługiwana"
|
||||
}
|
||||
|
|
|
@ -485,7 +485,7 @@
|
|||
|
||||
"submit_request" : "enviar um pedido",
|
||||
|
||||
"buy_alert_content" : "Atualmente, apoiamos apenas a compra de Bitcoin e Litecoin. Para comprar Bitcoin ou Litecoin, crie ou troque para sua carteira Bitcoin ou Litecoin.",
|
||||
"buy_alert_content" : "Atualmente, oferecemos suporte apenas à compra de Bitcoin, Litecoin e Monero. Crie ou troque para sua carteira Bitcoin, Litecoin ou Monero.",
|
||||
"sell_alert_content": "Atualmente, apoiamos apenas a venda de Bitcoin. Para vender Bitcoin, crie ou mude para sua carteira Bitcoin.",
|
||||
|
||||
"outdated_electrum_wallet_description" : "As novas carteiras Bitcoin criadas no Cake agora têm uma semente de 24 palavras. É obrigatório que você crie uma nova carteira Bitcoin e transfira todos os seus fundos para a nova carteira de 24 palavras, e pare de usar carteiras com semente de 12 palavras. Faça isso imediatamente para garantir seus fundos.",
|
||||
|
@ -683,5 +683,18 @@
|
|||
"send_to_this_address" : "Envie ${currency} ${tag}para este endereço",
|
||||
"arrive_in_this_address" : "${currency} ${tag}chegará neste endereço",
|
||||
"do_not_send": "não envie",
|
||||
"error_dialog_content": "Ops, houve algum erro.\n\nPor favor, envie o relatório de falha para nossa equipe de suporte para melhorar o aplicativo."
|
||||
"error_dialog_content": "Ops, houve algum erro.\n\nPor favor, envie o relatório de falha para nossa equipe de suporte para melhorar o aplicativo.",
|
||||
"decimal_places_error": "Muitas casas decimais",
|
||||
"edit_node": "Editar nó",
|
||||
"invoice_details": "Detalhes da fatura",
|
||||
"donation_link_details": "Detalhes do link de doação",
|
||||
"anonpay_description": "Gere ${type}. O destinatário pode ${method} com qualquer criptomoeda suportada e você receberá fundos nesta carteira.",
|
||||
"create_invoice": "Criar recibo",
|
||||
"create_donation_link": "Criar link de doação",
|
||||
"optional_email_hint": "E-mail opcional de notificação do beneficiário",
|
||||
"optional_description": "Descrição opcional",
|
||||
"optional_name": "Nome do destinatário opcional",
|
||||
"clearnet_link": "link clear net",
|
||||
"onion_link": "ligação de cebola",
|
||||
"sell_monero_com_alert_content": "A venda de Monero ainda não é suportada"
|
||||
}
|
||||
|
|
|
@ -485,7 +485,7 @@
|
|||
|
||||
"submit_request" : "отправить запрос",
|
||||
|
||||
"buy_alert_content" : "В настоящее время мы поддерживаем только покупку Bitcoin и Litecoin. Чтобы купить Bitcoin или Litecoin, создайте или переключитесь на свой Bitcoin или Litecoin кошелек.",
|
||||
"buy_alert_content" : "В настоящее время мы поддерживаем только покупку Bitcoin, Litecoin и Monero. Пожалуйста, создайте или переключитесь на свой кошелек Bitcoin, Litecoin или Monero.",
|
||||
"sell_alert_content": "В настоящее время мы поддерживаем только продажу биткойнов. Чтобы продать биткойны, создайте или переключитесь на свой биткойн-кошелек.",
|
||||
|
||||
"outdated_electrum_wallet_description" : "Новые биткойн-кошельки, созданные в Cake, теперь содержат мнемоническую фразу из 24 слов. Вы обязательно должны создать новый биткойн-кошелек и перевести все свои средства в новый кошелек из 24 слов, а также прекратить использование кошельков с мнемонической фразой из 12 слов. Пожалуйста, сделайте это немедленно, чтобы обезопасить свои средства.",
|
||||
|
@ -684,5 +684,18 @@
|
|||
"send_to_this_address" : "Отправить ${currency} ${tag}на этот адрес",
|
||||
"arrive_in_this_address" : "${currency} ${tag}придет на этот адрес",
|
||||
"do_not_send": "Не отправлять",
|
||||
"error_dialog_content": "Ой, у нас какая-то ошибка.\n\nПожалуйста, отправьте отчет о сбое в нашу службу поддержки, чтобы сделать приложение лучше."
|
||||
"error_dialog_content": "Ой, у нас какая-то ошибка.\n\nПожалуйста, отправьте отчет о сбое в нашу службу поддержки, чтобы сделать приложение лучше.",
|
||||
"decimal_places_error": "Слишком много десятичных знаков",
|
||||
"edit_node": "Редактировать узел",
|
||||
"invoice_details": "Детали счета",
|
||||
"donation_link_details": "Информация о ссылке для пожертвований",
|
||||
"anonpay_description": "Создайте ${type}. Получатель может использовать ${method} с любой поддерживаемой криптовалютой, и вы получите средства на этот кошелек.",
|
||||
"create_invoice": "Создать счет",
|
||||
"create_donation_link": "Создать ссылку для пожертвований",
|
||||
"optional_email_hint": "Необязательное электронное письмо с уведомлением получателя платежа",
|
||||
"optional_description": "Дополнительное описание",
|
||||
"optional_name": "Необязательное имя получателя",
|
||||
"clearnet_link": "Клирнет ссылка",
|
||||
"onion_link": "Луковая ссылка",
|
||||
"sell_monero_com_alert_content": "Продажа Monero пока не поддерживается"
|
||||
}
|
||||
|
|
|
@ -483,7 +483,7 @@
|
|||
|
||||
"submit_request" : "ส่งคำขอ",
|
||||
|
||||
"buy_alert_content" : "ในปัจจุบันเรารองรับการซื้อ Bitcoin และ Litecoin เท่านั้น หากต้องการซื้อ Bitcoin หรือ Litecoin โปรดสร้างหรือเปลี่ยนเป็นกระเป๋า Bitcoin หรือ Litecoin ของคุณ",
|
||||
"buy_alert_content" : "ขณะนี้เรารองรับการซื้อ Bitcoin, Litecoin และ Monero เท่านั้น โปรดสร้างหรือเปลี่ยนเป็นกระเป๋าเงิน Bitcoin, Litecoin หรือ Monero ของคุณ",
|
||||
"sell_alert_content" : "ในปัจจุบันเรารองรับการขาย Bitcoin เท่านั้น หากต้องการขาย Bitcoin โปรดสร้างหรือเปลี่ยนเป็นกระเป๋า Bitcoin ของคุณ",
|
||||
|
||||
"outdated_electrum_wallet_description" : "กระเป๋า Bitcoin ใหม่ที่สร้างใน Cake มี seed ขนาด 24 คำ ซึ่งจำเป็นต้องสร้างกระเป๋า Bitcoin ใหม่และโอนทุกเงินของคุณไปยังกระเป๋าใหม่ขนาด 24 คำ และหยุดใช้กระเป๋าที่มี seed ขนาด 12 คำ กรุณาทำด่วนเพื่อรักษาเงินของคุณ",
|
||||
|
@ -682,5 +682,18 @@
|
|||
"send_to_this_address" : "ส่ง ${currency} ${tag}ไปยังที่อยู่นี้",
|
||||
"arrive_in_this_address" : "${currency} ${tag}จะมาถึงที่อยู่นี้",
|
||||
"do_not_send": "อย่าส่ง",
|
||||
"error_dialog_content": "อ๊ะ เราพบข้อผิดพลาดบางอย่าง\n\nโปรดส่งรายงานข้อขัดข้องไปยังทีมสนับสนุนของเราเพื่อปรับปรุงแอปพลิเคชันให้ดียิ่งขึ้น"
|
||||
"error_dialog_content": "อ๊ะ เราพบข้อผิดพลาดบางอย่าง\n\nโปรดส่งรายงานข้อขัดข้องไปยังทีมสนับสนุนของเราเพื่อปรับปรุงแอปพลิเคชันให้ดียิ่งขึ้น",
|
||||
"decimal_places_error": "ทศนิยมมากเกินไป",
|
||||
"edit_node": "แก้ไขโหนด",
|
||||
"invoice_details": "รายละเอียดใบแจ้งหนี้",
|
||||
"donation_link_details": "รายละเอียดลิงค์บริจาค",
|
||||
"anonpay_description": "สร้าง ${type} ผู้รับสามารถ ${method} ด้วยสกุลเงินดิจิทัลที่รองรับ และคุณจะได้รับเงินในกระเป๋าสตางค์นี้",
|
||||
"create_invoice": "สร้างใบแจ้งหนี้",
|
||||
"create_donation_link": "สร้างลิงค์บริจาค",
|
||||
"optional_email_hint": "อีเมลแจ้งผู้รับเงินเพิ่มเติม",
|
||||
"optional_description": "คำอธิบายเพิ่มเติม",
|
||||
"optional_name": "ชื่อผู้รับเพิ่มเติม",
|
||||
"clearnet_link": "ลิงค์เคลียร์เน็ต",
|
||||
"onion_link": "ลิงค์หัวหอม",
|
||||
"sell_monero_com_alert_content": "ยังไม่รองรับการขาย Monero"
|
||||
}
|
||||
|
|
|
@ -485,7 +485,7 @@
|
|||
|
||||
"submit_request" : "talep gönder",
|
||||
|
||||
"buy_alert_content" : "Şu anda sadece Bitcoin ve Litecoin satın alımını destekliyoruz. Bitcoin veya Litecoin satın almak için lütfen Bitcoin veya Litecoin cüzdanınızı oluşturun veya bu cüzdanlardan birine geçiş yapın.",
|
||||
"buy_alert_content" : "Şu anda yalnızca Bitcoin, Litecoin ve Monero satın alımını destekliyoruz. Lütfen Bitcoin, Litecoin veya Monero cüzdanınızı oluşturun veya cüzdanınıza geçiş yapın.",
|
||||
"sell_alert_content": "Şu anda sadece Bitcoin satışını destekliyoruz. Bitcoin satmak için lütfen Bitcoin cüzdanınızı oluşturun veya Bitcoin cüzdanınıza geçiş yapın.",
|
||||
|
||||
"outdated_electrum_wallet_description" : "Cake'te oluşturulan yeni Bitcoin cüzdanları artık 24 kelimelik bir tohuma sahip. Yeni bir Bitcoin cüzdanı oluşturmanız ve tüm paranızı 24 kelimelik yeni cüzdana aktarmanız ve 12 kelimelik tohuma sahip cüzdanları kullanmayı bırakmanız zorunludur. Lütfen paranızı güvence altına almak için bunu hemen yapın.",
|
||||
|
@ -684,5 +684,18 @@
|
|||
"send_to_this_address" : "Bu adrese ${currency} ${tag}gönder",
|
||||
"arrive_in_this_address" : "${currency} ${tag}bu adrese ulaşacak",
|
||||
"do_not_send": "Gönderme",
|
||||
"error_dialog_content": "Hay aksi, bir hatamız var.\n\nUygulamayı daha iyi hale getirmek için lütfen kilitlenme raporunu destek ekibimize gönderin."
|
||||
"error_dialog_content": "Hay aksi, bir hatamız var.\n\nUygulamayı daha iyi hale getirmek için lütfen kilitlenme raporunu destek ekibimize gönderin.",
|
||||
"decimal_places_error": "Çok fazla ondalık basamak",
|
||||
"edit_node": "Düğümü Düzenle",
|
||||
"invoice_details": "fatura detayları",
|
||||
"donation_link_details": "Bağış bağlantısı ayrıntıları",
|
||||
"anonpay_description": "${type} oluşturun. Alıcı, desteklenen herhangi bir kripto para birimi ile ${method} yapabilir ve bu cüzdanda para alırsınız.",
|
||||
"create_invoice": "Fatura oluşturmak",
|
||||
"create_donation_link": "Bağış bağlantısı oluştur",
|
||||
"optional_email_hint": "İsteğe bağlı alacaklı bildirim e-postası",
|
||||
"optional_description": "İsteğe bağlı açıklama",
|
||||
"optional_name": "İsteğe bağlı alıcı adı",
|
||||
"clearnet_link": "Net bağlantı",
|
||||
"onion_link": "soğan bağlantısı",
|
||||
"sell_monero_com_alert_content": "Monero satışı henüz desteklenmiyor"
|
||||
}
|
||||
|
|
|
@ -484,7 +484,7 @@
|
|||
|
||||
"submit_request" : "надіслати запит",
|
||||
|
||||
"buy_alert_content" : "В даний час ми підтримуємо лише придбання Bitcoin та Litecoin. Щоб купити Bitcoin або Litecoin, будь ласка, створіть або перейдіть на свій гаманець Bitcoin або Litecoin.",
|
||||
"buy_alert_content" : "Наразі ми підтримуємо лише придбання Bitcoin, Litecoin і Monero. Створіть або перейдіть на свій гаманець Bitcoin, Litecoin або Monero.",
|
||||
"sell_alert_content": "Наразі ми підтримуємо лише продаж біткойнів. Щоб продати біткойн, створіть або перейдіть на свій біткойн-гаманець.",
|
||||
|
||||
"outdated_electrum_wallet_description" : "Нові біткойн-гаманці, створені в Cake, тепер містять мнемонічну фразу з 24 слів. Обов’язково стовріть новий біткойн-гаманець, переведіть всі кошти на новий гаманець із 24 слів і припиніть використання гаманців із мнемонічною фразою з 12 слів. Зробіть це негайно, щоб убезпечити свої кошти.",
|
||||
|
@ -683,5 +683,18 @@
|
|||
"send_to_this_address" : "Надіслати ${currency} ${tag}на цю адресу",
|
||||
"arrive_in_this_address" : "${currency} ${tag}надійде на цю адресу",
|
||||
"do_not_send": "Не надсилайте",
|
||||
"error_dialog_content": "На жаль, ми отримали помилку.\n\nБудь ласка, надішліть звіт про збій нашій команді підтримки, щоб покращити додаток."
|
||||
"error_dialog_content": "На жаль, ми отримали помилку.\n\nБудь ласка, надішліть звіт про збій нашій команді підтримки, щоб покращити додаток.",
|
||||
"decimal_places_error": "Забагато знаків після коми",
|
||||
"edit_node": "Редагувати вузол",
|
||||
"invoice_details": "Реквізити рахунку-фактури",
|
||||
"donation_link_details": "Деталі посилання для пожертв",
|
||||
"anonpay_description": "Згенерувати ${type}. Одержувач може ${method} будь-якою підтримуваною криптовалютою, і ви отримаєте кошти на цей гаманець.",
|
||||
"create_invoice": "Створити рахунок-фактуру",
|
||||
"create_donation_link": "Створити посилання для пожертв",
|
||||
"optional_email_hint": "Додаткова електронна адреса для сповіщення одержувача",
|
||||
"optional_description": "Додатковий опис",
|
||||
"optional_name": "Додаткове ім'я одержувача",
|
||||
"clearnet_link": "Посилання Clearnet",
|
||||
"onion_link": "Посилання на цибулю",
|
||||
"sell_monero_com_alert_content": "Продаж Monero ще не підтримується"
|
||||
}
|
||||
|
|
|
@ -487,7 +487,7 @@
|
|||
|
||||
"submit_request" : "درخواست بھیج دو",
|
||||
|
||||
"buy_alert_content" : "فی الحال ہم صرف Bitcoin اور Litecoin کی خریداری کی حمایت کرتے ہیں۔ Bitcoin یا Litecoin خریدنے کے لیے، براہ کرم اپنا Bitcoin یا Litecoin والیٹ بنائیں یا اس میں سوئچ کریں۔",
|
||||
"buy_alert_content" : "فی الحال ہم صرف Bitcoin، Litecoin، اور Monero کی خریداری کی حمایت کرتے ہیں۔ براہ کرم اپنا Bitcoin، Litecoin، یا Monero والیٹ بنائیں یا اس پر سوئچ کریں۔",
|
||||
"sell_alert_content" : "ہم فی الحال صرف Bitcoin کی فروخت کی حمایت کرتے ہیں۔ Bitcoin فروخت کرنے کے لیے، براہ کرم اپنا Bitcoin والیٹ بنائیں یا اس میں سوئچ کریں۔",
|
||||
|
||||
"outdated_electrum_wallet_description" : "Cake میں بنائے گئے نئے Bitcoin بٹوے میں اب 24 الفاظ کا بیج ہے۔ یہ لازمی ہے کہ آپ ایک نیا Bitcoin والیٹ بنائیں اور اپنے تمام فنڈز کو نئے 24 الفاظ والے والیٹ میں منتقل کریں، اور 12 الفاظ کے بیج والے بٹوے کا استعمال بند کریں۔ براہ کرم اپنے فنڈز کو محفوظ بنانے کے لیے فوری طور پر ایسا کریں۔",
|
||||
|
@ -685,5 +685,18 @@
|
|||
"send_to_this_address" : "اس پتے پر ${currency} ${tag} بھیجیں۔",
|
||||
"arrive_in_this_address" : "${currency} ${tag}اس پتے پر پہنچے گا۔",
|
||||
"do_not_send" : "مت بھیجیں۔",
|
||||
"error_dialog_content" : "افوہ، ہمیں کچھ خرابی ملی۔\n\nایپلی کیشن کو بہتر بنانے کے لیے براہ کرم کریش رپورٹ ہماری سپورٹ ٹیم کو بھیجیں۔"
|
||||
"error_dialog_content" : "افوہ، ہمیں کچھ خرابی ملی۔\n\nایپلی کیشن کو بہتر بنانے کے لیے براہ کرم کریش رپورٹ ہماری سپورٹ ٹیم کو بھیجیں۔",
|
||||
"decimal_places_error": "بہت زیادہ اعشاریہ جگہیں۔",
|
||||
"edit_node": "نوڈ میں ترمیم کریں۔",
|
||||
"invoice_details": "رسید کی تفصیلات",
|
||||
"donation_link_details": "عطیہ کے لنک کی تفصیلات",
|
||||
"anonpay_description": "${type} بنائیں۔ وصول کنندہ کسی بھی تعاون یافتہ کرپٹو کرنسی کے ساتھ ${method} کرسکتا ہے، اور آپ کو اس بٹوے میں فنڈز موصول ہوں گے۔",
|
||||
"create_invoice": "انوائس بنائیں",
|
||||
"create_donation_link": "عطیہ کا لنک بنائیں",
|
||||
"optional_email_hint": "اختیاری وصول کنندہ کی اطلاع کا ای میل",
|
||||
"optional_description": "اختیاری تفصیل",
|
||||
"optional_name": "اختیاری وصول کنندہ کا نام",
|
||||
"clearnet_link": "کلیرنیٹ لنک",
|
||||
"onion_link": "پیاز کا لنک",
|
||||
"sell_monero_com_alert_content": "Monero فروخت کرنا ابھی تک تعاون یافتہ نہیں ہے۔"
|
||||
}
|
||||
|
|
|
@ -484,7 +484,8 @@
|
|||
|
||||
"submit_request" : "提交请求",
|
||||
|
||||
"buy_alert_content" : "目前我们只支持购买比特币和莱特币。 要购买比特币或莱特币,请创建或切换到您的比特币或莱特币钱包。",
|
||||
"buy_alert_content" : "目前我们只支持购买比特币、莱特币和门罗币。 请创建或切换到您的比特币、莱特币或门罗币钱包。",
|
||||
"sell_alert_content" : "我们目前只支持比特币的销售。 要出售比特币,请创建或切换到您的比特币钱包。",
|
||||
|
||||
"outdated_electrum_wallet_description" : "在Cake创建的新比特币钱包现在有一个24字的种子。你必须创建一个新的比特币钱包,并将你所有的资金转移到新的24字钱包,并停止使用12字种子的钱包。请立即这样做以保证你的资金安全。",
|
||||
"understand" : "我已知晓",
|
||||
|
@ -682,5 +683,18 @@
|
|||
"send_to_this_address" : "发送 ${currency} ${tag}到这个地址",
|
||||
"arrive_in_this_address" : "${currency} ${tag}将到达此地址",
|
||||
"do_not_send": "不要发送",
|
||||
"error_dialog_content": "糟糕,我们遇到了一些错误。\n\n请将崩溃报告发送给我们的支持团队,以改进应用程序。"
|
||||
"error_dialog_content": "糟糕,我们遇到了一些错误。\n\n请将崩溃报告发送给我们的支持团队,以改进应用程序。",
|
||||
"decimal_places_error": "小数位太多",
|
||||
"edit_node": "编辑节点",
|
||||
"invoice_details": "发票明细",
|
||||
"donation_link_details": "捐赠链接详情",
|
||||
"anonpay_description": "生成 ${type}。收款人可以使用任何受支持的加密货币 ${method},您将在此钱包中收到资金。",
|
||||
"create_invoice": "创建发票",
|
||||
"create_donation_link": "创建捐赠链接",
|
||||
"optional_email_hint": "可选的收款人通知电子邮件",
|
||||
"optional_description": "可选说明",
|
||||
"optional_name": "可选收件人姓名",
|
||||
"clearnet_link": "明网链接",
|
||||
"onion_link": "洋葱链接",
|
||||
"sell_monero_com_alert_content": "尚不支持出售门罗币"
|
||||
}
|
||||
|
|
|
@ -14,14 +14,14 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
|
|||
APP_ANDROID_TYPE=$1
|
||||
|
||||
MONERO_COM_NAME="Monero.com"
|
||||
MONERO_COM_VERSION="1.3.0"
|
||||
MONERO_COM_BUILD_NUMBER=40
|
||||
MONERO_COM_VERSION="1.3.2"
|
||||
MONERO_COM_BUILD_NUMBER=42
|
||||
MONERO_COM_BUNDLE_ID="com.monero.app"
|
||||
MONERO_COM_PACKAGE="com.monero.app"
|
||||
|
||||
CAKEWALLET_NAME="Cake Wallet"
|
||||
CAKEWALLET_VERSION="4.6.0"
|
||||
CAKEWALLET_BUILD_NUMBER=146
|
||||
CAKEWALLET_VERSION="4.6.2"
|
||||
CAKEWALLET_BUILD_NUMBER=151
|
||||
CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
|
||||
CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"
|
||||
|
||||
|
|
|
@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
|
|||
APP_IOS_TYPE=$1
|
||||
|
||||
MONERO_COM_NAME="Monero.com"
|
||||
MONERO_COM_VERSION="1.3.0"
|
||||
MONERO_COM_BUILD_NUMBER=38
|
||||
MONERO_COM_VERSION="1.3.2"
|
||||
MONERO_COM_BUILD_NUMBER=40
|
||||
MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
|
||||
|
||||
CAKEWALLET_NAME="Cake Wallet"
|
||||
CAKEWALLET_VERSION="4.6.0"
|
||||
CAKEWALLET_BUILD_NUMBER=142
|
||||
CAKEWALLET_VERSION="4.6.2"
|
||||
CAKEWALLET_BUILD_NUMBER=145
|
||||
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
|
||||
|
||||
HAVEN_NAME="Haven"
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue