Dashboard desktop view (#737)

* Add build scripts for macOS. Add macos for cw_monero plugin. Add macos proj to the application. * - Update Flutter secure storage to work with macos - Enable uni links only on Mobile - Update devcelocale to work with macos * Add network access to mac * Change Dashboard view on desktop size screens * Add on Tap to desktop_action_button.dart Remove unused functions * Fix arch match for monero lib for darwin x86_64 -> x86-64 * Add Bundle ID in entitlements files through app config script * Update deployment target to 10.13 * Revert back to Cake fork for secure storage * Revert back to Cake fork for secure storage * Revert mac os version * Revert mac os version * Add platform channel specific code for mac os * Add desktop sidebar * [skip ci] Add desktop sidebar * [skip ci] Add desktop sidebar * - Remove legacy migration from macos - Remove wake lock native code and just use the ready made package * Remove wake lock native code and just use the ready made package * Remove unstoppable domain from macos since it's not supported * Temporarily fetch unstoppable domains only on mobile * refactor desktop settings sidebar * Ignore increasing brightness for non-mobile platforms * Add Wallet selection dropdown to dashboard desktop view * Generate MacOS icons * localize settings * fix dashboard sidebar and responsive utils * Change Mac os app name and bundle id * Fix exchange page as fullScreenDialog * Remove constants * - Refactor onRamper to have a single point of modification - Enlarge initial app size - update Flutter and Packages * Add pubspec.lock and Podfile.lock to gitignore * Remove Podfile.lock from cache * Fix bug on sidebar reset * Fix issues from code review * [skip ci] reformat desktop dashboard * [skip ci] reformat desktop dashboard * Revert removing .lock files * Revert changes in .gitignore * [skip ci] remove .project changes * [skip ci] remove .project changes * Separate Dashboard desktop view from mobile view * constraint images and pincoded box * Remove drawer from mac os * - Listen to keyboard events in PIN screen - Fix PIN buttons style * Fix desktop nav bar UI * Add Marketplace to dashboard view * Update trailing icon to open transaction page * Update widget contraints * Add empty trailing to center page title on desktop * Refresh desktop dashboard actions on wallet change * Change ionia welcome page animation * Fix Constrained width screens UI * Refactor sidebar state management * remove empty line * Add max width constrain to Welcome page * Change Exchange page UI depending on platform * - Change design/paddings for Send page on desktop view - Make AddTemplateButton instead of having it duplicated in send/exchange * Fix Desktop dashboard actions background color * Constrain primary Buttons width * Make side menu items toggle back to dashboard * Add padding to support page * Add width constraints to desktop dashboard * Fix UI issues, paddings and alignments * Rename misleading variable Change initial mac window size * Fix wallet create in settings * remove unnecessary code * remove unnecessary code * Remove duplicated constrains * - Use close icon on main screens - Minor UI fixes * fix pageview controller reset index * Add create and restore wallet options to dropdown menu * Fix desktop background color and address book view issues * Fix input field * Add onFieldSubmitted to allow "enter" button interaction * Fix issue from code review * Fix Popup width constraint and add focus orders * Fix variable name * Fix issues from code review * refactor dropdown items * Fix alignment in create and restore wallet screens * Fix dropdown change state bug Hide scanner for desktop * remove space * override navbar with desktopnavbar * Remove autofocus * remove unused code * Fix ionia input field alignment * Replace removed code * Add app lock feature on mac * Add assertion to avoid null * Add Nano currency image * Enable adding contact from send screen * Fix UI issues Add missing translation * pop only PIN screen after successful auth * Add back wallet settings page to desktop settings actions * Fix Navigation animation for settings screens * Fixate MobX version to fix restore issue * CW-324 Refresh current settings page if wallet changed (#811) * Fix refresh current settings page if wallet changed * Fix refresh current settings page if wallet changed * Refresh Wallet Seeds/Keys List upon wallet change --------- Co-authored-by: OmarHatem <omarh.ismail1@gmail.com> * Remove navigation workaround for duplicate key, and fix the issue by handling creation/disposing of global key (#840) * Cw 323 add wallet list to settings on mac (#843) * Remove navigation workaround for duplicate key, and fix the issue by handling creation/disposing of global key * - Register Wallet List as singleton in Desktop to be modify the same instance from settings and dropdown - General Fixes and Enhancements * Fix Changing/Restoring wallet from settings * Fix Create wallet not showing seeds screens if launched from settings * Add max width constraint for Alerts * - Add Desktop API keys - Fix Change back up password issue - Fix Popup width * Sync Mac with latest main updates * Swap Transactions icon with lock icon * Save backup file locally on desktop * Sync with latest main updates * Fix Navigation issues with anonpay * Update macos build version * Remove deprecated custom wake lock code for Android * Remove Legacy CryptoSwift package from MacOS * - Refactor Payfura page code - Add OnRamper new configs to onramper_buy_provider.dart - Fix Conflicts with main * Updated device locale package * Update android tools * Revert changes and update only gradle version * Downgrade android tools version * Update gradle version * Update package/gradle/plugin version * - Fixate device locale version - Downgrade gradle version * Update kotlin version * Update gradle version * Trial for a custom fork from devicelocale * Fixate shared preferences package version * Revert gradle version * Revert kotlin version * Downgrade gradle version * Downgrade gradle version * Repair cache and clean before build * Fixate flutter version * update google services version * revert google services version * Force shared pref android version * Override shared prefs android package version * Override shared prefs android package [skip ci] --------- Co-authored-by: M <m@cakewallet.com> Co-authored-by: Godwin Asuquo <godilite@gmail.com> Co-authored-by: Godwin Asuquo <41484542+godilite@users.noreply.github.com>

Omar Hatem committed Apr 14, 2023 at 06:39 UTC c5477e4f9ea8a0d4d9ad77db2171999664a8b0c4
231 files changed +9932 -2639
.github/workflows/pr_test_build.yml
+2
@@ -99,6 +99,7 @@ jobs:
99 echo "const backupSalt = '${{ secrets.BACKUP_SALT }}';" >> lib/.secrets.g.dart
100 echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
101 echo "const changeNowApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart
102 + echo "const changeNowApiKeyDesktop = '${{ secrets.CHANGE_NOW_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart
103 echo "const wyreSecretKey = '${{ secrets.WYRE_SECRET_KEY }}';" >> lib/.secrets.g.dart
104 echo "const wyreApiKey = '${{ secrets.WYRE_API_KEY }}';" >> lib/.secrets.g.dart
105 echo "const wyreAccountId = '${{ secrets.WYRE_ACCOUNT_ID }}';" >> lib/.secrets.g.dart
@@ -107,6 +108,7 @@ jobs:
108 echo "const sideShiftAffiliateId = '${{ secrets.SIDE_SHIFT_AFFILIATE_ID }}';" >> lib/.secrets.g.dart
109 echo "const sideShiftApiKey = '${{ secrets.SIDE_SHIFT_API_KEY }}';" >> lib/.secrets.g.dart
110 echo "const simpleSwapApiKey = '${{ secrets.SIMPLE_SWAP_API_KEY }}';" >> lib/.secrets.g.dart
111 + echo "const simpleSwapApiKeyDesktop = '${{ secrets.SIMPLE_SWAP_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart
112 echo "const onramperApiKey = '${{ secrets.ONRAMPER_API_KEY }}';" >> lib/.secrets.g.dart
113 echo "const anypayToken = '${{ secrets.ANY_PAY_TOKEN }}';" >> lib/.secrets.g.dart
114 echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart
.gitignore
+5
@@ -135,3 +135,8 @@ assets/images/app_logo.png
135 /pubspec.lock
136 /android/app.properties
137 /android/app/src/main/AndroidManifest.xml
138 +
139 +
140 +macos/Runner/Info.plist
141 +macos/Runner/DebugProfile.entitlements
142 +macos/Runner/Release.entitlements
\ No newline at end of file
.metadata
+22 -2
@@ -1,10 +1,30 @@
1 # This file tracks properties of this Flutter project.
2 # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 #
4 -# This file should be version controlled and should not be manually edited.
4 +# This file should be version controlled.
5
6 version:
7 - revision: 20e59316b8b8474554b38493b8ca888794b0234a
7 + revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
8 channel: stable
9
10 project_type: app
11 +
12 +# Tracks metadata for the flutter migrate command
13 +migration:
14 + platforms:
15 + - platform: root
16 + create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
17 + base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
18 + - platform: macos
19 + create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
20 + base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
21 +
22 + # User provided section
23 +
24 + # List of Local paths (relative to this file) that should be
25 + # ignored by the migrate tool.
26 + #
27 + # Files that are not part of the templates will be ignored by default.
28 + unmanaged_files:
29 + - 'lib/main.dart'
30 + - 'ios/Runner.xcodeproj/project.pbxproj'
android/app/src/main/java/com/cakewallet/cake_wallet/MainActivity.java
-8
@@ -41,14 +41,6 @@ public class MainActivity extends FlutterFragmentActivity {
41
42 try {
43 switch (call.method) {
44 - case "enableWakeScreen":
45 - getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
46 - handler.post(() -> result.success(true));
47 - break;
48 - case "disableWakeScreen":
49 - getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
50 - handler.post(() -> result.success(true));
51 - break;
44 case "sec_random":
45 int count = call.argument("count");
46 SecureRandom random = new SecureRandom();
android/app/src/main/java/com/cakewallet/haven/MainActivity.java
-8
@@ -40,14 +40,6 @@ public class MainActivity extends FlutterFragmentActivity {
40
41 try {
42 switch (call.method) {
43 - case "enableWakeScreen":
44 - getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
45 - handler.post(() -> result.success(true));
46 - break;
47 - case "disableWakeScreen":
48 - getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
49 - handler.post(() -> result.success(true));
50 - break;
43 case "sec_random":
44 int count = call.argument("count");
45 SecureRandom random = new SecureRandom();
android/app/src/main/java/com/monero/app/MainActivity.java
-8
@@ -40,14 +40,6 @@ public class MainActivity extends FlutterFragmentActivity {
40
41 try {
42 switch (call.method) {
43 - case "enableWakeScreen":
44 - getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
45 - handler.post(() -> result.success(true));
46 - break;
47 - case "disableWakeScreen":
48 - getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
49 - handler.post(() -> result.success(true));
50 - break;
43 case "sec_random":
44 int count = call.argument("count");
45 SecureRandom random = new SecureRandom();
assets/images/desktop_transactions_outline_icon.png
Binary files /dev/null and b/assets/images/desktop_transactions_outline_icon.png differ
assets/images/desktop_transactions_solid_icon.png
Binary files /dev/null and b/assets/images/desktop_transactions_solid_icon.png differ
assets/images/settings_outline.png
Binary files /dev/null and b/assets/images/settings_outline.png differ
assets/images/support_icon.png
Binary files /dev/null and b/assets/images/support_icon.png differ
assets/images/wallet_outline.png
Binary files /dev/null and b/assets/images/wallet_outline.png differ
assets/images/wallet_solid.png
Binary files /dev/null and b/assets/images/wallet_solid.png differ
cw_monero/.gitignore
+4 -1
@@ -8,4 +8,7 @@ build/
8
9 ios/External/
10 android/.externalNativeBuild/
11 -android/.cxx/
\ No newline at end of file
11 +android/.cxx/
12 +
13 +macos/cw_monero.podspec
14 +macos/External/
\ No newline at end of file
cw_monero/.metadata
+23 -3
@@ -1,10 +1,30 @@
1 # This file tracks properties of this Flutter project.
2 # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 #
4 -# This file should be version controlled and should not be manually edited.
4 +# This file should be version controlled.
5
6 version:
7 - revision: 798e4272a2e43d7daab75f225a13442e384ee0cd
8 - channel: dev
7 + revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
8 + channel: stable
9
10 project_type: plugin
11 +
12 +# Tracks metadata for the flutter migrate command
13 +migration:
14 + platforms:
15 + - platform: root
16 + create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
17 + base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
18 + - platform: macos
19 + create_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
20 + base_revision: e3c29ec00c9c825c891d75054c63fcc46454dca1
21 +
22 + # User provided section
23 +
24 + # List of Local paths (relative to this file) that should be
25 + # ignored by the migrate tool.
26 + #
27 + # Files that are not part of the templates will be ignored by default.
28 + unmanaged_files:
29 + - 'lib/main.dart'
30 + - 'ios/Runner.xcodeproj/project.pbxproj'
cw_monero/analysis_options.yaml new
+4
@@ -0,0 +1,4 @@
1 +include: package:flutter_lints/flutter.yaml
2 +
3 +# Additional information about this file can be found at
4 +# https://dart.dev/guides/language/analysis-options
cw_monero/example/.gitignore new
+44
@@ -0,0 +1,44 @@
1 +# Miscellaneous
2 +*.class
3 +*.log
4 +*.pyc
5 +*.swp
6 +.DS_Store
7 +.atom/
8 +.buildlog/
9 +.history
10 +.svn/
11 +migrate_working_dir/
12 +
13 +# IntelliJ related
14 +*.iml
15 +*.ipr
16 +*.iws
17 +.idea/
18 +
19 +# The .vscode folder contains launch configuration and tasks you configure in
20 +# VS Code which you may wish to be included in version control, so this line
21 +# is commented out by default.
22 +#.vscode/
23 +
24 +# Flutter/Dart/Pub related
25 +**/doc/api/
26 +**/ios/Flutter/.last_build_id
27 +.dart_tool/
28 +.flutter-plugins
29 +.flutter-plugins-dependencies
30 +.packages
31 +.pub-cache/
32 +.pub/
33 +/build/
34 +
35 +# Symbolication related
36 +app.*.symbols
37 +
38 +# Obfuscation related
39 +app.*.map.json
40 +
41 +# Android Studio will place build artifacts here
42 +/android/app/debug
43 +/android/app/profile
44 +/android/app/release
cw_monero/example/README.md new
+16
@@ -0,0 +1,16 @@
1 +# cw_monero_example
2 +
3 +Demonstrates how to use the cw_monero plugin.
4 +
5 +## Getting Started
6 +
7 +This project is a starting point for a Flutter application.
8 +
9 +A few resources to get you started if this is your first Flutter project:
10 +
11 +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
12 +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
13 +
14 +For help getting started with Flutter development, view the
15 +[online documentation](https://docs.flutter.dev/), which offers tutorials,
16 +samples, guidance on mobile development, and a full API reference.
cw_monero/example/analysis_options.yaml new
+29
@@ -0,0 +1,29 @@
1 +# This file configures the analyzer, which statically analyzes Dart code to
2 +# check for errors, warnings, and lints.
3 +#
4 +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
5 +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
6 +# invoked from the command line by running `flutter analyze`.
7 +
8 +# The following line activates a set of recommended lints for Flutter apps,
9 +# packages, and plugins designed to encourage good coding practices.
10 +include: package:flutter_lints/flutter.yaml
11 +
12 +linter:
13 + # The lint rules applied to this project can be customized in the
14 + # section below to disable rules from the `package:flutter_lints/flutter.yaml`
15 + # included above or to enable additional rules. A list of all available lints
16 + # and their documentation is published at
17 + # https://dart-lang.github.io/linter/lints/index.html.
18 + #
19 + # Instead of disabling a lint rule for the entire project in the
20 + # section below, it can also be suppressed for a single line of code
21 + # or a specific dart file by using the `// ignore: name_of_lint` and
22 + # `// ignore_for_file: name_of_lint` syntax on the line or in the file
23 + # producing the lint.
24 + rules:
25 + # avoid_print: false # Uncomment to disable the `avoid_print` rule
26 + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
27 +
28 +# Additional information about this file can be found at
29 +# https://dart.dev/guides/language/analysis-options
cw_monero/example/lib/main.dart new
+63
@@ -0,0 +1,63 @@
1 +import 'package:flutter/material.dart';
2 +import 'dart:async';
3 +
4 +import 'package:flutter/services.dart';
5 +import 'package:cw_monero/cw_monero.dart';
6 +
7 +void main() {
8 + runApp(const MyApp());
9 +}
10 +
11 +class MyApp extends StatefulWidget {
12 + const MyApp({super.key});
13 +
14 + @override
15 + State<MyApp> createState() => _MyAppState();
16 +}
17 +
18 +class _MyAppState extends State<MyApp> {
19 + String _platformVersion = 'Unknown';
20 + final _cwMoneroPlugin = CwMonero();
21 +
22 + @override
23 + void initState() {
24 + super.initState();
25 + initPlatformState();
26 + }
27 +
28 + // Platform messages are asynchronous, so we initialize in an async method.
29 + Future<void> initPlatformState() async {
30 + String platformVersion;
31 + // Platform messages may fail, so we use a try/catch PlatformException.
32 + // We also handle the message potentially returning null.
33 + try {
34 + platformVersion =
35 + await _cwMoneroPlugin.getPlatformVersion() ?? 'Unknown platform version';
36 + } on PlatformException {
37 + platformVersion = 'Failed to get platform version.';
38 + }
39 +
40 + // If the widget was removed from the tree while the asynchronous platform
41 + // message was in flight, we want to discard the reply rather than calling
42 + // setState to update our non-existent appearance.
43 + if (!mounted) return;
44 +
45 + setState(() {
46 + _platformVersion = platformVersion;
47 + });
48 + }
49 +
50 + @override
51 + Widget build(BuildContext context) {
52 + return MaterialApp(
53 + home: Scaffold(
54 + appBar: AppBar(
55 + title: const Text('Plugin example app'),
56 + ),
57 + body: Center(
58 + child: Text('Running on: $_platformVersion\n'),
59 + ),
60 + ),
61 + );
62 + }
63 +}
cw_monero/example/macos/.gitignore new
+7
@@ -0,0 +1,7 @@
1 +# Flutter-related
2 +**/Flutter/ephemeral/
3 +**/Pods/
4 +
5 +# Xcode-related
6 +**/dgph
7 +**/xcuserdata/
cw_monero/example/macos/Flutter/Flutter-Debug.xcconfig new
+2
@@ -0,0 +1,2 @@
1 +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 +#include "ephemeral/Flutter-Generated.xcconfig"
cw_monero/example/macos/Flutter/Flutter-Release.xcconfig new
+2
@@ -0,0 +1,2 @@
1 +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 +#include "ephemeral/Flutter-Generated.xcconfig"
cw_monero/example/macos/Flutter/GeneratedPluginRegistrant.swift new
+14
@@ -0,0 +1,14 @@
1 +//
2 +// Generated file. Do not edit.
3 +//
4 +
5 +import FlutterMacOS
6 +import Foundation
7 +
8 +import cw_monero
9 +import path_provider_foundation
10 +
11 +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
12 + CwMoneroPlugin.register(with: registry.registrar(forPlugin: "CwMoneroPlugin"))
13 + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
14 +}
cw_monero/example/macos/Podfile new
+40
@@ -0,0 +1,40 @@
1 +platform :osx, '10.11'
2 +
3 +# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
4 +ENV['COCOAPODS_DISABLE_STATS'] = 'true'
5 +
6 +project 'Runner', {
7 + 'Debug' => :debug,
8 + 'Profile' => :release,
9 + 'Release' => :release,
10 +}
11 +
12 +def flutter_root
13 + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)
14 + unless File.exist?(generated_xcode_build_settings_path)
15 + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first"
16 + end
17 +
18 + File.foreach(generated_xcode_build_settings_path) do |line|
19 + matches = line.match(/FLUTTER_ROOT\=(.*)/)
20 + return matches[1].strip if matches
21 + end
22 + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\""
23 +end
24 +
25 +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
26 +
27 +flutter_macos_podfile_setup
28 +
29 +target 'Runner' do
30 + use_frameworks!
31 + use_modular_headers!
32 +
33 + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))
34 +end
35 +
36 +post_install do |installer|
37 + installer.pods_project.targets.each do |target|
38 + flutter_additional_macos_build_settings(target)
39 + end
40 +end
cw_monero/example/macos/Podfile.lock new
+22
@@ -0,0 +1,22 @@
1 +PODS:
2 + - FlutterMacOS (1.0.0)
3 + - path_provider_macos (0.0.1):
4 + - FlutterMacOS
5 +
6 +DEPENDENCIES:
7 + - FlutterMacOS (from `Flutter/ephemeral`)
8 + - path_provider_macos (from `Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos`)
9 +
10 +EXTERNAL SOURCES:
11 + FlutterMacOS:
12 + :path: Flutter/ephemeral
13 + path_provider_macos:
14 + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos
15 +
16 +SPEC CHECKSUMS:
17 + FlutterMacOS: ae6af50a8ea7d6103d888583d46bd8328a7e9811
18 + path_provider_macos: 3c0c3b4b0d4a76d2bf989a913c2de869c5641a19
19 +
20 +PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c
21 +
22 +COCOAPODS: 1.11.2
cw_monero/example/macos/Runner.xcodeproj/project.pbxproj new
+632
@@ -0,0 +1,632 @@
1 +// !$*UTF8*$!
2 +{
3 + archiveVersion = 1;
4 + classes = {
5 + };
6 + objectVersion = 51;
7 + objects = {
8 +
9 +/* Begin PBXAggregateTarget section */
10 + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = {
11 + isa = PBXAggregateTarget;
12 + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */;
13 + buildPhases = (
14 + 33CC111E2044C6BF0003C045 /* ShellScript */,
15 + );
16 + dependencies = (
17 + );
18 + name = "Flutter Assemble";
19 + productName = FLX;
20 + };
21 +/* End PBXAggregateTarget section */
22 +
23 +/* Begin PBXBuildFile section */
24 + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };
25 + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };
26 + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
27 + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
28 + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
29 + 428E7496E2068D0AB138F295 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C29B2253BA962B7A415DBA77 /* Pods_Runner.framework */; };
30 +/* End PBXBuildFile section */
31 +
32 +/* Begin PBXContainerItemProxy section */
33 + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = {
34 + isa = PBXContainerItemProxy;
35 + containerPortal = 33CC10E52044A3C60003C045 /* Project object */;
36 + proxyType = 1;
37 + remoteGlobalIDString = 33CC111A2044C6BA0003C045;
38 + remoteInfo = FLX;
39 + };
40 +/* End PBXContainerItemProxy section */
41 +
42 +/* Begin PBXCopyFilesBuildPhase section */
43 + 33CC110E2044A8840003C045 /* Bundle Framework */ = {
44 + isa = PBXCopyFilesBuildPhase;
45 + buildActionMask = 2147483647;
46 + dstPath = "";
47 + dstSubfolderSpec = 10;
48 + files = (
49 + );
50 + name = "Bundle Framework";
51 + runOnlyForDeploymentPostprocessing = 0;
52 + };
53 +/* End PBXCopyFilesBuildPhase section */
54 +
55 +/* Begin PBXFileReference section */
56 + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
57 + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
58 + 33CC10ED2044A3C60003C045 /* cw_monero_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = cw_monero_example.app; sourceTree = BUILT_PRODUCTS_DIR; };
59 + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
60 + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
61 + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
62 + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = "<group>"; };
63 + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = "<group>"; };
64 + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = "<group>"; };
65 + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = "<group>"; };
66 + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = "<group>"; };
67 + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
68 + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
69 + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
70 + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
71 + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
72 + A9CDA1605413332AB9056C23 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
73 + C29B2253BA962B7A415DBA77 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
74 + E434913D71DC2682EF8E9059 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
75 + EEF09839C86335F78056F812 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
76 +/* End PBXFileReference section */
77 +
78 +/* Begin PBXFrameworksBuildPhase section */
79 + 33CC10EA2044A3C60003C045 /* Frameworks */ = {
80 + isa = PBXFrameworksBuildPhase;
81 + buildActionMask = 2147483647;
82 + files = (
83 + 428E7496E2068D0AB138F295 /* Pods_Runner.framework in Frameworks */,
84 + );
85 + runOnlyForDeploymentPostprocessing = 0;
86 + };
87 +/* End PBXFrameworksBuildPhase section */
88 +
89 +/* Begin PBXGroup section */
90 + 33BA886A226E78AF003329D5 /* Configs */ = {
91 + isa = PBXGroup;
92 + children = (
93 + 33E5194F232828860026EE4D /* AppInfo.xcconfig */,
94 + 9740EEB21CF90195004384FC /* Debug.xcconfig */,
95 + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
96 + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */,
97 + );
98 + path = Configs;
99 + sourceTree = "<group>";
100 + };
101 + 33CC10E42044A3C60003C045 = {
102 + isa = PBXGroup;
103 + children = (
104 + 33FAB671232836740065AC1E /* Runner */,
105 + 33CEB47122A05771004F2AC0 /* Flutter */,
106 + 33CC10EE2044A3C60003C045 /* Products */,
107 + D73912EC22F37F3D000D13A0 /* Frameworks */,
108 + 77870A4C94A9AB6EEC2EE261 /* Pods */,
109 + );
110 + sourceTree = "<group>";
111 + };
112 + 33CC10EE2044A3C60003C045 /* Products */ = {
113 + isa = PBXGroup;
114 + children = (
115 + 33CC10ED2044A3C60003C045 /* cw_monero_example.app */,
116 + );
117 + name = Products;
118 + sourceTree = "<group>";
119 + };
120 + 33CC11242044D66E0003C045 /* Resources */ = {
121 + isa = PBXGroup;
122 + children = (
123 + 33CC10F22044A3C60003C045 /* Assets.xcassets */,
124 + 33CC10F42044A3C60003C045 /* MainMenu.xib */,
125 + 33CC10F72044A3C60003C045 /* Info.plist */,
126 + );
127 + name = Resources;
128 + path = ..;
129 + sourceTree = "<group>";
130 + };
131 + 33CEB47122A05771004F2AC0 /* Flutter */ = {
132 + isa = PBXGroup;
133 + children = (
134 + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */,
135 + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */,
136 + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */,
137 + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */,
138 + );
139 + path = Flutter;
140 + sourceTree = "<group>";
141 + };
142 + 33FAB671232836740065AC1E /* Runner */ = {
143 + isa = PBXGroup;
144 + children = (
145 + 33CC10F02044A3C60003C045 /* AppDelegate.swift */,
146 + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */,
147 + 33E51913231747F40026EE4D /* DebugProfile.entitlements */,
148 + 33E51914231749380026EE4D /* Release.entitlements */,
149 + 33CC11242044D66E0003C045 /* Resources */,
150 + 33BA886A226E78AF003329D5 /* Configs */,
151 + );
152 + path = Runner;
153 + sourceTree = "<group>";
154 + };
155 + 77870A4C94A9AB6EEC2EE261 /* Pods */ = {
156 + isa = PBXGroup;
157 + children = (
158 + EEF09839C86335F78056F812 /* Pods-Runner.debug.xcconfig */,
159 + A9CDA1605413332AB9056C23 /* Pods-Runner.release.xcconfig */,
160 + E434913D71DC2682EF8E9059 /* Pods-Runner.profile.xcconfig */,
161 + );
162 + name = Pods;
163 + path = Pods;
164 + sourceTree = "<group>";
165 + };
166 + D73912EC22F37F3D000D13A0 /* Frameworks */ = {
167 + isa = PBXGroup;
168 + children = (
169 + C29B2253BA962B7A415DBA77 /* Pods_Runner.framework */,
170 + );
171 + name = Frameworks;
172 + sourceTree = "<group>";
173 + };
174 +/* End PBXGroup section */
175 +
176 +/* Begin PBXNativeTarget section */
177 + 33CC10EC2044A3C60003C045 /* Runner */ = {
178 + isa = PBXNativeTarget;
179 + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
180 + buildPhases = (
181 + 0A239C1738C005E3F6E4DFC6 /* [CP] Check Pods Manifest.lock */,
182 + 33CC10E92044A3C60003C045 /* Sources */,
183 + 33CC10EA2044A3C60003C045 /* Frameworks */,
184 + 33CC10EB2044A3C60003C045 /* Resources */,
185 + 33CC110E2044A8840003C045 /* Bundle Framework */,
186 + 3399D490228B24CF009A79C7 /* ShellScript */,
187 + 0CEAA82AE8A029C31B39F234 /* [CP] Embed Pods Frameworks */,
188 + );
189 + buildRules = (
190 + );
191 + dependencies = (
192 + 33CC11202044C79F0003C045 /* PBXTargetDependency */,
193 + );
194 + name = Runner;
195 + productName = Runner;
196 + productReference = 33CC10ED2044A3C60003C045 /* cw_monero_example.app */;
197 + productType = "com.apple.product-type.application";
198 + };
199 +/* End PBXNativeTarget section */
200 +
201 +/* Begin PBXProject section */
202 + 33CC10E52044A3C60003C045 /* Project object */ = {
203 + isa = PBXProject;
204 + attributes = {
205 + LastSwiftUpdateCheck = 0920;
206 + LastUpgradeCheck = 1300;
207 + ORGANIZATIONNAME = "";
208 + TargetAttributes = {
209 + 33CC10EC2044A3C60003C045 = {
210 + CreatedOnToolsVersion = 9.2;
211 + LastSwiftMigration = 1100;
212 + ProvisioningStyle = Automatic;
213 + SystemCapabilities = {
214 + com.apple.Sandbox = {
215 + enabled = 1;
216 + };
217 + };
218 + };
219 + 33CC111A2044C6BA0003C045 = {
220 + CreatedOnToolsVersion = 9.2;
221 + ProvisioningStyle = Manual;
222 + };
223 + };
224 + };
225 + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */;
226 + compatibilityVersion = "Xcode 9.3";
227 + developmentRegion = en;
228 + hasScannedForEncodings = 0;
229 + knownRegions = (
230 + en,
231 + Base,
232 + );
233 + mainGroup = 33CC10E42044A3C60003C045;
234 + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */;
235 + projectDirPath = "";
236 + projectRoot = "";
237 + targets = (
238 + 33CC10EC2044A3C60003C045 /* Runner */,
239 + 33CC111A2044C6BA0003C045 /* Flutter Assemble */,
240 + );
241 + };
242 +/* End PBXProject section */
243 +
244 +/* Begin PBXResourcesBuildPhase section */
245 + 33CC10EB2044A3C60003C045 /* Resources */ = {
246 + isa = PBXResourcesBuildPhase;
247 + buildActionMask = 2147483647;
248 + files = (
249 + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */,
250 + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */,
251 + );
252 + runOnlyForDeploymentPostprocessing = 0;
253 + };
254 +/* End PBXResourcesBuildPhase section */
255 +
256 +/* Begin PBXShellScriptBuildPhase section */
257 + 0A239C1738C005E3F6E4DFC6 /* [CP] Check Pods Manifest.lock */ = {
258 + isa = PBXShellScriptBuildPhase;
259 + buildActionMask = 2147483647;
260 + files = (
261 + );
262 + inputFileListPaths = (
263 + );
264 + inputPaths = (
265 + "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
266 + "${PODS_ROOT}/Manifest.lock",
267 + );
268 + name = "[CP] Check Pods Manifest.lock";
269 + outputFileListPaths = (
270 + );
271 + outputPaths = (
272 + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
273 + );
274 + runOnlyForDeploymentPostprocessing = 0;
275 + shellPath = /bin/sh;
276 + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
277 + showEnvVarsInLog = 0;
278 + };
279 + 0CEAA82AE8A029C31B39F234 /* [CP] Embed Pods Frameworks */ = {
280 + isa = PBXShellScriptBuildPhase;
281 + buildActionMask = 2147483647;
282 + files = (
283 + );
284 + inputFileListPaths = (
285 + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
286 + );
287 + name = "[CP] Embed Pods Frameworks";
288 + outputFileListPaths = (
289 + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
290 + );
291 + runOnlyForDeploymentPostprocessing = 0;
292 + shellPath = /bin/sh;
293 + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
294 + showEnvVarsInLog = 0;
295 + };
296 + 3399D490228B24CF009A79C7 /* ShellScript */ = {
297 + isa = PBXShellScriptBuildPhase;
298 + buildActionMask = 2147483647;
299 + files = (
300 + );
301 + inputFileListPaths = (
302 + );
303 + inputPaths = (
304 + );
305 + outputFileListPaths = (
306 + );
307 + outputPaths = (
308 + );
309 + runOnlyForDeploymentPostprocessing = 0;
310 + shellPath = /bin/sh;
311 + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n";
312 + };
313 + 33CC111E2044C6BF0003C045 /* ShellScript */ = {
314 + isa = PBXShellScriptBuildPhase;
315 + buildActionMask = 2147483647;
316 + files = (
317 + );
318 + inputFileListPaths = (
319 + Flutter/ephemeral/FlutterInputs.xcfilelist,
320 + );
321 + inputPaths = (
322 + Flutter/ephemeral/tripwire,
323 + );
324 + outputFileListPaths = (
325 + Flutter/ephemeral/FlutterOutputs.xcfilelist,
326 + );
327 + outputPaths = (
328 + );
329 + runOnlyForDeploymentPostprocessing = 0;
330 + shellPath = /bin/sh;
331 + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
332 + };
333 +/* End PBXShellScriptBuildPhase section */
334 +
335 +/* Begin PBXSourcesBuildPhase section */
336 + 33CC10E92044A3C60003C045 /* Sources */ = {
337 + isa = PBXSourcesBuildPhase;
338 + buildActionMask = 2147483647;
339 + files = (
340 + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */,
341 + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */,
342 + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */,
343 + );
344 + runOnlyForDeploymentPostprocessing = 0;
345 + };
346 +/* End PBXSourcesBuildPhase section */
347 +
348 +/* Begin PBXTargetDependency section */
349 + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = {
350 + isa = PBXTargetDependency;
351 + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */;
352 + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */;
353 + };
354 +/* End PBXTargetDependency section */
355 +
356 +/* Begin PBXVariantGroup section */
357 + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = {
358 + isa = PBXVariantGroup;
359 + children = (
360 + 33CC10F52044A3C60003C045 /* Base */,
361 + );
362 + name = MainMenu.xib;
363 + path = Runner;
364 + sourceTree = "<group>";
365 + };
366 +/* End PBXVariantGroup section */
367 +
368 +/* Begin XCBuildConfiguration section */
369 + 338D0CE9231458BD00FA5F75 /* Profile */ = {
370 + isa = XCBuildConfiguration;
371 + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
372 + buildSettings = {
373 + ALWAYS_SEARCH_USER_PATHS = NO;
374 + CLANG_ANALYZER_NONNULL = YES;
375 + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
376 + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
377 + CLANG_CXX_LIBRARY = "libc++";
378 + CLANG_ENABLE_MODULES = YES;
379 + CLANG_ENABLE_OBJC_ARC = YES;
380 + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
381 + CLANG_WARN_BOOL_CONVERSION = YES;
382 + CLANG_WARN_CONSTANT_CONVERSION = YES;
383 + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
384 + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
385 + CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
386 + CLANG_WARN_EMPTY_BODY = YES;
387 + CLANG_WARN_ENUM_CONVERSION = YES;
388 + CLANG_WARN_INFINITE_RECURSION = YES;
389 + CLANG_WARN_INT_CONVERSION = YES;
390 + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
391 + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
392 + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
393 + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
394 + CLANG_WARN_SUSPICIOUS_MOVE = YES;
395 + CODE_SIGN_IDENTITY = "-";
396 + COPY_PHASE_STRIP = NO;
397 + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
398 + ENABLE_NS_ASSERTIONS = NO;
399 + ENABLE_STRICT_OBJC_MSGSEND = YES;
400 + GCC_C_LANGUAGE_STANDARD = gnu11;
401 + GCC_NO_COMMON_BLOCKS = YES;
402 + GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
403 + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
404 + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
405 + GCC_WARN_UNUSED_FUNCTION = YES;
406 + GCC_WARN_UNUSED_VARIABLE = YES;
407 + MACOSX_DEPLOYMENT_TARGET = 10.11;
408 + MTL_ENABLE_DEBUG_INFO = NO;
409 + SDKROOT = macosx;
410 + SWIFT_COMPILATION_MODE = wholemodule;
411 + SWIFT_OPTIMIZATION_LEVEL = "-O";
412 + };
413 + name = Profile;
414 + };
415 + 338D0CEA231458BD00FA5F75 /* Profile */ = {
416 + isa = XCBuildConfiguration;
417 + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
418 + buildSettings = {
419 + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
420 + CLANG_ENABLE_MODULES = YES;
421 + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
422 + CODE_SIGN_STYLE = Automatic;
423 + COMBINE_HIDPI_IMAGES = YES;
424 + INFOPLIST_FILE = Runner/Info.plist;
425 + LD_RUNPATH_SEARCH_PATHS = (
426 + "$(inherited)",
427 + "@executable_path/../Frameworks",
428 + );
429 + PROVISIONING_PROFILE_SPECIFIER = "";
430 + SWIFT_VERSION = 5.0;
431 + };
432 + name = Profile;
433 + };
434 + 338D0CEB231458BD00FA5F75 /* Profile */ = {
435 + isa = XCBuildConfiguration;
436 + buildSettings = {
437 + CODE_SIGN_STYLE = Manual;
438 + PRODUCT_NAME = "$(TARGET_NAME)";
439 + };
440 + name = Profile;
441 + };
442 + 33CC10F92044A3C60003C045 /* Debug */ = {
443 + isa = XCBuildConfiguration;
444 + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
445 + buildSettings = {
446 + ALWAYS_SEARCH_USER_PATHS = NO;
447 + CLANG_ANALYZER_NONNULL = YES;
448 + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
449 + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
450 + CLANG_CXX_LIBRARY = "libc++";
451 + CLANG_ENABLE_MODULES = YES;
452 + CLANG_ENABLE_OBJC_ARC = YES;
453 + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
454 + CLANG_WARN_BOOL_CONVERSION = YES;
455 + CLANG_WARN_CONSTANT_CONVERSION = YES;
456 + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
457 + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
458 + CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
459 + CLANG_WARN_EMPTY_BODY = YES;
460 + CLANG_WARN_ENUM_CONVERSION = YES;
461 + CLANG_WARN_INFINITE_RECURSION = YES;
462 + CLANG_WARN_INT_CONVERSION = YES;
463 + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
464 + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
465 + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
466 + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
467 + CLANG_WARN_SUSPICIOUS_MOVE = YES;
468 + CODE_SIGN_IDENTITY = "-";
469 + COPY_PHASE_STRIP = NO;
470 + DEBUG_INFORMATION_FORMAT = dwarf;
471 + ENABLE_STRICT_OBJC_MSGSEND = YES;
472 + ENABLE_TESTABILITY = YES;
473 + GCC_C_LANGUAGE_STANDARD = gnu11;
474 + GCC_DYNAMIC_NO_PIC = NO;
475 + GCC_NO_COMMON_BLOCKS = YES;
476 + GCC_OPTIMIZATION_LEVEL = 0;
477 + GCC_PREPROCESSOR_DEFINITIONS = (
478 + "DEBUG=1",
479 + "$(inherited)",
480 + );
481 + GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
482 + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
483 + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
484 + GCC_WARN_UNUSED_FUNCTION = YES;
485 + GCC_WARN_UNUSED_VARIABLE = YES;
486 + MACOSX_DEPLOYMENT_TARGET = 10.11;
487 + MTL_ENABLE_DEBUG_INFO = YES;
488 + ONLY_ACTIVE_ARCH = YES;
489 + SDKROOT = macosx;
490 + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
491 + SWIFT_OPTIMIZATION_LEVEL = "-Onone";
492 + };
493 + name = Debug;
494 + };
495 + 33CC10FA2044A3C60003C045 /* Release */ = {
496 + isa = XCBuildConfiguration;
497 + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
498 + buildSettings = {
499 + ALWAYS_SEARCH_USER_PATHS = NO;
500 + CLANG_ANALYZER_NONNULL = YES;
501 + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
502 + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
503 + CLANG_CXX_LIBRARY = "libc++";
504 + CLANG_ENABLE_MODULES = YES;
505 + CLANG_ENABLE_OBJC_ARC = YES;
506 + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
507 + CLANG_WARN_BOOL_CONVERSION = YES;
508 + CLANG_WARN_CONSTANT_CONVERSION = YES;
509 + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
510 + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
511 + CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
512 + CLANG_WARN_EMPTY_BODY = YES;
513 + CLANG_WARN_ENUM_CONVERSION = YES;
514 + CLANG_WARN_INFINITE_RECURSION = YES;
515 + CLANG_WARN_INT_CONVERSION = YES;
516 + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
517 + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
518 + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
519 + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
520 + CLANG_WARN_SUSPICIOUS_MOVE = YES;
521 + CODE_SIGN_IDENTITY = "-";
522 + COPY_PHASE_STRIP = NO;
523 + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
524 + ENABLE_NS_ASSERTIONS = NO;
525 + ENABLE_STRICT_OBJC_MSGSEND = YES;
526 + GCC_C_LANGUAGE_STANDARD = gnu11;
527 + GCC_NO_COMMON_BLOCKS = YES;
528 + GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
529 + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
530 + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
531 + GCC_WARN_UNUSED_FUNCTION = YES;
532 + GCC_WARN_UNUSED_VARIABLE = YES;
533 + MACOSX_DEPLOYMENT_TARGET = 10.11;
534 + MTL_ENABLE_DEBUG_INFO = NO;
535 + SDKROOT = macosx;
536 + SWIFT_COMPILATION_MODE = wholemodule;
537 + SWIFT_OPTIMIZATION_LEVEL = "-O";
538 + };
539 + name = Release;
540 + };
541 + 33CC10FC2044A3C60003C045 /* Debug */ = {
542 + isa = XCBuildConfiguration;
543 + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
544 + buildSettings = {
545 + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
546 + CLANG_ENABLE_MODULES = YES;
547 + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
548 + CODE_SIGN_STYLE = Automatic;
549 + COMBINE_HIDPI_IMAGES = YES;
550 + INFOPLIST_FILE = Runner/Info.plist;
551 + LD_RUNPATH_SEARCH_PATHS = (
552 + "$(inherited)",
553 + "@executable_path/../Frameworks",
554 + );
555 + PROVISIONING_PROFILE_SPECIFIER = "";
556 + SWIFT_OPTIMIZATION_LEVEL = "-Onone";
557 + SWIFT_VERSION = 5.0;
558 + };
559 + name = Debug;
560 + };
561 + 33CC10FD2044A3C60003C045 /* Release */ = {
562 + isa = XCBuildConfiguration;
563 + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
564 + buildSettings = {
565 + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
566 + CLANG_ENABLE_MODULES = YES;
567 + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;
568 + CODE_SIGN_STYLE = Automatic;
569 + COMBINE_HIDPI_IMAGES = YES;
570 + INFOPLIST_FILE = Runner/Info.plist;
571 + LD_RUNPATH_SEARCH_PATHS = (
572 + "$(inherited)",
573 + "@executable_path/../Frameworks",
574 + );
575 + PROVISIONING_PROFILE_SPECIFIER = "";
576 + SWIFT_VERSION = 5.0;
577 + };
578 + name = Release;
579 + };
580 + 33CC111C2044C6BA0003C045 /* Debug */ = {
581 + isa = XCBuildConfiguration;
582 + buildSettings = {
583 + CODE_SIGN_STYLE = Manual;
584 + PRODUCT_NAME = "$(TARGET_NAME)";
585 + };
586 + name = Debug;
587 + };
588 + 33CC111D2044C6BA0003C045 /* Release */ = {
589 + isa = XCBuildConfiguration;
590 + buildSettings = {
591 + CODE_SIGN_STYLE = Automatic;
592 + PRODUCT_NAME = "$(TARGET_NAME)";
593 + };
594 + name = Release;
595 + };
596 +/* End XCBuildConfiguration section */
597 +
598 +/* Begin XCConfigurationList section */
599 + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = {
600 + isa = XCConfigurationList;
601 + buildConfigurations = (
602 + 33CC10F92044A3C60003C045 /* Debug */,
603 + 33CC10FA2044A3C60003C045 /* Release */,
604 + 338D0CE9231458BD00FA5F75 /* Profile */,
605 + );
606 + defaultConfigurationIsVisible = 0;
607 + defaultConfigurationName = Release;
608 + };
609 + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = {
610 + isa = XCConfigurationList;
611 + buildConfigurations = (
612 + 33CC10FC2044A3C60003C045 /* Debug */,
613 + 33CC10FD2044A3C60003C045 /* Release */,
614 + 338D0CEA231458BD00FA5F75 /* Profile */,
615 + );
616 + defaultConfigurationIsVisible = 0;
617 + defaultConfigurationName = Release;
618 + };
619 + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = {
620 + isa = XCConfigurationList;
621 + buildConfigurations = (
622 + 33CC111C2044C6BA0003C045 /* Debug */,
623 + 33CC111D2044C6BA0003C045 /* Release */,
624 + 338D0CEB231458BD00FA5F75 /* Profile */,
625 + );
626 + defaultConfigurationIsVisible = 0;
627 + defaultConfigurationName = Release;
628 + };
629 +/* End XCConfigurationList section */
630 + };
631 + rootObject = 33CC10E52044A3C60003C045 /* Project object */;
632 +}
cw_monero/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new
+8
@@ -0,0 +1,8 @@
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 +<plist version="1.0">
4 +<dict>
5 + <key>IDEDidComputeMac32BitWarning</key>
6 + <true/>
7 +</dict>
8 +</plist>
cw_monero/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new
+87
@@ -0,0 +1,87 @@
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<Scheme
3 + LastUpgradeVersion = "1300"
4 + version = "1.3">
5 + <BuildAction
6 + parallelizeBuildables = "YES"
7 + buildImplicitDependencies = "YES">
8 + <BuildActionEntries>
9 + <BuildActionEntry
10 + buildForTesting = "YES"
11 + buildForRunning = "YES"
12 + buildForProfiling = "YES"
13 + buildForArchiving = "YES"
14 + buildForAnalyzing = "YES">
15 + <BuildableReference
16 + BuildableIdentifier = "primary"
17 + BlueprintIdentifier = "33CC10EC2044A3C60003C045"
18 + BuildableName = "cw_monero_example.app"
19 + BlueprintName = "Runner"
20 + ReferencedContainer = "container:Runner.xcodeproj">
21 + </BuildableReference>
22 + </BuildActionEntry>
23 + </BuildActionEntries>
24 + </BuildAction>
25 + <TestAction
26 + buildConfiguration = "Debug"
27 + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28 + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29 + shouldUseLaunchSchemeArgsEnv = "YES">
30 + <MacroExpansion>
31 + <BuildableReference
32 + BuildableIdentifier = "primary"
33 + BlueprintIdentifier = "33CC10EC2044A3C60003C045"
34 + BuildableName = "cw_monero_example.app"
35 + BlueprintName = "Runner"
36 + ReferencedContainer = "container:Runner.xcodeproj">
37 + </BuildableReference>
38 + </MacroExpansion>
39 + <Testables>
40 + </Testables>
41 + </TestAction>
42 + <LaunchAction
43 + buildConfiguration = "Debug"
44 + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
45 + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
46 + launchStyle = "0"
47 + useCustomWorkingDirectory = "NO"
48 + ignoresPersistentStateOnLaunch = "NO"
49 + debugDocumentVersioning = "YES"
50 + debugServiceExtension = "internal"
51 + allowLocationSimulation = "YES">
52 + <BuildableProductRunnable
53 + runnableDebuggingMode = "0">
54 + <BuildableReference
55 + BuildableIdentifier = "primary"
56 + BlueprintIdentifier = "33CC10EC2044A3C60003C045"
57 + BuildableName = "cw_monero_example.app"
58 + BlueprintName = "Runner"
59 + ReferencedContainer = "container:Runner.xcodeproj">
60 + </BuildableReference>
61 + </BuildableProductRunnable>
62 + </LaunchAction>
63 + <ProfileAction
64 + buildConfiguration = "Profile"
65 + shouldUseLaunchSchemeArgsEnv = "YES"
66 + savedToolIdentifier = ""
67 + useCustomWorkingDirectory = "NO"
68 + debugDocumentVersioning = "YES">
69 + <BuildableProductRunnable
70 + runnableDebuggingMode = "0">
71 + <BuildableReference
72 + BuildableIdentifier = "primary"
73 + BlueprintIdentifier = "33CC10EC2044A3C60003C045"
74 + BuildableName = "cw_monero_example.app"
75 + BlueprintName = "Runner"
76 + ReferencedContainer = "container:Runner.xcodeproj">
77 + </BuildableReference>
78 + </BuildableProductRunnable>
79 + </ProfileAction>
80 + <AnalyzeAction
81 + buildConfiguration = "Debug">
82 + </AnalyzeAction>
83 + <ArchiveAction
84 + buildConfiguration = "Release"
85 + revealArchiveInOrganizer = "YES">
86 + </ArchiveAction>
87 +</Scheme>
cw_monero/example/macos/Runner.xcworkspace/contents.xcworkspacedata new
+10
@@ -0,0 +1,10 @@
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<Workspace
3 + version = "1.0">
4 + <FileRef
5 + location = "group:Runner.xcodeproj">
6 + </FileRef>
7 + <FileRef
8 + location = "group:Pods/Pods.xcodeproj">
9 + </FileRef>
10 +</Workspace>
cw_monero/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new
+8
@@ -0,0 +1,8 @@
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 +<plist version="1.0">
4 +<dict>
5 + <key>IDEDidComputeMac32BitWarning</key>
6 + <true/>
7 +</dict>
8 +</plist>
cw_monero/example/macos/Runner/AppDelegate.swift new
+9
@@ -0,0 +1,9 @@
1 +import Cocoa
2 +import FlutterMacOS
3 +
4 +@NSApplicationMain
5 +class AppDelegate: FlutterAppDelegate {
6 + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
7 + return true
8 + }
9 +}
cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new
+68
@@ -0,0 +1,68 @@
1 +{
2 + "images" : [
3 + {
4 + "size" : "16x16",
5 + "idiom" : "mac",
6 + "filename" : "app_icon_16.png",
7 + "scale" : "1x"
8 + },
9 + {
10 + "size" : "16x16",
11 + "idiom" : "mac",
12 + "filename" : "app_icon_32.png",
13 + "scale" : "2x"
14 + },
15 + {
16 + "size" : "32x32",
17 + "idiom" : "mac",
18 + "filename" : "app_icon_32.png",
19 + "scale" : "1x"
20 + },
21 + {
22 + "size" : "32x32",
23 + "idiom" : "mac",
24 + "filename" : "app_icon_64.png",
25 + "scale" : "2x"
26 + },
27 + {
28 + "size" : "128x128",
29 + "idiom" : "mac",
30 + "filename" : "app_icon_128.png",
31 + "scale" : "1x"
32 + },
33 + {
34 + "size" : "128x128",
35 + "idiom" : "mac",
36 + "filename" : "app_icon_256.png",
37 + "scale" : "2x"
38 + },
39 + {
40 + "size" : "256x256",
41 + "idiom" : "mac",
42 + "filename" : "app_icon_256.png",
43 + "scale" : "1x"
44 + },
45 + {
46 + "size" : "256x256",
47 + "idiom" : "mac",
48 + "filename" : "app_icon_512.png",
49 + "scale" : "2x"
50 + },
51 + {
52 + "size" : "512x512",
53 + "idiom" : "mac",
54 + "filename" : "app_icon_512.png",
55 + "scale" : "1x"
56 + },
57 + {
58 + "size" : "512x512",
59 + "idiom" : "mac",
60 + "filename" : "app_icon_1024.png",
61 + "scale" : "2x"
62 + }
63 + ],
64 + "info" : {
65 + "version" : 1,
66 + "author" : "xcode"
67 + }
68 +}
cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
Binary files /dev/null and b/cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ
cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png
Binary files /dev/null and b/cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ
cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
Binary files /dev/null and b/cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ
cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png
Binary files /dev/null and b/cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ
cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
Binary files /dev/null and b/cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ
cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png
Binary files /dev/null and b/cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ
cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png
Binary files /dev/null and b/cw_monero/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ
cw_monero/example/macos/Runner/Base.lproj/MainMenu.xib new
+343
@@ -0,0 +1,343 @@
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
3 + <dependencies>
4 + <deployment identifier="macosx"/>
5 + <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
6 + <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
7 + </dependencies>
8 + <objects>
9 + <customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
10 + <connections>
11 + <outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
12 + </connections>
13 + </customObject>
14 + <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
15 + <customObject id="-3" userLabel="Application" customClass="NSObject"/>
16 + <customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Runner" customModuleProvider="target">
17 + <connections>
18 + <outlet property="applicationMenu" destination="uQy-DD-JDr" id="XBo-yE-nKs"/>
19 + <outlet property="mainFlutterWindow" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
20 + </connections>
21 + </customObject>
22 + <customObject id="YLy-65-1bz" customClass="NSFontManager"/>
23 + <menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
24 + <items>
25 + <menuItem title="APP_NAME" id="1Xt-HY-uBw">
26 + <modifierMask key="keyEquivalentModifierMask"/>
27 + <menu key="submenu" title="APP_NAME" systemMenu="apple" id="uQy-DD-JDr">
28 + <items>
29 + <menuItem title="About APP_NAME" id="5kV-Vb-QxS">
30 + <modifierMask key="keyEquivalentModifierMask"/>
31 + <connections>
32 + <action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
33 + </connections>
34 + </menuItem>
35 + <menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
36 + <menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
37 + <menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
38 + <menuItem title="Services" id="NMo-om-nkz">
39 + <modifierMask key="keyEquivalentModifierMask"/>
40 + <menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
41 + </menuItem>
42 + <menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
43 + <menuItem title="Hide APP_NAME" keyEquivalent="h" id="Olw-nP-bQN">
44 + <connections>
45 + <action selector="hide:" target="-1" id="PnN-Uc-m68"/>
46 + </connections>
47 + </menuItem>
48 + <menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
49 + <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
50 + <connections>
51 + <action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
52 + </connections>
53 + </menuItem>
54 + <menuItem title="Show All" id="Kd2-mp-pUS">
55 + <modifierMask key="keyEquivalentModifierMask"/>
56 + <connections>
57 + <action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
58 + </connections>
59 + </menuItem>
60 + <menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
61 + <menuItem title="Quit APP_NAME" keyEquivalent="q" id="4sb-4s-VLi">
62 + <connections>
63 + <action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
64 + </connections>
65 + </menuItem>
66 + </items>
67 + </menu>
68 + </menuItem>
69 + <menuItem title="Edit" id="5QF-Oa-p0T">
70 + <modifierMask key="keyEquivalentModifierMask"/>
71 + <menu key="submenu" title="Edit" id="W48-6f-4Dl">
72 + <items>
73 + <menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
74 + <connections>
75 + <action selector="undo:" target="-1" id="M6e-cu-g7V"/>
76 + </connections>
77 + </menuItem>
78 + <menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
79 + <connections>
80 + <action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
81 + </connections>
82 + </menuItem>
83 + <menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
84 + <menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
85 + <connections>
86 + <action selector="cut:" target="-1" id="YJe-68-I9s"/>
87 + </connections>
88 + </menuItem>
89 + <menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
90 + <connections>
91 + <action selector="copy:" target="-1" id="G1f-GL-Joy"/>
92 + </connections>
93 + </menuItem>
94 + <menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
95 + <connections>
96 + <action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
97 + </connections>
98 + </menuItem>
99 + <menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
100 + <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
101 + <connections>
102 + <action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/>
103 + </connections>
104 + </menuItem>
105 + <menuItem title="Delete" id="pa3-QI-u2k">
106 + <modifierMask key="keyEquivalentModifierMask"/>
107 + <connections>
108 + <action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
109 + </connections>
110 + </menuItem>
111 + <menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
112 + <connections>
113 + <action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
114 + </connections>
115 + </menuItem>
116 + <menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
117 + <menuItem title="Find" id="4EN-yA-p0u">
118 + <modifierMask key="keyEquivalentModifierMask"/>
119 + <menu key="submenu" title="Find" id="1b7-l0-nxx">
120 + <items>
121 + <menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
122 + <connections>
123 + <action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/>
124 + </connections>
125 + </menuItem>
126 + <menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
127 + <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
128 + <connections>
129 + <action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/>
130 + </connections>
131 + </menuItem>
132 + <menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
133 + <connections>
134 + <action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/>
135 + </connections>
136 + </menuItem>
137 + <menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
138 + <connections>
139 + <action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/>
140 + </connections>
141 + </menuItem>
142 + <menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
143 + <connections>
144 + <action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/>
145 + </connections>
146 + </menuItem>
147 + <menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
148 + <connections>
149 + <action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/>
150 + </connections>
151 + </menuItem>
152 + </items>
153 + </menu>
154 + </menuItem>
155 + <menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
156 + <modifierMask key="keyEquivalentModifierMask"/>
157 + <menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
158 + <items>
159 + <menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
160 + <connections>
161 + <action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/>
162 + </connections>
163 + </menuItem>
164 + <menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
165 + <connections>
166 + <action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/>
167 + </connections>
168 + </menuItem>
169 + <menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
170 + <menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
171 + <modifierMask key="keyEquivalentModifierMask"/>
172 + <connections>
173 + <action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/>
174 + </connections>
175 + </menuItem>
176 + <menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
177 + <modifierMask key="keyEquivalentModifierMask"/>
178 + <connections>
179 + <action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/>
180 + </connections>
181 + </menuItem>
182 + <menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
183 + <modifierMask key="keyEquivalentModifierMask"/>
184 + <connections>
185 + <action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/>
186 + </connections>
187 + </menuItem>
188 + </items>
189 + </menu>
190 + </menuItem>
191 + <menuItem title="Substitutions" id="9ic-FL-obx">
192 + <modifierMask key="keyEquivalentModifierMask"/>
193 + <menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
194 + <items>
195 + <menuItem title="Show Substitutions" id="z6F-FW-3nz">
196 + <modifierMask key="keyEquivalentModifierMask"/>
197 + <connections>
198 + <action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/>
199 + </connections>
200 + </menuItem>
201 + <menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
202 + <menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
203 + <modifierMask key="keyEquivalentModifierMask"/>
204 + <connections>
205 + <action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/>
206 + </connections>
207 + </menuItem>
208 + <menuItem title="Smart Quotes" id="hQb-2v-fYv">
209 + <modifierMask key="keyEquivalentModifierMask"/>
210 + <connections>
211 + <action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/>
212 + </connections>
213 + </menuItem>
214 + <menuItem title="Smart Dashes" id="rgM-f4-ycn">
215 + <modifierMask key="keyEquivalentModifierMask"/>
216 + <connections>
217 + <action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/>
218 + </connections>
219 + </menuItem>
220 + <menuItem title="Smart Links" id="cwL-P1-jid">
221 + <modifierMask key="keyEquivalentModifierMask"/>
222 + <connections>
223 + <action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/>
224 + </connections>
225 + </menuItem>
226 + <menuItem title="Data Detectors" id="tRr-pd-1PS">
227 + <modifierMask key="keyEquivalentModifierMask"/>
228 + <connections>
229 + <action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/>
230 + </connections>
231 + </menuItem>
232 + <menuItem title="Text Replacement" id="HFQ-gK-NFA">
233 + <modifierMask key="keyEquivalentModifierMask"/>
234 + <connections>
235 + <action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/>
236 + </connections>
237 + </menuItem>
238 + </items>
239 + </menu>
240 + </menuItem>
241 + <menuItem title="Transformations" id="2oI-Rn-ZJC">
242 + <modifierMask key="keyEquivalentModifierMask"/>
243 + <menu key="submenu" title="Transformations" id="c8a-y6-VQd">
244 + <items>
245 + <menuItem title="Make Upper Case" id="vmV-6d-7jI">
246 + <modifierMask key="keyEquivalentModifierMask"/>
247 + <connections>
248 + <action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/>
249 + </connections>
250 + </menuItem>
251 + <menuItem title="Make Lower Case" id="d9M-CD-aMd">
252 + <modifierMask key="keyEquivalentModifierMask"/>
253 + <connections>
254 + <action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/>
255 + </connections>
256 + </menuItem>
257 + <menuItem title="Capitalize" id="UEZ-Bs-lqG">
258 + <modifierMask key="keyEquivalentModifierMask"/>
259 + <connections>
260 + <action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/>
261 + </connections>
262 + </menuItem>
263 + </items>
264 + </menu>
265 + </menuItem>
266 + <menuItem title="Speech" id="xrE-MZ-jX0">
267 + <modifierMask key="keyEquivalentModifierMask"/>
268 + <menu key="submenu" title="Speech" id="3rS-ZA-NoH">
269 + <items>
270 + <menuItem title="Start Speaking" id="Ynk-f8-cLZ">
271 + <modifierMask key="keyEquivalentModifierMask"/>
272 + <connections>
273 + <action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/>
274 + </connections>
275 + </menuItem>
276 + <menuItem title="Stop Speaking" id="Oyz-dy-DGm">
277 + <modifierMask key="keyEquivalentModifierMask"/>
278 + <connections>
279 + <action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/>
280 + </connections>
281 + </menuItem>
282 + </items>
283 + </menu>
284 + </menuItem>
285 + </items>
286 + </menu>
287 + </menuItem>
288 + <menuItem title="View" id="H8h-7b-M4v">
289 + <modifierMask key="keyEquivalentModifierMask"/>
290 + <menu key="submenu" title="View" id="HyV-fh-RgO">
291 + <items>
292 + <menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
293 + <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
294 + <connections>
295 + <action selector="toggleFullScreen:" target="-1" id="dU3-MA-1Rq"/>
296 + </connections>
297 + </menuItem>
298 + </items>
299 + </menu>
300 + </menuItem>
301 + <menuItem title="Window" id="aUF-d1-5bR">
302 + <modifierMask key="keyEquivalentModifierMask"/>
303 + <menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
304 + <items>
305 + <menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
306 + <connections>
307 + <action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
308 + </connections>
309 + </menuItem>
310 + <menuItem title="Zoom" id="R4o-n2-Eq4">
311 + <modifierMask key="keyEquivalentModifierMask"/>
312 + <connections>
313 + <action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
314 + </connections>
315 + </menuItem>
316 + <menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
317 + <menuItem title="Bring All to Front" id="LE2-aR-0XJ">
318 + <modifierMask key="keyEquivalentModifierMask"/>
319 + <connections>
320 + <action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
321 + </connections>
322 + </menuItem>
323 + </items>
324 + </menu>
325 + </menuItem>
326 + <menuItem title="Help" id="EPT-qC-fAb">
327 + <modifierMask key="keyEquivalentModifierMask"/>
328 + <menu key="submenu" title="Help" systemMenu="help" id="rJ0-wn-3NY"/>
329 + </menuItem>
330 + </items>
331 + <point key="canvasLocation" x="142" y="-258"/>
332 + </menu>
333 + <window title="APP_NAME" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g" customClass="MainFlutterWindow" customModule="Runner" customModuleProvider="target">
334 + <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
335 + <rect key="contentRect" x="335" y="390" width="800" height="600"/>
336 + <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1577"/>
337 + <view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
338 + <rect key="frame" x="0.0" y="0.0" width="800" height="600"/>
339 + <autoresizingMask key="autoresizingMask"/>
340 + </view>
341 + </window>
342 + </objects>
343 +</document>
cw_monero/example/macos/Runner/Configs/AppInfo.xcconfig new
+14
@@ -0,0 +1,14 @@
1 +// Application-level settings for the Runner target.
2 +//
3 +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the
4 +// future. If not, the values below would default to using the project name when this becomes a
5 +// 'flutter create' template.
6 +
7 +// The application's name. By default this is also the title of the Flutter window.
8 +PRODUCT_NAME = cw_monero_example
9 +
10 +// The application's bundle identifier
11 +PRODUCT_BUNDLE_IDENTIFIER = com.cakewallet.cwMoneroExample
12 +
13 +// The copyright displayed in application information
14 +PRODUCT_COPYRIGHT = Copyright © 2022 com.cakewallet. All rights reserved.
cw_monero/example/macos/Runner/Configs/Debug.xcconfig new
+2
@@ -0,0 +1,2 @@
1 +#include "../../Flutter/Flutter-Debug.xcconfig"
2 +#include "Warnings.xcconfig"
cw_monero/example/macos/Runner/Configs/Release.xcconfig new
+2
@@ -0,0 +1,2 @@
1 +#include "../../Flutter/Flutter-Release.xcconfig"
2 +#include "Warnings.xcconfig"
cw_monero/example/macos/Runner/Configs/Warnings.xcconfig new
+13
@@ -0,0 +1,13 @@
1 +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings
2 +GCC_WARN_UNDECLARED_SELECTOR = YES
3 +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES
4 +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE
5 +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
6 +CLANG_WARN_PRAGMA_PACK = YES
7 +CLANG_WARN_STRICT_PROTOTYPES = YES
8 +CLANG_WARN_COMMA = YES
9 +GCC_WARN_STRICT_SELECTOR_MATCH = YES
10 +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES
11 +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
12 +GCC_WARN_SHADOW = YES
13 +CLANG_WARN_UNREACHABLE_CODE = YES
cw_monero/example/macos/Runner/DebugProfile.entitlements new
+12
@@ -0,0 +1,12 @@
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 +<plist version="1.0">
4 +<dict>
5 + <key>com.apple.security.app-sandbox</key>
6 + <true/>
7 + <key>com.apple.security.cs.allow-jit</key>
8 + <true/>
9 + <key>com.apple.security.network.server</key>
10 + <true/>
11 +</dict>
12 +</plist>
cw_monero/example/macos/Runner/Info.plist new
+32
@@ -0,0 +1,32 @@
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 +<plist version="1.0">
4 +<dict>
5 + <key>CFBundleDevelopmentRegion</key>
6 + <string>$(DEVELOPMENT_LANGUAGE)</string>
7 + <key>CFBundleExecutable</key>
8 + <string>$(EXECUTABLE_NAME)</string>
9 + <key>CFBundleIconFile</key>
10 + <string></string>
11 + <key>CFBundleIdentifier</key>
12 + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
13 + <key>CFBundleInfoDictionaryVersion</key>
14 + <string>6.0</string>
15 + <key>CFBundleName</key>
16 + <string>$(PRODUCT_NAME)</string>
17 + <key>CFBundlePackageType</key>
18 + <string>APPL</string>
19 + <key>CFBundleShortVersionString</key>
20 + <string>$(FLUTTER_BUILD_NAME)</string>
21 + <key>CFBundleVersion</key>
22 + <string>$(FLUTTER_BUILD_NUMBER)</string>
23 + <key>LSMinimumSystemVersion</key>
24 + <string>$(MACOSX_DEPLOYMENT_TARGET)</string>
25 + <key>NSHumanReadableCopyright</key>
26 + <string>$(PRODUCT_COPYRIGHT)</string>
27 + <key>NSMainNibFile</key>
28 + <string>MainMenu</string>
29 + <key>NSPrincipalClass</key>
30 + <string>NSApplication</string>
31 +</dict>
32 +</plist>
cw_monero/example/macos/Runner/MainFlutterWindow.swift new
+15
@@ -0,0 +1,15 @@
1 +import Cocoa
2 +import FlutterMacOS
3 +
4 +class MainFlutterWindow: NSWindow {
5 + override func awakeFromNib() {
6 + let flutterViewController = FlutterViewController.init()
7 + let windowFrame = self.frame
8 + self.contentViewController = flutterViewController
9 + self.setFrame(windowFrame, display: true)
10 +
11 + RegisterGeneratedPlugins(registry: flutterViewController)
12 +
13 + super.awakeFromNib()
14 + }
15 +}
cw_monero/example/macos/Runner/Release.entitlements new
+8
@@ -0,0 +1,8 @@
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 +<plist version="1.0">
4 +<dict>
5 + <key>com.apple.security.app-sandbox</key>
6 + <true/>
7 +</dict>
8 +</plist>
cw_monero/example/pubspec.lock new
+403
@@ -0,0 +1,403 @@
1 +# Generated by pub
2 +# See https://dart.dev/tools/pub/glossary#lockfile
3 +packages:
4 + args:
5 + dependency: transitive
6 + description:
7 + name: args
8 + sha256: "139d809800a412ebb26a3892da228b2d0ba36f0ef5d9a82166e5e52ec8d61611"
9 + url: "https://pub.dev"
10 + source: hosted
11 + version: "2.3.2"
12 + asn1lib:
13 + dependency: transitive
14 + description:
15 + name: asn1lib
16 + sha256: ab96a1cb3beeccf8145c52e449233fe68364c9641623acd3adad66f8184f1039
17 + url: "https://pub.dev"
18 + source: hosted
19 + version: "1.4.0"
20 + async:
21 + dependency: transitive
22 + description:
23 + name: async
24 + sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0
25 + url: "https://pub.dev"
26 + source: hosted
27 + version: "2.10.0"
28 + boolean_selector:
29 + dependency: transitive
30 + description:
31 + name: boolean_selector
32 + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
33 + url: "https://pub.dev"
34 + source: hosted
35 + version: "2.1.1"
36 + characters:
37 + dependency: transitive
38 + description:
39 + name: characters
40 + sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c
41 + url: "https://pub.dev"
42 + source: hosted
43 + version: "1.2.1"
44 + clock:
45 + dependency: transitive
46 + description:
47 + name: clock
48 + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
49 + url: "https://pub.dev"
50 + source: hosted
51 + version: "1.1.1"
52 + collection:
53 + dependency: transitive
54 + description:
55 + name: collection
56 + sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0
57 + url: "https://pub.dev"
58 + source: hosted
59 + version: "1.17.0"
60 + convert:
61 + dependency: transitive
62 + description:
63 + name: convert
64 + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
65 + url: "https://pub.dev"
66 + source: hosted
67 + version: "3.1.1"
68 + crypto:
69 + dependency: transitive
70 + description:
71 + name: crypto
72 + sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67
73 + url: "https://pub.dev"
74 + source: hosted
75 + version: "3.0.2"
76 + cupertino_icons:
77 + dependency: "direct main"
78 + description:
79 + name: cupertino_icons
80 + sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be
81 + url: "https://pub.dev"
82 + source: hosted
83 + version: "1.0.5"
84 + cw_core:
85 + dependency: transitive
86 + description:
87 + path: "../../cw_core"
88 + relative: true
89 + source: path
90 + version: "0.0.1"
91 + cw_monero:
92 + dependency: "direct main"
93 + description:
94 + path: ".."
95 + relative: true
96 + source: path
97 + version: "0.0.1"
98 + encrypt:
99 + dependency: transitive
100 + description:
101 + name: encrypt
102 + sha256: "4fd4e4fdc21b9d7d4141823e1e6515cd94e7b8d84749504c232999fba25d9bbb"
103 + url: "https://pub.dev"
104 + source: hosted
105 + version: "5.0.1"
106 + fake_async:
107 + dependency: transitive
108 + description:
109 + name: fake_async
110 + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
111 + url: "https://pub.dev"
112 + source: hosted
113 + version: "1.3.1"
114 + ffi:
115 + dependency: transitive
116 + description:
117 + name: ffi
118 + sha256: "13a6ccf6a459a125b3fcdb6ec73bd5ff90822e071207c663bfd1f70062d51d18"
119 + url: "https://pub.dev"
120 + source: hosted
121 + version: "1.2.1"
122 + file:
123 + dependency: transitive
124 + description:
125 + name: file
126 + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d"
127 + url: "https://pub.dev"
128 + source: hosted
129 + version: "6.1.4"
130 + flutter:
131 + dependency: "direct main"
132 + description: flutter
133 + source: sdk
134 + version: "0.0.0"
135 + flutter_lints:
136 + dependency: "direct dev"
137 + description:
138 + name: flutter_lints
139 + sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c
140 + url: "https://pub.dev"
141 + source: hosted
142 + version: "2.0.1"
143 + flutter_mobx:
144 + dependency: transitive
145 + description:
146 + name: flutter_mobx
147 + sha256: "0da4add0016387a7bf309a0d0c41d36c6b3ae25ed7a176409267f166509e723e"
148 + url: "https://pub.dev"
149 + source: hosted
150 + version: "2.0.6+5"
151 + flutter_test:
152 + dependency: "direct dev"
153 + description: flutter
154 + source: sdk
155 + version: "0.0.0"
156 + http:
157 + dependency: transitive
158 + description:
159 + name: http
160 + sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482"
161 + url: "https://pub.dev"
162 + source: hosted
163 + version: "0.13.5"
164 + http_parser:
165 + dependency: transitive
166 + description:
167 + name: http_parser
168 + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
169 + url: "https://pub.dev"
170 + source: hosted
171 + version: "4.0.2"
172 + intl:
173 + dependency: transitive
174 + description:
175 + name: intl
176 + sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91"
177 + url: "https://pub.dev"
178 + source: hosted
179 + version: "0.17.0"
180 + js:
181 + dependency: transitive
182 + description:
183 + name: js
184 + sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7"
185 + url: "https://pub.dev"
186 + source: hosted
187 + version: "0.6.5"
188 + lints:
189 + dependency: transitive
190 + description:
191 + name: lints
192 + sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593"
193 + url: "https://pub.dev"
194 + source: hosted
195 + version: "2.0.1"
196 + matcher:
197 + dependency: transitive
198 + description:
199 + name: matcher
200 + sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72"
201 + url: "https://pub.dev"
202 + source: hosted
203 + version: "0.12.13"
204 + material_color_utilities:
205 + dependency: transitive
206 + description:
207 + name: material_color_utilities
208 + sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
209 + url: "https://pub.dev"
210 + source: hosted
211 + version: "0.2.0"
212 + meta:
213 + dependency: transitive
214 + description:
215 + name: meta
216 + sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42"
217 + url: "https://pub.dev"
218 + source: hosted
219 + version: "1.8.0"
220 + mobx:
221 + dependency: transitive
222 + description:
223 + name: mobx
224 + sha256: f1862bd92c6a903fab67338f27e2f731117c3cb9ea37cee1a487f9e4e0de314a
225 + url: "https://pub.dev"
226 + source: hosted
227 + version: "2.1.3+1"
228 + path:
229 + dependency: transitive
230 + description:
231 + name: path
232 + sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b
233 + url: "https://pub.dev"
234 + source: hosted
235 + version: "1.8.2"
236 + path_provider:
237 + dependency: transitive
238 + description:
239 + name: path_provider
240 + sha256: dcea5feb97d8abf90cab9e9030b497fb7c3cbf26b7a1fe9e3ef7dcb0a1ddec95
241 + url: "https://pub.dev"
242 + source: hosted
243 + version: "2.0.12"
244 + path_provider_android:
245 + dependency: transitive
246 + description:
247 + name: path_provider_android
248 + sha256: a776c088d671b27f6e3aa8881d64b87b3e80201c64e8869b811325de7a76c15e
249 + url: "https://pub.dev"
250 + source: hosted
251 + version: "2.0.22"
252 + path_provider_foundation:
253 + dependency: transitive
254 + description:
255 + name: path_provider_foundation
256 + sha256: "62a68e7e1c6c459f9289859e2fae58290c981ce21d1697faf54910fe1faa4c74"
257 + url: "https://pub.dev"
258 + source: hosted
259 + version: "2.1.1"
260 + path_provider_linux:
261 + dependency: transitive
262 + description:
263 + name: path_provider_linux
264 + sha256: ab0987bf95bc591da42dffb38c77398fc43309f0b9b894dcc5d6f40c4b26c379
265 + url: "https://pub.dev"
266 + source: hosted
267 + version: "2.1.7"
268 + path_provider_platform_interface:
269 + dependency: transitive
270 + description:
271 + name: path_provider_platform_interface
272 + sha256: f0abc8ebd7253741f05488b4813d936b4d07c6bae3e86148a09e342ee4b08e76
273 + url: "https://pub.dev"
274 + source: hosted
275 + version: "2.0.5"
276 + path_provider_windows:
277 + dependency: transitive
278 + description:
279 + name: path_provider_windows
280 + sha256: a34ecd7fb548f8e57321fd8e50d865d266941b54e6c3b7758cf8f37c24116905
281 + url: "https://pub.dev"
282 + source: hosted
283 + version: "2.0.7"
284 + platform:
285 + dependency: transitive
286 + description:
287 + name: platform
288 + sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76"
289 + url: "https://pub.dev"
290 + source: hosted
291 + version: "3.1.0"
292 + plugin_platform_interface:
293 + dependency: transitive
294 + description:
295 + name: plugin_platform_interface
296 + sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a
297 + url: "https://pub.dev"
298 + source: hosted
299 + version: "2.1.3"
300 + pointycastle:
301 + dependency: transitive
302 + description:
303 + name: pointycastle
304 + sha256: db7306cf0249f838d1a24af52b5a5887c5bf7f31d8bb4e827d071dc0939ad346
305 + url: "https://pub.dev"
306 + source: hosted
307 + version: "3.6.2"
308 + process:
309 + dependency: transitive
310 + description:
311 + name: process
312 + sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09"
313 + url: "https://pub.dev"
314 + source: hosted
315 + version: "4.2.4"
316 + sky_engine:
317 + dependency: transitive
318 + description: flutter
319 + source: sdk
320 + version: "0.0.99"
321 + source_span:
322 + dependency: transitive
323 + description:
324 + name: source_span
325 + sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
326 + url: "https://pub.dev"
327 + source: hosted
328 + version: "1.9.1"
329 + stack_trace:
330 + dependency: transitive
331 + description:
332 + name: stack_trace
333 + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
334 + url: "https://pub.dev"
335 + source: hosted
336 + version: "1.11.0"
337 + stream_channel:
338 + dependency: transitive
339 + description:
340 + name: stream_channel
341 + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
342 + url: "https://pub.dev"
343 + source: hosted
344 + version: "2.1.1"
345 + string_scanner:
346 + dependency: transitive
347 + description:
348 + name: string_scanner
349 + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
350 + url: "https://pub.dev"
351 + source: hosted
352 + version: "1.2.0"
353 + term_glyph:
354 + dependency: transitive
355 + description:
356 + name: term_glyph
357 + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
358 + url: "https://pub.dev"
359 + source: hosted
360 + version: "1.2.1"
361 + test_api:
362 + dependency: transitive
363 + description:
364 + name: test_api
365 + sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206
366 + url: "https://pub.dev"
367 + source: hosted
368 + version: "0.4.16"
369 + typed_data:
370 + dependency: transitive
371 + description:
372 + name: typed_data
373 + sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5"
374 + url: "https://pub.dev"
375 + source: hosted
376 + version: "1.3.1"
377 + vector_math:
378 + dependency: transitive
379 + description:
380 + name: vector_math
381 + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
382 + url: "https://pub.dev"
383 + source: hosted
384 + version: "2.1.4"
385 + win32:
386 + dependency: transitive
387 + description:
388 + name: win32
389 + sha256: c0e3a4f7be7dae51d8f152230b86627e3397c1ba8c3fa58e63d44a9f3edc9cef
390 + url: "https://pub.dev"
391 + source: hosted
392 + version: "2.6.1"
393 + xdg_directories:
394 + dependency: transitive
395 + description:
396 + name: xdg_directories
397 + sha256: bd512f03919aac5f1313eb8249f223bacf4927031bf60b02601f81f687689e86
398 + url: "https://pub.dev"
399 + source: hosted
400 + version: "0.2.0+3"
401 +sdks:
402 + dart: ">=2.18.1 <3.0.0"
403 + flutter: ">=3.0.0"
cw_monero/example/pubspec.yaml new
+84
@@ -0,0 +1,84 @@
1 +name: cw_monero_example
2 +description: Demonstrates how to use the cw_monero plugin.
3 +
4 +# The following line prevents the package from being accidentally published to
5 +# pub.dev using `flutter pub publish`. This is preferred for private packages.
6 +publish_to: 'none' # Remove this line if you wish to publish to pub.dev
7 +
8 +environment:
9 + sdk: '>=2.18.1 <3.0.0'
10 +
11 +# Dependencies specify other packages that your package needs in order to work.
12 +# To automatically upgrade your package dependencies to the latest versions
13 +# consider running `flutter pub upgrade --major-versions`. Alternatively,
14 +# dependencies can be manually updated by changing the version numbers below to
15 +# the latest version available on pub.dev. To see which dependencies have newer
16 +# versions available, run `flutter pub outdated`.
17 +dependencies:
18 + flutter:
19 + sdk: flutter
20 +
21 + cw_monero:
22 + # When depending on this package from a real application you should use:
23 + # cw_monero: ^x.y.z
24 + # See https://dart.dev/tools/pub/dependencies#version-constraints
25 + # The example app is bundled with the plugin so we use a path dependency on
26 + # the parent directory to use the current plugin's version.
27 + path: ../
28 +
29 + # The following adds the Cupertino Icons font to your application.
30 + # Use with the CupertinoIcons class for iOS style icons.
31 + cupertino_icons: ^1.0.2
32 +
33 +dev_dependencies:
34 + flutter_test:
35 + sdk: flutter
36 +
37 + # The "flutter_lints" package below contains a set of recommended lints to
38 + # encourage good coding practices. The lint set provided by the package is
39 + # activated in the `analysis_options.yaml` file located at the root of your
40 + # package. See that file for information about deactivating specific lint
41 + # rules and activating additional ones.
42 + flutter_lints: ^2.0.0
43 +
44 +# For information on the generic Dart part of this file, see the
45 +# following page: https://dart.dev/tools/pub/pubspec
46 +
47 +# The following section is specific to Flutter packages.
48 +flutter:
49 +
50 + # The following line ensures that the Material Icons font is
51 + # included with your application, so that you can use the icons in
52 + # the material Icons class.
53 + uses-material-design: true
54 +
55 + # To add assets to your application, add an assets section, like this:
56 + # assets:
57 + # - images/a_dot_burr.jpeg
58 + # - images/a_dot_ham.jpeg
59 +
60 + # An image asset can refer to one or more resolution-specific "variants", see
61 + # https://flutter.dev/assets-and-images/#resolution-aware
62 +
63 + # For details regarding adding assets from package dependencies, see
64 + # https://flutter.dev/assets-and-images/#from-packages
65 +
66 + # To add custom fonts to your application, add a fonts section here,
67 + # in this "flutter" section. Each entry in this list should have a
68 + # "family" key with the font family name, and a "fonts" key with a
69 + # list giving the asset and other descriptors for the font. For
70 + # example:
71 + # fonts:
72 + # - family: Schyler
73 + # fonts:
74 + # - asset: fonts/Schyler-Regular.ttf
75 + # - asset: fonts/Schyler-Italic.ttf
76 + # style: italic
77 + # - family: Trajan Pro
78 + # fonts:
79 + # - asset: fonts/TrajanPro.ttf
80 + # - asset: fonts/TrajanPro_Bold.ttf
81 + # weight: 700
82 + #
83 + # For details regarding fonts from package dependencies,
84 + # see https://flutter.dev/custom-fonts/#from-packages
cw_monero/example/test/widget_test.dart new
+27
@@ -0,0 +1,27 @@
1 +// This is a basic Flutter widget test.
2 +//
3 +// To perform an interaction with a widget in your test, use the WidgetTester
4 +// utility in the flutter_test package. For example, you can send tap and scroll
5 +// gestures. You can also use WidgetTester to find child widgets in the widget
6 +// tree, read text, and verify that the values of widget properties are correct.
7 +
8 +import 'package:flutter/material.dart';
9 +import 'package:flutter_test/flutter_test.dart';
10 +
11 +import 'package:cw_monero_example/main.dart';
12 +
13 +void main() {
14 + testWidgets('Verify Platform version', (WidgetTester tester) async {
15 + // Build our app and trigger a frame.
16 + await tester.pumpWidget(const MyApp());
17 +
18 + // Verify that platform version is retrieved.
19 + expect(
20 + find.byWidgetPredicate(
21 + (Widget widget) => widget is Text &&
22 + widget.data!.startsWith('Running on:'),
23 + ),
24 + findsOneWidget,
25 + );
26 + });
27 +}
cw_monero/lib/cw_monero.dart new
+8
@@ -0,0 +1,8 @@
1 +
2 +import 'cw_monero_platform_interface.dart';
3 +
4 +class CwMonero {
5 + Future<String?> getPlatformVersion() {
6 + return CwMoneroPlatform.instance.getPlatformVersion();
7 + }
8 +}
cw_monero/lib/cw_monero_method_channel.dart new
+17
@@ -0,0 +1,17 @@
1 +import 'package:flutter/foundation.dart';
2 +import 'package:flutter/services.dart';
3 +
4 +import 'cw_monero_platform_interface.dart';
5 +
6 +/// An implementation of [CwMoneroPlatform] that uses method channels.
7 +class MethodChannelCwMonero extends CwMoneroPlatform {
8 + /// The method channel used to interact with the native platform.
9 + @visibleForTesting
10 + final methodChannel = const MethodChannel('cw_monero');
11 +
12 + @override
13 + Future<String?> getPlatformVersion() async {
14 + final version = await methodChannel.invokeMethod<String>('getPlatformVersion');
15 + return version;
16 + }
17 +}
cw_monero/lib/cw_monero_platform_interface.dart new
+29
@@ -0,0 +1,29 @@
1 +import 'package:plugin_platform_interface/plugin_platform_interface.dart';
2 +
3 +import 'cw_monero_method_channel.dart';
4 +
5 +abstract class CwMoneroPlatform extends PlatformInterface {
6 + /// Constructs a CwMoneroPlatform.
7 + CwMoneroPlatform() : super(token: _token);
8 +
9 + static final Object _token = Object();
10 +
11 + static CwMoneroPlatform _instance = MethodChannelCwMonero();
12 +
13 + /// The default instance of [CwMoneroPlatform] to use.
14 + ///
15 + /// Defaults to [MethodChannelCwMonero].
16 + static CwMoneroPlatform get instance => _instance;
17 +
18 + /// Platform-specific implementations should set this with their own
19 + /// platform-specific class that extends [CwMoneroPlatform] when
20 + /// they register themselves.
21 + static set instance(CwMoneroPlatform instance) {
22 + PlatformInterface.verifyToken(instance, _token);
23 + _instance = instance;
24 + }
25 +
26 + Future<String?> getPlatformVersion() {
27 + throw UnimplementedError('platformVersion() has not been implemented.');
28 + }
29 +}
cw_monero/macos/Classes/CwMoneroPlugin.swift new
+19
@@ -0,0 +1,19 @@
1 +import Cocoa
2 +import FlutterMacOS
3 +
4 +public class CwMoneroPlugin: NSObject, FlutterPlugin {
5 + public static func register(with registrar: FlutterPluginRegistrar) {
6 + let channel = FlutterMethodChannel(name: "cw_monero", binaryMessenger: registrar.messenger)
7 + let instance = CwMoneroPlugin()
8 + registrar.addMethodCallDelegate(instance, channel: channel)
9 + }
10 +
11 + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
12 + switch call.method {
13 + case "getPlatformVersion":
14 + result("macOS " + ProcessInfo.processInfo.operatingSystemVersionString)
15 + default:
16 + result(FlutterMethodNotImplemented)
17 + }
18 + }
19 +}
cw_monero/macos/Classes/CwWalletListener.h new
+23
@@ -0,0 +1,23 @@
1 +#include <stdint.h>
2 +
3 +struct CWMoneroWalletListener;
4 +
5 +typedef int8_t (*on_new_block_callback)(uint64_t height);
6 +typedef int8_t (*on_need_to_refresh_callback)();
7 +
8 +typedef struct CWMoneroWalletListener
9 +{
10 + // on_money_spent_callback *on_money_spent;
11 + // on_money_received_callback *on_money_received;
12 + // on_unconfirmed_money_received_callback *on_unconfirmed_money_received;
13 + // on_new_block_callback *on_new_block;
14 + // on_updated_callback *on_updated;
15 + // on_refreshed_callback *on_refreshed;
16 +
17 + on_new_block_callback on_new_block;
18 +} CWMoneroWalletListener;
19 +
20 +struct TestListener {
21 + // int8_t x;
22 + on_new_block_callback on_new_block;
23 +};
\ No newline at end of file
cw_monero/macos/Classes/monero_api.cpp new
+798
@@ -0,0 +1,798 @@
1 +#include <stdint.h>
2 +#include "cstdlib"
3 +#include <chrono>
4 +#include <functional>
5 +#include <iostream>
6 +#include <unistd.h>
7 +#include <mutex>
8 +#include "thread"
9 +#include "CwWalletListener.h"
10 +#if __APPLE__
11 +// Fix for randomx on ios
12 +void __clear_cache(void* start, void* end) { }
13 +#include "../External/macos/include/wallet2_api.h"
14 +#else
15 +#include "../External/android/include/wallet2_api.h"
16 +#endif
17 +
18 +using namespace std::chrono_literals;
19 +#ifdef __cplusplus
20 +extern "C"
21 +{
22 +#endif
23 + const uint64_t MONERO_BLOCK_SIZE = 1000;
24 +
25 + struct Utf8Box
26 + {
27 + char *value;
28 +
29 + Utf8Box(char *_value)
30 + {
31 + value = _value;
32 + }
33 + };
34 +
35 + struct SubaddressRow
36 + {
37 + uint64_t id;
38 + char *address;
39 + char *label;
40 +
41 + SubaddressRow(std::size_t _id, char *_address, char *_label)
42 + {
43 + id = static_cast<uint64_t>(_id);
44 + address = _address;
45 + label = _label;
46 + }
47 + };
48 +
49 + struct AccountRow
50 + {
51 + uint64_t id;
52 + char *label;
53 +
54 + AccountRow(std::size_t _id, char *_label)
55 + {
56 + id = static_cast<uint64_t>(_id);
57 + label = _label;
58 + }
59 + };
60 +
61 + struct MoneroWalletListener : Monero::WalletListener
62 + {
63 + uint64_t m_height;
64 + bool m_need_to_refresh;
65 + bool m_new_transaction;
66 +
67 + MoneroWalletListener()
68 + {
69 + m_height = 0;
70 + m_need_to_refresh = false;
71 + m_new_transaction = false;
72 + }
73 +
74 + void moneySpent(const std::string &txId, uint64_t amount)
75 + {
76 + m_new_transaction = true;
77 + }
78 +
79 + void moneyReceived(const std::string &txId, uint64_t amount)
80 + {
81 + m_new_transaction = true;
82 + }
83 +
84 + void unconfirmedMoneyReceived(const std::string &txId, uint64_t amount)
85 + {
86 + m_new_transaction = true;
87 + }
88 +
89 + void newBlock(uint64_t height)
90 + {
91 + m_height = height;
92 + }
93 +
94 + void updated()
95 + {
96 + m_new_transaction = true;
97 + }
98 +
99 + void refreshed()
100 + {
101 + m_need_to_refresh = true;
102 + }
103 +
104 + void resetNeedToRefresh()
105 + {
106 + m_need_to_refresh = false;
107 + }
108 +
109 + bool isNeedToRefresh()
110 + {
111 + return m_need_to_refresh;
112 + }
113 +
114 + bool isNewTransactionExist()
115 + {
116 + return m_new_transaction;
117 + }
118 +
119 + void resetIsNewTransactionExist()
120 + {
121 + m_new_transaction = false;
122 + }
123 +
124 + uint64_t height()
125 + {
126 + return m_height;
127 + }
128 + };
129 +
130 + struct TransactionInfoRow
131 + {
132 + uint64_t amount;
133 + uint64_t fee;
134 + uint64_t blockHeight;
135 + uint64_t confirmations;
136 + uint32_t subaddrAccount;
137 + int8_t direction;
138 + int8_t isPending;
139 + uint32_t subaddrIndex;
140 +
141 + char *hash;
142 + char *paymentId;
143 +
144 + int64_t datetime;
145 +
146 + TransactionInfoRow(Monero::TransactionInfo *transaction)
147 + {
148 + amount = transaction->amount();
149 + fee = transaction->fee();
150 + blockHeight = transaction->blockHeight();
151 + subaddrAccount = transaction->subaddrAccount();
152 + std::set<uint32_t>::iterator it = transaction->subaddrIndex().begin();
153 + subaddrIndex = *it;
154 + confirmations = transaction->confirmations();
155 + datetime = static_cast<int64_t>(transaction->timestamp());
156 + direction = transaction->direction();
157 + isPending = static_cast<int8_t>(transaction->isPending());
158 + std::string *hash_str = new std::string(transaction->hash());
159 + hash = strdup(hash_str->c_str());
160 + paymentId = strdup(transaction->paymentId().c_str());
161 + }
162 + };
163 +
164 + struct PendingTransactionRaw
165 + {
166 + uint64_t amount;
167 + uint64_t fee;
168 + char *hash;
169 + char *hex;
170 + char *txKey;
171 + Monero::PendingTransaction *transaction;
172 +
173 + PendingTransactionRaw(Monero::PendingTransaction *_transaction)
174 + {
175 + transaction = _transaction;
176 + amount = _transaction->amount();
177 + fee = _transaction->fee();
178 + hash = strdup(_transaction->txid()[0].c_str());
179 + hex = strdup(_transaction->hex()[0].c_str());
180 + txKey = strdup(_transaction->txKey()[0].c_str());
181 + }
182 + };
183 +
184 + Monero::Wallet *m_wallet;
185 + Monero::TransactionHistory *m_transaction_history;
186 + MoneroWalletListener *m_listener;
187 + Monero::Subaddress *m_subaddress;
188 + Monero::SubaddressAccount *m_account;
189 + uint64_t m_last_known_wallet_height;
190 + uint64_t m_cached_syncing_blockchain_height = 0;
191 + std::mutex store_lock;
192 + bool is_storing = false;
193 +
194 + void change_current_wallet(Monero::Wallet *wallet)
195 + {
196 + m_wallet = wallet;
197 + m_listener = nullptr;
198 +
199 +
200 + if (wallet != nullptr)
201 + {
202 + m_transaction_history = wallet->history();
203 + }
204 + else
205 + {
206 + m_transaction_history = nullptr;
207 + }
208 +
209 + if (wallet != nullptr)
210 + {
211 + m_account = wallet->subaddressAccount();
212 + }
213 + else
214 + {
215 + m_account = nullptr;
216 + }
217 +
218 + if (wallet != nullptr)
219 + {
220 + m_subaddress = wallet->subaddress();
221 + }
222 + else
223 + {
224 + m_subaddress = nullptr;
225 + }
226 + }
227 +
228 + Monero::Wallet *get_current_wallet()
229 + {
230 + return m_wallet;
231 + }
232 +
233 + bool create_wallet(char *path, char *password, char *language, int32_t networkType, char *error)
234 + {
235 + Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
236 + Monero::WalletManager *walletManager = Monero::WalletManagerFactory::getWalletManager();
237 + Monero::Wallet *wallet = walletManager->createWallet(path, password, language, _networkType);
238 +
239 + int status;
240 + std::string errorString;
241 +
242 + wallet->statusWithErrorString(status, errorString);
243 +
244 + if (wallet->status() != Monero::Wallet::Status_Ok)
245 + {
246 + error = strdup(wallet->errorString().c_str());
247 + return false;
248 + }
249 +
250 + change_current_wallet(wallet);
251 +
252 + return true;
253 + }
254 +
255 + bool restore_wallet_from_seed(char *path, char *password, char *seed, int32_t networkType, uint64_t restoreHeight, char *error)
256 + {
257 + Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
258 + Monero::Wallet *wallet = Monero::WalletManagerFactory::getWalletManager()->recoveryWallet(
259 + std::string(path),
260 + std::string(password),
261 + std::string(seed),
262 + _networkType,
263 + (uint64_t)restoreHeight);
264 +
265 + int status;
266 + std::string errorString;
267 +
268 + wallet->statusWithErrorString(status, errorString);
269 +
270 + if (status != Monero::Wallet::Status_Ok || !errorString.empty())
271 + {
272 + error = strdup(errorString.c_str());
273 + return false;
274 + }
275 +
276 + change_current_wallet(wallet);
277 + return true;
278 + }
279 +
280 + bool restore_wallet_from_keys(char *path, char *password, char *language, char *address, char *viewKey, char *spendKey, int32_t networkType, uint64_t restoreHeight, char *error)
281 + {
282 + Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
283 + Monero::Wallet *wallet = Monero::WalletManagerFactory::getWalletManager()->createWalletFromKeys(
284 + std::string(path),
285 + std::string(password),
286 + std::string(language),
287 + _networkType,
288 + (uint64_t)restoreHeight,
289 + std::string(address),
290 + std::string(viewKey),
291 + std::string(spendKey));
292 +
293 + int status;
294 + std::string errorString;
295 +
296 + wallet->statusWithErrorString(status, errorString);
297 +
298 + if (status != Monero::Wallet::Status_Ok || !errorString.empty())
299 + {
300 + error = strdup(errorString.c_str());
301 + return false;
302 + }
303 +
304 + change_current_wallet(wallet);
305 + return true;
306 + }
307 +
308 + bool load_wallet(char *path, char *password, int32_t nettype)
309 + {
310 + nice(19);
311 + Monero::NetworkType networkType = static_cast<Monero::NetworkType>(nettype);
312 + Monero::WalletManager *walletManager = Monero::WalletManagerFactory::getWalletManager();
313 + Monero::Wallet *wallet = walletManager->openWallet(std::string(path), std::string(password), networkType);
314 + int status;
315 + std::string errorString;
316 +
317 + wallet->statusWithErrorString(status, errorString);
318 + change_current_wallet(wallet);
319 +
320 + return !(status != Monero::Wallet::Status_Ok || !errorString.empty());
321 + }
322 +
323 + char *error_string() {
324 + return strdup(get_current_wallet()->errorString().c_str());
325 + }
326 +
327 +
328 + bool is_wallet_exist(char *path)
329 + {
330 + return Monero::WalletManagerFactory::getWalletManager()->walletExists(std::string(path));
331 + }
332 +
333 + void close_current_wallet()
334 + {
335 + Monero::WalletManagerFactory::getWalletManager()->closeWallet(get_current_wallet());
336 + change_current_wallet(nullptr);
337 + }
338 +
339 + char *get_filename()
340 + {
341 + return strdup(get_current_wallet()->filename().c_str());
342 + }
343 +
344 + char *secret_view_key()
345 + {
346 + return strdup(get_current_wallet()->secretViewKey().c_str());
347 + }
348 +
349 + char *public_view_key()
350 + {
351 + return strdup(get_current_wallet()->publicViewKey().c_str());
352 + }
353 +
354 + char *secret_spend_key()
355 + {
356 + return strdup(get_current_wallet()->secretSpendKey().c_str());
357 + }
358 +
359 + char *public_spend_key()
360 + {
361 + return strdup(get_current_wallet()->publicSpendKey().c_str());
362 + }
363 +
364 + char *get_address(uint32_t account_index, uint32_t address_index)
365 + {
366 + return strdup(get_current_wallet()->address(account_index, address_index).c_str());
367 + }
368 +
369 +
370 + const char *seed()
371 + {
372 + return strdup(get_current_wallet()->seed().c_str());
373 + }
374 +
375 + uint64_t get_full_balance(uint32_t account_index)
376 + {
377 + return get_current_wallet()->balance(account_index);
378 + }
379 +
380 + uint64_t get_unlocked_balance(uint32_t account_index)
381 + {
382 + return get_current_wallet()->unlockedBalance(account_index);
383 + }
384 +
385 + uint64_t get_current_height()
386 + {
387 + return get_current_wallet()->blockChainHeight();
388 + }
389 +
390 + uint64_t get_node_height()
391 + {
392 + return get_current_wallet()->daemonBlockChainHeight();
393 + }
394 +
395 + bool connect_to_node(char *error)
396 + {
397 + nice(19);
398 + bool is_connected = get_current_wallet()->connectToDaemon();
399 +
400 + if (!is_connected)
401 + {
402 + error = strdup(get_current_wallet()->errorString().c_str());
403 + }
404 +
405 + return is_connected;
406 + }
407 +
408 + bool setup_node(char *address, char *login, char *password, bool use_ssl, bool is_light_wallet, char *error)
409 + {
410 + nice(19);
411 + Monero::Wallet *wallet = get_current_wallet();
412 +
413 + std::string _login = "";
414 + std::string _password = "";
415 +
416 + if (login != nullptr)
417 + {
418 + _login = std::string(login);
419 + }
420 +
421 + if (password != nullptr)
422 + {
423 + _password = std::string(password);
424 + }
425 +
426 + bool inited = wallet->init(std::string(address), 0, _login, _password, use_ssl, is_light_wallet);
427 +
428 + if (!inited)
429 + {
430 + error = strdup(wallet->errorString().c_str());
431 + } else if (!wallet->connectToDaemon()) {
432 + error = strdup(wallet->errorString().c_str());
433 + }
434 +
435 + return inited;
436 + }
437 +
438 + bool is_connected()
439 + {
440 + return get_current_wallet()->connected();
441 + }
442 +
443 + void start_refresh()
444 + {
445 + get_current_wallet()->refreshAsync();
446 + get_current_wallet()->startRefresh();
447 + }
448 +
449 + void set_refresh_from_block_height(uint64_t height)
450 + {
451 + get_current_wallet()->setRefreshFromBlockHeight(height);
452 + }
453 +
454 + void set_recovering_from_seed(bool is_recovery)
455 + {
456 + get_current_wallet()->setRecoveringFromSeed(is_recovery);
457 + }
458 +
459 + void store(char *path)
460 + {
461 + store_lock.lock();
462 + if (is_storing) {
463 + return;
464 + }
465 +
466 + is_storing = true;
467 + get_current_wallet()->store(std::string(path));
468 + is_storing = false;
469 + store_lock.unlock();
470 + }
471 +
472 + bool set_password(char *password, Utf8Box &error) {
473 + bool is_changed = get_current_wallet()->setPassword(std::string(password));
474 +
475 + if (!is_changed) {
476 + error = Utf8Box(strdup(get_current_wallet()->errorString().c_str()));
477 + }
478 +
479 + return is_changed;
480 + }
481 +
482 + bool transaction_create(char *address, char *payment_id, char *amount,
483 + uint8_t priority_raw, uint32_t subaddr_account, Utf8Box &error, PendingTransactionRaw &pendingTransaction)
484 + {
485 + nice(19);
486 +
487 + auto priority = static_cast<Monero::PendingTransaction::Priority>(priority_raw);
488 + std::string _payment_id;
489 + Monero::PendingTransaction *transaction;
490 +
491 + if (payment_id != nullptr)
492 + {
493 + _payment_id = std::string(payment_id);
494 + }
495 +
496 + if (amount != nullptr)
497 + {
498 + uint64_t _amount = Monero::Wallet::amountFromString(std::string(amount));
499 + transaction = m_wallet->createTransaction(std::string(address), _payment_id, _amount, m_wallet->defaultMixin(), priority, subaddr_account);
500 + }
501 + else
502 + {
503 + transaction = m_wallet->createTransaction(std::string(address), _payment_id, Monero::optional<uint64_t>(), m_wallet->defaultMixin(), priority, subaddr_account);
504 + }
505 +
506 + int status = transaction->status();
507 +
508 + if (status == Monero::PendingTransaction::Status::Status_Error || status == Monero::PendingTransaction::Status::Status_Critical)
509 + {
510 + error = Utf8Box(strdup(transaction->errorString().c_str()));
511 + return false;
512 + }
513 +
514 + if (m_listener != nullptr) {
515 + m_listener->m_new_transaction = true;
516 + }
517 +
518 + pendingTransaction = PendingTransactionRaw(transaction);
519 + return true;
520 + }
521 +
522 + bool transaction_create_mult_dest(char **addresses, char *payment_id, char **amounts, uint32_t size,
523 + uint8_t priority_raw, uint32_t subaddr_account, Utf8Box &error, PendingTransactionRaw &pendingTransaction)
524 + {
525 + nice(19);
526 +
527 + std::vector<std::string> _addresses;
528 + std::vector<uint64_t> _amounts;
529 +
530 + for (int i = 0; i < size; i++) {
531 + _addresses.push_back(std::string(*addresses));
532 + _amounts.push_back(Monero::Wallet::amountFromString(std::string(*amounts)));
533 + addresses++;
534 + amounts++;
535 + }
536 +
537 + auto priority = static_cast<Monero::PendingTransaction::Priority>(priority_raw);
538 + std::string _payment_id;
539 + Monero::PendingTransaction *transaction;
540 +
541 + if (payment_id != nullptr)
542 + {
543 + _payment_id = std::string(payment_id);
544 + }
545 +
546 + transaction = m_wallet->createTransactionMultDest(_addresses, _payment_id, _amounts, m_wallet->defaultMixin(), priority, subaddr_account);
547 +
548 + int status = transaction->status();
549 +
550 + if (status == Monero::PendingTransaction::Status::Status_Error || status == Monero::PendingTransaction::Status::Status_Critical)
551 + {
552 + error = Utf8Box(strdup(transaction->errorString().c_str()));
553 + return false;
554 + }
555 +
556 + if (m_listener != nullptr) {
557 + m_listener->m_new_transaction = true;
558 + }
559 +
560 + pendingTransaction = PendingTransactionRaw(transaction);
561 + return true;
562 + }
563 +
564 + bool transaction_commit(PendingTransactionRaw *transaction, Utf8Box &error)
565 + {
566 + bool committed = transaction->transaction->commit();
567 +
568 + if (!committed)
569 + {
570 + error = Utf8Box(strdup(transaction->transaction->errorString().c_str()));
571 + } else if (m_listener != nullptr) {
572 + m_listener->m_new_transaction = true;
573 + }
574 +
575 + return committed;
576 + }
577 +
578 + uint64_t get_node_height_or_update(uint64_t base_eight)
579 + {
580 + if (m_cached_syncing_blockchain_height < base_eight) {
581 + m_cached_syncing_blockchain_height = base_eight;
582 + }
583 +
584 + return m_cached_syncing_blockchain_height;
585 + }
586 +
587 + uint64_t get_syncing_height()
588 + {
589 + if (m_listener == nullptr) {
590 + return 0;
591 + }
592 +
593 + uint64_t height = m_listener->height();
594 +
595 + if (height <= 1) {
596 + return 0;
597 + }
598 +
599 + if (height != m_last_known_wallet_height)
600 + {
601 + m_last_known_wallet_height = height;
602 + }
603 +
604 + return height;
605 + }
606 +
607 + uint64_t is_needed_to_refresh()
608 + {
609 + if (m_listener == nullptr) {
610 + return false;
611 + }
612 +
613 + bool should_refresh = m_listener->isNeedToRefresh();
614 +
615 + if (should_refresh) {
616 + m_listener->resetNeedToRefresh();
617 + }
618 +
619 + return should_refresh;
620 + }
621 +
622 + uint8_t is_new_transaction_exist()
623 + {
624 + if (m_listener == nullptr) {
625 + return false;
626 + }
627 +
628 + bool is_new_transaction_exist = m_listener->isNewTransactionExist();
629 +
630 + if (is_new_transaction_exist)
631 + {
632 + m_listener->resetIsNewTransactionExist();
633 + }
634 +
635 + return is_new_transaction_exist;
636 + }
637 +
638 + void set_listener()
639 + {
640 + m_last_known_wallet_height = 0;
641 +
642 + if (m_listener != nullptr)
643 + {
644 + free(m_listener);
645 + }
646 +
647 + m_listener = new MoneroWalletListener();
648 + get_current_wallet()->setListener(m_listener);
649 + }
650 +
651 + int64_t *subaddrress_get_all()
652 + {
653 + std::vector<Monero::SubaddressRow *> _subaddresses = m_subaddress->getAll();
654 + size_t size = _subaddresses.size();
655 + int64_t *subaddresses = (int64_t *)malloc(size * sizeof(int64_t));
656 +
657 + for (int i = 0; i < size; i++)
658 + {
659 + Monero::SubaddressRow *row = _subaddresses[i];
660 + SubaddressRow *_row = new SubaddressRow(row->getRowId(), strdup(row->getAddress().c_str()), strdup(row->getLabel().c_str()));
661 + subaddresses[i] = reinterpret_cast<int64_t>(_row);
662 + }
663 +
664 + return subaddresses;
665 + }
666 +
667 + int32_t subaddrress_size()
668 + {
669 + std::vector<Monero::SubaddressRow *> _subaddresses = m_subaddress->getAll();
670 + return _subaddresses.size();
671 + }
672 +
673 + void subaddress_add_row(uint32_t accountIndex, char *label)
674 + {
675 + m_subaddress->addRow(accountIndex, std::string(label));
676 + }
677 +
678 + void subaddress_set_label(uint32_t accountIndex, uint32_t addressIndex, char *label)
679 + {
680 + m_subaddress->setLabel(accountIndex, addressIndex, std::string(label));
681 + }
682 +
683 + void subaddress_refresh(uint32_t accountIndex)
684 + {
685 + m_subaddress->refresh(accountIndex);
686 + }
687 +
688 + int32_t account_size()
689 + {
690 + std::vector<Monero::SubaddressAccountRow *> _accocunts = m_account->getAll();
691 + return _accocunts.size();
692 + }
693 +
694 + int64_t *account_get_all()
695 + {
696 + std::vector<Monero::SubaddressAccountRow *> _accocunts = m_account->getAll();
697 + size_t size = _accocunts.size();
698 + int64_t *accocunts = (int64_t *)malloc(size * sizeof(int64_t));
699 +
700 + for (int i = 0; i < size; i++)
701 + {
702 + Monero::SubaddressAccountRow *row = _accocunts[i];
703 + AccountRow *_row = new AccountRow(row->getRowId(), strdup(row->getLabel().c_str()));
704 + accocunts[i] = reinterpret_cast<int64_t>(_row);
705 + }
706 +
707 + return accocunts;
708 + }
709 +
710 + void account_add_row(char *label)
711 + {
712 + m_account->addRow(std::string(label));
713 + }
714 +
715 + void account_set_label_row(uint32_t account_index, char *label)
716 + {
717 + m_account->setLabel(account_index, label);
718 + }
719 +
720 + void account_refresh()
721 + {
722 + m_account->refresh();
723 + }
724 +
725 + int64_t *transactions_get_all()
726 + {
727 + std::vector<Monero::TransactionInfo *> transactions = m_transaction_history->getAll();
728 + size_t size = transactions.size();
729 + int64_t *transactionAddresses = (int64_t *)malloc(size * sizeof(int64_t));
730 +
731 + for (int i = 0; i < size; i++)
732 + {
733 + Monero::TransactionInfo *row = transactions[i];
734 + TransactionInfoRow *tx = new TransactionInfoRow(row);
735 + transactionAddresses[i] = reinterpret_cast<int64_t>(tx);
736 + }
737 +
738 + return transactionAddresses;
739 + }
740 +
741 + void transactions_refresh()
742 + {
743 + m_transaction_history->refresh();
744 + }
745 +
746 + int64_t transactions_count()
747 + {
748 + return m_transaction_history->count();
749 + }
750 +
751 + int LedgerExchange(
752 + unsigned char *command,
753 + unsigned int cmd_len,
754 + unsigned char *response,
755 + unsigned int max_resp_len)
756 + {
757 + return -1;
758 + }
759 +
760 + int LedgerFind(char *buffer, size_t len)
761 + {
762 + return -1;
763 + }
764 +
765 + void on_startup()
766 + {
767 + Monero::Utils::onStartup();
768 + Monero::WalletManagerFactory::setLogLevel(0);
769 + }
770 +
771 + void rescan_blockchain()
772 + {
773 + m_wallet->rescanBlockchainAsync();
774 + }
775 +
776 + char * get_tx_key(char * txId)
777 + {
778 + return strdup(m_wallet->getTxKey(std::string(txId)).c_str());
779 + }
780 +
781 + char *get_subaddress_label(uint32_t accountIndex, uint32_t addressIndex)
782 + {
783 + return strdup(get_current_wallet()->getSubaddressLabel(accountIndex, addressIndex).c_str());
784 + }
785 +
786 + void set_trusted_daemon(bool arg)
787 + {
788 + m_wallet->setTrustedDaemon(arg);
789 + }
790 +
791 + bool trusted_daemon()
792 + {
793 + return m_wallet->trustedDaemon();
794 + }
795 +
796 +#ifdef __cplusplus
797 +}
798 +#endif
cw_monero/macos/Classes/monero_api.h new
+38
@@ -0,0 +1,38 @@
1 +#include <stdint.h>
2 +#include <stdio.h>
3 +#include <stdbool.h>
4 +#include "CwWalletListener.h"
5 +
6 +#ifdef __cplusplus
7 +extern "C" {
8 +#endif
9 +
10 +bool create_wallet(char *path, char *password, char *language, int32_t networkType, char *error);
11 +bool restore_wallet_from_seed(char *path, char *password, char *seed, int32_t networkType, uint64_t restoreHeight, char *error);
12 +bool restore_wallet_from_keys(char *path, char *password, char *language, char *address, char *viewKey, char *spendKey, int32_t networkType, uint64_t restoreHeight, char *error);
13 +void load_wallet(char *path, char *password, int32_t nettype);
14 +bool is_wallet_exist(char *path);
15 +
16 +char *get_filename();
17 +const char *seed();
18 +char *get_address(uint32_t account_index, uint32_t address_index);
19 +uint64_t get_full_balance(uint32_t account_index);
20 +uint64_t get_unlocked_balance(uint32_t account_index);
21 +uint64_t get_current_height();
22 +uint64_t get_node_height();
23 +
24 +bool is_connected();
25 +
26 +bool setup_node(char *address, char *login, char *password, bool use_ssl, bool is_light_wallet, char *error);
27 +bool connect_to_node(char *error);
28 +void start_refresh();
29 +void set_refresh_from_block_height(uint64_t height);
30 +void set_recovering_from_seed(bool is_recovery);
31 +void store(char *path);
32 +
33 +void set_trusted_daemon(bool arg);
34 +bool trusted_daemon();
35 +
36 +#ifdef __cplusplus
37 +}
38 +#endif
\ No newline at end of file
cw_monero/macos/cw_monero_base.podspec new
+56
@@ -0,0 +1,56 @@
1 +#
2 +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
3 +# Run `pod lib lint cw_monero.podspec` to validate before publishing.
4 +#
5 +Pod::Spec.new do |s|
6 + s.name = 'cw_monero'
7 + s.version = '0.0.1'
8 + s.summary = 'CW Monero'
9 + s.description = 'Cake Wallet wrapper over Monero project.'
10 + s.homepage = 'http://cakewallet.com'
11 + s.license = { :file => '../LICENSE' }
12 + s.author = { 'CakeWallet' => 'support@cakewallet.com' }
13 + s.source = { :path => '.' }
14 + s.source_files = 'Classes/**/*'
15 + s.dependency 'FlutterMacOS'
16 + s.public_header_files = 'Classes/**/*.h, Classes/*.h, External/macos/libs/monero/include/External/ios/**/*.h'
17 + s.platform = :osx, '10.11'
18 + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS' => '#___VALID_ARCHS___#', 'ENABLE_BITCODE' => 'NO' }
19 + s.swift_version = '5.0'
20 + s.libraries = 'iconv'
21 +
22 + s.subspec 'OpenSSL' do |openssl|
23 + openssl.preserve_paths = '../../../../../cw_shared_external/ios/External/macos/include/**/*.h'
24 + openssl.vendored_libraries = '../../../../../cw_shared_external/ios/External/macos/lib/libcrypto.a', '../../../../../cw_shared_external/ios/External/ios/lib/libssl.a'
25 + openssl.libraries = 'ssl', 'crypto'
26 + openssl.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/macos/include/**" }
27 + end
28 +
29 + s.subspec 'Sodium' do |sodium|
30 + sodium.preserve_paths = '../../../../../cw_shared_external/ios/External/macos/include/**/*.h'
31 + sodium.vendored_libraries = '../../../../../cw_shared_external/ios/External/macos/lib/libsodium.a'
32 + sodium.libraries = 'sodium'
33 + sodium.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/macos/include/**" }
34 + end
35 +
36 + s.subspec 'Unbound' do |unbound|
37 + unbound.preserve_paths = '../../../../../cw_shared_external/ios/External/macos/include/**/*.h'
38 + unbound.vendored_libraries = '../../../../../cw_shared_external/ios/External/macos/lib/libunbound.a'
39 + unbound.libraries = 'unbound'
40 + unbound.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/macos/include/**" }
41 + end
42 +
43 + s.subspec 'Boost' do |boost|
44 + boost.preserve_paths = '../../../../../cw_shared_external/ios/External/macos/include/**/*.h',
45 + boost.vendored_libraries = '../../../../../cw_shared_external/ios/External/macos/lib/libboost.a',
46 + boost.libraries = 'boost'
47 + boost.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/macos/include/**" }
48 + end
49 +
50 + s.subspec 'Monero' do |monero|
51 + monero.preserve_paths = 'External/macos/include/**/*.h'
52 + monero.vendored_libraries = 'External/macos/lib/libmonero.a'
53 + monero.libraries = 'monero'
54 + monero.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/macos/include" }
55 + end
56 +end
cw_monero/pubspec.yaml
+9 -2
@@ -40,8 +40,15 @@ flutter:
40 # be modified. They are used by the tooling to maintain consistency when
41 # adding or updating assets for this project.
42 plugin:
43 - androidPackage: com.cakewallet.monero
44 - pluginClass: CwMoneroPlugin
43 + platforms:
44 + android:
45 + package: com.cakewallet.monero
46 + pluginClass: CwMoneroPlugin
47 + ios:
48 + pluginClass: CwMoneroPlugin
49 +
50 + macos:
51 + pluginClass: CwMoneroPlugin
52
53 # To add assets to your plugin package, add an assets section, like this:
54 # assets:
cw_monero/test/cw_monero_method_channel_test.dart new
+24
@@ -0,0 +1,24 @@
1 +import 'package:flutter/services.dart';
2 +import 'package:flutter_test/flutter_test.dart';
3 +import 'package:cw_monero/cw_monero_method_channel.dart';
4 +
5 +void main() {
6 + MethodChannelCwMonero platform = MethodChannelCwMonero();
7 + const MethodChannel channel = MethodChannel('cw_monero');
8 +
9 + TestWidgetsFlutterBinding.ensureInitialized();
10 +
11 + setUp(() {
12 + channel.setMockMethodCallHandler((MethodCall methodCall) async {
13 + return '42';
14 + });
15 + });
16 +
17 + tearDown(() {
18 + channel.setMockMethodCallHandler(null);
19 + });
20 +
21 + test('getPlatformVersion', () async {
22 + expect(await platform.getPlatformVersion(), '42');
23 + });
24 +}
cw_monero/test/cw_monero_test.dart new
+29
@@ -0,0 +1,29 @@
1 +import 'package:flutter_test/flutter_test.dart';
2 +import 'package:cw_monero/cw_monero.dart';
3 +import 'package:cw_monero/cw_monero_platform_interface.dart';
4 +import 'package:cw_monero/cw_monero_method_channel.dart';
5 +import 'package:plugin_platform_interface/plugin_platform_interface.dart';
6 +
7 +class MockCwMoneroPlatform
8 + with MockPlatformInterfaceMixin
9 + implements CwMoneroPlatform {
10 +
11 + @override
12 + Future<String?> getPlatformVersion() => Future.value('42');
13 +}
14 +
15 +void main() {
16 + final CwMoneroPlatform initialPlatform = CwMoneroPlatform.instance;
17 +
18 + test('$MethodChannelCwMonero is the default instance', () {
19 + expect(initialPlatform, isInstanceOf<MethodChannelCwMonero>());
20 + });
21 +
22 + test('getPlatformVersion', () async {
23 + CwMonero cwMoneroPlugin = CwMonero();
24 + MockCwMoneroPlatform fakePlatform = MockCwMoneroPlatform();
25 + CwMoneroPlatform.instance = fakePlatform;
26 +
27 + expect(await cwMoneroPlugin.getPlatformVersion(), '42');
28 + });
29 +}
ios/CakeWallet/wakeLock.swift deleted
-20
@@ -1,20 +0,0 @@
1 -//
2 -// wakeLock.swift
3 -// Runner
4 -//
5 -// Created by Godwin Asuquo on 1/21/22.
6 -//
7 -
8 -import Foundation
9 -import UIKit
10 -
11 -func enableWakeScreen() -> Bool{
12 - UIApplication.shared.isIdleTimerDisabled = true
13 -
14 - return true
15 -}
16 -
17 -func disableWakeScreen() -> Bool{
18 - UIApplication.shared.isIdleTimerDisabled = false
19 - return true
20 -}
ios/Runner.xcodeproj/project.pbxproj
-2
@@ -12,7 +12,6 @@
12 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
13 20ED0868E1BD7E12278C0CB3 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B26E3F56D69167FBB1DC160A /* Pods_Runner.framework */; };
14 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
15 - 5AFFEBFD279AD49C00F906A4 /* wakeLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AFFEBFC279AD49C00F906A4 /* wakeLock.swift */; };
15 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
16 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
17 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
@@ -282,7 +281,6 @@
281 files = (
282 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
283 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
285 - 5AFFEBFD279AD49C00F906A4 /* wakeLock.swift in Sources */,
284 0C9D68C9264854B60011B691 /* secRandom.swift in Sources */,
285 0C44A71A2518EF8000B570ED /* decrypt.swift in Sources */,
286 );
ios/Runner/AppDelegate.swift
-5
@@ -96,11 +96,6 @@ import UnstoppableDomainsResolution
96
97 result(address)
98 }
99 - case "enableWakeScreen":
100 - result(enableWakeScreen())
101 -
102 - case "disableWakeScreen":
103 - result(disableWakeScreen())
99
100 default:
101 result(FlutterMethodNotImplemented)
lib/buy/moonpay/moonpay_buy_provider.dart
+3 -3
@@ -23,7 +23,7 @@ class MoonPaySellProvider {
23 final bool isTest;
24 final String baseUrl;
25
26 - Future<String> requestUrl({required CryptoCurrency currency, required String refundWalletAddress}) async {
26 + Future<Uri> requestUrl({required CryptoCurrency currency, required String refundWalletAddress}) async {
27 final originalUri = Uri.https(
28 baseUrl, '', <String, dynamic>{
29 'apiKey': _apiKey,
@@ -37,13 +37,13 @@ class MoonPaySellProvider {
37 final signature = base64.encode(digest.bytes);
38
39 if (isTest) {
40 - return originalUri.toString();
40 + return originalUri;
41 }
42
43 final query = Map<String, dynamic>.from(originalUri.queryParameters);
44 query['signature'] = signature;
45 final signedUri = originalUri.replace(queryParameters: query);
46 - return signedUri.toString();
46 + return signedUri;
47 }
48 }
49
lib/buy/onramper/onramper_buy_provider.dart new
+69
@@ -0,0 +1,69 @@
1 +import 'package:cake_wallet/.secrets.g.dart' as secrets;
2 +import 'package:cake_wallet/store/settings_store.dart';
3 +import 'package:cake_wallet/themes/theme_base.dart';
4 +import 'package:cw_core/wallet_base.dart';
5 +
6 +class OnRamperBuyProvider {
7 + OnRamperBuyProvider({required SettingsStore settingsStore, required WalletBase wallet})
8 + : this._settingsStore = settingsStore,
9 + this._wallet = wallet;
10 +
11 + final SettingsStore _settingsStore;
12 + final WalletBase _wallet;
13 +
14 + static const _baseUrl = 'buy.onramper.com';
15 +
16 + static String get _apiKey => secrets.onramperApiKey;
17 +
18 + Uri requestUrl() {
19 + String primaryColor,
20 + secondaryColor,
21 + primaryTextColor,
22 + secondaryTextColor,
23 + containerColor,
24 + cardColor;
25 +
26 + switch (_settingsStore.currentTheme.type) {
27 + case ThemeType.bright:
28 + primaryColor = '815dfbff';
29 + secondaryColor = 'ffffff';
30 + primaryTextColor = '141519';
31 + secondaryTextColor = '6b6f80';
32 + containerColor = 'ffffff';
33 + cardColor = 'f2f0faff';
34 + break;
35 + case ThemeType.light:
36 + primaryColor = '2194ffff';
37 + secondaryColor = 'ffffff';
38 + primaryTextColor = '141519';
39 + secondaryTextColor = '6b6f80';
40 + containerColor = 'ffffff';
41 + cardColor = 'e5f7ff';
42 + break;
43 + case ThemeType.dark:
44 + primaryColor = '456effff';
45 + secondaryColor = '1b2747ff';
46 + primaryTextColor = 'ffffff';
47 + secondaryTextColor = 'ffffff';
48 + containerColor = '19233C';
49 + cardColor = '232f4fff';
50 + break;
51 + }
52 +
53 +
54 + return Uri.https(_baseUrl, '', <String, dynamic>{
55 + 'apiKey': _apiKey,
56 + 'defaultCrypto': _wallet.currency.title,
57 + 'defaultFiat': _settingsStore.fiatCurrency.title,
58 + 'wallets': '${_wallet.currency.title}:${_wallet.walletAddresses.address}',
59 + 'supportSell': "false",
60 + 'supportSwap': "false",
61 + 'primaryColor': primaryColor,
62 + 'secondaryColor': secondaryColor,
63 + 'primaryTextColor': primaryTextColor,
64 + 'secondaryTextColor': secondaryTextColor,
65 + 'containerColor': containerColor,
66 + 'cardColor': cardColor
67 + });
68 + }
69 +}
lib/buy/payfura/payfura_buy_provider.dart new
+24
@@ -0,0 +1,24 @@
1 +import 'package:cake_wallet/.secrets.g.dart' as secrets;
2 +import 'package:cake_wallet/store/settings_store.dart';
3 +import 'package:cw_core/wallet_base.dart';
4 +
5 +class PayfuraBuyProvider {
6 + PayfuraBuyProvider({required SettingsStore settingsStore, required WalletBase wallet})
7 + : this._settingsStore = settingsStore,
8 + this._wallet = wallet;
9 +
10 + final SettingsStore _settingsStore;
11 + final WalletBase _wallet;
12 +
13 + static const _baseUrl = 'exchange.payfura.com';
14 +
15 + Uri requestUrl() {
16 + return Uri.https(_baseUrl, '', <String, dynamic>{
17 + 'apiKey': secrets.payfuraApiKey,
18 + 'to': _wallet.currency.title,
19 + 'from': _settingsStore.fiatCurrency.title,
20 + 'walletAddress': '${_wallet.currency.title}:${_wallet.walletAddresses.address}',
21 + 'mode': 'buy'
22 + });
23 + }
24 +}
lib/di.dart
+93 -41
@@ -1,17 +1,22 @@
1 import 'package:cake_wallet/anonpay/anonpay_api.dart';
2 import 'package:cake_wallet/anonpay/anonpay_info_base.dart';
3 import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
4 +import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
5 +import 'package:cake_wallet/buy/payfura/payfura_buy_provider.dart';
6 import 'package:cake_wallet/core/yat_service.dart';
7 import 'package:cake_wallet/entities/exchange_api_mode.dart';
8 import 'package:cake_wallet/entities/parse_address_from_domain.dart';
9 import 'package:cake_wallet/entities/receive_page_option.dart';
8 -import 'package:cake_wallet/entities/wake_lock.dart';
10 import 'package:cake_wallet/ionia/ionia_anypay.dart';
11 import 'package:cake_wallet/ionia/ionia_gift_card.dart';
12 import 'package:cake_wallet/ionia/ionia_tip.dart';
13 import 'package:cake_wallet/src/screens/anonpay_details/anonpay_details_page.dart';
14 import 'package:cake_wallet/src/screens/buy/onramper_page.dart';
15 import 'package:cake_wallet/src/screens/buy/payfura_page.dart';
16 +import 'package:cake_wallet/src/screens/dashboard/desktop_dashboard_page.dart';
17 +import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar_wrapper.dart';
18 +import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_wallet_selection_dropdown.dart';
19 +import 'package:cake_wallet/src/screens/dashboard/widgets/transactions_page.dart';
20 import 'package:cake_wallet/src/screens/receive/anonpay_invoice_page.dart';
21 import 'package:cake_wallet/src/screens/receive/anonpay_receive_page.dart';
22 import 'package:cake_wallet/src/screens/settings/display_settings_page.dart';
@@ -22,8 +27,11 @@ import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_redeem_page.dar
27 import 'package:cake_wallet/src/screens/ionia/cards/ionia_gift_card_detail_page.dart';
28 import 'package:cake_wallet/src/screens/ionia/cards/ionia_more_options_page.dart';
29 import 'package:cake_wallet/src/screens/settings/connection_sync_page.dart';
30 +import 'package:cake_wallet/themes/theme_list.dart';
31 +import 'package:cake_wallet/utils/device_info.dart';
32 import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart';
33 import 'package:cake_wallet/utils/payment_request.dart';
34 +import 'package:cake_wallet/view_model/dashboard/desktop_sidebar_view_model.dart';
35 import 'package:cake_wallet/view_model/anon_invoice_page_view_model.dart';
36 import 'package:cake_wallet/view_model/anonpay_details_view_model.dart';
37 import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
@@ -143,7 +151,6 @@ import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
151 import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
152 import 'package:cake_wallet/view_model/wallet_seed_view_model.dart';
153 import 'package:cake_wallet/view_model/exchange/exchange_view_model.dart';
146 -import 'package:flutter/foundation.dart';
154 import 'package:flutter/widgets.dart';
155 import 'package:get_it/get_it.dart';
156 import 'package:hive/hive.dart';
@@ -219,12 +226,16 @@ Future setup(
226 () => SharedPreferences.getInstance());
227 }
228
222 - final isBitcoinBuyEnabled = (secrets.wyreSecretKey?.isNotEmpty ?? false) &&
223 - (secrets.wyreApiKey?.isNotEmpty ?? false) &&
224 - (secrets.wyreAccountId?.isNotEmpty ?? false);
229 + final isBitcoinBuyEnabled = (secrets.wyreSecretKey.isNotEmpty ?? false) &&
230 + (secrets.wyreApiKey.isNotEmpty ?? false) &&
231 + (secrets.wyreAccountId.isNotEmpty ?? false);
232
233 final settingsStore = await SettingsStoreBase.load(
227 - nodeSource: _nodeSource, isBitcoinBuyEnabled: isBitcoinBuyEnabled);
234 + nodeSource: _nodeSource,
235 + isBitcoinBuyEnabled: isBitcoinBuyEnabled,
236 + // Enforce darkTheme on platforms other than mobile till the design for other themes is completed
237 + initialTheme: DeviceInfo.instance.isMobile ? null : ThemeList.darkTheme,
238 + );
239
240 if (_isSetupFinished) {
241 return;
@@ -375,42 +386,64 @@ Future setup(
386 .registerFactoryParam<AuthPage, void Function(bool, AuthPageState), bool>(
387 (onAuthFinished, closable) => AuthPage(getIt.get<AuthViewModel>(),
388 onAuthenticationFinished: onAuthFinished,
378 - closable: closable ?? false));
389 + closable: closable));
390
391 getIt.registerFactory(() =>
392 BalancePage(dashboardViewModel: getIt.get<DashboardViewModel>(), settingsStore: getIt.get<SettingsStore>()));
393
383 - getIt.registerFactory<DashboardPage>(() => DashboardPage( balancePage: getIt.get<BalancePage>(), walletViewModel: getIt.get<DashboardViewModel>(), addressListViewModel: getIt.get<WalletAddressListViewModel>()));
384 -
394 + getIt.registerFactory<DashboardPage>(() => DashboardPage(
395 + balancePage: getIt.get<BalancePage>(),
396 + dashboardViewModel: getIt.get<DashboardViewModel>(),
397 + addressListViewModel: getIt.get<WalletAddressListViewModel>(),
398 + ));
399 + getIt.registerFactory<DesktopSidebarWrapper>(() {
400 + final GlobalKey<NavigatorState> _navigatorKey = GlobalKey<NavigatorState>();
401 + return DesktopSidebarWrapper(
402 + dashboardViewModel: getIt.get<DashboardViewModel>(),
403 + desktopSidebarViewModel: getIt.get<DesktopSidebarViewModel>(),
404 + child: getIt.get<DesktopDashboardPage>(param1: _navigatorKey),
405 + desktopNavigatorKey: _navigatorKey,
406 + );
407 + });
408 + getIt.registerFactoryParam<DesktopDashboardPage, GlobalKey<NavigatorState>, void>(
409 + (desktopKey, _) => DesktopDashboardPage(
410 + balancePage: getIt.get<BalancePage>(),
411 + dashboardViewModel: getIt.get<DashboardViewModel>(),
412 + addressListViewModel: getIt.get<WalletAddressListViewModel>(),
413 + desktopKey: desktopKey,
414 + ));
415 +
416 + getIt.registerFactory<TransactionsPage>(() => TransactionsPage(dashboardViewModel: getIt.get<DashboardViewModel>()));
417 +
418 getIt.registerFactoryParam<ReceiveOptionViewModel, ReceivePageOption?, void>((pageOption, _) => ReceiveOptionViewModel(
419 getIt.get<AppStore>().wallet!, pageOption));
420
388 - getIt.registerFactoryParam<AnonInvoicePageViewModel, List<dynamic>, void>((args, _) {
421 + getIt.registerFactoryParam<AnonInvoicePageViewModel, List<dynamic>, void>((args, _) {
422 final address = args.first as String;
423 final pageOption = args.last as ReceivePageOption;
424 return AnonInvoicePageViewModel(
392 - getIt.get<AnonPayApi>(),
393 - address,
394 - getIt.get<SettingsStore>(),
395 - getIt.get<AppStore>().wallet!,
396 - _anonpayInvoiceInfoSource,
425 + getIt.get<AnonPayApi>(),
426 + address,
427 + getIt.get<SettingsStore>(),
428 + getIt.get<AppStore>().wallet!,
429 + _anonpayInvoiceInfoSource,
430 getIt.get<SharedPreferences>(),
431 pageOption,
399 - );
432 + );
433 });
434
402 - getIt.registerFactoryParam<AnonPayInvoicePage, List<dynamic>, void>((List<dynamic> args, _) {
435 + getIt.registerFactoryParam<AnonPayInvoicePage, List<dynamic>, void>((List<dynamic> args, _) {
436 final pageOption = args.last as ReceivePageOption;
437 return AnonPayInvoicePage(
405 - getIt.get<AnonInvoicePageViewModel>(param1: args),
438 + getIt.get<AnonInvoicePageViewModel>(param1: args),
439 getIt.get<ReceiveOptionViewModel>(param1: pageOption));
407 - });
408 -
440 + });
441 +
442 getIt.registerFactory<ReceivePage>(() => ReceivePage(
443 addressListViewModel: getIt.get<WalletAddressListViewModel>()));
444 getIt.registerFactory<AddressPage>(() => AddressPage(
445 addressListViewModel: getIt.get<WalletAddressListViewModel>(),
413 - walletViewModel: getIt.get<DashboardViewModel>(),
446 + dashboardViewModel: getIt.get<DashboardViewModel>(),
447 receiveOptionViewModel: getIt.get<ReceiveOptionViewModel>()));
448
449 getIt.registerFactoryParam<WalletAddressEditOrCreateViewModel, WalletAddressListItem?, void>(
@@ -445,13 +478,25 @@ Future setup(
478 getIt.registerFactory(() => SendTemplatePage(
479 sendTemplateViewModel: getIt.get<SendTemplateViewModel>()));
480
448 - getIt.registerFactory(() => WalletListViewModel(
449 - _walletInfoSource,
450 - getIt.get<AppStore>(),
451 - getIt.get<WalletLoadingService>(),
452 - getIt.get<AuthService>(),
453 - ),
454 - );
481 + if (DeviceInfo.instance.isMobile) {
482 + getIt.registerFactory(() => WalletListViewModel(
483 + _walletInfoSource,
484 + getIt.get<AppStore>(),
485 + getIt.get<WalletLoadingService>(),
486 + getIt.get<AuthService>(),
487 + ),
488 + );
489 + } else {
490 + // register wallet list view model as singleton on desktop since it can be accessed
491 + // from multiple places at the same time (Wallets DropDown, Wallets List in settings)
492 + getIt.registerLazySingleton(() => WalletListViewModel(
493 + _walletInfoSource,
494 + getIt.get<AppStore>(),
495 + getIt.get<WalletLoadingService>(),
496 + getIt.get<AuthService>(),
497 + ),
498 + );
499 + }
500
501 getIt.registerFactory(() =>
502 WalletListPage(walletListViewModel: getIt.get<WalletListViewModel>()));
@@ -523,7 +568,7 @@ Future setup(
568 isNewWalletCreated: isWalletCreated));
569
570 getIt
526 - .registerFactory(() => WalletKeysViewModel(getIt.get<AppStore>().wallet!));
571 + .registerFactory(() => WalletKeysViewModel(getIt.get<AppStore>()));
572
573 getIt.registerFactory(() => WalletKeysPage(getIt.get<WalletKeysViewModel>()));
574
@@ -543,8 +588,7 @@ Future setup(
588
589 getIt.registerFactory(() {
590 final appStore = getIt.get<AppStore>();
546 - return NodeListViewModel(
547 - _nodeSource, appStore.wallet!, appStore.settingsStore);
591 + return NodeListViewModel(_nodeSource, appStore);
592 });
593
594 getIt.registerFactory(() => ConnectionSyncPage(getIt.get<NodeListViewModel>(), getIt.get<DashboardViewModel>()));
@@ -570,13 +614,19 @@ Future setup(
614 editingNode: editingNode,
615 isSelected: isSelected));
616
573 - getIt.registerFactory(() => OnRamperPage(
617 + getIt.registerFactory<OnRamperBuyProvider>(() => OnRamperBuyProvider(
618 settingsStore: getIt.get<AppStore>().settingsStore,
575 - wallet: getIt.get<AppStore>().wallet!));
619 + wallet: getIt.get<AppStore>().wallet!,
620 + ));
621
577 - getIt.registerFactory(() => PayFuraPage(
578 - settingsStore: getIt.get<AppStore>().settingsStore,
579 - wallet: getIt.get<AppStore>().wallet!));
622 + getIt.registerFactory(() => OnRamperPage(getIt.get<OnRamperBuyProvider>()));
623 +
624 + getIt.registerFactory<PayfuraBuyProvider>(() => PayfuraBuyProvider(
625 + settingsStore: getIt.get<AppStore>().settingsStore,
626 + wallet: getIt.get<AppStore>().wallet!,
627 + ));
628 +
629 + getIt.registerFactory(() => PayFuraPage(getIt.get<PayfuraBuyProvider>()));
630
631 getIt.registerFactory(() => ExchangeViewModel(
632 getIt.get<AppStore>().wallet!,
@@ -759,8 +809,6 @@ Future setup(
809 param1: item, param2: unspentCoinsListViewModel));
810 });
811
762 - getIt.registerFactory(() => WakeLock());
763 -
812 getIt.registerFactory(() => YatService());
813
814 getIt.registerFactory(() => AddressResolver(yatService: getIt.get<YatService>(),
@@ -873,11 +921,15 @@ Future setup(
921 getIt.registerFactory(() => IoniaAccountPage(getIt.get<IoniaAccountViewModel>()));
922
923 getIt.registerFactory(() => IoniaAccountCardsPage(getIt.get<IoniaAccountViewModel>()));
876 -
924 +
925 getIt.registerFactory(() => AnonPayApi(useTorOnly: getIt.get<SettingsStore>().exchangeStatus == ExchangeApiMode.torOnly,
878 - wallet: getIt.get<AppStore>().wallet!)
926 + wallet: getIt.get<AppStore>().wallet!)
927 );
928
929 + getIt.registerFactory(() => DesktopWalletSelectionDropDown(getIt.get<WalletListViewModel>()));
930 +
931 + getIt.registerFactory(() => DesktopSidebarViewModel());
932 +
933 getIt.registerFactoryParam<AnonpayDetailsViewModel, AnonpayInvoiceInfo, void>(
934 (AnonpayInvoiceInfo anonpayInvoiceInfo, _)
935 => AnonpayDetailsViewModel(
@@ -890,7 +942,7 @@ Future setup(
942 (AnonpayInfoBase anonpayInvoiceInfo, _) => AnonPayReceivePage(invoiceInfo: anonpayInvoiceInfo));
943
944 getIt.registerFactoryParam<AnonpayDetailsPage, AnonpayInvoiceInfo, void>(
893 - (AnonpayInvoiceInfo anonpayInvoiceInfo, _)
945 + (AnonpayInvoiceInfo anonpayInvoiceInfo, _)
946 => AnonpayDetailsPage(anonpayDetailsViewModel: getIt.get<AnonpayDetailsViewModel>(param1: anonpayInvoiceInfo)));
947
948 getIt.registerFactoryParam<IoniaPaymentStatusViewModel, IoniaAnyPayPaymentInfo, AnyPayPaymentCommittedInfo>(
lib/entities/desktop_dropdown_item.dart new
+9
@@ -0,0 +1,9 @@
1 +import 'package:flutter/material.dart';
2 +
3 +class DesktopDropdownItem {
4 + final Function() onSelected;
5 + final Widget child;
6 + final bool isSelected;
7 +
8 + DesktopDropdownItem({required this.onSelected, required this.child, this.isSelected = false});
9 +}
lib/entities/main_actions.dart new
+142
@@ -0,0 +1,142 @@
1 +import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
2 +import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
3 +import 'package:cake_wallet/buy/payfura/payfura_buy_provider.dart';
4 +import 'package:cake_wallet/di.dart';
5 +import 'package:cake_wallet/generated/i18n.dart';
6 +import 'package:cake_wallet/routes.dart';
7 +import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
8 +import 'package:cake_wallet/utils/device_info.dart';
9 +import 'package:cake_wallet/utils/show_pop_up.dart';
10 +import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
11 +import 'package:cw_core/wallet_type.dart';
12 +import 'package:flutter/material.dart';
13 +import 'package:url_launcher/url_launcher.dart';
14 +
15 +class MainActions {
16 + final String Function(BuildContext context) name;
17 + final String image;
18 +
19 + final bool Function(DashboardViewModel viewModel)? isEnabled;
20 + final bool Function(DashboardViewModel viewModel)? canShow;
21 + final Future<void> Function(BuildContext context, DashboardViewModel viewModel) onTap;
22 +
23 + MainActions._({
24 + required this.name,
25 + required this.image,
26 + this.isEnabled,
27 + this.canShow,
28 + required this.onTap,
29 + });
30 +
31 + static List<MainActions> all = [
32 + buyAction,
33 + receiveAction,
34 + exchangeAction,
35 + sendAction,
36 + sellAction,
37 + ];
38 +
39 + static MainActions buyAction = MainActions._(
40 + name: (context) => S.of(context).buy,
41 + image: 'assets/images/buy.png',
42 + isEnabled: (viewModel) => viewModel.isEnabledBuyAction,
43 + canShow: (viewModel) => viewModel.hasBuyAction,
44 + onTap: (BuildContext context, DashboardViewModel viewModel) async {
45 + final walletType = viewModel.type;
46 +
47 + switch (walletType) {
48 + case WalletType.bitcoin:
49 + case WalletType.litecoin:
50 + if (DeviceInfo.instance.isMobile) {
51 + Navigator.of(context).pushNamed(Routes.onramperPage);
52 + } else {
53 + final uri = getIt
54 + .get<OnRamperBuyProvider>()
55 + .requestUrl();
56 + await launchUrl(uri);
57 + }
58 + break;
59 + case WalletType.monero:
60 + if (DeviceInfo.instance.isMobile) {
61 + Navigator.of(context).pushNamed(Routes.payfuraPage);
62 + } else {
63 + final uri = getIt
64 + .get<PayfuraBuyProvider>()
65 + .requestUrl();
66 + await launchUrl(uri);
67 + }
68 + break;
69 + default:
70 + await showPopUp<void>(
71 + context: context,
72 + builder: (BuildContext context) {
73 + return AlertWithOneAction(
74 + alertTitle: S.of(context).buy,
75 + alertContent: S.of(context).buy_alert_content,
76 + buttonText: S.of(context).ok,
77 + buttonAction: () => Navigator.of(context).pop());
78 + });
79 + }
80 + },
81 + );
82 +
83 + static MainActions receiveAction = MainActions._(
84 + name: (context) => S.of(context).receive,
85 + image: 'assets/images/received.png',
86 + onTap: (BuildContext context, DashboardViewModel viewModel) async {
87 + Navigator.pushNamed(context, Routes.addressPage);
88 + },
89 + );
90 +
91 + static MainActions exchangeAction = MainActions._(
92 + name: (context) => S.of(context).exchange,
93 + image: 'assets/images/transfer.png',
94 + isEnabled: (viewModel) => viewModel.isEnabledExchangeAction,
95 + canShow: (viewModel) => viewModel.hasExchangeAction,
96 + onTap: (BuildContext context, DashboardViewModel viewModel) async {
97 + if (viewModel.isEnabledExchangeAction) {
98 + await Navigator.of(context).pushNamed(Routes.exchange);
99 + }
100 + },
101 + );
102 +
103 + static MainActions sendAction = MainActions._(
104 + name: (context) => S.of(context).send,
105 + image: 'assets/images/upload.png',
106 + onTap: (BuildContext context, DashboardViewModel viewModel) async {
107 + Navigator.pushNamed(context, Routes.send);
108 + },
109 + );
110 +
111 + static MainActions sellAction = MainActions._(
112 + name: (context) => S.of(context).sell,
113 + image: 'assets/images/sell.png',
114 + isEnabled: (viewModel) => viewModel.isEnabledSellAction,
115 + canShow: (viewModel) => viewModel.hasSellAction,
116 + onTap: (BuildContext context, DashboardViewModel viewModel) async {
117 + final walletType = viewModel.type;
118 +
119 + switch (walletType) {
120 + case WalletType.bitcoin:
121 + final moonPaySellProvider = MoonPaySellProvider();
122 + final uri = await moonPaySellProvider.requestUrl(
123 + currency: viewModel.wallet.currency,
124 + refundWalletAddress: viewModel.wallet.walletAddresses.address,
125 + );
126 + await launchUrl(uri);
127 + break;
128 + default:
129 + await showPopUp<void>(
130 + context: context,
131 + builder: (BuildContext context) {
132 + return AlertWithOneAction(
133 + alertTitle: S.of(context).sell,
134 + alertContent: S.of(context).sell_alert_content,
135 + buttonText: S.of(context).ok,
136 + buttonAction: () => Navigator.of(context).pop());
137 + },
138 + );
139 + }
140 + },
141 + );
142 +}
lib/entities/unstoppable_domain_address.dart
+13 -7
@@ -1,3 +1,4 @@
1 +import 'package:cake_wallet/utils/device_info.dart';
2 import 'package:flutter/services.dart';
3
4 const channel = MethodChannel('com.cake_wallet/native_utils');
@@ -6,13 +7,18 @@ Future<String> fetchUnstoppableDomainAddress(String domain, String ticker) async
7 var address = '';
8
9 try {
9 - address = await channel.invokeMethod<String>(
10 - 'getUnstoppableDomainAddress',
11 - <String, String> {
12 - 'domain' : domain,
13 - 'ticker' : ticker
14 - }
15 - ) ?? '';
10 + if (DeviceInfo.instance.isMobile) {
11 + address = await channel.invokeMethod<String>(
12 + 'getUnstoppableDomainAddress',
13 + <String, String> {
14 + 'domain' : domain,
15 + 'ticker' : ticker
16 + }
17 + ) ?? '';
18 + } else {
19 + // TODO: Integrate with Unstoppable domains resolution API
20 + return address;
21 + }
22 } catch (e) {
23 print('Unstoppable domain error: ${e.toString()}');
24 address = '';
lib/entities/wake_lock.dart deleted
-21
@@ -1,21 +0,0 @@
1 -import 'package:flutter/services.dart';
2 -
3 -class WakeLock {
4 - static const _utils = const MethodChannel('com.cake_wallet/native_utils');
5 -
6 - Future<void> enableWake() async {
7 - try {
8 - await _utils.invokeMethod<bool>('enableWakeScreen');
9 - } on PlatformException catch (_) {
10 - print('Failed enabling screen wakelock');
11 - }
12 - }
13 -
14 - Future<void> disableWake() async {
15 - try {
16 - await _utils.invokeMethod<bool>('disableWakeScreen');
17 - } on PlatformException catch (_) {
18 - print('Failed enabling screen wakelock');
19 - }
20 - }
21 -}
lib/exchange/changenow/changenow_exchange_provider.dart
+2 -1
@@ -1,5 +1,6 @@
1 import 'dart:convert';
2 import 'package:cake_wallet/exchange/trade_not_found_exeption.dart';
3 +import 'package:cake_wallet/utils/device_info.dart';
4 import 'package:http/http.dart';
5 import 'package:cake_wallet/.secrets.g.dart' as secrets;
6 import 'package:cw_core/crypto_currency.dart';
@@ -24,7 +25,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
25 .expand((i) => i)
26 .toList());
27
27 - static const apiKey = secrets.changeNowApiKey;
28 + static final apiKey = DeviceInfo.instance.isMobile ? secrets.changeNowApiKey : secrets.changeNowApiKeyDesktop;
29 static const apiAuthority = 'api.changenow.io';
30 static const createTradePath = '/v2/exchange';
31 static const findTradeByIdPath = '/v2/exchange/by-id';
lib/exchange/simpleswap/simpleswap_exchange_provider.dart
+2 -1
@@ -6,6 +6,7 @@ import 'package:cake_wallet/exchange/simpleswap/simpleswap_request.dart';
6 import 'package:cake_wallet/exchange/trade_not_created_exeption.dart';
7 import 'package:cake_wallet/exchange/trade_not_found_exeption.dart';
8 import 'package:cake_wallet/exchange/trade_state.dart';
9 +import 'package:cake_wallet/utils/device_info.dart';
10 import 'package:cw_core/crypto_currency.dart';
11 import 'package:cake_wallet/exchange/trade_request.dart';
12 import 'package:cake_wallet/exchange/trade.dart';
@@ -29,7 +30,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
30 static const rangePath = '/v1/get_ranges';
31 static const getExchangePath = '/v1/get_exchange';
32 static const createExchangePath = '/v1/create_exchange';
32 - static const apiKey = secrets.simpleSwapApiKey;
33 + static final apiKey = DeviceInfo.instance.isMobile ? secrets.simpleSwapApiKey : secrets.simpleSwapApiKeyDesktop;
34
35 @override
36 ExchangeProviderDescription get description =>
lib/reactions/on_authentication_state_change.dart
+2 -2
@@ -9,8 +9,8 @@ ReactionDisposer? _onAuthenticationStateChange;
9
10 dynamic loginError;
11
12 -void startAuthenticationStateChange(AuthenticationStore authenticationStore,
13 - GlobalKey<NavigatorState> navigatorKey) {
12 +void startAuthenticationStateChange(
13 + AuthenticationStore authenticationStore, GlobalKey<NavigatorState> navigatorKey) {
14 _onAuthenticationStateChange ??= autorun((_) async {
15 final state = authenticationStore.state;
16
lib/reactions/on_wallet_sync_status_change.dart
+3 -6
@@ -1,6 +1,4 @@
1 -import 'package:cake_wallet/di.dart';
1 import 'package:cake_wallet/entities/update_haven_rate.dart';
3 -import 'package:cake_wallet/entities/wake_lock.dart';
2 import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
3 import 'package:cw_core/wallet_type.dart';
4 import 'package:mobx/mobx.dart';
@@ -9,7 +7,7 @@ import 'package:cw_core/wallet_base.dart';
7 import 'package:cw_core/balance.dart';
8 import 'package:cw_core/transaction_info.dart';
9 import 'package:cw_core/sync_status.dart';
12 -import 'package:flutter/services.dart';
10 +import 'package:wakelock/wakelock.dart';
11
12 ReactionDisposer? _onWalletSyncStatusChangeReaction;
13
@@ -17,7 +15,6 @@ void startWalletSyncStatusChangeReaction(
15 WalletBase<Balance, TransactionHistoryBase<TransactionInfo>,
16 TransactionInfo> wallet,
17 FiatConversionStore fiatConversionStore) {
20 - final _wakeLock = getIt.get<WakeLock>();
18 _onWalletSyncStatusChangeReaction?.reaction.dispose();
19 _onWalletSyncStatusChangeReaction =
20 reaction((_) => wallet.syncStatus, (SyncStatus status) async {
@@ -30,10 +27,10 @@ void startWalletSyncStatusChangeReaction(
27 }
28 }
29 if (status is SyncingSyncStatus) {
33 - await _wakeLock.enableWake();
30 + await Wakelock.enable();
31 }
32 if (status is SyncedSyncStatus || status is FailedSyncStatus) {
36 - await _wakeLock.disableWake();
33 + await Wakelock.disable();
34 }
35 } catch(e) {
36 print(e.toString());
lib/router.dart
+42 -8
@@ -11,6 +11,9 @@ import 'package:cake_wallet/src/screens/buy/payfura_page.dart';
11 import 'package:cake_wallet/src/screens/buy/pre_order_page.dart';
12 import 'package:cake_wallet/src/screens/receive/anonpay_invoice_page.dart';
13 import 'package:cake_wallet/src/screens/receive/anonpay_receive_page.dart';
14 +import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_dashboard_actions.dart';
15 +import 'package:cake_wallet/src/screens/dashboard/widgets/transactions_page.dart';
16 +import 'package:cake_wallet/src/screens/settings/desktop_settings/desktop_settings_page.dart';
17 import 'package:cake_wallet/src/screens/settings/display_settings_page.dart';
18 import 'package:cake_wallet/src/screens/settings/other_settings_page.dart';
19 import 'package:cake_wallet/src/screens/settings/privacy_page.dart';
@@ -32,6 +35,7 @@ import 'package:cake_wallet/src/screens/support/support_page.dart';
35 import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart';
36 import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart';
37 import 'package:cake_wallet/utils/payment_request.dart';
38 +import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
39 import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
40 import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
41 import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
@@ -295,22 +299,27 @@ Route<dynamic> createRoute(RouteSettings settings) {
299
300 case Routes.connectionSync:
301 return CupertinoPageRoute<void>(
302 + fullscreenDialog: true,
303 builder: (_) => getIt.get<ConnectionSyncPage>());
304
305 case Routes.securityBackupPage:
306 return CupertinoPageRoute<void>(
307 + fullscreenDialog: true,
308 builder: (_) => getIt.get<SecurityBackupPage>());
309
310 case Routes.privacyPage:
311 return CupertinoPageRoute<void>(
312 + fullscreenDialog: true,
313 builder: (_) => getIt.get<PrivacyPage>());
314
315 case Routes.displaySettingsPage:
316 return CupertinoPageRoute<void>(
317 + fullscreenDialog: true,
318 builder: (_) => getIt.get<DisplaySettingsPage>());
319
320 case Routes.otherSettingsPage:
321 return CupertinoPageRoute<void>(
322 + fullscreenDialog: true,
323 builder: (_) => getIt.get<OtherSettingsPage>());
324
325 case Routes.newNode:
@@ -336,8 +345,8 @@ Route<dynamic> createRoute(RouteSettings settings) {
345
346 case Routes.addressBook:
347 return MaterialPageRoute<void>(
339 - builder: (_) =>
340 - getIt.get<ContactListPage>());
348 + fullscreenDialog: true,
349 + builder: (_) => getIt.get<ContactListPage>());
350
351 case Routes.pickerAddressBook:
352 final selectedCurrency = settings.arguments as CryptoCurrency?;
@@ -394,6 +403,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
403
404 case Routes.exchange:
405 return CupertinoPageRoute<void>(
406 + fullscreenDialog: true,
407 builder: (_) => getIt.get<ExchangePage>());
408
409 case Routes.exchangeTemplate:
@@ -425,6 +435,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
435
436 case Routes.support:
437 return CupertinoPageRoute<void>(
438 + fullscreenDialog: true,
439 builder: (_) => getIt.get<SupportPage>());
440
441 case Routes.unspentCoinsList:
@@ -447,11 +458,14 @@ Route<dynamic> createRoute(RouteSettings settings) {
458 getIt.get<FullscreenQRPage>(
459 param1: args['qrData'] as String,
460 param2: args['version'] as int?,
450 -
461 +
462 ));
463
464 case Routes.ioniaWelcomePage:
454 - return CupertinoPageRoute<void>(builder: (_) => getIt.get<IoniaWelcomePage>());
465 + return CupertinoPageRoute<void>(
466 + fullscreenDialog: true,
467 + builder: (_) => getIt.get<IoniaWelcomePage>(),
468 + );
469
470 case Routes.ioniaLoginPage:
471 return CupertinoPageRoute<void>( builder: (_) => getIt.get<IoniaLoginPage>());
@@ -524,19 +538,39 @@ Route<dynamic> createRoute(RouteSettings settings) {
538 getIt.get<AdvancedPrivacySettingsViewModel>(param1: type),
539 getIt.get<NodeCreateOrEditViewModel>(param1: type),
540 ));
527 -
541 +
542 case Routes.anonPayInvoicePage:
543 final args = settings.arguments as List;
544 return CupertinoPageRoute<void>(builder: (_) => getIt.get<AnonPayInvoicePage>(param1: args));
531 -
545 +
546 case Routes.anonPayReceivePage:
547 final anonInvoiceViewData = settings.arguments as AnonpayInfoBase;
548 return CupertinoPageRoute<void>(builder: (_) => getIt.get<AnonPayReceivePage>(param1: anonInvoiceViewData));
535 -
549 +
550 case Routes.anonPayDetailsPage:
551 final anonInvoiceViewData = settings.arguments as AnonpayInvoiceInfo;
552 return CupertinoPageRoute<void>(builder: (_) => getIt.get<AnonpayDetailsPage>(param1: anonInvoiceViewData));
539 -
553 +
554 + case Routes.desktop_actions:
555 + return PageRouteBuilder(
556 + opaque: false,
557 + pageBuilder: (_, __, ___) => DesktopDashboardActions(getIt<DashboardViewModel>()),
558 + );
559 +
560 + case Routes.desktop_settings_page:
561 + return CupertinoPageRoute<void>(
562 + builder: (_) => DesktopSettingsPage());
563 +
564 + case Routes.empty_no_route:
565 + return MaterialPageRoute<void>(
566 + builder: (_) => SizedBox.shrink());
567 +
568 + case Routes.transactionsPage:
569 + return CupertinoPageRoute<void>(
570 + settings: settings,
571 + fullscreenDialog: true,
572 + builder: (_) => getIt.get<TransactionsPage>());
573 +
574 default:
575 return MaterialPageRoute<void>(
576 builder: (_) => Scaffold(
lib/routes.dart
+4
@@ -37,6 +37,8 @@ class Routes {
37 static const restoreWalletFromSeedDetails = '/restore_from_seed_details';
38 static const exchange = '/exchange';
39 static const settings = '/settings';
40 + static const desktop_settings_page = '/desktop_settings_page';
41 + static const empty_no_route = '/empty_no_route';
42 static const unlock = '/auth_not_closable';
43 static const rescan = '/rescan';
44 static const faq = '/faq';
@@ -86,4 +88,6 @@ class Routes {
88 static const anonPayReceivePage = '/anon_pay_receive_page';
89 static const anonPayDetailsPage = '/anon_pay_details_page';
90 static const payfuraPage = '/pay_fura_page';
91 + static const desktop_actions = '/desktop_actions';
92 + static const transactionsPage = '/transactions_page';
93 }
lib/src/screens/backup/backup_page.dart
+25 -8
@@ -1,6 +1,8 @@
1 import 'dart:io';
2 import 'package:cake_wallet/palette.dart';
3 +import 'package:cake_wallet/utils/exception_handler.dart';
4 import 'package:cake_wallet/utils/share_util.dart';
5 +import 'package:file_picker/file_picker.dart';
6 import 'package:flutter/material.dart';
7 import 'package:flutter/services.dart';
8 import 'package:flutter_mobx/flutter_mobx.dart';
@@ -27,8 +29,7 @@ class BackupPage extends BasePage {
29 @override
30 Widget trailing(BuildContext context) => TrailButton(
31 caption: S.of(context).change_password,
30 - onPressed: () =>
31 - Navigator.of(context).pushNamed(Routes.editBackupPassword),
32 + onPressed: () => Navigator.of(context).pushNamed(Routes.editBackupPassword),
33 textColor: Palette.blueCraiola);
34
35 @override
@@ -51,9 +52,8 @@ class BackupPage extends BasePage {
52 child: Observer(
53 builder: (_) => GestureDetector(
54 onTap: () {
54 - Clipboard.setData(ClipboardData(
55 - text:
56 - backupViewModelBase.backupPassword));
55 + Clipboard.setData(
56 + ClipboardData(text: backupViewModelBase.backupPassword));
57 showBar<void>(
58 context,
59 S.of(context).transaction_details_copied(
@@ -108,8 +108,10 @@ class BackupPage extends BasePage {
108
109 if (Platform.isAndroid) {
110 onExportAndroid(context, backup);
111 - } else {
111 + } else if (Platform.isIOS) {
112 await share(backup, context);
113 + } else {
114 + await _saveFile(backup);
115 }
116 },
117 actionLeftButton: () => Navigator.of(dialogContext).pop());
@@ -133,8 +135,7 @@ class BackupPage extends BasePage {
135 return;
136 }
137
136 - await backupViewModelBase.saveToDownload(
137 - backup.name, backup.content);
138 + await backupViewModelBase.saveToDownload(backup.name, backup.content);
139 Navigator.of(dialogContext).pop();
140 },
141 actionLeftButton: () async {
@@ -149,4 +150,20 @@ class BackupPage extends BasePage {
150 await ShareUtil.shareFile(filePath: path, fileName: backup.name, context: context);
151 await backupViewModelBase.removeBackupFileLocally(backup);
152 }
153 +
154 + Future<void> _saveFile(BackupExportFile backup) async {
155 + String? outputFile = await FilePicker.platform
156 + .saveFile(dialogTitle: 'Save Your File to desired location', fileName: backup.name);
157 +
158 + try {
159 + File returnedFile = File(outputFile!);
160 + await returnedFile.writeAsBytes(backup.content);
161 + } catch (exception, stackTrace) {
162 + ExceptionHandler.onError(FlutterErrorDetails(
163 + exception: exception,
164 + stack: stackTrace,
165 + library: "Export Backup",
166 + ));
167 + }
168 + }
169 }
lib/src/screens/backup/edit_backup_password_page.dart
+2 -1
@@ -66,7 +66,8 @@ class EditBackupPasswordPage extends BasePage {
66 leftButtonText: S.of(context).cancel,
67 actionRightButton: () async {
68 await editBackupPasswordViewModel.save();
69 - Navigator.of(dialogContext)..pop()..pop();
69 + Navigator.of(dialogContext).pop();
70 + Navigator.of(context).pop();
71 },
72 actionLeftButton: () => Navigator.of(dialogContext).pop());
73 });
lib/src/screens/base_page.dart
+15 -10
@@ -1,4 +1,5 @@
1 import 'package:cake_wallet/themes/theme_base.dart';
2 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
3 import 'package:flutter/cupertino.dart';
4 import 'package:flutter/material.dart';
5 import 'package:cake_wallet/palette.dart';
@@ -20,7 +21,7 @@ abstract class BasePage extends StatelessWidget {
21
22 String? get title => null;
23
23 - bool get isModalBackButton => false;
24 + bool get canUseCloseIcon => false;
25
26 Color get backgroundLightColor => Colors.white;
27
@@ -50,23 +51,27 @@ abstract class BasePage extends StatelessWidget {
51 }
52
53 final _backButton = Icon(Icons.arrow_back_ios,
53 - color: titleColor ?? Theme.of(context).primaryTextTheme!.headline6!.color!,
54 + color: titleColor ?? Theme.of(context).primaryTextTheme.headline6!.color!,
55 size: 16,);
56 final _closeButton = currentTheme.type == ThemeType.dark
57 ? closeButtonImageDarkTheme : closeButtonImage;
58
59 + bool isMobileView = ResponsiveLayoutUtil.instance.isMobile(context);
60 +
61 return SizedBox(
59 - height: 37,
60 - width: 37,
62 + height: isMobileView ? 37 : 45,
63 + width: isMobileView ? 37 : 45,
64 child: ButtonTheme(
65 minWidth: double.minPositive,
66 child: TextButton(
64 - // FIX-ME: Style
65 - //highlightColor: Colors.transparent,
66 - //splashColor: Colors.transparent,
67 - //padding: EdgeInsets.all(0),
67 + style: ButtonStyle(
68 + overlayColor: MaterialStateColor.resolveWith((states) => Colors.transparent),
69 + ),
70 onPressed: () => onClose(context),
69 - child: isModalBackButton ? _closeButton : _backButton),
71 + child: canUseCloseIcon && !isMobileView
72 + ? _closeButton
73 + : _backButton,
74 + ),
75 ),
76 );
77 }
@@ -92,7 +97,7 @@ abstract class BasePage extends StatelessWidget {
97 ObstructingPreferredSizeWidget appBar(BuildContext context) {
98 final appBarColor = currentTheme.type == ThemeType.dark
99 ? backgroundDarkColor : backgroundLightColor;
95 -
100 +
101 switch (appBarStyle) {
102 case AppBarStyle.regular:
103 // FIX-ME: NavBar no context
lib/src/screens/buy/onramper_page.dart
+7 -37
@@ -1,60 +1,30 @@
1 +import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
2 import 'package:cake_wallet/generated/i18n.dart';
3 import 'package:cake_wallet/src/screens/base_page.dart';
3 -import 'package:cake_wallet/store/settings_store.dart';
4 -import 'package:cw_core/wallet_base.dart';
4 import 'package:flutter/material.dart';
6 -import 'package:cake_wallet/.secrets.g.dart' as secrets;
5 import 'package:flutter_inappwebview/flutter_inappwebview.dart';
6 import 'package:permission_handler/permission_handler.dart';
7
8 class OnRamperPage extends BasePage {
11 - OnRamperPage({required this.settingsStore, required this.wallet});
9 + OnRamperPage(this._onRamperBuyProvider);
10
13 - final SettingsStore settingsStore;
14 - final WalletBase wallet;
11 + final OnRamperBuyProvider _onRamperBuyProvider;
12
13 @override
14 String get title => S.current.buy;
15
16 @override
17 Widget body(BuildContext context) {
21 - final darkMode = Theme.of(context).brightness == Brightness.dark;
22 - return OnRamperPageBody(
23 - settingsStore: settingsStore,
24 - wallet: wallet,
25 - darkMode: darkMode,
26 - backgroundColor: darkMode ? backgroundDarkColor : backgroundLightColor,
27 - supportSell: false,
28 - supportSwap: false);
18 + return OnRamperPageBody(_onRamperBuyProvider);
19 }
20 }
21
22 class OnRamperPageBody extends StatefulWidget {
33 - OnRamperPageBody(
34 - {required this.settingsStore,
35 - required this.wallet,
36 - required this.darkMode,
37 - required this.supportSell,
38 - required this.supportSwap,
39 - required this.backgroundColor});
23 + OnRamperPageBody(this.onRamperBuyProvider);
24
41 - static const baseUrl = 'widget.onramper.com';
42 - final SettingsStore settingsStore;
43 - final WalletBase wallet;
44 - final Color backgroundColor;
45 - final bool darkMode;
46 - final bool supportSell;
47 - final bool supportSwap;
25 + final OnRamperBuyProvider onRamperBuyProvider;
26
49 - Uri get uri => Uri.https(baseUrl, '', <String, dynamic>{
50 - 'apiKey': secrets.onramperApiKey,
51 - 'defaultCrypto': wallet.currency.title,
52 - 'defaultFiat': settingsStore.fiatCurrency.title,
53 - 'wallets': '${wallet.currency.title}:${wallet.walletAddresses.address}',
54 - 'darkMode': darkMode.toString(),
55 - 'supportSell': supportSell.toString(),
56 - 'supportSwap': supportSwap.toString()
57 - });
27 + Uri get uri => onRamperBuyProvider.requestUrl();
28
29 @override
30 OnRamperPageBodyState createState() => OnRamperPageBodyState();
lib/src/screens/buy/payfura_page.dart
+7 -22
@@ -1,45 +1,30 @@
1 +import 'package:cake_wallet/buy/payfura/payfura_buy_provider.dart';
2 import 'package:cake_wallet/generated/i18n.dart';
3 import 'package:cake_wallet/src/screens/base_page.dart';
3 -import 'package:cake_wallet/store/settings_store.dart';
4 -import 'package:cw_core/wallet_base.dart';
4 import 'package:flutter/material.dart';
6 -import 'package:cake_wallet/.secrets.g.dart' as secrets;
5 import 'package:flutter_inappwebview/flutter_inappwebview.dart';
6 import 'package:permission_handler/permission_handler.dart';
7
8 class PayFuraPage extends BasePage {
11 - PayFuraPage({required this.settingsStore, required this.wallet});
9 + PayFuraPage(this._PayfuraBuyProvider);
10
13 - final SettingsStore settingsStore;
14 - final WalletBase wallet;
11 + final PayfuraBuyProvider _PayfuraBuyProvider;
12
13 @override
14 String get title => S.current.buy;
15
16 @override
17 Widget body(BuildContext context) {
21 - return PayFuraPageBody(
22 - settingsStore: settingsStore,
23 - wallet: wallet);
18 + return PayFuraPageBody(_PayfuraBuyProvider);
19 }
20 }
21
22 class PayFuraPageBody extends StatefulWidget {
28 - PayFuraPageBody(
29 - {required this.settingsStore,
30 - required this.wallet});
23 + PayFuraPageBody(this._PayfuraBuyProvider);
24
32 - static const baseUrl = 'exchange.payfura.com';
33 - final SettingsStore settingsStore;
34 - final WalletBase wallet;
25 + final PayfuraBuyProvider _PayfuraBuyProvider;
26
36 - Uri get uri => Uri.https(baseUrl, '', <String, dynamic>{
37 - 'apiKey': secrets.payfuraApiKey,
38 - 'to': wallet.currency.title,
39 - 'from': settingsStore.fiatCurrency.title,
40 - 'walletAddress': '${wallet.currency.title}:${wallet.walletAddresses.address}',
41 - 'mode': 'buy'
42 - });
27 + Uri get uri => _PayfuraBuyProvider.requestUrl();
28
29 @override
30 PayFuraPageBodyState createState() => PayFuraPageBodyState();
lib/src/screens/contact/contact_list_page.dart
-4
@@ -24,10 +24,6 @@ class ContactListPage extends BasePage {
24
25 @override
26 Widget? trailing(BuildContext context) {
27 - if (!contactListViewModel.isEditable) {
28 - return null;
29 - }
30 -
27 return Container(
28 width: 32.0,
29 height: 32.0,
lib/src/screens/dashboard/dashboard_page.dart
+118 -194
@@ -1,12 +1,15 @@
1 import 'dart:async';
2 +import 'package:cake_wallet/di.dart';
3 +import 'package:cake_wallet/entities/main_actions.dart';
4 +import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar_wrapper.dart';
5 import 'package:cake_wallet/src/screens/dashboard/widgets/market_place_page.dart';
6 import 'package:cake_wallet/wallet_type_utils.dart';
4 -import 'package:cw_core/wallet_type.dart';
7 import 'package:cake_wallet/generated/i18n.dart';
8 import 'package:cake_wallet/routes.dart';
9 import 'package:cake_wallet/src/screens/yat_emoji_id.dart';
10 import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
11 import 'package:cake_wallet/themes/theme_base.dart';
12 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
13 import 'package:cake_wallet/utils/show_pop_up.dart';
14 import 'package:flutter/material.dart';
15 import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
@@ -21,17 +24,41 @@ import 'package:flutter_mobx/flutter_mobx.dart';
24 import 'package:mobx/mobx.dart';
25 import 'package:smooth_page_indicator/smooth_page_indicator.dart';
26 import 'package:cake_wallet/main.dart';
24 -import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
25 -import 'package:url_launcher/url_launcher.dart';
27
27 -class DashboardPage extends BasePage {
28 +class DashboardPage extends StatelessWidget {
29 DashboardPage({
30 required this.balancePage,
30 - required this.walletViewModel,
31 + required this.dashboardViewModel,
32 required this.addressListViewModel,
33 });
34 +
35 final BalancePage balancePage;
34 -
36 + final DashboardViewModel dashboardViewModel;
37 + final WalletAddressListViewModel addressListViewModel;
38 +
39 + @override
40 + Widget build(BuildContext context) {
41 + return Scaffold(
42 + body: ResponsiveLayoutUtil.instance.isMobile(context)
43 + ? _DashboardPageView(
44 + balancePage: balancePage,
45 + dashboardViewModel: dashboardViewModel,
46 + addressListViewModel: addressListViewModel,
47 + )
48 + : getIt.get<DesktopSidebarWrapper>(),
49 + );
50 + }
51 +}
52 +
53 +class _DashboardPageView extends BasePage {
54 + _DashboardPageView({
55 + required this.balancePage,
56 + required this.dashboardViewModel,
57 + required this.addressListViewModel,
58 + });
59 +
60 + final BalancePage balancePage;
61 +
62 @override
63 Color get backgroundLightColor =>
64 currentTheme.type == ThemeType.bright ? Colors.transparent : Colors.white;
@@ -54,19 +81,19 @@ class DashboardPage extends BasePage {
81 bool get resizeToAvoidBottomInset => false;
82
83 @override
57 - Widget get endDrawer => MenuWidget(walletViewModel);
84 + Widget get endDrawer => MenuWidget(dashboardViewModel);
85
86 @override
87 Widget middle(BuildContext context) {
61 - return SyncIndicator(dashboardViewModel: walletViewModel,
62 - onTap: () => Navigator.of(context, rootNavigator: true)
63 - .pushNamed(Routes.connectionSync));
88 + return SyncIndicator(
89 + dashboardViewModel: dashboardViewModel,
90 + onTap: () => Navigator.of(context, rootNavigator: true).pushNamed(Routes.connectionSync));
91 }
92
93 @override
94 Widget trailing(BuildContext context) {
95 final menuButton = Image.asset('assets/images/menu.png',
69 - color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!);
96 + color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!);
97
98 return Container(
99 alignment: Alignment.centerRight,
@@ -80,7 +107,7 @@ class DashboardPage extends BasePage {
107 child: menuButton));
108 }
109
83 - final DashboardViewModel walletViewModel;
110 + final DashboardViewModel dashboardViewModel;
111 final WalletAddressListViewModel addressListViewModel;
112 final controller = PageController(initialPage: 1);
113
@@ -90,141 +117,97 @@ class DashboardPage extends BasePage {
117
118 @override
119 Widget body(BuildContext context) {
93 - final sendImage = Image.asset('assets/images/upload.png',
94 - height: 24,
95 - width: 24,
96 - color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!);
97 - final receiveImage = Image.asset('assets/images/received.png',
98 - height: 24,
99 - width: 24,
100 - color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!);
120 _setEffects(context);
121
122 return SafeArea(
104 - minimum: EdgeInsets.only(bottom: 24),
123 + minimum: EdgeInsets.only(bottom: 24),
124 child: Column(
106 - mainAxisSize: MainAxisSize.max,
107 - children: <Widget>[
108 - Expanded(
109 - child: PageView.builder(
110 - controller: controller,
111 - itemCount: pages.length,
112 - itemBuilder: (context, index) => pages[index])),
113 - Padding(
114 - padding: EdgeInsets.only(bottom: 24, top: 10),
115 - child: SmoothPageIndicator(
116 - controller: controller,
117 - count: pages.length,
118 - effect: ColorTransitionEffect(
119 - spacing: 6.0,
120 - radius: 6.0,
121 - dotWidth: 6.0,
122 - dotHeight: 6.0,
123 - dotColor: Theme.of(context).indicatorColor,
124 - activeDotColor: Theme.of(context)
125 - .accentTextTheme!
126 - .headline4!
127 - .backgroundColor!),
128 - )),
129 - Observer(builder: (_) {
130 - return ClipRect(
131 - child:Container(
132 - margin: const EdgeInsets.only(left: 16, right: 16),
133 - child: Container(
134 - decoration: BoxDecoration(
135 - borderRadius: BorderRadius.circular(50.0),
136 - border: Border.all(color: currentTheme.type == ThemeType.bright ? Color.fromRGBO(255, 255, 255, 0.2): Colors.transparent, width: 1, ),
137 - color:Theme.of(context).textTheme!.headline6!.backgroundColor!),
125 + mainAxisSize: MainAxisSize.max,
126 + children: <Widget>[
127 + Expanded(
128 + child: PageView.builder(
129 + controller: controller,
130 + itemCount: pages.length,
131 + itemBuilder: (context, index) => pages[index])),
132 + Padding(
133 + padding: EdgeInsets.only(bottom: 24, top: 10),
134 + child: SmoothPageIndicator(
135 + controller: controller,
136 + count: pages.length,
137 + effect: ColorTransitionEffect(
138 + spacing: 6.0,
139 + radius: 6.0,
140 + dotWidth: 6.0,
141 + dotHeight: 6.0,
142 + dotColor: Theme.of(context).indicatorColor,
143 + activeDotColor:
144 + Theme.of(context).accentTextTheme!.headline4!.backgroundColor!),
145 + )),
146 + Observer(builder: (_) {
147 + return ClipRect(
148 child: Container(
139 - padding: EdgeInsets.only(left: 32, right: 32),
140 - child: Row(
141 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
142 - children: <Widget>[
143 - if (walletViewModel.hasBuyAction)
144 - ActionButton(
145 - image: Image.asset('assets/images/buy.png',
146 - height: 24,
147 - width: 24,
148 - color: !walletViewModel.isEnabledBuyAction
149 - ? Theme.of(context)
150 - .accentTextTheme!
151 - .headline3!
152 - .backgroundColor!
153 - : Theme.of(context).accentTextTheme!.headline2!.backgroundColor!),
154 - title: S.of(context).buy,
155 - onClick: () async => await _onClickBuyButton(context),
156 - textColor: !walletViewModel.isEnabledBuyAction
157 - ? Theme.of(context)
158 - .accentTextTheme!
159 - .headline3!
160 - .backgroundColor!
161 - : null),
162 - ActionButton(
163 - image: receiveImage,
164 - title: S.of(context).receive,
165 - route: Routes.addressPage),
166 - if (walletViewModel.hasExchangeAction)
167 - ActionButton(
168 - image: Image.asset('assets/images/transfer.png',
169 - height: 24,
170 - width: 24,
171 - color: !walletViewModel.isEnabledExchangeAction
172 - ? Theme.of(context)
173 - .accentTextTheme!
174 - .headline3!
175 - .backgroundColor!
176 - : Theme.of(context).accentTextTheme!.headline2!.backgroundColor!),
177 - title: S.of(context).exchange,
178 - onClick: () async => _onClickExchangeButton(context),
179 - textColor: !walletViewModel.isEnabledExchangeAction
180 - ? Theme.of(context)
181 - .accentTextTheme!
182 - .headline3!
183 - .backgroundColor!
184 - : null),
185 - ActionButton(
186 - image: sendImage,
187 - title: S.of(context).send,
188 - route: Routes.send),
189 - if (walletViewModel.hasSellAction)
190 - ActionButton(
191 - image: Image.asset('assets/images/sell.png',
192 - height: 24,
193 - width: 24,
194 - color: !walletViewModel.isEnabledSellAction
195 - ? Theme.of(context)
196 - .accentTextTheme!
197 - .headline3!
198 - .backgroundColor!
199 - : Theme.of(context).accentTextTheme!.headline2!.backgroundColor!),
200 - title: S.of(context).sell,
201 - onClick: () async => await _onClickSellButton(context),
202 - textColor: !walletViewModel.isEnabledSellAction
203 - ? Theme.of(context)
204 - .accentTextTheme!
205 - .headline3!
206 - .backgroundColor!
207 - : null),
208 - ],
209 - ),),
210 - ),),);
211 - }),
212 -
213 - ],
214 - ));
149 + margin: const EdgeInsets.only(left: 16, right: 16),
150 + child: Container(
151 + decoration: BoxDecoration(
152 + borderRadius: BorderRadius.circular(50.0),
153 + border: Border.all(
154 + color: currentTheme.type == ThemeType.bright
155 + ? Color.fromRGBO(255, 255, 255, 0.2)
156 + : Colors.transparent,
157 + width: 1,
158 + ),
159 + color: Theme.of(context).textTheme.headline6!.backgroundColor!,
160 + ),
161 + child: Container(
162 + padding: EdgeInsets.only(left: 32, right: 32),
163 + child: Row(
164 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
165 + children: MainActions.all
166 + .where((element) => element.canShow?.call(dashboardViewModel) ?? true)
167 + .map((action) => ActionButton(
168 + image: Image.asset(action.image,
169 + height: 24,
170 + width: 24,
171 + color: action.isEnabled?.call(dashboardViewModel) ?? true
172 + ? Theme.of(context)
173 + .accentTextTheme
174 + .headline2!
175 + .backgroundColor!
176 + : Theme.of(context)
177 + .accentTextTheme
178 + .headline3!
179 + .backgroundColor!),
180 + title: action.name(context),
181 + onClick: () async => await action.onTap(context, dashboardViewModel),
182 + textColor: action.isEnabled?.call(dashboardViewModel) ?? true
183 + ? null
184 + : Theme.of(context)
185 + .accentTextTheme
186 + .headline3!
187 + .backgroundColor!,
188 + ))
189 + .toList(),
190 + ),
191 + ),
192 + ),
193 + ),
194 + );
195 + }),
196 + ],
197 + ));
198 }
199
200 void _setEffects(BuildContext context) async {
201 if (_isEffectsInstalled) {
202 return;
203 }
221 - pages.add(MarketPlacePage(dashboardViewModel: walletViewModel));
204 + pages.add(MarketPlacePage(dashboardViewModel: dashboardViewModel));
205 pages.add(balancePage);
223 - pages.add(TransactionsPage(dashboardViewModel: walletViewModel));
206 + pages.add(TransactionsPage(dashboardViewModel: dashboardViewModel));
207 _isEffectsInstalled = true;
208
209 autorun((_) async {
227 - if (!walletViewModel.isOutdatedElectrumWallet) {
210 + if (!dashboardViewModel.isOutdatedElectrumWallet) {
211 return;
212 }
213
@@ -235,8 +218,7 @@ class DashboardPage extends BasePage {
218 builder: (BuildContext context) {
219 return AlertWithOneAction(
220 alertTitle: S.of(context).pre_seed_title,
238 - alertContent:
239 - S.of(context).outdated_electrum_wallet_description,
221 + alertContent: S.of(context).outdated_electrum_wallet_description,
222 buttonText: S.of(context).understand,
223 buttonAction: () => Navigator.of(context).pop());
224 });
@@ -253,13 +235,13 @@ class DashboardPage extends BasePage {
235 Future<void>.delayed(Duration(milliseconds: 500)).then((_) {
236 showPopUp<void>(
237 context: navigatorKey.currentContext!,
256 - builder: (_) => YatEmojiId(walletViewModel.yatStore.emoji));
238 + builder: (_) => YatEmojiId(dashboardViewModel.yatStore.emoji));
239 needToPresentYat = false;
240 });
241 }
242 });
243
262 - walletViewModel.yatStore.emojiIncommingStream.listen((String emoji) {
244 + dashboardViewModel.yatStore.emojiIncommingStream.listen((String emoji) {
245 if (!_isEffectsInstalled || emoji.isEmpty) {
246 return;
247 }
@@ -267,62 +249,4 @@ class DashboardPage extends BasePage {
249 needToPresentYat = true;
250 });
251 }
270 -
271 - Future<void> _onClickBuyButton(BuildContext context) async {
272 - final walletType = walletViewModel.type;
273 -
274 - switch (walletType) {
275 - case WalletType.bitcoin:
276 - Navigator.of(context).pushNamed(Routes.onramperPage);
277 - break;
278 - case WalletType.litecoin:
279 - Navigator.of(context).pushNamed(Routes.onramperPage);
280 - break;
281 - case WalletType.monero:
282 - Navigator.of(context).pushNamed(Routes.payfuraPage);
283 - break;
284 - default:
285 - await showPopUp<void>(
286 - context: context,
287 - builder: (BuildContext context) {
288 - return AlertWithOneAction(
289 - alertTitle: S.of(context).buy,
290 - alertContent: S.of(context).buy_alert_content,
291 - buttonText: S.of(context).ok,
292 - buttonAction: () => Navigator.of(context).pop());
293 - });
294 - }
295 - }
296 -
297 - Future<void> _onClickSellButton(BuildContext context) async {
298 - final walletType = walletViewModel.type;
299 -
300 - switch (walletType) {
301 - case WalletType.bitcoin:
302 - final moonPaySellProvider = MoonPaySellProvider();
303 - final uri = await moonPaySellProvider.requestUrl(
304 - currency: walletViewModel.wallet.currency,
305 - refundWalletAddress:
306 - walletViewModel.wallet.walletAddresses.address);
307 - await launch(uri);
308 - break;
309 - default:
310 - await showPopUp<void>(
311 - context: context,
312 - builder: (BuildContext context) {
313 - return AlertWithOneAction(
314 - alertTitle: S.of(context).sell,
315 - alertContent: isMoneroOnly ? S.of(context).sell_monero_com_alert_content
316 - : S.of(context).sell_alert_content,
317 - buttonText: S.of(context).ok,
318 - buttonAction: () => Navigator.of(context).pop());
319 - });
320 - }
321 - }
322 -
323 - Future<void> _onClickExchangeButton(BuildContext context) async {
324 - if (walletViewModel.isEnabledExchangeAction) {
325 - await Navigator.of(context).pushNamed(Routes.exchange);
326 - }
327 - }
252 }
lib/src/screens/dashboard/desktop_dashboard_page.dart new
+111
@@ -0,0 +1,111 @@
1 +import 'dart:async';
2 +import 'package:cake_wallet/generated/i18n.dart';
3 +import 'package:cake_wallet/routes.dart';
4 +import 'package:cake_wallet/src/screens/yat_emoji_id.dart';
5 +import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
6 +import 'package:cake_wallet/utils/show_pop_up.dart';
7 +import 'package:flutter/material.dart';
8 +import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
9 +import 'package:cake_wallet/src/screens/dashboard/widgets/balance_page.dart';
10 +import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart';
11 +import 'package:mobx/mobx.dart';
12 +import 'package:cake_wallet/main.dart';
13 +import 'package:cake_wallet/router.dart' as Router;
14 +
15 +class DesktopDashboardPage extends StatelessWidget {
16 + DesktopDashboardPage({
17 + required this.balancePage,
18 + required this.dashboardViewModel,
19 + required this.addressListViewModel,
20 + required this.desktopKey,
21 + });
22 +
23 + final BalancePage balancePage;
24 + final DashboardViewModel dashboardViewModel;
25 + final WalletAddressListViewModel addressListViewModel;
26 + final GlobalKey<NavigatorState> desktopKey;
27 +
28 + bool _isEffectsInstalled = false;
29 + StreamSubscription<bool>? _onInactiveSub;
30 +
31 + @override
32 + Widget build(BuildContext context) {
33 + _setEffects(context);
34 +
35 + return Container(
36 + color: Theme.of(context).backgroundColor,
37 + child: Row(
38 + crossAxisAlignment: CrossAxisAlignment.start,
39 + children: [
40 + Container(
41 + width: 400,
42 + child: balancePage,
43 + ),
44 + Flexible(
45 + child: ConstrainedBox(
46 + constraints: BoxConstraints(maxWidth: 500),
47 + child: Navigator(
48 + key: desktopKey,
49 + initialRoute: Routes.desktop_actions,
50 + onGenerateRoute: (settings) => Router.createRoute(settings),
51 + onGenerateInitialRoutes: (NavigatorState navigator, String initialRouteName) {
52 + return [
53 + navigator.widget.onGenerateRoute!(RouteSettings(name: initialRouteName))!
54 + ];
55 + },
56 + ),
57 + ),
58 + ),
59 + ],
60 + ),
61 + );
62 + }
63 +
64 + void _setEffects(BuildContext context) async {
65 + if (_isEffectsInstalled) {
66 + return;
67 + }
68 + _isEffectsInstalled = true;
69 +
70 + autorun((_) async {
71 + if (!dashboardViewModel.isOutdatedElectrumWallet) {
72 + return;
73 + }
74 +
75 + await Future<void>.delayed(Duration(seconds: 1));
76 + await showPopUp<void>(
77 + context: context,
78 + builder: (BuildContext context) {
79 + return AlertWithOneAction(
80 + alertTitle: S.of(context).pre_seed_title,
81 + alertContent: S.of(context).outdated_electrum_wallet_description,
82 + buttonText: S.of(context).understand,
83 + buttonAction: () => Navigator.of(context).pop());
84 + });
85 + });
86 +
87 + var needToPresentYat = false;
88 + var isInactive = false;
89 +
90 + _onInactiveSub = rootKey.currentState!.isInactive.listen((inactive) {
91 + isInactive = inactive;
92 +
93 + if (needToPresentYat) {
94 + Future<void>.delayed(Duration(milliseconds: 500)).then((_) {
95 + showPopUp<void>(
96 + context: navigatorKey.currentContext!,
97 + builder: (_) => YatEmojiId(dashboardViewModel.yatStore.emoji));
98 + needToPresentYat = false;
99 + });
100 + }
101 + });
102 +
103 + dashboardViewModel.yatStore.emojiIncommingStream.listen((String emoji) {
104 + if (!_isEffectsInstalled || emoji.isEmpty) {
105 + return;
106 + }
107 +
108 + needToPresentYat = true;
109 + });
110 + }
111 +}
lib/src/screens/dashboard/desktop_widgets/desktop_action_button.dart new
+69
@@ -0,0 +1,69 @@
1 +import 'package:auto_size_text/auto_size_text.dart';
2 +import 'package:flutter/material.dart';
3 +
4 +class DesktopActionButton extends StatelessWidget {
5 + final String image;
6 + final String title;
7 + final bool canShow;
8 + final bool isEnabled;
9 + final Function() onTap;
10 +
11 + const DesktopActionButton({
12 + Key? key,
13 + required this.title,
14 + required this.image,
15 + required this.onTap,
16 + bool? canShow,
17 + bool? isEnabled,
18 + }) : this.isEnabled = isEnabled ?? true,
19 + this.canShow = canShow ?? true,
20 + super(key: key);
21 +
22 + @override
23 + Widget build(BuildContext context) {
24 + return Padding(
25 + padding: const EdgeInsets.fromLTRB(8, 0, 8, 8),
26 + child: GestureDetector(
27 + onTap: onTap,
28 + child: Container(
29 + padding: EdgeInsets.symmetric(vertical: 25),
30 + width: double.infinity,
31 + decoration: BoxDecoration(
32 + borderRadius: BorderRadius.circular(15.0),
33 + color: Theme.of(context).textTheme.headline6!.backgroundColor!,
34 + ),
35 + child: Center(
36 + child: Row(
37 + mainAxisSize: MainAxisSize.min,
38 + children: [
39 + Image.asset(
40 + image,
41 + height: 30,
42 + width: 30,
43 + color: isEnabled
44 + ? Theme.of(context).accentTextTheme.headline2!.backgroundColor!
45 + : Theme.of(context).accentTextTheme.headline3!.backgroundColor!,
46 + ),
47 + const SizedBox(width: 10),
48 + AutoSizeText(
49 + title,
50 + style: TextStyle(
51 + fontSize: 24,
52 + fontFamily: 'Lato',
53 + fontWeight: FontWeight.bold,
54 + color: isEnabled
55 + ? Theme.of(context).accentTextTheme.headline2!.backgroundColor!
56 + : null,
57 + height: 1,
58 + ),
59 + maxLines: 1,
60 + textAlign: TextAlign.center,
61 + )
62 + ],
63 + ),
64 + ),
65 + ),
66 + ),
67 + );
68 + }
69 +}
lib/src/screens/dashboard/desktop_widgets/desktop_dashboard_actions.dart new
+80
@@ -0,0 +1,80 @@
1 +import 'package:cake_wallet/entities/main_actions.dart';
2 +import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_action_button.dart';
3 +import 'package:cake_wallet/src/screens/dashboard/widgets/market_place_page.dart';
4 +import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
5 +import 'package:flutter/material.dart';
6 +import 'package:flutter_mobx/flutter_mobx.dart';
7 +
8 +class DesktopDashboardActions extends StatelessWidget {
9 + final DashboardViewModel dashboardViewModel;
10 +
11 + const DesktopDashboardActions(this.dashboardViewModel, {Key? key}) : super(key: key);
12 +
13 + @override
14 + Widget build(BuildContext context) {
15 + return Observer(
16 + builder: (_) {
17 + return Column(
18 + children: [
19 + const SizedBox(height: 16),
20 + DesktopActionButton(
21 + title: MainActions.exchangeAction.name(context),
22 + image: MainActions.exchangeAction.image,
23 + canShow: MainActions.exchangeAction.canShow?.call(dashboardViewModel),
24 + isEnabled: MainActions.exchangeAction.isEnabled?.call(dashboardViewModel),
25 + onTap: () async => await MainActions.exchangeAction.onTap(context, dashboardViewModel),
26 + ),
27 + Row(
28 + children: [
29 + Expanded(
30 + child: DesktopActionButton(
31 + title: MainActions.receiveAction.name(context),
32 + image: MainActions.receiveAction.image,
33 + canShow: MainActions.receiveAction.canShow?.call(dashboardViewModel),
34 + isEnabled: MainActions.receiveAction.isEnabled?.call(dashboardViewModel),
35 + onTap: () async =>
36 + await MainActions.receiveAction.onTap(context, dashboardViewModel),
37 + ),
38 + ),
39 + Expanded(
40 + child: DesktopActionButton(
41 + title: MainActions.sendAction.name(context),
42 + image: MainActions.sendAction.image,
43 + canShow: MainActions.sendAction.canShow?.call(dashboardViewModel),
44 + isEnabled: MainActions.sendAction.isEnabled?.call(dashboardViewModel),
45 + onTap: () async => await MainActions.sendAction.onTap(context, dashboardViewModel),
46 + ),
47 + ),
48 + ],
49 + ),
50 + Row(
51 + children: [
52 + Expanded(
53 + child: DesktopActionButton(
54 + title: MainActions.buyAction.name(context),
55 + image: MainActions.buyAction.image,
56 + canShow: MainActions.buyAction.canShow?.call(dashboardViewModel),
57 + isEnabled: MainActions.buyAction.isEnabled?.call(dashboardViewModel),
58 + onTap: () async => await MainActions.buyAction.onTap(context, dashboardViewModel),
59 + ),
60 + ),
61 + Expanded(
62 + child: DesktopActionButton(
63 + title: MainActions.sellAction.name(context),
64 + image: MainActions.sellAction.image,
65 + canShow: MainActions.sellAction.canShow?.call(dashboardViewModel),
66 + isEnabled: MainActions.sellAction.isEnabled?.call(dashboardViewModel),
67 + onTap: () async => await MainActions.sellAction.onTap(context, dashboardViewModel),
68 + ),
69 + ),
70 + ],
71 + ),
72 + Expanded(
73 + child: MarketPlacePage(dashboardViewModel: dashboardViewModel),
74 + ),
75 + ],
76 + );
77 + }
78 + );
79 + }
80 +}
lib/src/screens/dashboard/desktop_widgets/desktop_dashboard_navbar.dart new
+48
@@ -0,0 +1,48 @@
1 +import 'package:cake_wallet/di.dart';
2 +import 'package:cake_wallet/store/settings_store.dart';
3 +import 'package:cake_wallet/themes/theme_base.dart';
4 +import 'package:flutter/cupertino.dart';
5 +import 'package:flutter/material.dart';
6 +
7 +class DesktopDashboardNavbar extends StatelessWidget implements ObstructingPreferredSizeWidget {
8 + final Widget leading;
9 + final Widget middle;
10 + final Widget trailing;
11 +
12 + DesktopDashboardNavbar({
13 + super.key,
14 + required this.leading,
15 + required this.middle,
16 + required this.trailing,
17 + });
18 +
19 + ThemeBase get currentTheme => getIt.get<SettingsStore>().currentTheme;
20 +
21 + @override
22 + Widget build(BuildContext context) {
23 + final appBarColor =
24 + currentTheme.type == ThemeType.dark ? Colors.black.withOpacity(0.1) : Colors.white;
25 +
26 + return Container(
27 + padding: const EdgeInsetsDirectional.only(end: 24),
28 + color: appBarColor,
29 + child: Center(
30 + child: Row(
31 + mainAxisSize: MainAxisSize.max,
32 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
33 + children: [
34 + Flexible(child: leading),
35 + middle,
36 + trailing,
37 + ],
38 + ),
39 + ),
40 + );
41 + }
42 +
43 + @override
44 + Size get preferredSize => Size.fromHeight(60);
45 +
46 + @override
47 + bool shouldFullyObstruct(BuildContext context) => false;
48 +}
lib/src/screens/dashboard/desktop_widgets/desktop_sidebar/side_menu.dart new
+32
@@ -0,0 +1,32 @@
1 +import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar/side_menu_item.dart';
2 +import 'package:flutter/material.dart';
3 +
4 +class SideMenu extends StatelessWidget {
5 + const SideMenu({
6 + super.key,
7 + required this.topItems,
8 + required this.bottomItems,
9 + required this.width,
10 + });
11 +
12 + final List<SideMenuItem> topItems;
13 + final List<SideMenuItem> bottomItems;
14 + final double width;
15 +
16 + @override
17 + Widget build(BuildContext context) {
18 + return Container(
19 + color: Colors.black.withOpacity(0.1),
20 + width: width,
21 + height: MediaQuery.of(context).size.height,
22 + child: Column(
23 + children: [
24 + ...topItems,
25 + Spacer(),
26 + ...bottomItems,
27 + SizedBox(height: 30),
28 + ],
29 + ),
30 + );
31 + }
32 +}
lib/src/screens/dashboard/desktop_widgets/desktop_sidebar/side_menu_item.dart new
+50
@@ -0,0 +1,50 @@
1 +import 'package:flutter/material.dart';
2 +
3 +class SideMenuItem extends StatelessWidget {
4 + const SideMenuItem({
5 + Key? key,
6 + required this.onTap,
7 + this.imagePath,
8 + this.icon,
9 + this.isSelected = false,
10 + }) : assert((icon != null && imagePath == null) || (icon == null && imagePath != null));
11 +
12 + final void Function() onTap;
13 + final String? imagePath;
14 + final IconData? icon;
15 + final bool isSelected;
16 +
17 + Color _setColor(BuildContext context) {
18 + if (isSelected) {
19 + return Theme.of(context).primaryTextTheme.headline6!.color!;
20 + } else {
21 + return Theme.of(context).highlightColor;
22 + }
23 + }
24 +
25 + @override
26 + Widget build(BuildContext context) {
27 + return InkWell(
28 + child: Padding(
29 + padding: EdgeInsets.all(20),
30 + child: icon != null
31 + ? Icon(
32 + icon,
33 + color: _setColor(context),
34 + )
35 + : Image.asset(
36 + imagePath ?? '',
37 + fit: BoxFit.cover,
38 + height: 30,
39 + width: 30,
40 + color: _setColor(context),
41 + ),
42 + ),
43 + onTap: () => onTap.call(),
44 + highlightColor: Colors.transparent,
45 + focusColor: Colors.transparent,
46 + hoverColor: Colors.transparent,
47 + splashColor: Colors.transparent,
48 + );
49 + }
50 +}
lib/src/screens/dashboard/desktop_widgets/desktop_sidebar_wrapper.dart new
+175
@@ -0,0 +1,175 @@
1 +import 'package:cake_wallet/di.dart';
2 +import 'package:cake_wallet/routes.dart';
3 +import 'package:cake_wallet/src/screens/auth/auth_page.dart';
4 +import 'package:cake_wallet/src/screens/base_page.dart';
5 +import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_dashboard_navbar.dart';
6 +import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar/side_menu.dart';
7 +import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar/side_menu_item.dart';
8 +import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_wallet_selection_dropdown.dart';
9 +import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator.dart';
10 +import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
11 +import 'package:cake_wallet/view_model/dashboard/desktop_sidebar_view_model.dart';
12 +import 'package:flutter/cupertino.dart';
13 +import 'package:flutter/material.dart';
14 +import 'package:flutter_mobx/flutter_mobx.dart';
15 +import 'package:cake_wallet/router.dart' as Router;
16 +import 'package:mobx/mobx.dart';
17 +
18 +class DesktopSidebarWrapper extends BasePage {
19 + final Widget child;
20 + final DesktopSidebarViewModel desktopSidebarViewModel;
21 + final DashboardViewModel dashboardViewModel;
22 + final GlobalKey<NavigatorState> desktopNavigatorKey;
23 +
24 + DesktopSidebarWrapper({
25 + required this.child,
26 + required this.desktopSidebarViewModel,
27 + required this.dashboardViewModel,
28 + required this.desktopNavigatorKey,
29 + });
30 +
31 + @override
32 + ObstructingPreferredSizeWidget appBar(BuildContext context) => DesktopDashboardNavbar(
33 + leading: Padding(
34 + padding: EdgeInsets.only(left: sideMenuWidth),
35 + child: getIt<DesktopWalletSelectionDropDown>(),
36 + ),
37 + middle: SyncIndicator(
38 + dashboardViewModel: dashboardViewModel,
39 + onTap: () => Navigator.of(context, rootNavigator: true).pushNamed(Routes.connectionSync),
40 + ),
41 + trailing: InkWell(
42 + onTap: () {
43 + Navigator.of(context).pushNamed(
44 + Routes.unlock,
45 + arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
46 + if (isAuthenticatedSuccessfully) {
47 + auth.close();
48 + }
49 + },
50 + );
51 + },
52 + child: Icon(Icons.lock_outline),
53 + ),
54 + );
55 +
56 + @override
57 + bool get resizeToAvoidBottomInset => false;
58 +
59 + final pageController = PageController();
60 +
61 + final selectedIconPath = 'assets/images/desktop_transactions_solid_icon.png';
62 + final unselectedIconPath = 'assets/images/desktop_transactions_outline_icon.png';
63 +
64 + double get sideMenuWidth => 76.0;
65 +
66 + @override
67 + Widget body(BuildContext context) {
68 + _setEffects();
69 +
70 + return Row(
71 + crossAxisAlignment: CrossAxisAlignment.start,
72 + children: [
73 + Observer(builder: (_) {
74 + return SideMenu(
75 + width: sideMenuWidth,
76 + topItems: [
77 + SideMenuItem(
78 + imagePath: 'assets/images/wallet_outline.png',
79 + isSelected: desktopSidebarViewModel.currentPage == SidebarItem.dashboard,
80 + onTap: () => desktopSidebarViewModel.onPageChange(SidebarItem.dashboard),
81 + ),
82 + SideMenuItem(
83 + onTap: () {
84 + String? currentPath;
85 +
86 + desktopNavigatorKey.currentState?.popUntil((route) {
87 + currentPath = route.settings.name;
88 + return true;
89 + });
90 +
91 + switch (currentPath) {
92 + case Routes.transactionsPage:
93 + desktopSidebarViewModel.resetSidebar();
94 + break;
95 + default:
96 + desktopSidebarViewModel.resetSidebar();
97 + Future.delayed(Duration(milliseconds: 10), () {
98 + desktopSidebarViewModel.onPageChange(SidebarItem.transactions);
99 + desktopNavigatorKey.currentState?.pushNamed(Routes.transactionsPage);
100 + });
101 + }
102 + },
103 + isSelected: desktopSidebarViewModel.currentPage == SidebarItem.transactions,
104 + imagePath: desktopSidebarViewModel.currentPage == SidebarItem.transactions
105 + ? selectedIconPath
106 + : unselectedIconPath,
107 + ),
108 + ],
109 + bottomItems: [
110 + SideMenuItem(
111 + imagePath: 'assets/images/support_icon.png',
112 + isSelected: desktopSidebarViewModel.currentPage == SidebarItem.support,
113 + onTap: () => desktopSidebarViewModel.onPageChange(SidebarItem.support)),
114 + SideMenuItem(
115 + imagePath: 'assets/images/settings_outline.png',
116 + isSelected: desktopSidebarViewModel.currentPage == SidebarItem.settings,
117 + onTap: () => desktopSidebarViewModel.onPageChange(SidebarItem.settings),
118 + ),
119 + ],
120 + );
121 + }),
122 + Expanded(
123 + child: PageView(
124 + controller: pageController,
125 + physics: NeverScrollableScrollPhysics(),
126 + children: [
127 + child,
128 + Container(
129 + color: Theme.of(context).backgroundColor,
130 + padding: EdgeInsets.all(20),
131 + child: Navigator(
132 + initialRoute: Routes.support,
133 + onGenerateRoute: (settings) => Router.createRoute(settings),
134 + onGenerateInitialRoutes: (NavigatorState navigator, String initialRouteName) {
135 + return [
136 + navigator.widget.onGenerateRoute!(RouteSettings(name: initialRouteName))!
137 + ];
138 + },
139 + ),
140 + ),
141 + Navigator(
142 + initialRoute: Routes.desktop_settings_page,
143 + onGenerateRoute: (settings) => Router.createRoute(settings),
144 + onGenerateInitialRoutes: (NavigatorState navigator, String initialRouteName) {
145 + return [
146 + navigator.widget.onGenerateRoute!(RouteSettings(name: initialRouteName))!
147 + ];
148 + },
149 + ),
150 + ],
151 + ),
152 + ),
153 + ],
154 + );
155 + }
156 +
157 + void _setEffects() async {
158 + reaction<SidebarItem>((_) => desktopSidebarViewModel.currentPage, (page) {
159 + String? currentPath;
160 +
161 + desktopNavigatorKey.currentState?.popUntil((route) {
162 + currentPath = route.settings.name;
163 + return true;
164 + });
165 + if (page == SidebarItem.transactions) {
166 + return;
167 + }
168 +
169 + if (currentPath == Routes.transactionsPage) {
170 + Navigator.of(desktopNavigatorKey.currentContext!).pop();
171 + }
172 + pageController.jumpToPage(page.index);
173 + });
174 + }
175 +}
lib/src/screens/dashboard/desktop_widgets/desktop_wallet_selection_dropdown.dart new
+199
@@ -0,0 +1,199 @@
1 +import 'package:another_flushbar/flushbar.dart';
2 +import 'package:cake_wallet/entities/desktop_dropdown_item.dart';
3 +import 'package:cake_wallet/generated/i18n.dart';
4 +import 'package:cake_wallet/routes.dart';
5 +import 'package:cake_wallet/src/screens/auth/auth_page.dart';
6 +import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/dropdown_item_widget.dart';
7 +import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
8 +import 'package:cake_wallet/utils/show_bar.dart';
9 +import 'package:cake_wallet/utils/show_pop_up.dart';
10 +import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
11 +import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
12 +import 'package:cake_wallet/wallet_type_utils.dart';
13 +import 'package:cw_core/wallet_type.dart';
14 +import 'package:flutter/material.dart';
15 +import 'package:flutter_mobx/flutter_mobx.dart';
16 +
17 +class DesktopWalletSelectionDropDown extends StatefulWidget {
18 + final WalletListViewModel walletListViewModel;
19 +
20 + DesktopWalletSelectionDropDown(this.walletListViewModel, {Key? key}) : super(key: key);
21 +
22 + @override
23 + State<DesktopWalletSelectionDropDown> createState() => _DesktopWalletSelectionDropDownState();
24 +}
25 +
26 +class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionDropDown> {
27 + final moneroIcon = Image.asset('assets/images/monero_logo.png', height: 24, width: 24);
28 + final bitcoinIcon = Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
29 + final litecoinIcon = Image.asset('assets/images/litecoin_icon.png', height: 24, width: 24);
30 + final havenIcon = Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
31 + final nonWalletTypeIcon = Image.asset('assets/images/close.png', height: 24, width: 24);
32 +
33 + Image _newWalletImage(BuildContext context) => Image.asset(
34 + 'assets/images/new_wallet.png',
35 + height: 12,
36 + width: 12,
37 + color: Theme.of(context).primaryTextTheme.headline6!.color!,
38 + );
39 +
40 + Image _restoreWalletImage(BuildContext context) => Image.asset(
41 + 'assets/images/restore_wallet.png',
42 + height: 12,
43 + width: 12,
44 + color: Theme.of(context).primaryTextTheme.headline6!.color!,
45 + );
46 +
47 + Flushbar<void>? _progressBar;
48 +
49 + @override
50 + Widget build(BuildContext context) {
51 + final themeData = Theme.of(context);
52 + return Observer(builder: (context) {
53 + final dropDownItems = [
54 + ...widget.walletListViewModel.wallets
55 + .map((wallet) => DesktopDropdownItem(
56 + isSelected: wallet.isCurrent,
57 + child: ConstrainedBox(
58 + constraints: BoxConstraints(maxWidth: 500),
59 + child: DropDownItemWidget(
60 + title: wallet.name,
61 + image: wallet.isEnabled ? _imageFor(type: wallet.type) : nonWalletTypeIcon),
62 + ),
63 + onSelected: () => _onSelectedWallet(wallet),
64 + ))
65 + .toList(),
66 + DesktopDropdownItem(
67 + onSelected: () => _navigateToCreateWallet(),
68 + child: DropDownItemWidget(
69 + title: S.of(context).create_new,
70 + image: _newWalletImage(context),
71 + ),
72 + ),
73 + DesktopDropdownItem(
74 + onSelected: () => _navigateToRestoreWallet(),
75 + child: DropDownItemWidget(
76 + title: S.of(context).restore_wallet,
77 + image: _restoreWalletImage(context),
78 + ),
79 + ),
80 + ];
81 +
82 + return DropdownButton<DesktopDropdownItem>(
83 + items: dropDownItems
84 + .map(
85 + (wallet) => DropdownMenuItem<DesktopDropdownItem>(
86 + child: wallet.child,
87 + value: wallet,
88 + ),
89 + )
90 + .toList(),
91 + onChanged: (item) {
92 + item?.onSelected();
93 + },
94 + dropdownColor: themeData.textTheme.bodyText1?.decorationColor,
95 + style: TextStyle(color: themeData.primaryTextTheme.headline6?.color),
96 + selectedItemBuilder: (context) => dropDownItems.map((item) => item.child).toList(),
97 + value: dropDownItems.firstWhere((element) => element.isSelected),
98 + underline: const SizedBox(),
99 + focusColor: Colors.transparent,
100 + borderRadius: BorderRadius.circular(15.0),
101 + );
102 + });
103 + }
104 +
105 + void _onSelectedWallet(WalletListItem selectedWallet) async {
106 + if (selectedWallet.isCurrent || !selectedWallet.isEnabled) {
107 + return;
108 + }
109 + final confirmed = await showPopUp<bool>(
110 + context: context,
111 + builder: (dialogContext) {
112 + return AlertWithTwoActions(
113 + alertTitle: S.of(context).change_wallet_alert_title,
114 + alertContent: S.of(context).change_wallet_alert_content(selectedWallet.name),
115 + leftButtonText: S.of(context).cancel,
116 + rightButtonText: S.of(context).change,
117 + actionLeftButton: () => Navigator.of(context).pop(false),
118 + actionRightButton: () => Navigator.of(context).pop(true));
119 + }) ??
120 + false;
121 +
122 + if (confirmed) {
123 + await _loadWallet(selectedWallet);
124 + }
125 + }
126 +
127 + Image _imageFor({required WalletType type}) {
128 + switch (type) {
129 + case WalletType.bitcoin:
130 + return bitcoinIcon;
131 + case WalletType.monero:
132 + return moneroIcon;
133 + case WalletType.litecoin:
134 + return litecoinIcon;
135 + case WalletType.haven:
136 + return havenIcon;
137 + default:
138 + return nonWalletTypeIcon;
139 + }
140 + }
141 +
142 + Future<void> _loadWallet(WalletListItem wallet) async {
143 + if (await widget.walletListViewModel.checkIfAuthRequired()) {
144 + await Navigator.of(context).pushNamed(Routes.auth,
145 + arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) async {
146 + if (!isAuthenticatedSuccessfully) {
147 + return;
148 + }
149 +
150 + try {
151 + auth.changeProcessText(S.of(context).wallet_list_loading_wallet(wallet.name));
152 + await widget.walletListViewModel.loadWallet(wallet);
153 + auth.hideProgressText();
154 + auth.close();
155 + setState(() {});
156 + } catch (e) {
157 + auth.changeProcessText(
158 + S.of(context).wallet_list_failed_to_load(wallet.name, e.toString()));
159 + }
160 + });
161 + } else {
162 + try {
163 + changeProcessText(S.of(context).wallet_list_loading_wallet(wallet.name));
164 + await widget.walletListViewModel.loadWallet(wallet);
165 + hideProgressText();
166 + setState(() {});
167 + } catch (e) {
168 + changeProcessText(S.of(context).wallet_list_failed_to_load(wallet.name, e.toString()));
169 + }
170 + }
171 + }
172 +
173 + void _navigateToCreateWallet() {
174 + if (isSingleCoin) {
175 + Navigator.of(context)
176 + .pushNamed(Routes.newWallet, arguments: widget.walletListViewModel.currentWalletType);
177 + } else {
178 + Navigator.of(context).pushNamed(Routes.newWalletType);
179 + }
180 + }
181 +
182 + void _navigateToRestoreWallet() {
183 + if (isSingleCoin) {
184 + Navigator.of(context)
185 + .pushNamed(Routes.restoreWallet, arguments: widget.walletListViewModel.currentWalletType);
186 + } else {
187 + Navigator.of(context).pushNamed(Routes.restoreWalletType);
188 + }
189 + }
190 +
191 + void changeProcessText(String text) {
192 + _progressBar = createBar<void>(text, duration: null)..show(context);
193 + }
194 +
195 + void hideProgressText() {
196 + _progressBar?.dismiss();
197 + _progressBar = null;
198 + }
199 +}
lib/src/screens/dashboard/desktop_widgets/dropdown_item_widget.dart new
+36
@@ -0,0 +1,36 @@
1 +import 'package:flutter/material.dart';
2 +
3 +class DropDownItemWidget extends StatelessWidget {
4 + const DropDownItemWidget({super.key, required this.title, required this.image});
5 + final double tileHeight = 60;
6 + final Image image;
7 + final String title;
8 +
9 + @override
10 + Widget build(BuildContext context) {
11 + return Container(
12 + height: tileHeight,
13 + padding: EdgeInsets.symmetric(horizontal: 20),
14 + child: Row(
15 + crossAxisAlignment: CrossAxisAlignment.center,
16 + mainAxisSize: MainAxisSize.min,
17 + children: <Widget>[
18 + image,
19 + SizedBox(width: 10),
20 + Flexible(
21 + child: Text(
22 + title,
23 + style: TextStyle(
24 + fontSize: 22,
25 + fontWeight: FontWeight.w500,
26 + color: Theme.of(context).primaryTextTheme.headline6!.color!,
27 + ),
28 + overflow: TextOverflow.ellipsis,
29 + maxLines: 1,
30 + ),
31 + )
32 + ],
33 + ),
34 + );
35 + }
36 +}
lib/src/screens/dashboard/wallet_menu.dart deleted
-74
@@ -1,74 +0,0 @@
1 -import 'package:cake_wallet/palette.dart';
2 -import 'package:cake_wallet/src/screens/dashboard/wallet_menu_item.dart';
3 -import 'package:flutter/material.dart';
4 -import 'package:cake_wallet/routes.dart';
5 -import 'package:cake_wallet/generated/i18n.dart';
6 -
7 -// FIXME: terrible design
8 -
9 -class WalletMenu {
10 - WalletMenu(this.context, this.reconnect, this.hasRescan) : items = [] {
11 - items.addAll([
12 - WalletMenuItem(
13 - title: S.current.connection_sync,
14 - image: Image.asset('assets/images/nodes_menu.png',
15 - height: 16, width: 16),
16 - handler: () => Navigator.of(context).pushNamed(Routes.connectionSync),
17 - ),
18 - WalletMenuItem(
19 - title: S.current.wallets,
20 - image: Image.asset('assets/images/wallet_menu.png',
21 - height: 16, width: 16),
22 - handler: () => Navigator.of(context).pushNamed(Routes.walletList),
23 - ),
24 - WalletMenuItem(
25 - title: S.current.address_book_menu,
26 - image: Image.asset('assets/images/open_book_menu.png',
27 - height: 16, width: 16),
28 - handler: () => Navigator.of(context).pushNamed(Routes.addressBook),
29 - ),
30 - WalletMenuItem(
31 - title: S.current.security_and_backup,
32 - image:
33 - Image.asset('assets/images/key_menu.png', height: 16, width: 16),
34 - handler: () {
35 - Navigator.of(context).pushNamed(Routes.securityBackupPage);
36 - }),
37 - WalletMenuItem(
38 - title: S.current.privacy_settings,
39 - image:
40 - Image.asset('assets/images/privacy_menu.png', height: 16, width: 16),
41 - handler: () {
42 - Navigator.of(context).pushNamed(Routes.privacyPage);
43 - }),
44 - WalletMenuItem(
45 - title: S.current.display_settings,
46 - image: Image.asset('assets/images/eye_menu.png',
47 - height: 16, width: 16),
48 - handler: () => Navigator.of(context).pushNamed(Routes.displaySettingsPage),
49 - ),
50 - WalletMenuItem(
51 - title: S.current.other_settings,
52 - image: Image.asset('assets/images/settings_menu.png',
53 - height: 16, width: 16),
54 - handler: () => Navigator.of(context).pushNamed(Routes.otherSettingsPage),
55 - ),
56 - WalletMenuItem(
57 - title: S.current.settings_support,
58 - image: Image.asset('assets/images/question_mark.png',
59 - height: 16, width: 16, color: Palette.darkBlue),
60 - handler: () => Navigator.of(context).pushNamed(Routes.support),
61 - ),
62 - ]);
63 - }
64 -
65 - final List<WalletMenuItem> items;
66 - final BuildContext context;
67 - final Future<void> Function() reconnect;
68 - final bool hasRescan;
69 -
70 - void action(int index) {
71 - final item = items[index];
72 - item.handler();
73 - }
74 -}
lib/src/screens/dashboard/wallet_menu_item.dart deleted
-12
@@ -1,12 +0,0 @@
1 -import 'package:flutter/material.dart';
2 -
3 -class WalletMenuItem {
4 - WalletMenuItem({
5 - required this.title,
6 - required this.image,
7 - required this.handler});
8 -
9 - final String title;
10 - final Image image;
11 - final void Function() handler;
12 -}
\ No newline at end of file
lib/src/screens/dashboard/widgets/address_page.dart
+9 -28
@@ -24,12 +24,12 @@ import 'package:cake_wallet/di.dart';
24 class AddressPage extends BasePage {
25 AddressPage({
26 required this.addressListViewModel,
27 - required this.walletViewModel,
27 + required this.dashboardViewModel,
28 required this.receiveOptionViewModel,
29 }) : _cryptoAmountFocus = FocusNode();
30
31 final WalletAddressListViewModel addressListViewModel;
32 - final DashboardViewModel walletViewModel;
32 + final DashboardViewModel dashboardViewModel;
33 final ReceiveOptionViewModel receiveOptionViewModel;
34
35 final FocusNode _cryptoAmountFocus;
@@ -47,28 +47,10 @@ class AddressPage extends BasePage {
47 bool effectsInstalled = false;
48
49 @override
50 - Widget leading(BuildContext context) {
51 - final _backButton = Icon(
52 - Icons.arrow_back_ios,
53 - color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!,
54 - size: 16,
55 - );
50 + Color get titleColor => Colors.white;
51
57 - return SizedBox(
58 - height: 37,
59 - width: 37,
60 - child: ButtonTheme(
61 - minWidth: double.minPositive,
62 - child: TextButton(
63 - // FIX-ME: Style
64 - //highlightColor: Colors.transparent,
65 - //splashColor: Colors.transparent,
66 - //padding: EdgeInsets.all(0),
67 - onPressed: () => onClose(context),
68 - child: _backButton),
69 - ),
70 - );
71 - }
52 + @override
53 + bool get canUseCloseIcon => true;
54
55 @override
56 Widget middle(BuildContext context) =>
@@ -116,8 +98,8 @@ class AddressPage extends BasePage {
98 _setEffects(context);
99
100 autorun((_) async {
119 - if (!walletViewModel.isOutdatedElectrumWallet ||
120 - !walletViewModel.settingsStore.shouldShowReceiveWarning) {
101 + if (!dashboardViewModel.isOutdatedElectrumWallet ||
102 + !dashboardViewModel.settingsStore.shouldShowReceiveWarning) {
103 return;
104 }
105
@@ -133,7 +115,7 @@ class AddressPage extends BasePage {
115 actionLeftButton: () => Navigator.of(context).pop(),
116 rightButtonText: S.of(context).do_not_show_me,
117 actionRightButton: () {
136 - walletViewModel.settingsStore.setShouldShowReceiveWarning(false);
118 + dashboardViewModel.settingsStore.setShouldShowReceiveWarning(false);
119 Navigator.of(context).pop();
120 });
121 });
@@ -163,7 +145,7 @@ class AddressPage extends BasePage {
145 addressListViewModel: addressListViewModel,
146 amountTextFieldFocusNode: _cryptoAmountFocus,
147 isAmountFieldShow: !addressListViewModel.hasAccounts,
166 - isLight: walletViewModel.settingsStore.currentTheme.type == ThemeType.light))
148 + isLight: dashboardViewModel.settingsStore.currentTheme.type == ThemeType.light))
149 ),
150 Observer(builder: (_) {
151 return addressListViewModel.hasAddressList
@@ -222,7 +204,6 @@ class AddressPage extends BasePage {
204 }
205
206 reaction((_) => receiveOptionViewModel.selectedReceiveOption, (ReceivePageOption option) {
225 - Navigator.pop(context);
207 switch (option) {
208 case ReceivePageOption.anonPayInvoice:
209 Navigator.pushReplacementNamed(
lib/src/screens/dashboard/widgets/balance_page.dart
+2 -7
@@ -1,10 +1,8 @@
1 -import 'package:cake_wallet/di.dart';
2 -import 'package:cake_wallet/src/widgets/standard_list.dart';
1 import 'package:cake_wallet/store/settings_store.dart';
2 import 'package:cake_wallet/themes/theme_base.dart';
3 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
4 import 'package:flutter/material.dart';
5 import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
7 -import 'package:flutter/scheduler.dart';
6 import 'package:flutter_mobx/flutter_mobx.dart';
7 import 'package:auto_size_text/auto_size_text.dart';
8 import 'package:cake_wallet/src/widgets/introducing_card.dart';
@@ -16,9 +14,6 @@ class BalancePage extends StatelessWidget{
14
15 final DashboardViewModel dashboardViewModel;
16 final SettingsStore settingsStore;
19 -
20 - Color get backgroundLightColor =>
21 - settingsStore.currentTheme.type == ThemeType.bright ? Colors.transparent : Colors.white;
17
18 @override
19 Widget build(BuildContext context) {
@@ -29,7 +24,7 @@ class BalancePage extends StatelessWidget{
24 child: Column(
25 crossAxisAlignment: CrossAxisAlignment.start,
26 children: [
32 - SizedBox(height: 56),
27 + SizedBox(height: ResponsiveLayoutUtil.instance.isMobile(context) ? 56 : 16),
28 Container(
29 margin: const EdgeInsets.only(left: 24, bottom: 16),
30 child: Observer(builder: (_) {
lib/src/screens/dashboard/widgets/menu_widget.dart
+46 -105
@@ -1,10 +1,9 @@
1 -import 'dart:ui';
1 +import 'package:cake_wallet/src/widgets/setting_action_button.dart';
2 +import 'package:cake_wallet/src/widgets/setting_actions.dart';
3 import 'package:flutter/material.dart';
4 import 'package:cake_wallet/palette.dart';
5 import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
6 import 'package:cw_core/wallet_type.dart';
6 -import 'package:cake_wallet/src/screens/dashboard/wallet_menu.dart';
7 -import 'package:flutter/rendering.dart';
7 import 'package:flutter_mobx/flutter_mobx.dart';
8
9 // FIXME: terrible design.
@@ -19,18 +18,18 @@ class MenuWidget extends StatefulWidget {
18 }
19
20 class MenuWidgetState extends State<MenuWidget> {
22 - MenuWidgetState()
23 - : this.menuWidth = 0,
24 - this.screenWidth = 0,
25 - this.screenHeight = 0,
26 - this.headerHeight = 120,
27 - this.tileHeight = 60,
28 - this.fromTopEdge = 50,
29 - this.fromBottomEdge = 25,
30 - this.moneroIcon = Image.asset('assets/images/monero_menu.png'),
31 - this.bitcoinIcon = Image.asset('assets/images/bitcoin_menu.png'),
32 - this.litecoinIcon = Image.asset('assets/images/litecoin_menu.png'),
33 - this.havenIcon = Image.asset('assets/images/haven_menu.png');
21 + MenuWidgetState()
22 + : this.menuWidth = 0,
23 + this.screenWidth = 0,
24 + this.screenHeight = 0,
25 + this.headerHeight = 120,
26 + this.tileHeight = 60,
27 + this.fromTopEdge = 50,
28 + this.fromBottomEdge = 25,
29 + this.moneroIcon = Image.asset('assets/images/monero_menu.png'),
30 + this.bitcoinIcon = Image.asset('assets/images/bitcoin_menu.png'),
31 + this.litecoinIcon = Image.asset('assets/images/litecoin_menu.png'),
32 + this.havenIcon = Image.asset('assets/images/haven_menu.png');
33
34 final largeScreen = 731;
35
@@ -82,16 +81,12 @@ class MenuWidgetState extends State<MenuWidget> {
81
82 @override
83 Widget build(BuildContext context) {
85 - final walletMenu = WalletMenu(
86 - context,
87 - () async => widget.dashboardViewModel.reconnect(),
88 - widget.dashboardViewModel.hasRescan);
89 - final itemCount = walletMenu.items.length;
84 + final itemCount = SettingActions.all.length;
85
86 moneroIcon = Image.asset('assets/images/monero_menu.png',
92 - color: Theme.of(context).accentTextTheme!.overline!.decorationColor!);
87 + color: Theme.of(context).accentTextTheme.overline!.decorationColor!);
88 bitcoinIcon = Image.asset('assets/images/bitcoin_menu.png',
94 - color: Theme.of(context).accentTextTheme!.overline!.decorationColor!);
89 + color: Theme.of(context).accentTextTheme.overline!.decorationColor!);
90 litecoinIcon = Image.asset('assets/images/litecoin_menu.png');
91 havenIcon = Image.asset('assets/images/haven_menu.png');
92
@@ -105,17 +100,15 @@ class MenuWidgetState extends State<MenuWidget> {
100 height: 60,
101 width: 4,
102 decoration: BoxDecoration(
108 - borderRadius: BorderRadius.all(Radius.circular(2)),
109 - color: PaletteDark.gray),
103 + borderRadius: BorderRadius.all(Radius.circular(2)), color: PaletteDark.gray),
104 )),
105 SizedBox(width: 12),
106 Expanded(
107 child: ClipRRect(
108 borderRadius: BorderRadius.only(
115 - topLeft: Radius.circular(24),
116 - bottomLeft: Radius.circular(24)),
109 + topLeft: Radius.circular(24), bottomLeft: Radius.circular(24)),
110 child: Container(
118 - color: Theme.of(context).textTheme!.bodyText1!.decorationColor!,
111 + color: Theme.of(context).textTheme.bodyText1!.decorationColor!,
112 child: ListView.separated(
113 padding: EdgeInsets.only(top: 0),
114 itemBuilder: (_, index) {
@@ -123,25 +116,13 @@ class MenuWidgetState extends State<MenuWidget> {
116 return Container(
117 height: headerHeight,
118 decoration: BoxDecoration(
126 - gradient: LinearGradient(
127 - colors: [
128 - Theme.of(context)
129 - .accentTextTheme!
130 - .headline4!
131 - .color!,
132 - Theme.of(context)
133 - .accentTextTheme!
134 - .headline4!
135 - .decorationColor!,
136 - ],
137 - begin: Alignment.topLeft,
138 - end: Alignment.bottomRight),
119 + gradient: LinearGradient(colors: [
120 + Theme.of(context).accentTextTheme.headline4!.color!,
121 + Theme.of(context).accentTextTheme.headline4!.decorationColor!,
122 + ], begin: Alignment.topLeft, end: Alignment.bottomRight),
123 ),
124 padding: EdgeInsets.only(
141 - left: 24,
142 - top: fromTopEdge,
143 - right: 24,
144 - bottom: fromBottomEdge),
125 + left: 24, top: fromTopEdge, right: 24, bottom: fromBottomEdge),
126 child: Row(
127 mainAxisAlignment: MainAxisAlignment.start,
128 children: <Widget>[
@@ -150,13 +131,10 @@ class MenuWidgetState extends State<MenuWidget> {
131 SingleChildScrollView(
132 child: Container(
133 child: Column(
153 - crossAxisAlignment:
154 - CrossAxisAlignment.start,
155 - mainAxisAlignment:
156 - widget.dashboardViewModel.subname !=
157 - null
158 - ? MainAxisAlignment.spaceBetween
159 - : MainAxisAlignment.center,
134 + crossAxisAlignment: CrossAxisAlignment.start,
135 + mainAxisAlignment: widget.dashboardViewModel.subname.isNotEmpty
136 + ? MainAxisAlignment.spaceBetween
137 + : MainAxisAlignment.center,
138 children: <Widget>[
139 Text(
140 widget.dashboardViewModel.name,
@@ -165,19 +143,16 @@ class MenuWidgetState extends State<MenuWidget> {
143 fontSize: 16,
144 fontWeight: FontWeight.bold),
145 ),
168 - if (widget.dashboardViewModel.subname !=
169 - null)
146 + if (widget.dashboardViewModel.subname.isNotEmpty)
147 Observer(
148 builder: (_) => Text(
172 - widget.dashboardViewModel
173 - .subname,
149 + widget.dashboardViewModel.subname,
150 style: TextStyle(
151 color: Theme.of(context)
176 - .accentTextTheme!
152 + .accentTextTheme
153 .overline!
154 .decorationColor!,
179 - fontWeight:
180 - FontWeight.w500,
155 + fontWeight: FontWeight.w500,
156 fontSize: 12),
157 ))
158 ],
@@ -190,58 +165,24 @@ class MenuWidgetState extends State<MenuWidget> {
165
166 index--;
167
193 - final item = walletMenu.items[index];
194 - final title = item.title;
195 - final image = item.image ?? Offstage();
168 + final item = SettingActions.all[index];
169 +
170 final isLastTile = index == itemCount - 1;
171
198 - return GestureDetector(
199 - onTap: () {
200 - Navigator.of(context).pop();
201 - walletMenu.action(index);
202 - },
203 - child: Container(
204 - color: Theme.of(context)
205 - .textTheme!
206 - .bodyText1!
207 - .decorationColor!,
208 - height: isLastTile ? headerHeight : tileHeight,
209 - padding: isLastTile
210 - ? EdgeInsets.only(
211 - left: 24,
212 - right: 24,
213 - top: fromBottomEdge,
214 - //bottom: fromTopEdge
215 - )
216 - : EdgeInsets.only(left: 24, right: 24),
217 - alignment: isLastTile ? Alignment.topLeft : null,
218 - child: Row(
219 - mainAxisAlignment: MainAxisAlignment.start,
220 - crossAxisAlignment: CrossAxisAlignment.center,
221 - children: <Widget>[
222 - image,
223 - SizedBox(width: 16),
224 - Expanded(
225 - child: Text(
226 - title,
227 - style: TextStyle(
228 - color: Theme.of(context)
229 - .textTheme!
230 - .headline3!
231 - .color!,
232 - fontSize: 16,
233 - fontWeight: FontWeight.bold),
234 - ))
235 - ],
236 - ),
237 - ));
172 + return SettingActionButton(
173 + isLastTile: isLastTile,
174 + tileHeight: tileHeight,
175 + selectionActive: false,
176 + fromBottomEdge: fromBottomEdge,
177 + fromTopEdge: fromTopEdge,
178 + onTap: () => item.onTap.call(context),
179 + image: item.image,
180 + title: item.name,
181 + );
182 },
183 separatorBuilder: (_, index) => Container(
184 height: 1,
241 - color: Theme.of(context)
242 - .primaryTextTheme!
243 - .caption!
244 - .decorationColor!,
185 + color: Theme.of(context).primaryTextTheme.caption!.decorationColor!,
186 ),
187 itemCount: itemCount + 1),
188 )))
lib/src/screens/dashboard/widgets/present_receive_option_picker.dart
+5 -1
@@ -86,7 +86,11 @@ class PresentReceiveOptionPicker extends StatelessWidget {
86 itemBuilder: (_, index) {
87 final option = receiveOptionViewModel.options[index];
88 return InkWell(
89 - onTap: () => receiveOptionViewModel.selectReceiveOption(option),
89 + onTap: () {
90 + Navigator.pop(popUpContext);
91 +
92 + receiveOptionViewModel.selectReceiveOption(option);
93 + },
94 child: Padding(
95 padding: const EdgeInsets.only(left: 24, right: 24),
96 child: Observer(builder: (_) {
lib/src/screens/dashboard/widgets/transactions_page.dart
+1
@@ -25,6 +25,7 @@ class TransactionsPage extends StatelessWidget {
25 @override
26 Widget build(BuildContext context) {
27 return Container(
28 + color: Theme.of(context).backgroundColor,
29 padding: EdgeInsets.only(top: 24, bottom: 24),
30 child: Column(
31 children: <Widget>[
lib/src/screens/exchange/exchange_page.dart
+153 -264
@@ -1,13 +1,14 @@
1 -import 'dart:ui';
1 import 'package:cake_wallet/di.dart';
2 +import 'package:cake_wallet/src/screens/exchange/widgets/desktop_exchange_cards_section.dart';
3 +import 'package:cake_wallet/src/screens/exchange/widgets/mobile_exchange_cards_section.dart';
4 +import 'package:cake_wallet/src/widgets/add_template_button.dart';
5 import 'package:cake_wallet/utils/debounce.dart';
6 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
7 import 'package:cw_core/sync_status.dart';
8 import 'package:cw_core/wallet_type.dart';
9 import 'package:cake_wallet/entities/parse_address_from_domain.dart';
10 import 'package:cake_wallet/src/screens/send/widgets/extract_address_from_parsed.dart';
11 import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
9 -import 'package:dotted_border/dotted_border.dart';
10 -import 'package:flutter/cupertino.dart';
12 import 'package:flutter/material.dart';
13 import 'package:flutter_mobx/flutter_mobx.dart';
14 import 'package:keyboard_actions/keyboard_actions.dart';
@@ -35,7 +36,14 @@ import 'package:cake_wallet/src/screens/exchange/widgets/present_provider_picker
36 import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator_icon.dart';
37
38 class ExchangePage extends BasePage {
38 - ExchangePage(this.exchangeViewModel);
39 + ExchangePage(this.exchangeViewModel) {
40 + depositWalletName = exchangeViewModel.depositCurrency == CryptoCurrency.xmr
41 + ? exchangeViewModel.wallet.name
42 + : null;
43 + receiveWalletName = exchangeViewModel.receiveCurrency == CryptoCurrency.xmr
44 + ? exchangeViewModel.wallet.name
45 + : null;
46 + }
47
48 final ExchangeViewModel exchangeViewModel;
49 final depositKey = GlobalKey<ExchangeCardState>();
@@ -49,6 +57,20 @@ class ExchangePage extends BasePage {
57 final _depositAmountDebounce = Debounce(Duration(milliseconds: 500));
58 var _isReactionsSet = false;
59
60 + final arrowBottomPurple = Image.asset(
61 + 'assets/images/arrow_bottom_purple_icon.png',
62 + color: Colors.white,
63 + height: 8,
64 + );
65 + final arrowBottomCakeGreen = Image.asset(
66 + 'assets/images/arrow_bottom_cake_green.png',
67 + color: Colors.white,
68 + height: 8,
69 + );
70 +
71 + late final String? depositWalletName;
72 + late final String? receiveWalletName;
73 +
74 @override
75 String get title => S.current.exchange;
76
@@ -86,27 +108,10 @@ class ExchangePage extends BasePage {
108 });
109
110 @override
89 - Widget body(BuildContext context) {
90 - final arrowBottomPurple = Image.asset(
91 - 'assets/images/arrow_bottom_purple_icon.png',
92 - color: Colors.white,
93 - height: 8,
94 - );
95 - final arrowBottomCakeGreen = Image.asset(
96 - 'assets/images/arrow_bottom_cake_green.png',
97 - color: Colors.white,
98 - height: 8,
99 - );
100 -
101 - final depositWalletName =
102 - exchangeViewModel.depositCurrency == CryptoCurrency.xmr
103 - ? exchangeViewModel.wallet.name
104 - : null;
105 - final receiveWalletName =
106 - exchangeViewModel.receiveCurrency == CryptoCurrency.xmr
107 - ? exchangeViewModel.wallet.name
108 - : null;
111 + bool get canUseCloseIcon => true;
112
113 + @override
114 + Widget body(BuildContext context) {
115 WidgetsBinding.instance
116 .addPostFrameCallback((_) => _setReactions(context, exchangeViewModel));
117
@@ -137,201 +142,7 @@ class ExchangePage extends BasePage {
142 contentPadding: EdgeInsets.only(bottom: 24),
143 content: Observer(builder: (_) => Column(
144 children: <Widget>[
140 - Container(
141 - padding: EdgeInsets.only(bottom: 32),
142 - decoration: BoxDecoration(
143 - borderRadius: BorderRadius.only(
144 - bottomLeft: Radius.circular(24),
145 - bottomRight: Radius.circular(24)),
146 - gradient: LinearGradient(
147 - colors: [
148 - Theme.of(context).primaryTextTheme!.bodyText2!.color!,
149 - Theme.of(context)
150 - .primaryTextTheme!
151 - .bodyText2!
152 - .decorationColor!,
153 - ],
154 - stops: [
155 - 0.35,
156 - 1.0
157 - ],
158 - begin: Alignment.topLeft,
159 - end: Alignment.bottomRight),
160 - ),
161 - child: Column(
162 - children: <Widget>[
163 - Container(
164 - decoration: BoxDecoration(
165 - borderRadius: BorderRadius.only(
166 - bottomLeft: Radius.circular(24),
167 - bottomRight: Radius.circular(24)),
168 - gradient: LinearGradient(
169 - colors: [
170 - Theme.of(context)
171 - .primaryTextTheme!
172 - .subtitle2!
173 - .color!,
174 - Theme.of(context)
175 - .primaryTextTheme!
176 - .subtitle2!
177 - .decorationColor!,
178 - ],
179 - begin: Alignment.topLeft,
180 - end: Alignment.bottomRight),
181 - ),
182 - padding: EdgeInsets.fromLTRB(24, 100, 24, 32),
183 - child: Observer(
184 - builder: (_) => ExchangeCard(
185 - onDispose: disposeBestRateSync,
186 - hasAllAmount: exchangeViewModel.hasAllAmount,
187 - allAmount: exchangeViewModel.hasAllAmount
188 - ? () => exchangeViewModel
189 - .calculateDepositAllAmount()
190 - : null,
191 - amountFocusNode: _depositAmountFocus,
192 - addressFocusNode: _depositAddressFocus,
193 - key: depositKey,
194 - title: S.of(context).you_will_send,
195 - initialCurrency:
196 - exchangeViewModel.depositCurrency,
197 - initialWalletName: depositWalletName ?? '',
198 - initialAddress:
199 - exchangeViewModel.depositCurrency ==
200 - exchangeViewModel.wallet.currency
201 - ? exchangeViewModel.wallet.walletAddresses.address
202 - : exchangeViewModel.depositAddress,
203 - initialIsAmountEditable: true,
204 - initialIsAddressEditable:
205 - exchangeViewModel.isDepositAddressEnabled,
206 - isAmountEstimated: false,
207 - hasRefundAddress: true,
208 - isMoneroWallet: exchangeViewModel.isMoneroWallet,
209 - currencies: exchangeViewModel.depositCurrencies,
210 - onCurrencySelected: (currency) {
211 - // FIXME: need to move it into view model
212 - if (currency == CryptoCurrency.xmr &&
213 - exchangeViewModel.wallet.type !=
214 - WalletType.monero) {
215 - showPopUp<void>(
216 - context: context,
217 - builder: (dialogContext) {
218 - return AlertWithOneAction(
219 - alertTitle: S.of(context).error,
220 - alertContent: S
221 - .of(context)
222 - .exchange_incorrect_current_wallet_for_xmr,
223 - buttonText: S.of(context).ok,
224 - buttonAction: () =>
225 - Navigator.of(dialogContext)
226 - .pop());
227 - });
228 - return;
229 - }
230 -
231 - exchangeViewModel.changeDepositCurrency(
232 - currency: currency);
233 - },
234 - imageArrow: arrowBottomPurple,
235 - currencyButtonColor: Colors.transparent,
236 - addressButtonsColor:
237 - Theme.of(context).focusColor!,
238 - borderColor: Theme.of(context)
239 - .primaryTextTheme!
240 - .bodyText1!
241 - .color!,
242 - currencyValueValidator: AmountValidator(
243 - currency: exchangeViewModel.depositCurrency),
244 - addressTextFieldValidator: AddressValidator(
245 - type: exchangeViewModel.depositCurrency),
246 - onPushPasteButton: (context) async {
247 - final domain =
248 - exchangeViewModel.depositAddress;
249 - final ticker = exchangeViewModel
250 - .depositCurrency.title.toLowerCase();
251 - exchangeViewModel.depositAddress =
252 - await fetchParsedAddress(
253 - context, domain, ticker);
254 - },
255 - onPushAddressBookButton: (context) async {
256 - final domain =
257 - exchangeViewModel.depositAddress;
258 - final ticker = exchangeViewModel
259 - .depositCurrency.title.toLowerCase();
260 - exchangeViewModel.depositAddress =
261 - await fetchParsedAddress(
262 - context, domain, ticker);
263 - },
264 - ),
265 - ),
266 - ),
267 - Padding(
268 - padding:
269 - EdgeInsets.only(top: 29, left: 24, right: 24),
270 - child: Observer(
271 - builder: (_) => ExchangeCard(
272 - onDispose: disposeBestRateSync,
273 - amountFocusNode: _receiveAmountFocus,
274 - addressFocusNode: _receiveAddressFocus,
275 - key: receiveKey,
276 - title: S.of(context).you_will_get,
277 - initialCurrency:
278 - exchangeViewModel.receiveCurrency,
279 - initialWalletName: receiveWalletName ?? '',
280 - initialAddress: exchangeViewModel
281 - .receiveCurrency ==
282 - exchangeViewModel.wallet.currency
283 - ? exchangeViewModel.wallet.walletAddresses.address
284 - : exchangeViewModel.receiveAddress,
285 - initialIsAmountEditable: exchangeViewModel
286 - .isReceiveAmountEditable,
287 - initialIsAddressEditable:
288 - exchangeViewModel
289 - .isReceiveAddressEnabled,
290 - isAmountEstimated: true,
291 - isMoneroWallet: exchangeViewModel.isMoneroWallet,
292 - currencies:
293 - exchangeViewModel.receiveCurrencies,
294 - onCurrencySelected: (currency) =>
295 - exchangeViewModel
296 - .changeReceiveCurrency(
297 - currency: currency),
298 - imageArrow: arrowBottomCakeGreen,
299 - currencyButtonColor: Colors.transparent,
300 - addressButtonsColor:
301 - Theme.of(context).focusColor!,
302 - borderColor: Theme.of(context)
303 - .primaryTextTheme!
304 - .bodyText1!
305 - .decorationColor!,
306 - currencyValueValidator: AmountValidator(
307 - currency: exchangeViewModel.receiveCurrency),
308 - addressTextFieldValidator:
309 - AddressValidator(
310 - type: exchangeViewModel
311 - .receiveCurrency),
312 - onPushPasteButton: (context) async {
313 - final domain =
314 - exchangeViewModel.receiveAddress;
315 - final ticker = exchangeViewModel
316 - .receiveCurrency.title.toLowerCase();
317 - exchangeViewModel.receiveAddress =
318 - await fetchParsedAddress(
319 - context, domain, ticker);
320 - },
321 - onPushAddressBookButton: (context) async {
322 - final domain =
323 - exchangeViewModel.receiveAddress;
324 - final ticker = exchangeViewModel
325 - .receiveCurrency.title.toLowerCase();
326 - exchangeViewModel.receiveAddress =
327 - await fetchParsedAddress(
328 - context, domain, ticker);
329 - },
330 - )),
331 - )
332 - ],
333 - ),
334 - ),
145 + _exchangeCardsSection(context),
146 Padding(
147 padding: EdgeInsets.only(top: 12, left: 24),
148 child: Row(
@@ -427,50 +238,9 @@ class ExchangePage extends BasePage {
238
239 return Row(
240 children: <Widget>[
430 - GestureDetector(
431 - onTap: () =>
432 - Navigator.of(context).pushNamed(Routes.exchangeTemplate),
433 - child: Container(
434 - padding: EdgeInsets.only(left: 1, right: 10),
435 - child: DottedBorder(
436 - borderType: BorderType.RRect,
437 - dashPattern: [6, 4],
438 - color: Theme.of(context)
439 - .primaryTextTheme!
440 - .headline3!
441 - .decorationColor!,
442 - strokeWidth: 2,
443 - radius: Radius.circular(20),
444 - child: Container(
445 - height: 34,
446 - padding: EdgeInsets.only(left: 10, right: 10),
447 - alignment: Alignment.center,
448 - decoration: BoxDecoration(
449 - borderRadius: BorderRadius.all(Radius.circular(20)),
450 - color: Colors.transparent,
451 - ),
452 - child: templates.length >= 1
453 - ? Icon(
454 - Icons.add,
455 - color: Theme.of(context)
456 - .primaryTextTheme!
457 - .headline2!
458 - .color!,
459 - )
460 - : Text(
461 - S.of(context).new_template,
462 - style: TextStyle(
463 - fontSize: 14,
464 - fontWeight: FontWeight.w600,
465 - color: Theme.of(context)
466 - .primaryTextTheme!
467 - .headline2!
468 - .color!,
469 - ),
470 - ),
471 - ),
472 - ),
473 - ),
241 + AddTemplateButton(
242 + onTap: () => Navigator.of(context).pushNamed(Routes.exchangeTemplate),
243 + currentTemplatesLength: templates.length,
244 ),
245 ListView.builder(
246 scrollDirection: Axis.horizontal,
@@ -808,5 +578,124 @@ class ExchangePage extends BasePage {
578 }
579 }
580
811 - void disposeBestRateSync() => exchangeViewModel.bestRateSync?.cancel();
581 + void disposeBestRateSync() => exchangeViewModel.bestRateSync.cancel();
582 +
583 + Widget _exchangeCardsSection(BuildContext context) {
584 + final firstExchangeCard = Observer(builder: (_) => ExchangeCard(
585 + onDispose: disposeBestRateSync,
586 + hasAllAmount: exchangeViewModel.hasAllAmount,
587 + allAmount: exchangeViewModel.hasAllAmount
588 + ? () => exchangeViewModel.calculateDepositAllAmount()
589 + : null,
590 + amountFocusNode: _depositAmountFocus,
591 + addressFocusNode: _depositAddressFocus,
592 + key: depositKey,
593 + title: S.of(context).you_will_send,
594 + initialCurrency: exchangeViewModel.depositCurrency,
595 + initialWalletName: depositWalletName ?? '',
596 + initialAddress:
597 + exchangeViewModel.depositCurrency == exchangeViewModel.wallet.currency
598 + ? exchangeViewModel.wallet.walletAddresses.address
599 + : exchangeViewModel.depositAddress,
600 + initialIsAmountEditable: true,
601 + initialIsAddressEditable: exchangeViewModel.isDepositAddressEnabled,
602 + isAmountEstimated: false,
603 + hasRefundAddress: true,
604 + isMoneroWallet: exchangeViewModel.isMoneroWallet,
605 + currencies: exchangeViewModel.depositCurrencies,
606 + onCurrencySelected: (currency) {
607 + // FIXME: need to move it into view model
608 + if (currency == CryptoCurrency.xmr &&
609 + exchangeViewModel.wallet.type != WalletType.monero) {
610 + showPopUp<void>(
611 + context: context,
612 + builder: (dialogContext) {
613 + return AlertWithOneAction(
614 + alertTitle: S.of(context).error,
615 + alertContent:
616 + S.of(context).exchange_incorrect_current_wallet_for_xmr,
617 + buttonText: S.of(context).ok,
618 + buttonAction: () => Navigator.of(dialogContext).pop());
619 + });
620 + return;
621 + }
622 +
623 + exchangeViewModel.changeDepositCurrency(currency: currency);
624 + },
625 + imageArrow: arrowBottomPurple,
626 + currencyButtonColor: Colors.transparent,
627 + addressButtonsColor: Theme.of(context).focusColor!,
628 + borderColor: Theme.of(context).primaryTextTheme!.bodyText1!.color!,
629 + currencyValueValidator:
630 + AmountValidator(currency: exchangeViewModel.depositCurrency),
631 + addressTextFieldValidator:
632 + AddressValidator(type: exchangeViewModel.depositCurrency),
633 + onPushPasteButton: (context) async {
634 + final domain = exchangeViewModel.depositAddress;
635 + final ticker = exchangeViewModel.depositCurrency.title.toLowerCase();
636 + exchangeViewModel.depositAddress =
637 + await fetchParsedAddress(context, domain, ticker);
638 + },
639 + onPushAddressBookButton: (context) async {
640 + final domain = exchangeViewModel.depositAddress;
641 + final ticker = exchangeViewModel.depositCurrency.title.toLowerCase();
642 + exchangeViewModel.depositAddress =
643 + await fetchParsedAddress(context, domain, ticker);
644 + },
645 + ));
646 +
647 + final secondExchangeCard = Observer(builder: (_) => ExchangeCard(
648 + onDispose: disposeBestRateSync,
649 + amountFocusNode: _receiveAmountFocus,
650 + addressFocusNode: _receiveAddressFocus,
651 + key: receiveKey,
652 + title: S.of(context).you_will_get,
653 + initialCurrency: exchangeViewModel.receiveCurrency,
654 + initialWalletName: receiveWalletName ?? '',
655 + initialAddress:
656 + exchangeViewModel.receiveCurrency == exchangeViewModel.wallet.currency
657 + ? exchangeViewModel.wallet.walletAddresses.address
658 + : exchangeViewModel.receiveAddress,
659 + initialIsAmountEditable: exchangeViewModel.isReceiveAmountEditable,
660 + initialIsAddressEditable: exchangeViewModel.isReceiveAddressEnabled,
661 + isAmountEstimated: true,
662 + isMoneroWallet: exchangeViewModel.isMoneroWallet,
663 + currencies: exchangeViewModel.receiveCurrencies,
664 + onCurrencySelected: (currency) =>
665 + exchangeViewModel.changeReceiveCurrency(currency: currency),
666 + imageArrow: arrowBottomCakeGreen,
667 + currencyButtonColor: Colors.transparent,
668 + addressButtonsColor: Theme.of(context).focusColor!,
669 + borderColor:
670 + Theme.of(context).primaryTextTheme!.bodyText1!.decorationColor!,
671 + currencyValueValidator:
672 + AmountValidator(currency: exchangeViewModel.receiveCurrency),
673 + addressTextFieldValidator:
674 + AddressValidator(type: exchangeViewModel.receiveCurrency),
675 + onPushPasteButton: (context) async {
676 + final domain = exchangeViewModel.receiveAddress;
677 + final ticker = exchangeViewModel.receiveCurrency.title.toLowerCase();
678 + exchangeViewModel.receiveAddress =
679 + await fetchParsedAddress(context, domain, ticker);
680 + },
681 + onPushAddressBookButton: (context) async {
682 + final domain = exchangeViewModel.receiveAddress;
683 + final ticker = exchangeViewModel.receiveCurrency.title.toLowerCase();
684 + exchangeViewModel.receiveAddress =
685 + await fetchParsedAddress(context, domain, ticker);
686 + },
687 + ));
688 +
689 + if (ResponsiveLayoutUtil.instance.isMobile(context)) {
690 + return MobileExchangeCardsSection(
691 + firstExchangeCard: firstExchangeCard,
692 + secondExchangeCard: secondExchangeCard,
693 + );
694 + }
695 +
696 + return DesktopExchangeCardsSection(
697 + firstExchangeCard: firstExchangeCard,
698 + secondExchangeCard: secondExchangeCard,
699 + );
700 + }
701 }
lib/src/screens/exchange/exchange_template_page.dart
+92 -98
@@ -1,13 +1,9 @@
1 -import 'dart:ui';
1 import 'package:cake_wallet/exchange/exchange_provider.dart';
2 import 'package:cake_wallet/src/screens/base_page.dart';
3 import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
5 -import 'package:flutter/cupertino.dart';
4 import 'package:flutter/material.dart';
5 import 'package:flutter_mobx/flutter_mobx.dart';
6 import 'package:keyboard_actions/keyboard_actions.dart';
9 -import 'package:keyboard_actions/keyboard_actions_config.dart';
10 -import 'package:keyboard_actions/keyboard_actions_item.dart';
7 import 'package:mobx/mobx.dart';
8 import 'package:cake_wallet/generated/i18n.dart';
9 import 'package:cw_core/crypto_currency.dart';
@@ -78,7 +74,7 @@ class ExchangeTemplatePage extends BasePage {
74 config: KeyboardActionsConfig(
75 keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
76 keyboardBarColor:
81 - Theme.of(context).accentTextTheme!.bodyText1!.backgroundColor!,
77 + Theme.of(context).accentTextTheme.bodyText1!.backgroundColor!,
78 nextFocus: false,
79 actions: [
80 KeyboardActionsItem(
@@ -103,115 +99,114 @@ class ExchangeTemplatePage extends BasePage {
99 ),
100 gradient: LinearGradient(
101 colors: [
106 - Theme.of(context).primaryTextTheme!.bodyText2!.color!,
107 - Theme.of(context).primaryTextTheme!.bodyText2!.decorationColor!,
102 + Theme.of(context).primaryTextTheme.bodyText2!.color!,
103 + Theme.of(context).primaryTextTheme.bodyText2!.decorationColor!,
104 ],
105 stops: [0.35, 1.0],
106 begin: Alignment.topLeft,
107 end: Alignment.bottomRight),
108 ),
113 - child: Column(
114 - children: <Widget>[
115 - Container(
116 - decoration: BoxDecoration(
117 - borderRadius: BorderRadius.only(
118 - bottomLeft: Radius.circular(24),
119 - bottomRight: Radius.circular(24)
109 + child: FocusTraversalGroup(
110 + policy: OrderedTraversalPolicy(),
111 + child: Column(
112 + children: <Widget>[
113 + Container(
114 + decoration: BoxDecoration(
115 + borderRadius: BorderRadius.only(
116 + bottomLeft: Radius.circular(24),
117 + bottomRight: Radius.circular(24)
118 + ),
119 + gradient: LinearGradient(
120 + colors: [
121 + Theme.of(context)
122 + .primaryTextTheme.subtitle2!
123 + .color!,
124 + Theme.of(context)
125 + .primaryTextTheme.subtitle2!
126 + .decorationColor!,
127 + ],
128 + begin: Alignment.topLeft,
129 + end: Alignment.bottomRight),
130 ),
121 - gradient: LinearGradient(
122 - colors: [
123 - Theme.of(context)
124 - .primaryTextTheme!
125 - .subtitle2!
126 - .color!,
127 - Theme.of(context)
128 - .primaryTextTheme!
129 - .subtitle2!
130 - .decorationColor!,
131 - ],
132 - begin: Alignment.topLeft,
133 - end: Alignment.bottomRight),
134 - ),
135 - padding: EdgeInsets.fromLTRB(24, 100, 24, 32),
136 - child: Observer(
137 - builder: (_) => ExchangeCard(
138 - amountFocusNode: _depositAmountFocus,
139 - key: depositKey,
140 - title: S.of(context).you_will_send,
141 - initialCurrency:
142 - exchangeViewModel.depositCurrency,
143 - initialWalletName: depositWalletName ?? '',
144 - initialAddress: exchangeViewModel
145 - .depositCurrency ==
146 - exchangeViewModel.wallet.currency
147 - ? exchangeViewModel.wallet.walletAddresses.address
148 - : exchangeViewModel.depositAddress,
149 - initialIsAmountEditable: true,
150 - initialIsAddressEditable: exchangeViewModel
151 - .isDepositAddressEnabled,
152 - isAmountEstimated: false,
153 - hasRefundAddress: true,
154 - isMoneroWallet: exchangeViewModel.isMoneroWallet,
155 - currencies: CryptoCurrency.all,
156 - onCurrencySelected: (currency) =>
157 - exchangeViewModel.changeDepositCurrency(
158 - currency: currency),
159 - imageArrow: arrowBottomPurple,
160 - currencyButtonColor: Colors.transparent,
161 - addressButtonsColor:
162 - Theme.of(context).focusColor!,
163 - borderColor: Theme.of(context)
164 - .primaryTextTheme!
165 - .bodyText1!
166 - .color!,
167 - currencyValueValidator: AmountValidator(
168 - currency: exchangeViewModel.depositCurrency),
169 - //addressTextFieldValidator: AddressValidator(
170 - // type: exchangeViewModel.depositCurrency),
171 - ),
172 - ),
173 - ),
174 - Padding(
175 - padding: EdgeInsets.only(top: 29, left: 24, right: 24),
176 - child: Observer(
131 + padding: EdgeInsets.fromLTRB(24, 100, 24, 32),
132 + child: Observer(
133 builder: (_) => ExchangeCard(
178 - amountFocusNode: _receiveAmountFocus,
179 - key: receiveKey,
180 - title: S.of(context).you_will_get,
134 + amountFocusNode: _depositAmountFocus,
135 + key: depositKey,
136 + title: S.of(context).you_will_send,
137 initialCurrency:
182 - exchangeViewModel.receiveCurrency,
183 - initialWalletName: receiveWalletName ?? '',
184 - initialAddress:
185 - exchangeViewModel.receiveCurrency ==
138 + exchangeViewModel.depositCurrency,
139 + initialWalletName: depositWalletName ?? '',
140 + initialAddress: exchangeViewModel
141 + .depositCurrency ==
142 exchangeViewModel.wallet.currency
143 ? exchangeViewModel.wallet.walletAddresses.address
188 - : exchangeViewModel.receiveAddress,
189 - initialIsAmountEditable:
190 - exchangeViewModel.provider is
191 - XMRTOExchangeProvider ? true : false,
192 - initialIsAddressEditable:
193 - exchangeViewModel.isReceiveAddressEnabled,
194 - isAmountEstimated: true,
144 + : exchangeViewModel.depositAddress,
145 + initialIsAmountEditable: true,
146 + initialIsAddressEditable: exchangeViewModel
147 + .isDepositAddressEnabled,
148 + isAmountEstimated: false,
149 + hasRefundAddress: true,
150 isMoneroWallet: exchangeViewModel.isMoneroWallet,
196 - currencies: exchangeViewModel.receiveCurrencies,
151 + currencies: CryptoCurrency.all,
152 onCurrencySelected: (currency) =>
198 - exchangeViewModel.changeReceiveCurrency(
153 + exchangeViewModel.changeDepositCurrency(
154 currency: currency),
200 - imageArrow: arrowBottomCakeGreen,
155 + imageArrow: arrowBottomPurple,
156 currencyButtonColor: Colors.transparent,
157 addressButtonsColor:
203 - Theme.of(context).focusColor!,
158 + Theme.of(context).focusColor,
159 borderColor: Theme.of(context)
205 - .primaryTextTheme!
206 - .bodyText1!
207 - .decorationColor!,
160 + .primaryTextTheme.bodyText1!
161 + .color!,
162 currencyValueValidator: AmountValidator(
209 - currency: exchangeViewModel.receiveCurrency),
163 + currency: exchangeViewModel.depositCurrency),
164 //addressTextFieldValidator: AddressValidator(
211 - // type: exchangeViewModel.receiveCurrency),
212 - )),
213 - )
214 - ],
165 + // type: exchangeViewModel.depositCurrency),
166 + ),
167 + ),
168 + ),
169 + Padding(
170 + padding: EdgeInsets.only(top: 29, left: 24, right: 24),
171 + child: Observer(
172 + builder: (_) => ExchangeCard(
173 + amountFocusNode: _receiveAmountFocus,
174 + key: receiveKey,
175 + title: S.of(context).you_will_get,
176 + initialCurrency:
177 + exchangeViewModel.receiveCurrency,
178 + initialWalletName: receiveWalletName ?? '',
179 + initialAddress:
180 + exchangeViewModel.receiveCurrency ==
181 + exchangeViewModel.wallet.currency
182 + ? exchangeViewModel.wallet.walletAddresses.address
183 + : exchangeViewModel.receiveAddress,
184 + initialIsAmountEditable:
185 + exchangeViewModel.provider is
186 + XMRTOExchangeProvider ? true : false,
187 + initialIsAddressEditable:
188 + exchangeViewModel.isReceiveAddressEnabled,
189 + isAmountEstimated: true,
190 + isMoneroWallet: exchangeViewModel.isMoneroWallet,
191 + currencies: exchangeViewModel.receiveCurrencies,
192 + onCurrencySelected: (currency) =>
193 + exchangeViewModel.changeReceiveCurrency(
194 + currency: currency),
195 + imageArrow: arrowBottomCakeGreen,
196 + currencyButtonColor: Colors.transparent,
197 + addressButtonsColor:
198 + Theme.of(context).focusColor,
199 + borderColor: Theme.of(context)
200 + .primaryTextTheme.bodyText1!
201 + .decorationColor!,
202 + currencyValueValidator: AmountValidator(
203 + currency: exchangeViewModel.receiveCurrency),
204 + //addressTextFieldValidator: AddressValidator(
205 + // type: exchangeViewModel.receiveCurrency),
206 + )),
207 + )
208 + ],
209 + ),
210 ),
211 ),
212 bottomSectionPadding:
@@ -230,8 +225,7 @@ class ExchangeTemplatePage extends BasePage {
225 textAlign: TextAlign.center,
226 style: TextStyle(
227 color: Theme.of(context)
233 - .primaryTextTheme!
234 - .headline1!
228 + .primaryTextTheme.headline1!
229 .decorationColor!,
230 fontWeight: FontWeight.w500,
231 fontSize: 12),
lib/src/screens/exchange/widgets/currency_picker.dart
+7 -10
@@ -1,9 +1,8 @@
1 -import 'dart:ui';
1 import 'package:cake_wallet/src/screens/exchange/widgets/currency_picker_item_widget.dart';
2 import 'package:cake_wallet/src/screens/exchange/widgets/picker_item.dart';
3 import 'package:cake_wallet/src/widgets/alert_close_button.dart';
4 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
5 import 'package:cw_core/currency.dart';
6 -import 'package:flutter/cupertino.dart';
6 import 'package:flutter/material.dart';
7 import 'package:cw_core/crypto_currency.dart';
8 import 'package:cake_wallet/src/widgets/alert_background.dart';
@@ -68,11 +67,9 @@ class CurrencyPickerState extends State<CurrencyPicker> {
67 @override
68 Widget build(BuildContext context) {
69 return AlertBackground(
71 - child: Stack(
72 - alignment: Alignment.center,
73 - children: [
74 - Column(
70 + child: Column(
71 mainAxisSize: MainAxisSize.min,
72 + mainAxisAlignment: MainAxisAlignment.center,
73 children: <Widget>[
74 if (widget.title?.isNotEmpty ?? false)
75 Container(
@@ -94,10 +91,11 @@ class CurrencyPickerState extends State<CurrencyPicker> {
91 child: ClipRRect(
92 borderRadius: BorderRadius.all(Radius.circular(30)),
93 child: Container(
97 - color: Theme.of(context).accentTextTheme!.headline6!.color!,
94 + color: Theme.of(context).accentTextTheme.headline6!.color!,
95 child: ConstrainedBox(
96 constraints: BoxConstraints(
97 maxHeight: MediaQuery.of(context).size.height * 0.65,
98 + maxWidth: ResponsiveLayoutUtil.kPopupWidth
99 ),
100 child: Column(
101 mainAxisSize: MainAxisSize.min,
@@ -133,7 +131,7 @@ class CurrencyPickerState extends State<CurrencyPicker> {
131 ),
132 ),
133 Divider(
136 - color: Theme.of(context).accentTextTheme!.headline6!.backgroundColor!,
134 + color: Theme.of(context).accentTextTheme.headline6!.backgroundColor!,
135 height: 1,
136 ),
137 if (widget.selectedAtIndex != -1)
@@ -171,8 +169,7 @@ class CurrencyPickerState extends State<CurrencyPicker> {
169 ),
170 ),
171 ),
174 - ],
175 - ),
172 + SizedBox(height: ResponsiveLayoutUtil.kPopupSpaceHeight),
173 AlertCloseButton(),
174 ],
175 ),
lib/src/screens/exchange/widgets/desktop_exchange_cards_section.dart new
+31
@@ -0,0 +1,31 @@
1 +import 'package:flutter/material.dart';
2 +
3 +class DesktopExchangeCardsSection extends StatelessWidget {
4 + final Widget firstExchangeCard;
5 + final Widget secondExchangeCard;
6 +
7 + const DesktopExchangeCardsSection({
8 + Key? key,
9 + required this.firstExchangeCard,
10 + required this.secondExchangeCard,
11 + }) : super(key: key);
12 +
13 + @override
14 + Widget build(BuildContext context) {
15 + return FocusTraversalGroup(
16 + policy: OrderedTraversalPolicy(),
17 + child: Column(
18 + children: <Widget>[
19 + Padding(
20 + padding: EdgeInsets.only(top: 55, left: 24, right: 24),
21 + child: firstExchangeCard,
22 + ),
23 + Padding(
24 + padding: EdgeInsets.only(top: 29, left: 24, right: 24),
25 + child: secondExchangeCard,
26 + ),
27 + ],
28 + ),
29 + );
30 + }
31 +}
lib/src/screens/exchange/widgets/exchange_card.dart
+102 -105
@@ -160,7 +160,7 @@ class ExchangeCardState extends State<ExchangeCard> {
160 final copyImage = Image.asset('assets/images/copy_content.png',
161 height: 16,
162 width: 16,
163 - color: Theme.of(context).primaryTextTheme!.headline3!.color!);
163 + color: Theme.of(context).primaryTextTheme.headline3!.color!);
164
165 return Container(
166 width: double.infinity,
@@ -175,7 +175,7 @@ class ExchangeCardState extends State<ExchangeCard> {
175 style: TextStyle(
176 fontSize: 18,
177 fontWeight: FontWeight.w600,
178 - color: Theme.of(context).textTheme!.headline5!.color!),
178 + color: Theme.of(context).textTheme.headline5!.color!),
179 )
180 ],
181 ),
@@ -210,7 +210,7 @@ class ExchangeCardState extends State<ExchangeCard> {
210 child: Container(
211 height: 32,
212 decoration: BoxDecoration(
213 - color: widget.addressButtonsColor ?? Theme.of(context).primaryTextTheme!.headline4!.color!,
213 + color: widget.addressButtonsColor ?? Theme.of(context).primaryTextTheme.headline4!.color!,
214 borderRadius:
215 BorderRadius.all(Radius.circular(6))),
216 child: Center(
@@ -221,8 +221,7 @@ class ExchangeCardState extends State<ExchangeCard> {
221 fontSize: 12,
222 fontWeight: FontWeight.bold,
223 color: Theme.of(context)
224 - .primaryTextTheme!
225 - .headline4!
224 + .primaryTextTheme.headline4!
225 .decorationColor!)),
226 ),
227 ),
@@ -241,34 +240,36 @@ class ExchangeCardState extends State<ExchangeCard> {
240 mainAxisAlignment: MainAxisAlignment.spaceBetween,
241 children: [
242 Flexible(
244 - child: BaseTextFormField(
245 - focusNode: widget.amountFocusNode,
246 - controller: amountController,
247 - enabled: _isAmountEditable,
248 - textAlign: TextAlign.left,
249 - keyboardType: TextInputType.numberWithOptions(
250 - signed: false, decimal: true),
251 - inputFormatters: [
252 - FilteringTextInputFormatter.deny(
253 - RegExp('[\\-|\\ ]'))
254 - ],
255 - hintText: '0.0000',
256 - borderColor: Colors.transparent,
257 - //widget.borderColor,
258 - textStyle: TextStyle(
259 - fontSize: 16,
260 - fontWeight: FontWeight.w600,
261 - color: Colors.white),
262 - placeholderTextStyle: TextStyle(
263 - fontSize: 16,
264 - fontWeight: FontWeight.w600,
265 - color: Theme.of(context)
266 - .accentTextTheme!
267 - .headline1!
268 - .decorationColor!),
269 - validator: _isAmountEditable
270 - ? widget.currencyValueValidator
271 - : null),
243 + child: FocusTraversalOrder(
244 + order: NumericFocusOrder(1),
245 + child: BaseTextFormField(
246 + focusNode: widget.amountFocusNode,
247 + controller: amountController,
248 + enabled: _isAmountEditable,
249 + textAlign: TextAlign.left,
250 + keyboardType: TextInputType.numberWithOptions(
251 + signed: false, decimal: true),
252 + inputFormatters: [
253 + FilteringTextInputFormatter.deny(
254 + RegExp('[\\-|\\ ]'))
255 + ],
256 + hintText: '0.0000',
257 + borderColor: Colors.transparent,
258 + //widget.borderColor,
259 + textStyle: TextStyle(
260 + fontSize: 16,
261 + fontWeight: FontWeight.w600,
262 + color: Colors.white),
263 + placeholderTextStyle: TextStyle(
264 + fontSize: 16,
265 + fontWeight: FontWeight.w600,
266 + color: Theme.of(context)
267 + .accentTextTheme.headline1!
268 + .decorationColor!),
269 + validator: _isAmountEditable
270 + ? widget.currencyValueValidator
271 + : null),
272 + ),
273 ),
274 if (widget.hasAllAmount)
275 Container(
@@ -276,8 +277,7 @@ class ExchangeCardState extends State<ExchangeCard> {
277 width: 32,
278 decoration: BoxDecoration(
279 color: Theme.of(context)
279 - .primaryTextTheme!
280 - .headline4!
280 + .primaryTextTheme.headline4!
281 .color!,
282 borderRadius:
283 BorderRadius.all(Radius.circular(6))),
@@ -290,8 +290,7 @@ class ExchangeCardState extends State<ExchangeCard> {
290 fontSize: 12,
291 fontWeight: FontWeight.bold,
292 color: Theme.of(context)
293 - .primaryTextTheme!
294 - .headline4!
293 + .primaryTextTheme.headline4!
294 .decorationColor!)),
295 ),
296 ),
@@ -302,8 +301,7 @@ class ExchangeCardState extends State<ExchangeCard> {
301 ],
302 )),
303 Divider(height: 1,color: Theme.of(context)
305 - .primaryTextTheme!
306 - .headline5!
304 + .primaryTextTheme.headline5!
305 .decorationColor!),
306 Padding(
307 padding: EdgeInsets.only(top: 5),
@@ -321,8 +319,7 @@ class ExchangeCardState extends State<ExchangeCard> {
319 fontSize: 10,
320 height: 1.2,
321 color: Theme.of(context)
324 - .accentTextTheme!
325 - .headline1!
322 + .accentTextTheme.headline1!
323 .decorationColor!),
324 )
325 : Offstage(),
@@ -336,8 +333,7 @@ class ExchangeCardState extends State<ExchangeCard> {
333 fontSize: 10,
334 height: 1.2,
335 color: Theme.of(context)
339 - .accentTextTheme!
340 - .headline1!
336 + .accentTextTheme.headline1!
337 .decorationColor!))
338 : Offstage(),
339 ])),
@@ -351,71 +347,75 @@ class ExchangeCardState extends State<ExchangeCard> {
347 fontSize: 14,
348 fontWeight: FontWeight.w500,
349 color: Theme.of(context)
354 - .accentTextTheme!
355 - .headline1!
350 + .accentTextTheme.headline1!
351 .decorationColor!),
352 ))
353 : Offstage(),
354 _isAddressEditable
360 - ? Padding(
361 - padding: EdgeInsets.only(top: 20),
362 - child: AddressTextField(
363 - focusNode: widget.addressFocusNode,
364 - controller: addressController,
365 - onURIScanned: (uri) {
366 - final paymentRequest = PaymentRequest.fromUri(uri);
367 - addressController.text = paymentRequest.address;
368 -
369 - if (amountController.text.isNotEmpty) {
370 - _showAmountPopup(context, paymentRequest);
371 - return;
372 - }
373 - widget.amountFocusNode?.requestFocus();
374 - amountController.text = paymentRequest.amount;
375 - },
376 - placeholder: widget.hasRefundAddress
377 - ? S.of(context).refund_address
378 - : null,
379 - options: [
380 - AddressTextFieldOption.paste,
381 - AddressTextFieldOption.qrCode,
382 - AddressTextFieldOption.addressBook,
383 - ],
384 - isBorderExist: false,
385 - textStyle: TextStyle(
386 - fontSize: 16,
387 - fontWeight: FontWeight.w600,
388 - color: Colors.white),
389 - hintStyle: TextStyle(
390 - fontSize: 16,
391 - fontWeight: FontWeight.w600,
392 - color: Theme.of(context)
393 - .accentTextTheme!
394 - .headline1!
395 - .decorationColor!),
396 - buttonColor: widget.addressButtonsColor,
397 - validator: widget.addressTextFieldValidator,
398 - onPushPasteButton: widget.onPushPasteButton,
399 - onPushAddressBookButton: widget.onPushAddressBookButton,
400 - selectedCurrency: _selectedCurrency
355 + ? FocusTraversalOrder(
356 + order: NumericFocusOrder(2),
357 + child: Padding(
358 + padding: EdgeInsets.only(top: 20),
359 + child: AddressTextField(
360 + focusNode: widget.addressFocusNode,
361 + controller: addressController,
362 + onURIScanned: (uri) {
363 + final paymentRequest = PaymentRequest.fromUri(uri);
364 + addressController.text = paymentRequest.address;
365 +
366 + if (amountController.text.isNotEmpty) {
367 + _showAmountPopup(context, paymentRequest);
368 + return;
369 + }
370 + widget.amountFocusNode?.requestFocus();
371 + amountController.text = paymentRequest.amount;
372 + },
373 + placeholder: widget.hasRefundAddress
374 + ? S.of(context).refund_address
375 + : null,
376 + options: [
377 + AddressTextFieldOption.paste,
378 + AddressTextFieldOption.qrCode,
379 + AddressTextFieldOption.addressBook,
380 + ],
381 + isBorderExist: false,
382 + textStyle: TextStyle(
383 + fontSize: 16,
384 + fontWeight: FontWeight.w600,
385 + color: Colors.white),
386 + hintStyle: TextStyle(
387 + fontSize: 16,
388 + fontWeight: FontWeight.w600,
389 + color: Theme.of(context)
390 + .accentTextTheme.headline1!
391 + .decorationColor!),
392 + buttonColor: widget.addressButtonsColor,
393 + validator: widget.addressTextFieldValidator,
394 + onPushPasteButton: widget.onPushPasteButton,
395 + onPushAddressBookButton: widget.onPushAddressBookButton,
396 + selectedCurrency: _selectedCurrency
397 + ),
398 +
399 ),
402 -
403 - )
400 + )
401 : Padding(
402 padding: EdgeInsets.only(top: 10),
403 child: Builder(
404 builder: (context) => Stack(children: <Widget>[
408 - BaseTextFormField(
409 - controller: addressController,
410 - readOnly: true,
411 - borderColor: Colors.transparent,
412 - suffixIcon:
413 - SizedBox(width: _isMoneroWallet ? 80 : 36),
414 - textStyle: TextStyle(
415 - fontSize: 16,
416 - fontWeight: FontWeight.w600,
417 - color: Colors.white),
418 - validator: widget.addressTextFieldValidator),
405 + FocusTraversalOrder(
406 + order: NumericFocusOrder(3),
407 + child: BaseTextFormField(
408 + controller: addressController,
409 + readOnly: true,
410 + borderColor: Colors.transparent,
411 + suffixIcon:
412 + SizedBox(width: _isMoneroWallet ? 80 : 36),
413 + textStyle: TextStyle(
414 + fontSize: 16,
415 + fontWeight: FontWeight.w600,
416 + color: Colors.white),
417 + validator: widget.addressTextFieldValidator),
418 + ),
419 Positioned(
420 top: 2,
421 right: 0,
@@ -432,10 +432,8 @@ class ExchangeCardState extends State<ExchangeCard> {
432 child: InkWell(
433 onTap: () async {
434 final contact =
435 - await Navigator.of(context,
436 - rootNavigator: true)
437 - .pushNamed(Routes
438 - .pickerAddressBook);
435 + await Navigator.of(context)
436 + .pushNamed(Routes.pickerAddressBook);
437
438 if (contact is ContactBase &&
439 contact.address != null) {
@@ -458,8 +456,7 @@ class ExchangeCardState extends State<ExchangeCard> {
456 child: Image.asset(
457 'assets/images/open_book.png',
458 color: Theme.of(context)
461 - .primaryTextTheme!
462 - .headline4!
459 + .primaryTextTheme.headline4!
460 .decorationColor!,
461 )),
462 )),
lib/src/screens/exchange/widgets/mobile_exchange_cards_section.dart new
+58
@@ -0,0 +1,58 @@
1 +import 'package:flutter/material.dart';
2 +
3 +class MobileExchangeCardsSection extends StatelessWidget {
4 + final Widget firstExchangeCard;
5 + final Widget secondExchangeCard;
6 +
7 + const MobileExchangeCardsSection({
8 + Key? key,
9 + required this.firstExchangeCard,
10 + required this.secondExchangeCard,
11 + }) : super(key: key);
12 +
13 + @override
14 + Widget build(BuildContext context) {
15 + return Container(
16 + padding: EdgeInsets.only(bottom: 32),
17 + decoration: BoxDecoration(
18 + borderRadius: BorderRadius.only(
19 + bottomLeft: Radius.circular(24),
20 + bottomRight: Radius.circular(24),
21 + ),
22 + gradient: LinearGradient(
23 + colors: [
24 + Theme.of(context).primaryTextTheme.bodyText2!.color!,
25 + Theme.of(context).primaryTextTheme.bodyText2!.decorationColor!,
26 + ],
27 + stops: [0.35, 1.0],
28 + begin: Alignment.topLeft,
29 + end: Alignment.bottomRight,
30 + ),
31 + ),
32 + child: Column(
33 + children: <Widget>[
34 + Container(
35 + decoration: BoxDecoration(
36 + borderRadius: BorderRadius.only(
37 + bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
38 + gradient: LinearGradient(
39 + colors: [
40 + Theme.of(context).primaryTextTheme.subtitle2!.color!,
41 + Theme.of(context).primaryTextTheme.subtitle2!.decorationColor!,
42 + ],
43 + begin: Alignment.topLeft,
44 + end: Alignment.bottomRight,
45 + ),
46 + ),
47 + padding: EdgeInsets.fromLTRB(24, 100, 24, 32),
48 + child: firstExchangeCard,
49 + ),
50 + Padding(
51 + padding: EdgeInsets.only(top: 29, left: 24, right: 24),
52 + child: secondExchangeCard,
53 + )
54 + ],
55 + ),
56 + );
57 + }
58 +}
lib/src/screens/ionia/auth/ionia_create_account_page.dart
+9 -6
@@ -66,6 +66,7 @@ class IoniaCreateAccountPage extends BasePage {
66 validator: EmailValidator(),
67 keyboardType: TextInputType.emailAddress,
68 controller: _emailController,
69 + onSubmit: (_) => _createAccount(),
70 ),
71 ),
72 bottomSectionPadding: EdgeInsets.symmetric(vertical: 36, horizontal: 24),
@@ -77,12 +78,7 @@ class IoniaCreateAccountPage extends BasePage {
78 Observer(
79 builder: (_) => LoadingPrimaryButton(
80 text: S.of(context).create_account,
80 - onPressed: () async {
81 - if (_formKey.currentState != null && !_formKey.currentState!.validate()) {
82 - return;
83 - }
84 - await _authViewModel.createUser(_emailController.text);
85 - },
81 + onPressed: _createAccount,
82 isLoading: _authViewModel.createUserState is IoniaCreateStateLoading,
83 color: Theme.of(context).accentTextTheme!.bodyText1!.color!,
84 textColor: Colors.white,
@@ -151,4 +147,11 @@ class IoniaCreateAccountPage extends BasePage {
147 Routes.ioniaVerifyIoniaOtpPage,
148 arguments: [authViewModel.email, false],
149 );
150 +
151 + void _createAccount() async {
152 + if (_formKey.currentState != null && !_formKey.currentState!.validate()) {
153 + return;
154 + }
155 + await _authViewModel.createUser(_emailController.text);
156 + }
157 }
lib/src/screens/ionia/auth/ionia_login_page.dart
+9 -6
@@ -57,6 +57,7 @@ class IoniaLoginPage extends BasePage {
57 keyboardType: TextInputType.emailAddress,
58 validator: EmailValidator(),
59 controller: _emailController,
60 + onSubmit: (text) => _login(),
61 ),
62 ),
63 bottomSectionPadding: EdgeInsets.symmetric(vertical: 36, horizontal: 24),
@@ -68,12 +69,7 @@ class IoniaLoginPage extends BasePage {
69 Observer(
70 builder: (_) => LoadingPrimaryButton(
71 text: S.of(context).login,
71 - onPressed: () async {
72 - if (_formKey.currentState != null && !_formKey.currentState!.validate()) {
73 - return;
74 - }
75 - await _authViewModel.signIn(_emailController.text);
76 - },
72 + onPressed: _login,
73 isLoading: _authViewModel.signInState is IoniaCreateStateLoading,
74 color: Theme.of(context).accentTextTheme!.bodyText1!.color!,
75 textColor: Colors.white,
@@ -106,4 +102,11 @@ class IoniaLoginPage extends BasePage {
102 Routes.ioniaVerifyIoniaOtpPage,
103 arguments: [authViewModel.email, true],
104 );
105 +
106 + void _login() async {
107 + if (_formKey.currentState != null && !_formKey.currentState!.validate()) {
108 + return;
109 + }
110 + await _authViewModel.signIn(_emailController.text);
111 + }
112 }
lib/src/screens/ionia/auth/ionia_verify_otp_page.dart
+4 -1
@@ -82,6 +82,7 @@ class IoniaVerifyIoniaOtp extends BasePage {
82 keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true),
83 focusNode: _codeFocus,
84 controller: _codeController,
85 + onSubmit: (_) => _verify(),
86 ),
87 SizedBox(height: 14),
88 Text(
@@ -116,7 +117,7 @@ class IoniaVerifyIoniaOtp extends BasePage {
117 Observer(
118 builder: (_) => LoadingPrimaryButton(
119 text: S.of(context).continue_text,
119 - onPressed: () async => await _authViewModel.verifyEmail(_codeController.text),
120 + onPressed: _verify,
121 isDisabled: _authViewModel.otpState is IoniaOtpSendDisabled,
122 isLoading: _authViewModel.otpState is IoniaOtpValidating,
123 color: Theme.of(context).accentTextTheme!.bodyText1!.color!,
@@ -148,4 +149,6 @@ class IoniaVerifyIoniaOtp extends BasePage {
149 void _onOtpSuccessful(BuildContext context) =>
150 Navigator.of(context)
151 .pushNamedAndRemoveUntil(Routes.ioniaManageCardsPage, (route) => route.isFirst);
152 +
153 + void _verify() async => await _authViewModel.verifyEmail(_codeController.text);
154 }
lib/src/screens/ionia/cards/ionia_buy_gift_card.dart
+37 -28
@@ -6,6 +6,7 @@ import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
6 import 'package:cake_wallet/src/widgets/primary_button.dart';
7 import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
8 import 'package:cake_wallet/themes/theme_base.dart';
9 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
10 import 'package:cake_wallet/view_model/ionia/ionia_buy_card_view_model.dart';
11 import 'package:flutter/material.dart';
12 import 'package:flutter/services.dart';
@@ -44,7 +45,6 @@ class IoniaBuyGiftCardPage extends BasePage {
45
46 @override
47 Widget body(BuildContext context) {
47 - final _width = MediaQuery.of(context).size.width;
48 final merchant = ioniaBuyCardViewModel.ioniaMerchant;
49 return KeyboardActions(
50 disableScroll: true,
@@ -67,7 +67,10 @@ class IoniaBuyGiftCardPage extends BasePage {
67 Container(
68 padding: EdgeInsets.symmetric(horizontal: 25),
69 decoration: BoxDecoration(
70 - borderRadius: BorderRadius.only(bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
70 + borderRadius: BorderRadius.only(
71 + bottomLeft: Radius.circular(24),
72 + bottomRight: Radius.circular(24),
73 + ),
74 gradient: LinearGradient(colors: [
75 Theme.of(context).primaryTextTheme!.subtitle1!.color!,
76 Theme.of(context).primaryTextTheme!.subtitle1!.decorationColor!,
@@ -75,35 +78,28 @@ class IoniaBuyGiftCardPage extends BasePage {
78 ),
79 child: Column(
80 mainAxisSize: MainAxisSize.min,
78 - crossAxisAlignment: CrossAxisAlignment.stretch,
81 mainAxisAlignment: MainAxisAlignment.center,
82 children: [
83 SizedBox(height: 150),
82 - BaseTextFormField(
83 - controller: _amountController,
84 - focusNode: _amountFieldFocus,
85 - keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true),
86 - inputFormatters: [
87 - FilteringTextInputFormatter.deny(RegExp('[\-|\ ]')),
88 - FilteringTextInputFormatter.allow(RegExp(r'^\d+(\.|\,)?\d{0,2}'))],
89 - hintText: '1000',
90 - placeholderTextStyle: TextStyle(
91 - color: Theme.of(context).primaryTextTheme!.headline5!.color!,
92 - fontWeight: FontWeight.w600,
93 - fontSize: 36,
94 - ),
95 - borderColor: Theme.of(context).primaryTextTheme!.headline5!.color!,
96 - textColor: Colors.white,
97 - textStyle: TextStyle(
98 - color: Colors.white,
99 - fontSize: 36,
100 - ),
101 - prefixIcon: Padding(
102 - padding: EdgeInsets.only(
103 - top: 5.0,
104 - left: _width / 4,
84 + SizedBox(
85 + width: 200,
86 + child: BaseTextFormField(
87 + controller: _amountController,
88 + focusNode: _amountFieldFocus,
89 + keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true),
90 + inputFormatters: [
91 + FilteringTextInputFormatter.deny(RegExp('[\-|\ ]')),
92 + FilteringTextInputFormatter.allow(
93 + RegExp(r'^\d+(\.|\,)?\d{0,2}'),
94 + ),
95 + ],
96 + hintText: '1000',
97 + placeholderTextStyle: TextStyle(
98 + color: Theme.of(context).primaryTextTheme.headline5!.color!,
99 + fontWeight: FontWeight.w600,
100 + fontSize: 36,
101 ),
106 - child: Text(
102 + prefixIcon: Text(
103 'USD: ',
104 style: TextStyle(
105 color: Colors.white,
@@ -111,8 +107,17 @@ class IoniaBuyGiftCardPage extends BasePage {
107 fontSize: 36,
108 ),
109 ),
110 + textColor: Colors.white,
111 + textStyle: TextStyle(
112 + color: Colors.white,
113 + fontSize: 36,
114 + ),
115 ),
116 ),
117 + Divider(
118 + color: Theme.of(context).primaryTextTheme.headline5!.color!,
119 + height: 1,
120 + ),
121 SizedBox(height: 8),
122 Row(
123 mainAxisAlignment: MainAxisAlignment.spaceBetween,
@@ -140,7 +145,11 @@ class IoniaBuyGiftCardPage extends BasePage {
145 padding: const EdgeInsets.all(24.0),
146 child: CardItem(
147 title: merchant.legalName,
143 - backgroundColor: Theme.of(context).accentTextTheme!.headline1!.backgroundColor!.withOpacity(0.1),
148 + backgroundColor: Theme.of(context)
149 + .accentTextTheme!
150 + .headline1!
151 + .backgroundColor!
152 + .withOpacity(0.1),
153 discount: merchant.discount,
154 titleColor: Theme.of(context).accentTextTheme!.headline1!.backgroundColor!,
155 subtitleColor: Theme.of(context).hintColor,
lib/src/screens/new_wallet/new_wallet_page.dart
+112 -115
@@ -1,11 +1,12 @@
1 import 'package:cake_wallet/entities/generate_name.dart';
2 +import 'package:cake_wallet/main.dart';
3 import 'package:cake_wallet/routes.dart';
4 import 'package:cake_wallet/themes/theme_base.dart';
5 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
6 import 'package:cake_wallet/utils/show_pop_up.dart';
7 import 'package:mobx/mobx.dart';
8 import 'package:flutter_mobx/flutter_mobx.dart';
9 import 'package:flutter/material.dart';
8 -import 'package:flutter/cupertino.dart';
10 import 'package:cake_wallet/generated/i18n.dart';
11 import 'package:cake_wallet/core/wallet_name_validator.dart';
12 import 'package:cake_wallet/src/widgets/seed_language_selector.dart';
@@ -24,18 +25,14 @@ class NewWalletPage extends BasePage {
25
26 final walletNameImage = Image.asset('assets/images/wallet_name.png');
27
27 - final walletNameLightImage =
28 - Image.asset('assets/images/wallet_name_light.png');
28 + final walletNameLightImage = Image.asset('assets/images/wallet_name_light.png');
29
30 @override
31 String get title => S.current.new_wallet;
32
33 @override
34 Widget body(BuildContext context) => WalletNameForm(
35 - _walletNewVM,
36 - currentTheme.type == ThemeType.dark
37 - ? walletNameImage
38 - : walletNameLightImage);
35 + _walletNewVM, currentTheme.type == ThemeType.dark ? walletNameImage : walletNameLightImage);
36 }
37
38 class WalletNameForm extends StatefulWidget {
@@ -50,9 +47,9 @@ class WalletNameForm extends StatefulWidget {
47
48 class _WalletNameFormState extends State<WalletNameForm> {
49 _WalletNameFormState(this._walletNewVM)
53 - : _formKey = GlobalKey<FormState>(),
54 - _languageSelectorKey = GlobalKey<SeedLanguageSelectorState>(),
55 - _controller = TextEditingController();
50 + : _formKey = GlobalKey<FormState>(),
51 + _languageSelectorKey = GlobalKey<SeedLanguageSelectorState>(),
52 + _controller = TextEditingController();
53
54 static const aspectRatioImage = 1.22;
55
@@ -64,10 +61,9 @@ class _WalletNameFormState extends State<WalletNameForm> {
61
62 @override
63 void initState() {
67 - _stateReaction ??=
68 - reaction((_) => _walletNewVM.state, (ExecutionState state) {
64 + _stateReaction ??= reaction((_) => _walletNewVM.state, (ExecutionState state) async {
65 if (state is ExecutedSuccessfullyState) {
70 - Navigator.of(context)
66 + Navigator.of(navigatorKey.currentContext!)
67 .pushNamed(Routes.preSeed, arguments: _walletNewVM.type);
68 }
69
@@ -90,117 +86,118 @@ class _WalletNameFormState extends State<WalletNameForm> {
86
87 @override
88 Widget build(BuildContext context) {
93 - return Container(
89 + return Padding(
90 padding: EdgeInsets.only(top: 24),
91 child: ScrollableWithBottomSection(
92 contentPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
97 - content:
98 - Column(crossAxisAlignment: CrossAxisAlignment.center, children: [
99 - Padding(
100 - padding: EdgeInsets.only(left: 12, right: 12),
101 - child: AspectRatio(
102 - aspectRatio: aspectRatioImage,
103 - child:
104 - FittedBox(child: widget.walletImage, fit: BoxFit.fill)),
105 - ),
106 - Padding(
107 - padding: EdgeInsets.only(top: 24),
108 - child: Form(
109 - key: _formKey,
110 - child: Stack(
111 - alignment: Alignment.centerRight,
112 - children: [
113 - TextFormField(
114 - onChanged: (value) => _walletNewVM.name = value,
115 - controller: _controller,
116 - textAlign: TextAlign.center,
117 - style: TextStyle(
118 - fontSize: 20.0,
119 - fontWeight: FontWeight.w600,
120 - color:
121 - Theme.of(context).primaryTextTheme!.headline6!.color!),
122 - decoration: InputDecoration(
123 - hintStyle: TextStyle(
124 - fontSize: 18.0,
125 - fontWeight: FontWeight.w500,
126 - color: Theme.of(context)
127 - .accentTextTheme!
128 - .headline2!
129 - .color!),
130 - hintText: S.of(context).wallet_name,
131 - focusedBorder: UnderlineInputBorder(
132 - borderSide: BorderSide(
133 - color: Theme.of(context)
134 - .accentTextTheme!
135 - .headline2!
136 - .decorationColor!,
137 - width: 1.0)),
138 - enabledBorder: UnderlineInputBorder(
139 - borderSide: BorderSide(
140 - color: Theme.of(context)
141 - .accentTextTheme!
142 - .headline2!
143 - .decorationColor!,
144 - width: 1.0),
145 - ),
146 - suffixIcon: IconButton(
147 - onPressed: () async {
148 - final rName = await generateName();
149 - FocusManager.instance.primaryFocus?.unfocus();
150 -
151 - setState(() {
152 - _controller.text = rName;
153 - _walletNewVM.name = rName;
154 - _controller.selection = TextSelection.fromPosition(
155 - TextPosition(offset: _controller.text.length));
156 - });
157 - },
158 - icon: Container(
159 - padding: const EdgeInsets.all(8),
160 - decoration: BoxDecoration(
161 - borderRadius: BorderRadius.circular(6.0),
162 - color: Theme.of(context).hintColor,
163 - ),
164 - width: 34,
165 - height: 34,
166 - child: Image.asset(
167 - 'assets/images/refresh_icon.png',
168 - color: Theme.of(context)
169 - .primaryTextTheme!
170 - .headline4!
171 - .decorationColor!,
93 + content: Center(
94 + child: ConstrainedBox(
95 + constraints:
96 + BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
97 + child: Column(
98 + crossAxisAlignment: CrossAxisAlignment.center,
99 + children: [
100 + Padding(
101 + padding: EdgeInsets.only(left: 12, right: 12),
102 + child: AspectRatio(
103 + aspectRatio: aspectRatioImage,
104 + child: FittedBox(child: widget.walletImage, fit: BoxFit.fill)),
105 + ),
106 + Padding(
107 + padding: EdgeInsets.only(top: 24),
108 + child: Form(
109 + key: _formKey,
110 + child: Stack(
111 + alignment: Alignment.centerRight,
112 + children: [
113 + TextFormField(
114 + onChanged: (value) => _walletNewVM.name = value,
115 + controller: _controller,
116 + textAlign: TextAlign.center,
117 + style: TextStyle(
118 + fontSize: 20.0,
119 + fontWeight: FontWeight.w600,
120 + color: Theme.of(context).primaryTextTheme!.headline6!.color!),
121 + decoration: InputDecoration(
122 + hintStyle: TextStyle(
123 + fontSize: 18.0,
124 + fontWeight: FontWeight.w500,
125 + color: Theme.of(context).accentTextTheme!.headline2!.color!),
126 + hintText: S.of(context).wallet_name,
127 + focusedBorder: UnderlineInputBorder(
128 + borderSide: BorderSide(
129 + color: Theme.of(context)
130 + .accentTextTheme!
131 + .headline2!
132 + .decorationColor!,
133 + width: 1.0)),
134 + enabledBorder: UnderlineInputBorder(
135 + borderSide: BorderSide(
136 + color: Theme.of(context)
137 + .accentTextTheme!
138 + .headline2!
139 + .decorationColor!,
140 + width: 1.0),
141 + ),
142 + suffixIcon: IconButton(
143 + onPressed: () async {
144 + final rName = await generateName();
145 + FocusManager.instance.primaryFocus?.unfocus();
146 +
147 + setState(() {
148 + _controller.text = rName;
149 + _walletNewVM.name = rName;
150 + _controller.selection = TextSelection.fromPosition(
151 + TextPosition(offset: _controller.text.length));
152 + });
153 + },
154 + icon: Container(
155 + padding: const EdgeInsets.all(8),
156 + decoration: BoxDecoration(
157 + borderRadius: BorderRadius.circular(6.0),
158 + color: Theme.of(context).hintColor,
159 + ),
160 + width: 34,
161 + height: 34,
162 + child: Image.asset(
163 + 'assets/images/refresh_icon.png',
164 + color: Theme.of(context)
165 + .primaryTextTheme!
166 + .headline4!
167 + .decorationColor!,
168 + ),
169 + ),
170 + ),
171 ),
172 + validator: WalletNameValidator(),
173 ),
174 - ),
174 + ],
175 ),
176 - validator: WalletNameValidator(),
176 ),
178 - ],
179 - ),
177 + ),
178 + if (_walletNewVM.hasLanguageSelector) ...[
179 + Padding(
180 + padding: EdgeInsets.only(top: 40),
181 + child: Text(
182 + S.of(context).seed_language_choose,
183 + textAlign: TextAlign.center,
184 + style: TextStyle(
185 + fontSize: 16.0,
186 + fontWeight: FontWeight.w500,
187 + color: Theme.of(context).primaryTextTheme!.headline6!.color!),
188 + ),
189 + ),
190 + Padding(
191 + padding: EdgeInsets.only(top: 24),
192 + child: SeedLanguageSelector(
193 + key: _languageSelectorKey, initialSelected: defaultSeedLanguage),
194 + )
195 + ]
196 + ],
197 ),
198 ),
182 - if (_walletNewVM.hasLanguageSelector) ...[
183 - Padding(
184 - padding: EdgeInsets.only(top: 40),
185 - child: Text(
186 - S.of(context).seed_language_choose,
187 - textAlign: TextAlign.center,
188 - style: TextStyle(
189 - fontSize: 16.0,
190 - fontWeight: FontWeight.w500,
191 - color: Theme.of(context).primaryTextTheme!.headline6!.color!),
192 - ),
193 - ),
194 - Padding(
195 - padding: EdgeInsets.only(top: 24),
196 - child: SeedLanguageSelector(
197 - key: _languageSelectorKey,
198 - initialSelected: defaultSeedLanguage),
199 - )
200 - ]
201 - ]),
202 - bottomSectionPadding:
203 - EdgeInsets.all(24),
199 + ),
200 + bottomSectionPadding: EdgeInsets.all(24),
201 bottomSection: Column(
202 children: [
203 Observer(
lib/src/screens/new_wallet/new_wallet_type_page.dart
+46 -49
@@ -1,3 +1,4 @@
1 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
2 import 'package:cw_core/wallet_type.dart';
3 import 'package:cake_wallet/themes/theme_base.dart';
4 import 'package:flutter/material.dart';
@@ -13,23 +14,19 @@ class NewWalletTypePage extends BasePage {
14
15 final void Function(BuildContext, WalletType) onTypeSelected;
16 final walletTypeImage = Image.asset('assets/images/wallet_type.png');
16 - final walletTypeLightImage =
17 - Image.asset('assets/images/wallet_type_light.png');
17 + final walletTypeLightImage = Image.asset('assets/images/wallet_type_light.png');
18
19 @override
20 String get title => S.current.wallet_list_restore_wallet;
21
22 @override
23 Widget body(BuildContext context) => WalletTypeForm(
24 - onTypeSelected: onTypeSelected,
25 - walletImage: currentTheme.type == ThemeType.dark
26 - ? walletTypeImage
27 - : walletTypeLightImage);
24 + onTypeSelected: onTypeSelected,
25 + walletImage: currentTheme.type == ThemeType.dark ? walletTypeImage : walletTypeLightImage);
26 }
27
28 class WalletTypeForm extends StatefulWidget {
31 - WalletTypeForm({required this.onTypeSelected,
32 - required this.walletImage});
29 + WalletTypeForm({required this.onTypeSelected, required this.walletImage});
30
31 final void Function(BuildContext, WalletType) onTypeSelected;
32 final Image walletImage;
@@ -39,22 +36,16 @@ class WalletTypeForm extends StatefulWidget {
36 }
37
38 class WalletTypeFormState extends State<WalletTypeForm> {
42 - WalletTypeFormState()
43 - : types = availableWalletTypes;
39 + WalletTypeFormState() : types = availableWalletTypes;
40
41 static const aspectRatioImage = 1.22;
42
47 - final moneroIcon =
48 - Image.asset('assets/images/monero_logo.png', height: 24, width: 24);
49 - final bitcoinIcon =
50 - Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
51 - final litecoinIcon =
52 - Image.asset('assets/images/litecoin_icon.png', height: 24, width: 24);
43 + final moneroIcon = Image.asset('assets/images/monero_logo.png', height: 24, width: 24);
44 + final bitcoinIcon = Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
45 + final litecoinIcon = Image.asset('assets/images/litecoin_icon.png', height: 24, width: 24);
46 final walletTypeImage = Image.asset('assets/images/wallet_type.png');
54 - final walletTypeLightImage =
55 - Image.asset('assets/images/wallet_type_light.png');
56 - final havenIcon =
57 - Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
47 + final walletTypeLightImage = Image.asset('assets/images/wallet_type_light.png');
48 + final havenIcon = Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
49
50 WalletType? selected;
51 List<WalletType> types;
@@ -69,35 +60,40 @@ class WalletTypeFormState extends State<WalletTypeForm> {
60 Widget build(BuildContext context) {
61 return ScrollableWithBottomSection(
62 contentPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
72 - content: Column(
73 - crossAxisAlignment: CrossAxisAlignment.center,
74 - children: <Widget>[
75 - Padding(
76 - padding: EdgeInsets.only(left: 12, right: 12),
77 - child: AspectRatio(
78 - aspectRatio: aspectRatioImage,
79 - child: FittedBox(child: widget.walletImage, fit: BoxFit.fill)),
63 + content: Center(
64 + child: ConstrainedBox(
65 + constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
66 + child: Column(
67 + crossAxisAlignment: CrossAxisAlignment.center,
68 + children: <Widget>[
69 + Padding(
70 + padding: EdgeInsets.only(left: 12, right: 12),
71 + child: AspectRatio(
72 + aspectRatio: aspectRatioImage,
73 + child: FittedBox(child: widget.walletImage, fit: BoxFit.fill)),
74 + ),
75 + Padding(
76 + padding: EdgeInsets.only(top: 48),
77 + child: Text(
78 + S.of(context).choose_wallet_currency,
79 + textAlign: TextAlign.center,
80 + style: TextStyle(
81 + fontSize: 16,
82 + fontWeight: FontWeight.w500,
83 + color: Theme.of(context).primaryTextTheme.headline6!.color!),
84 + ),
85 + ),
86 + ...types.map((type) => Padding(
87 + padding: EdgeInsets.only(top: 24),
88 + child: SelectButton(
89 + image: _iconFor(type),
90 + text: walletTypeToDisplayName(type),
91 + isSelected: selected == type,
92 + onTap: () => setState(() => selected = type)),
93 + ))
94 + ],
95 ),
81 - Padding(
82 - padding: EdgeInsets.only(top: 48),
83 - child: Text(
84 - S.of(context).choose_wallet_currency,
85 - textAlign: TextAlign.center,
86 - style: TextStyle(
87 - fontSize: 16,
88 - fontWeight: FontWeight.w500,
89 - color: Theme.of(context).primaryTextTheme.headline6!.color!),
90 - ),
91 - ),
92 - ...types.map((type) => Padding(
93 - padding: EdgeInsets.only(top: 24),
94 - child: SelectButton(
95 - image: _iconFor(type),
96 - text: walletTypeToDisplayName(type),
97 - isSelected: selected == type,
98 - onTap: () => setState(() => selected = type)),
99 - ))
100 - ],
96 + ),
97 ),
98 bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
99 bottomSection: PrimaryButton(
@@ -121,7 +117,8 @@ class WalletTypeFormState extends State<WalletTypeForm> {
117 case WalletType.haven:
118 return havenIcon;
119 default:
124 - throw Exception('_iconFor: Incorrect Wallet Type. Cannot find icon for Wallet Type: ${type.toString()}');
120 + throw Exception(
121 + '_iconFor: Incorrect Wallet Type. Cannot find icon for Wallet Type: ${type.toString()}');
122 }
123 }
124
lib/src/screens/nodes/node_create_or_edit_page.dart
-1
@@ -4,7 +4,6 @@ import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
4 import 'package:cake_wallet/utils/show_pop_up.dart';
5 import 'package:cw_core/node.dart';
6 import 'package:flutter/material.dart';
7 -import 'package:flutter/cupertino.dart';
7 import 'package:flutter_mobx/flutter_mobx.dart';
8 import 'package:mobx/mobx.dart';
9 import 'package:cake_wallet/generated/i18n.dart';
lib/src/screens/pin_code/pin_code_widget.dart
+193 -166
@@ -1,17 +1,19 @@
1 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
2 import 'package:cake_wallet/utils/show_bar.dart';
3 import 'package:another_flushbar/flushbar.dart';
4 import 'package:flutter/material.dart';
5 import 'package:cake_wallet/generated/i18n.dart';
6 +import 'package:flutter/services.dart';
7
8 class PinCodeWidget extends StatefulWidget {
7 - PinCodeWidget(
8 - {required Key key,
9 - required this.onFullPin,
10 - required this.initialPinLength,
11 - required this.onChangedPin,
12 - required this.hasLengthSwitcher,
13 - this.onChangedPinLength,})
14 - : super(key: key);
9 + PinCodeWidget({
10 + required Key key,
11 + required this.onFullPin,
12 + required this.initialPinLength,
13 + required this.onChangedPin,
14 + required this.hasLengthSwitcher,
15 + this.onChangedPinLength,
16 + }) : super(key: key);
17
18 final void Function(String pin, PinCodeState state) onFullPin;
19 final void Function(String pin) onChangedPin;
@@ -25,10 +27,10 @@ class PinCodeWidget extends StatefulWidget {
27
28 class PinCodeState<T extends PinCodeWidget> extends State<T> {
29 PinCodeState()
28 - : _aspectRatio = 0,
29 - pinLength = 0,
30 - pin = '',
31 - title = '';
30 + : _aspectRatio = 0,
31 + pinLength = 0,
32 + pin = '',
33 + title = '';
34 static const defaultPinLength = fourPinLength;
35 static const sixPinLength = 6;
36 static const fourPinLength = 4;
@@ -75,8 +77,7 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
77 void setDefaultPinLength() => changePinLength(widget.initialPinLength);
78
79 void calculateAspectRatio() {
78 - final renderBox =
79 - _gridViewKey.currentContext!.findRenderObject() as RenderBox;
80 + final renderBox = _gridViewKey.currentContext!.findRenderObject() as RenderBox;
81 final cellWidth = renderBox.size.width / 3;
82 final cellHeight = renderBox.size.height / 4;
83
@@ -89,8 +90,7 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
90
91 void changeProcessText(String text) {
92 hideProgressText();
92 - _progressBar = createBar<void>(text, duration: null)
93 - ..show(_key.currentContext!);
93 + _progressBar = createBar<void>(text, duration: null)..show(_key.currentContext!);
94 }
95
96 void close() {
@@ -104,8 +104,8 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
104 }
105
106 @override
107 - Widget build(BuildContext context) => Scaffold(
108 - key: _key, body: body(context), resizeToAvoidBottomInset: false);
107 + Widget build(BuildContext context) =>
108 + Scaffold(key: _key, body: body(context), resizeToAvoidBottomInset: false);
109
110 Widget body(BuildContext context) {
111 final deleteIconImage = Image.asset(
@@ -117,157 +117,184 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
117 color: Theme.of(context).primaryTextTheme!.headline6!.color!,
118 );
119
120 - return Container(
121 - color: Theme.of(context).backgroundColor,
122 - padding: EdgeInsets.only(left: 40.0, right: 40.0, bottom: 40.0),
123 - child: Column(children: <Widget>[
124 - Spacer(flex: 2),
125 - Text(title,
126 - style: TextStyle(
127 - fontSize: 20,
128 - fontWeight: FontWeight.w500,
129 - color: Theme.of(context).primaryTextTheme!.headline6!.color!)),
130 - Spacer(flex: 3),
131 - Container(
132 - width: 180,
133 - child: Row(
134 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
135 - children: List.generate(pinLength, (index) {
136 - const size = 10.0;
137 - final isFilled = pin.length > index ? pin[index] != null : false;
138 -
139 - return Container(
140 - width: size,
141 - height: size,
142 - decoration: BoxDecoration(
143 - shape: BoxShape.circle,
144 - color: isFilled
145 - ? Theme.of(context).primaryTextTheme!.headline6!.color!
146 - : Theme.of(context)
147 - .accentTextTheme!
148 - .bodyText2!
149 - .color!
150 - .withOpacity(0.25),
151 - ));
152 - }),
153 - ),
154 - ),
155 - Spacer(flex: 2),
156 - if (widget.hasLengthSwitcher) ...[
157 - TextButton(
158 - onPressed: () {
159 - changePinLength(pinLength == PinCodeState.fourPinLength
160 - ? PinCodeState.sixPinLength
161 - : PinCodeState.fourPinLength);
162 - },
163 - child: Text(
164 - _changePinLengthText(),
120 + return RawKeyboardListener(
121 + focusNode: FocusNode(),
122 + autofocus: true,
123 + onKey: (keyEvent) {
124 + if (keyEvent is RawKeyDownEvent) {
125 + if (keyEvent.logicalKey.keyLabel == "Backspace") {
126 + _pop();
127 + return;
128 + }
129 + int? number = int.tryParse(keyEvent.character ?? '');
130 + if (number != null) {
131 + _push(number);
132 + }
133 + }
134 + },
135 + child: Container(
136 + color: Theme.of(context).backgroundColor,
137 + padding: EdgeInsets.only(left: 40.0, right: 40.0, bottom: 40.0),
138 + child: Column(
139 + children: <Widget>[
140 + Spacer(flex: 2),
141 + Text(title,
142 style: TextStyle(
166 - fontSize: 14.0,
167 - fontWeight: FontWeight.normal,
168 - color: Theme.of(context)
169 - .accentTextTheme!
170 - .bodyText2!
171 - .decorationColor!),
172 - ))
173 - ],
174 - Spacer(flex: 1),
175 - Flexible(
176 - flex: 24,
177 - child: Container(
178 - key: _gridViewKey,
179 - child: _aspectRatio > 0
180 - ? GridView.count(
181 - shrinkWrap: true,
182 - crossAxisCount: 3,
183 - childAspectRatio: _aspectRatio,
184 - physics: const NeverScrollableScrollPhysics(),
185 - children: List.generate(12, (index) {
186 - const double marginRight = 15;
187 - const double marginLeft = 15;
188 -
189 - if (index == 9) {
190 - return Container(
191 - margin: EdgeInsets.only(
192 - left: marginLeft, right: marginRight),
193 - child: TextButton(
194 - onPressed: () => null,
195 - // (widget.hasLengthSwitcher ||
196 - // !settingsStore
197 - // .allowBiometricalAuthentication)
198 - // ? null
199 - // : () {
200 - // FIXME
201 -// if (authStore != null) {
202 -// WidgetsBinding.instance.addPostFrameCallback((_) {
203 -// final biometricAuth = BiometricAuth();
204 -// biometricAuth.isAuthenticated().then(
205 -// (isAuth) {
206 -// if (isAuth) {
207 -// authStore.biometricAuth();
208 -// _key.currentState.showSnackBar(
209 -// SnackBar(
210 -// content: Text(S.of(context).authenticated),
211 -// backgroundColor: Colors.green,
212 -// ),
213 -// );
214 -// }
215 -// }
216 -// );
217 -// });
218 -// }
219 -// },
220 - // FIX-ME: Style
221 - //color: Theme.of(context).backgroundColor,
222 - //shape: CircleBorder(),
223 - child: Container()
224 - // (widget.hasLengthSwitcher ||
225 - // !settingsStore
226 - // .allowBiometricalAuthentication)
227 - // ? Offstage()
228 - // : faceImage,
143 + fontSize: 20,
144 + fontWeight: FontWeight.w500,
145 + color: Theme.of(context).primaryTextTheme!.headline6!.color!)),
146 + Spacer(flex: 3),
147 + Container(
148 + width: 180,
149 + child: Row(
150 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
151 + children: List.generate(pinLength, (index) {
152 + const size = 10.0;
153 + final isFilled = pin.length > index ? pin[index] != null : false;
154 +
155 + return Container(
156 + width: size,
157 + height: size,
158 + decoration: BoxDecoration(
159 + shape: BoxShape.circle,
160 + color: isFilled
161 + ? Theme.of(context).primaryTextTheme!.headline6!.color!
162 + : Theme.of(context)
163 + .accentTextTheme!
164 + .bodyText2!
165 + .color!
166 + .withOpacity(0.25),
167 + ));
168 + }),
169 + ),
170 + ),
171 + Spacer(flex: 2),
172 + if (widget.hasLengthSwitcher) ...[
173 + TextButton(
174 + onPressed: () {
175 + changePinLength(pinLength == PinCodeState.fourPinLength
176 + ? PinCodeState.sixPinLength
177 + : PinCodeState.fourPinLength);
178 + },
179 + child: Text(
180 + _changePinLengthText(),
181 + style: TextStyle(
182 + fontSize: 14.0,
183 + fontWeight: FontWeight.normal,
184 + color: Theme.of(context).accentTextTheme!.bodyText2!.decorationColor!),
185 + ),
186 + )
187 + ],
188 + Spacer(flex: 1),
189 + Flexible(
190 + flex: 24,
191 + child: Center(
192 + child: ConstrainedBox(
193 + constraints: BoxConstraints(
194 + maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint,
195 + ),
196 + child: Container(
197 + key: _gridViewKey,
198 + child: _aspectRatio > 0
199 + ? ScrollConfiguration(
200 + behavior: ScrollConfiguration.of(context).copyWith(scrollbars: false),
201 + child: GridView.count(
202 + shrinkWrap: true,
203 + crossAxisCount: 3,
204 + childAspectRatio: _aspectRatio,
205 + physics: const NeverScrollableScrollPhysics(),
206 + children: List.generate(12, (index) {
207 + const double marginRight = 15;
208 + const double marginLeft = 15;
209 +
210 + if (index == 9) {
211 + return Container(
212 + margin: EdgeInsets.only(left: marginLeft, right: marginRight),
213 + child: TextButton(
214 + onPressed: () => null,
215 + // (widget.hasLengthSwitcher ||
216 + // !settingsStore
217 + // .allowBiometricalAuthentication)
218 + // ? null
219 + // : () {
220 + // FIXME
221 + // if (authStore != null) {
222 + // WidgetsBinding.instance.addPostFrameCallback((_) {
223 + // final biometricAuth = BiometricAuth();
224 + // biometricAuth.isAuthenticated().then(
225 + // (isAuth) {
226 + // if (isAuth) {
227 + // authStore.biometricAuth();
228 + // _key.currentState.showSnackBar(
229 + // SnackBar(
230 + // content: Text(S.of(context).authenticated),
231 + // backgroundColor: Colors.green,
232 + // ),
233 + // );
234 + // }
235 + // }
236 + // );
237 + // });
238 + // }
239 + // },
240 + // FIX-ME: Style
241 + //color: Theme.of(context).backgroundColor,
242 + //shape: CircleBorder(),
243 + child: Container()
244 + // (widget.hasLengthSwitcher ||
245 + // !settingsStore
246 + // .allowBiometricalAuthentication)
247 + // ? Offstage()
248 + // : faceImage,
249 + ),
250 + );
251 + } else if (index == 10) {
252 + index = 0;
253 + } else if (index == 11) {
254 + return Container(
255 + margin: EdgeInsets.only(left: marginLeft, right: marginRight),
256 + child: TextButton(
257 + onPressed: () => _pop(),
258 + style: TextButton.styleFrom(
259 + backgroundColor: Theme.of(context).backgroundColor,
260 + shape: CircleBorder(),
261 + ),
262 + child: deleteIconImage,
263 + ),
264 + );
265 + } else {
266 + index++;
267 + }
268 +
269 + return Container(
270 + margin: EdgeInsets.only(left: marginLeft, right: marginRight),
271 + child: TextButton(
272 + onPressed: () => _push(index),
273 + style: TextButton.styleFrom(
274 + backgroundColor: Theme.of(context).backgroundColor,
275 + shape: CircleBorder(),
276 + ),
277 + child: Text('$index',
278 + style: TextStyle(
279 + fontSize: 30.0,
280 + fontWeight: FontWeight.w600,
281 + color: Theme.of(context)
282 + .primaryTextTheme!
283 + .headline6!
284 + .color!)),
285 ),
230 - );
231 - } else if (index == 10) {
232 - index = 0;
233 - } else if (index == 11) {
234 - return Container(
235 - margin: EdgeInsets.only(
236 - left: marginLeft, right: marginRight),
237 - child: TextButton(
238 - onPressed: () => _pop(),
239 - // FIX-ME: Style
240 - //color: Theme.of(context).backgroundColor,
241 - //shape: CircleBorder(),
242 - child: deleteIconImage,
243 - ),
244 - );
245 - } else {
246 - index++;
247 - }
248 -
249 - return Container(
250 - margin: EdgeInsets.only(
251 - left: marginLeft, right: marginRight),
252 - child: TextButton(
253 - onPressed: () => _push(index),
254 - // FIX-ME: Style
255 - //color: Theme.of(context).backgroundColor,
256 - //shape: CircleBorder(),
257 - child: Text('$index',
258 - style: TextStyle(
259 - fontSize: 30.0,
260 - fontWeight: FontWeight.w600,
261 - color: Theme.of(context)
262 - .primaryTextTheme!
263 - .headline6!
264 - .color!)),
286 + );
287 + }),
288 ),
266 - );
267 - }),
268 - )
269 - : null))
270 - ]),
289 + )
290 + : null,
291 + ),
292 + ),
293 + ),
294 + )
295 + ],
296 + ),
297 + ),
298 );
299 }
300
lib/src/screens/receive/anonpay_invoice_page.dart
+3 -3
@@ -8,6 +8,7 @@ import 'package:cake_wallet/src/screens/dashboard/widgets/present_receive_option
8 import 'package:cake_wallet/src/screens/receive/widgets/anonpay_input_form.dart';
9 import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
10 import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
11 +import 'package:cake_wallet/utils/device_info.dart';
12 import 'package:cake_wallet/view_model/anon_invoice_page_view_model.dart';
13 import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
14 import 'package:flutter/material.dart';
@@ -85,7 +86,7 @@ class AnonPayInvoicePage extends BasePage {
86 child: ScrollableWithBottomSection(
87 contentPadding: EdgeInsets.only(bottom: 24),
88 content: Container(
88 - decoration: BoxDecoration(
89 + decoration: DeviceInfo.instance.isMobile ? BoxDecoration(
90 borderRadius: BorderRadius.only(
91 bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
92 gradient: LinearGradient(
@@ -96,7 +97,7 @@ class AnonPayInvoicePage extends BasePage {
97 begin: Alignment.topLeft,
98 end: Alignment.bottomRight,
99 ),
99 - ),
100 + ) : null,
101 child: Observer(builder: (_) {
102 return Padding(
103 padding: EdgeInsets.fromLTRB(24, 120, 24, 0),
@@ -174,7 +175,6 @@ class AnonPayInvoicePage extends BasePage {
175 }
176
177 reaction((_) => receiveOptionViewModel.selectedReceiveOption, (ReceivePageOption option) {
177 - Navigator.pop(context);
178 switch (option) {
179 case ReceivePageOption.mainnet:
180 Navigator.popAndPushNamed(context, Routes.addressPage);
lib/src/screens/receive/widgets/qr_widget.dart
+43 -31
@@ -1,4 +1,5 @@
1 import 'package:cake_wallet/routes.dart';
2 +import 'package:cake_wallet/utils/device_info.dart';
3 import 'package:cake_wallet/utils/show_bar.dart';
4 import 'package:cw_core/wallet_type.dart';
5 import 'package:device_display_brightness/device_display_brightness.dart';
@@ -35,7 +36,7 @@ class QRWidget extends StatelessWidget {
36 @override
37 Widget build(BuildContext context) {
38 final copyImage = Image.asset('assets/images/copy_address.png',
38 - color: Theme.of(context).textTheme!.subtitle1!.decorationColor!);
39 + color: Theme.of(context).textTheme.subtitle1!.decorationColor!);
40
41 return Column(
42 mainAxisSize: MainAxisSize.min,
@@ -51,23 +52,18 @@ class QRWidget extends StatelessWidget {
52 style: TextStyle(
53 fontSize: 14,
54 fontWeight: FontWeight.w500,
54 - color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!),
55 + color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!),
56 ),
57 ),
58 Row(
59 children: <Widget>[
60 Spacer(flex: 3),
61 Observer(
61 - builder: (_) {
62 - return Flexible(
63 - flex: 5,
64 - child: GestureDetector(
65 - onTap: () async {
66 - // Get the current brightness:
67 - final double brightness = await DeviceDisplayBrightness.getBrightness();
68 -
69 - // ignore: unawaited_futures
70 - DeviceDisplayBrightness.setBrightness(1.0);
62 + builder: (_) => Flexible(
63 + flex: 5,
64 + child: GestureDetector(
65 + onTap: () {
66 + changeBrightnessForRoute(() async {
67 await Navigator.pushNamed(
68 context,
69 Routes.fullscreenQR,
@@ -75,31 +71,28 @@ class QRWidget extends StatelessWidget {
71 'qrData': addressListViewModel.uri.toString(),
72 },
73 );
78 - // ignore: unawaited_futures
79 - DeviceDisplayBrightness.setBrightness(brightness);
80 - },
81 - child: Hero(
82 - tag: Key(addressListViewModel.uri.toString()),
83 - child: Center(
84 - child: AspectRatio(
85 - aspectRatio: 1.0,
86 - child: Container(
87 - padding: EdgeInsets.all(5),
88 - decoration: BoxDecoration(
89 - border: Border.all(
90 - width: 3,
91 - color:
92 - Theme.of(context).accentTextTheme!.headline2!.backgroundColor!,
93 - ),
74 + });
75 + },
76 + child: Hero(
77 + tag: Key(addressListViewModel.uri.toString()),
78 + child: Center(
79 + child: AspectRatio(
80 + aspectRatio: 1.0,
81 + child: Container(
82 + padding: EdgeInsets.all(5),
83 + decoration: BoxDecoration(
84 + border: Border.all(
85 + width: 3,
86 + color: Theme.of(context).accentTextTheme.headline2!.backgroundColor!,
87 ),
95 - child: QrImage(data: addressListViewModel.uri.toString(), version: qrVersion),
88 ),
89 + child: QrImage(data: addressListViewModel.uri.toString()),
90 ),
91 ),
92 ),
93 ),
101 - );
102 - }
94 + ),
95 + ),
96 ),
97 Spacer(flex: 3)
98 ],
@@ -176,4 +169,23 @@ class QRWidget extends StatelessWidget {
169 ],
170 );
171 }
172 +
173 + Future<void> changeBrightnessForRoute(Future<void> Function() navigation) async {
174 + // if not mobile, just navigate
175 + if (!DeviceInfo.instance.isMobile) {
176 + navigation();
177 + return;
178 + }
179 +
180 + // Get the current brightness:
181 + final brightness = await DeviceDisplayBrightness.getBrightness();
182 +
183 + // ignore: unawaited_futures
184 + DeviceDisplayBrightness.setBrightness(1.0);
185 +
186 + await navigation();
187 +
188 + // ignore: unawaited_futures
189 + DeviceDisplayBrightness.setBrightness(brightness);
190 + }
191 }
lib/src/screens/restore/restore_from_backup_page.dart
+43 -37
@@ -1,6 +1,7 @@
1 import 'package:cake_wallet/core/execution_state.dart';
2 import 'package:cake_wallet/generated/i18n.dart';
3 import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
4 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
5 import 'package:cake_wallet/utils/show_pop_up.dart';
6 import 'package:flutter/material.dart';
7 import 'package:flutter/src/widgets/framework.dart';
@@ -39,43 +40,48 @@ class RestoreFromBackupPage extends BasePage {
40 }
41 });
42
42 - return Container(
43 - padding: EdgeInsets.only(bottom: 24, left: 24, right: 24),
44 - child: Column(children: [
45 - Expanded(
46 - child: Container(
47 - child: Center(
48 - child: TextFormField(
49 - obscureText: true,
50 - enableSuggestions: false,
51 - autocorrect: false,
52 - decoration: InputDecoration(
53 - hintText: S.of(context).enter_backup_password),
54 - keyboardType: TextInputType.visiblePassword,
55 - controller: textEditingController,
56 - style: TextStyle(fontSize: 26, color: Colors.black))),
57 - ),
58 - ),
59 - Container(
60 - child: Row(children: [
61 - Expanded(
62 - child: PrimaryButton(
63 - onPressed: () => presentFilePicker(),
64 - text: S.of(context).select_backup_file,
65 - color: Colors.grey,
66 - textColor: Colors.white)),
67 - SizedBox(width: 20),
68 - Expanded(child: Observer(builder: (_) {
69 - return LoadingPrimaryButton(
70 - isLoading:
71 - restoreFromBackupViewModel.state is IsExecutingState,
72 - onPressed: () => onImportHandler(context),
73 - text: S.of(context).import,
74 - color: Theme.of(context).accentTextTheme!.bodyText1!.color!,
75 - textColor: Colors.white);
76 - }))
77 - ])),
78 - ]));
43 + return Center(
44 + child: ConstrainedBox(
45 + constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
46 + child: Padding(
47 + padding: EdgeInsets.only(bottom: 24, left: 24, right: 24),
48 + child: Column(children: [
49 + Expanded(
50 + child: Container(
51 + child: Center(
52 + child: TextFormField(
53 + obscureText: true,
54 + enableSuggestions: false,
55 + autocorrect: false,
56 + decoration: InputDecoration(
57 + hintText: S.of(context).enter_backup_password),
58 + keyboardType: TextInputType.visiblePassword,
59 + controller: textEditingController,
60 + style: TextStyle(fontSize: 26, color: Colors.black))),
61 + ),
62 + ),
63 + Container(
64 + child: Row(children: [
65 + Expanded(
66 + child: PrimaryButton(
67 + onPressed: () => presentFilePicker(),
68 + text: S.of(context).select_backup_file,
69 + color: Colors.grey,
70 + textColor: Colors.white)),
71 + SizedBox(width: 20),
72 + Expanded(child: Observer(builder: (_) {
73 + return LoadingPrimaryButton(
74 + isLoading:
75 + restoreFromBackupViewModel.state is IsExecutingState,
76 + onPressed: () => onImportHandler(context),
77 + text: S.of(context).import,
78 + color: Theme.of(context).accentTextTheme!.bodyText1!.color!,
79 + textColor: Colors.white);
80 + }))
81 + ])),
82 + ])),
83 + ),
84 + );
85 }
86
87 Future<void> presentFilePicker() async {
lib/src/screens/restore/restore_options_page.dart
+28 -25
@@ -1,3 +1,4 @@
1 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
2 import 'package:flutter/material.dart';
3 import 'package:cake_wallet/routes.dart';
4 import 'package:flutter/cupertino.dart';
@@ -18,31 +19,33 @@ class RestoreOptionsPage extends BasePage {
19
20 @override
21 Widget body(BuildContext context) {
21 - return Container(
22 - width: double.infinity,
23 - height: double.infinity,
24 - padding: EdgeInsets.all(24),
25 - child: SingleChildScrollView(
26 - child: Column(
27 - children: <Widget>[
28 - RestoreButton(
29 - onPressed: () =>
30 - Navigator.pushNamed(context, Routes.restoreWalletOptionsFromWelcome),
31 - image: imageSeedKeys,
32 - title: S.of(context).restore_title_from_seed_keys,
33 - description:
34 - S.of(context).restore_description_from_seed_keys),
35 - Padding(
36 - padding: EdgeInsets.only(top: 24),
37 - child: RestoreButton(
22 + return Center(
23 + child: Container(
24 + width: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint,
25 + height: double.infinity,
26 + padding: EdgeInsets.symmetric(vertical: 24),
27 + child: SingleChildScrollView(
28 + child: Column(
29 + children: <Widget>[
30 + RestoreButton(
31 onPressed: () =>
39 - Navigator.pushNamed(context, Routes.restoreFromBackup),
40 - image: imageBackup,
41 - title: S.of(context).restore_title_from_backup,
42 - description: S.of(context).restore_description_from_backup),
43 - )
44 - ],
45 - ),
46 - ));
32 + Navigator.pushNamed(context, Routes.restoreWalletOptionsFromWelcome),
33 + image: imageSeedKeys,
34 + title: S.of(context).restore_title_from_seed_keys,
35 + description:
36 + S.of(context).restore_description_from_seed_keys),
37 + Padding(
38 + padding: EdgeInsets.only(top: 24),
39 + child: RestoreButton(
40 + onPressed: () =>
41 + Navigator.pushNamed(context, Routes.restoreFromBackup),
42 + image: imageBackup,
43 + title: S.of(context).restore_title_from_backup,
44 + description: S.of(context).restore_description_from_backup),
45 + )
46 + ],
47 + ),
48 + )),
49 + );
50 }
51 }
lib/src/screens/restore/wallet_restore_page.dart
+115 -127
@@ -1,5 +1,6 @@
1 import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
2 import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
3 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
4 import 'package:cw_core/wallet_type.dart';
5 import 'package:flutter/cupertino.dart';
6 import 'package:flutter/material.dart';
@@ -23,10 +24,8 @@ import 'package:cake_wallet/core/seed_validator.dart';
24
25 class WalletRestorePage extends BasePage {
26 WalletRestorePage(this.walletRestoreViewModel)
26 - : walletRestoreFromSeedFormKey =
27 - GlobalKey<WalletRestoreFromSeedFormState>(),
28 - walletRestoreFromKeysFormKey =
29 - GlobalKey<WalletRestoreFromKeysFromState>(),
27 + : walletRestoreFromSeedFormKey = GlobalKey<WalletRestoreFromSeedFormState>(),
28 + walletRestoreFromKeysFormKey = GlobalKey<WalletRestoreFromKeysFromState>(),
29 _pages = [],
30 _blockHeightFocusNode = FocusNode(),
31 _controller = PageController(initialPage: 0) {
@@ -36,9 +35,8 @@ class WalletRestorePage extends BasePage {
35 _pages.add(WalletRestoreFromSeedForm(
36 displayBlockHeightSelector:
37 walletRestoreViewModel.hasBlockchainHeightLanguageSelector,
39 - displayLanguageSelector:
40 - walletRestoreViewModel.hasSeedLanguageSelector,
41 - type: walletRestoreViewModel.type!,
38 + displayLanguageSelector: walletRestoreViewModel.hasSeedLanguageSelector,
39 + type: walletRestoreViewModel.type,
40 key: walletRestoreFromSeedFormKey,
41 blockHeightFocusNode: _blockHeightFocusNode,
42 onHeightOrDateEntered: (value) {
@@ -48,26 +46,22 @@ class WalletRestorePage extends BasePage {
46 },
47 onSeedChange: (String seed) {
48 if (walletRestoreViewModel.hasBlockchainHeightLanguageSelector) {
51 - final hasHeight = walletRestoreFromSeedFormKey
52 - .currentState!.blockchainHeightKey.currentState!.restoreHeightController
53 - .text
54 - .isNotEmpty;
49 + final hasHeight = walletRestoreFromSeedFormKey.currentState!.blockchainHeightKey
50 + .currentState!.restoreHeightController.text.isNotEmpty;
51 if (hasHeight) {
52 walletRestoreViewModel.isButtonEnabled = _isValidSeed();
53 }
54 } else {
59 - walletRestoreViewModel.isButtonEnabled = _isValidSeed();
55 + walletRestoreViewModel.isButtonEnabled = _isValidSeed();
56 }
57 },
58 onLanguageChange: (_) {
59 if (walletRestoreViewModel.hasBlockchainHeightLanguageSelector) {
64 - final hasHeight = walletRestoreFromSeedFormKey
65 - .currentState!.blockchainHeightKey.currentState!.restoreHeightController
66 - .text
67 - .isNotEmpty;
60 + final hasHeight = walletRestoreFromSeedFormKey.currentState!.blockchainHeightKey
61 + .currentState!.restoreHeightController.text.isNotEmpty;
62
63 if (hasHeight) {
70 - walletRestoreViewModel.isButtonEnabled = _isValidSeed();
64 + walletRestoreViewModel.isButtonEnabled = _isValidSeed();
65 }
66 } else {
67 walletRestoreViewModel.isButtonEnabled = _isValidSeed();
@@ -78,8 +72,7 @@ class WalletRestorePage extends BasePage {
72 _pages.add(WalletRestoreFromKeysFrom(
73 key: walletRestoreFromKeysFormKey,
74 walletRestoreViewModel: walletRestoreViewModel,
81 - onHeightOrDateEntered: (value) =>
82 - walletRestoreViewModel.isButtonEnabled = value));
75 + onHeightOrDateEntered: (value) => walletRestoreViewModel.isButtonEnabled = value));
76 break;
77 default:
78 break;
@@ -97,8 +90,7 @@ class WalletRestorePage extends BasePage {
90 fontSize: 18.0,
91 fontWeight: FontWeight.bold,
92 fontFamily: 'Lato',
100 - color: titleColor ??
101 - Theme.of(context).primaryTextTheme!.headline6!.color!),
93 + color: titleColor ?? Theme.of(context).primaryTextTheme.headline6!.color!),
94 ));
95
96 final WalletRestoreViewModel walletRestoreViewModel;
@@ -129,134 +121,134 @@ class WalletRestorePage extends BasePage {
121 reaction((_) => walletRestoreViewModel.mode, (WalletRestoreMode mode) {
122 walletRestoreViewModel.isButtonEnabled = false;
123
132 - walletRestoreFromSeedFormKey.currentState!.blockchainHeightKey.currentState
133 - !.restoreHeightController.text = '';
134 - walletRestoreFromSeedFormKey.currentState!.blockchainHeightKey.currentState
135 - !.dateController.text = '';
124 + walletRestoreFromSeedFormKey
125 + .currentState!.blockchainHeightKey.currentState!.restoreHeightController.text = '';
126 + walletRestoreFromSeedFormKey
127 + .currentState!.blockchainHeightKey.currentState!.dateController.text = '';
128 walletRestoreFromSeedFormKey.currentState!.nameTextEditingController.text = '';
129
138 - walletRestoreFromKeysFormKey.currentState!.blockchainHeightKey.currentState
139 - !.restoreHeightController.text = '';
140 - walletRestoreFromKeysFormKey.currentState!.blockchainHeightKey.currentState
141 - !.dateController.text = '';
130 + walletRestoreFromKeysFormKey
131 + .currentState!.blockchainHeightKey.currentState!.restoreHeightController.text = '';
132 + walletRestoreFromKeysFormKey
133 + .currentState!.blockchainHeightKey.currentState!.dateController.text = '';
134 walletRestoreFromKeysFormKey.currentState!.nameTextEditingController.text = '';
135 });
136
137 return KeyboardActions(
146 - config: KeyboardActionsConfig(
147 - keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
148 - keyboardBarColor: Theme.of(context).accentTextTheme!.bodyText1!
149 - .backgroundColor!,
150 - nextFocus: false,
151 - actions: [
152 - KeyboardActionsItem(
153 - focusNode: _blockHeightFocusNode,
154 - toolbarButtons: [(_) => KeyboardDoneButton()],
155 - )
156 - ]),
157 - child: Container(
158 - height: 0,
159 - color: Theme.of(context).backgroundColor,
160 - child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
161 - Expanded(
162 - child: PageView.builder(
163 - onPageChanged: (page) {
164 - walletRestoreViewModel.mode =
165 - page == 0 ? WalletRestoreMode.seed : WalletRestoreMode.keys;
166 - },
167 - controller: _controller,
168 - itemCount: _pages.length,
169 - itemBuilder: (_, index) =>
170 - SingleChildScrollView(child: _pages[index]))),
171 - if (_pages.length > 1)
172 - Padding(
173 - padding: EdgeInsets.only(top: 10),
174 - child: SmoothPageIndicator(
175 - controller: _controller,
176 - count: _pages.length,
177 - effect: ColorTransitionEffect(
178 - spacing: 6.0,
179 - radius: 6.0,
180 - dotWidth: 6.0,
181 - dotHeight: 6.0,
182 - dotColor: Theme.of(context).hintColor.withOpacity(0.5),
183 - activeDotColor: Theme.of(context).hintColor),
184 - )),
185 - Padding(
186 - padding: EdgeInsets.only(top: 20, bottom: 24, left: 24, right: 24),
187 - child: Observer(
188 - builder: (context) {
189 - return LoadingPrimaryButton(
190 - onPressed: _confirmForm,
191 - text: S.of(context).restore_recover,
192 - color:
193 - Theme.of(context).accentTextTheme!.subtitle2!.decorationColor!,
194 - textColor:
195 - Theme.of(context).accentTextTheme!.headline5!.decorationColor!,
196 - isLoading: walletRestoreViewModel.state is IsExecutingState,
197 - isDisabled: !walletRestoreViewModel.isButtonEnabled,
198 - );
199 - },
200 - ))
201 - ])));
138 + config: KeyboardActionsConfig(
139 + keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
140 + keyboardBarColor: Theme.of(context).accentTextTheme.bodyText1!.backgroundColor!,
141 + nextFocus: false,
142 + actions: [
143 + KeyboardActionsItem(
144 + focusNode: _blockHeightFocusNode,
145 + toolbarButtons: [(_) => KeyboardDoneButton()],
146 + )
147 + ],
148 + ),
149 + child: Container(
150 + height: 0,
151 + color: Theme.of(context).backgroundColor,
152 + child: Center(
153 + child: ConstrainedBox(
154 + constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
155 + child: Column(
156 + mainAxisAlignment: MainAxisAlignment.center,
157 + children: [
158 + Expanded(
159 + child: PageView.builder(
160 + onPageChanged: (page) {
161 + walletRestoreViewModel.mode =
162 + page == 0 ? WalletRestoreMode.seed : WalletRestoreMode.keys;
163 + },
164 + controller: _controller,
165 + itemCount: _pages.length,
166 + itemBuilder: (_, index) => SingleChildScrollView(child: _pages[index]),
167 + ),
168 + ),
169 + if (_pages.length > 1)
170 + Padding(
171 + padding: EdgeInsets.only(top: 10),
172 + child: SmoothPageIndicator(
173 + controller: _controller,
174 + count: _pages.length,
175 + effect: ColorTransitionEffect(
176 + spacing: 6.0,
177 + radius: 6.0,
178 + dotWidth: 6.0,
179 + dotHeight: 6.0,
180 + dotColor: Theme.of(context).hintColor.withOpacity(0.5),
181 + activeDotColor: Theme.of(context).hintColor,
182 + ),
183 + ),
184 + ),
185 + Padding(
186 + padding: EdgeInsets.only(top: 20, bottom: 24, left: 24, right: 24),
187 + child: Observer(
188 + builder: (context) {
189 + return LoadingPrimaryButton(
190 + onPressed: _confirmForm,
191 + text: S.of(context).restore_recover,
192 + color: Theme.of(context).accentTextTheme.subtitle2!.decorationColor!,
193 + textColor: Theme.of(context).accentTextTheme.headline5!.decorationColor!,
194 + isLoading: walletRestoreViewModel.state is IsExecutingState,
195 + isDisabled: !walletRestoreViewModel.isButtonEnabled,
196 + );
197 + },
198 + ),
199 + )
200 + ],
201 + ),
202 + ),
203 + ),
204 + ),
205 + );
206 }
207
208 bool _isValidSeed() {
205 - final seedWords = walletRestoreFromSeedFormKey
206 - .currentState
207 - !.seedWidgetStateKey
208 - .currentState
209 - !.text
210 - .split(' ');
209 + final seedWords =
210 + walletRestoreFromSeedFormKey.currentState!.seedWidgetStateKey.currentState!.text.split(' ');
211
212 - if ((walletRestoreViewModel.type == WalletType.monero || walletRestoreViewModel.type == WalletType.haven) &&
212 + if ((walletRestoreViewModel.type == WalletType.monero ||
213 + walletRestoreViewModel.type == WalletType.haven) &&
214 seedWords.length != WalletRestoreViewModelBase.moneroSeedMnemonicLength) {
215 return false;
216 }
216 -
217 +
218 if ((walletRestoreViewModel.type == WalletType.bitcoin ||
218 - walletRestoreViewModel.type == WalletType.litecoin) &&
219 - (seedWords.length != WalletRestoreViewModelBase.electrumSeedMnemonicLength &&
220 - seedWords.length != WalletRestoreViewModelBase.electrumShortSeedMnemonicLength)) {
219 + walletRestoreViewModel.type == WalletType.litecoin) &&
220 + (seedWords.length != WalletRestoreViewModelBase.electrumSeedMnemonicLength &&
221 + seedWords.length != WalletRestoreViewModelBase.electrumShortSeedMnemonicLength)) {
222 return false;
223 }
224
224 - final words = walletRestoreFromSeedFormKey
225 - .currentState
226 - !.seedWidgetStateKey
227 - .currentState
228 - !.words
229 - .toSet();
230 - return seedWords
231 - .toSet()
232 - .difference(words)
233 - .toSet()
234 - .isEmpty;
225 + final words =
226 + walletRestoreFromSeedFormKey.currentState!.seedWidgetStateKey.currentState!.words.toSet();
227 + return seedWords.toSet().difference(words).toSet().isEmpty;
228 }
229
230 Map<String, dynamic> _credentials() {
231 final credentials = <String, dynamic>{};
232
233 if (walletRestoreViewModel.mode == WalletRestoreMode.seed) {
241 - credentials['seed'] = walletRestoreFromSeedFormKey
242 - .currentState!.seedWidgetStateKey.currentState!.text;
234 + credentials['seed'] =
235 + walletRestoreFromSeedFormKey.currentState!.seedWidgetStateKey.currentState!.text;
236
237 if (walletRestoreViewModel.hasBlockchainHeightLanguageSelector) {
245 - credentials['height'] = walletRestoreFromSeedFormKey
246 - .currentState!.blockchainHeightKey.currentState!.height;
238 + credentials['height'] =
239 + walletRestoreFromSeedFormKey.currentState!.blockchainHeightKey.currentState!.height;
240 }
241
249 - credentials['name'] = walletRestoreFromSeedFormKey.currentState!.nameTextEditingController.text;
242 + credentials['name'] =
243 + walletRestoreFromSeedFormKey.currentState!.nameTextEditingController.text;
244 } else {
251 - credentials['address'] =
252 - walletRestoreFromKeysFormKey.currentState!.addressController.text;
253 - credentials['viewKey'] =
254 - walletRestoreFromKeysFormKey.currentState!.viewKeyController.text;
255 - credentials['spendKey'] =
256 - walletRestoreFromKeysFormKey.currentState!.spendKeyController.text;
257 - credentials['height'] = walletRestoreFromKeysFormKey
258 - .currentState!.blockchainHeightKey.currentState!.height;
259 - credentials['name'] = walletRestoreFromKeysFormKey.currentState!.nameTextEditingController.text;
245 + credentials['address'] = walletRestoreFromKeysFormKey.currentState!.addressController.text;
246 + credentials['viewKey'] = walletRestoreFromKeysFormKey.currentState!.viewKeyController.text;
247 + credentials['spendKey'] = walletRestoreFromKeysFormKey.currentState!.spendKeyController.text;
248 + credentials['height'] =
249 + walletRestoreFromKeysFormKey.currentState!.blockchainHeightKey.currentState!.height;
250 + credentials['name'] =
251 + walletRestoreFromKeysFormKey.currentState!.nameTextEditingController.text;
252 }
253
254 return credentials;
@@ -272,10 +264,8 @@ class WalletRestorePage extends BasePage {
264 : walletRestoreFromKeysFormKey.currentState!.formKey;
265
266 final name = walletRestoreViewModel.mode == WalletRestoreMode.seed
275 - ? walletRestoreFromSeedFormKey
276 - .currentState!.nameTextEditingController.value.text
277 - : walletRestoreFromKeysFormKey
278 - .currentState!.nameTextEditingController.value.text;
267 + ? walletRestoreFromSeedFormKey.currentState!.nameTextEditingController.value.text
268 + : walletRestoreFromKeysFormKey.currentState!.nameTextEditingController.value.text;
269
270 if (!formKey.currentState!.validate()) {
271 return;
@@ -301,5 +291,3 @@ class WalletRestorePage extends BasePage {
291 });
292 }
293 }
304 -
305 -
lib/src/screens/root/root.dart
+4 -1
@@ -1,5 +1,6 @@
1 import 'dart:async';
2 import 'package:cake_wallet/core/auth_service.dart';
3 +import 'package:cake_wallet/utils/device_info.dart';
4 import 'package:cake_wallet/utils/payment_request.dart';
5 import 'package:flutter/material.dart';
6 import 'package:cake_wallet/routes.dart';
@@ -54,7 +55,9 @@ class RootState extends State<Root> with WidgetsBindingObserver {
55 WidgetsBinding.instance.addObserver(this);
56 super.initState();
57
57 - initUniLinks();
58 + if (DeviceInfo.instance.isMobile) {
59 + initUniLinks();
60 + }
61 }
62
63 @override
lib/src/screens/seed/pre_seed_page.dart
+41 -36
@@ -1,3 +1,4 @@
1 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
2 import 'package:cw_core/wallet_type.dart';
3 import 'package:cake_wallet/routes.dart';
4 import 'package:cake_wallet/themes/theme_base.dart';
@@ -33,44 +34,48 @@ class PreSeedPage extends BasePage {
34 return WillPopScope(
35 onWillPop: () async => false,
36 child: Container(
37 + alignment: Alignment.center,
38 padding: EdgeInsets.all(24),
37 - child: Column(
38 - children: [
39 - Flexible(
40 - flex: 2,
41 - child: AspectRatio(
42 - aspectRatio: 1,
43 - child: FittedBox(child: image, fit: BoxFit.contain))),
44 - Flexible(
45 - flex: 3,
46 - child: Column(
47 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
48 - children: [
49 - Padding(
50 - padding: EdgeInsets.only(top: 70, left: 16, right: 16),
51 - child: Text(
52 - S
53 - .of(context)
54 - .pre_seed_description(wordsCount.toString()),
55 - textAlign: TextAlign.center,
56 - style: TextStyle(
57 - fontSize: 14,
58 - fontWeight: FontWeight.normal,
59 - color: Theme.of(context)
60 - .primaryTextTheme!
61 - .caption!
62 - .color!),
39 + child: ConstrainedBox(
40 + constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
41 + child: Column(
42 + children: [
43 + Flexible(
44 + flex: 2,
45 + child: AspectRatio(
46 + aspectRatio: 1,
47 + child: FittedBox(child: image, fit: BoxFit.contain))),
48 + Flexible(
49 + flex: 3,
50 + child: Column(
51 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
52 + children: [
53 + Padding(
54 + padding: EdgeInsets.only(top: 70, left: 16, right: 16),
55 + child: Text(
56 + S
57 + .of(context)
58 + .pre_seed_description(wordsCount.toString()),
59 + textAlign: TextAlign.center,
60 + style: TextStyle(
61 + fontSize: 14,
62 + fontWeight: FontWeight.normal,
63 + color: Theme.of(context)
64 + .primaryTextTheme!
65 + .caption!
66 + .color!),
67 + ),
68 ),
64 - ),
65 - PrimaryButton(
66 - onPressed: () => Navigator.of(context)
67 - .popAndPushNamed(Routes.seed, arguments: true),
68 - text: S.of(context).pre_seed_button_text,
69 - color: Theme.of(context).accentTextTheme!.bodyText1!.color!,
70 - textColor: Colors.white)
71 - ],
72 - ))
73 - ],
69 + PrimaryButton(
70 + onPressed: () => Navigator.of(context)
71 + .popAndPushNamed(Routes.seed, arguments: true),
72 + text: S.of(context).pre_seed_button_text,
73 + color: Theme.of(context).accentTextTheme!.bodyText1!.color!,
74 + textColor: Colors.white)
75 + ],
76 + ))
77 + ],
78 + ),
79 ),
80 ));
81 }
lib/src/screens/seed/wallet_seed_page.dart
+101 -95
@@ -2,6 +2,7 @@ import 'package:cake_wallet/palette.dart';
2 import 'package:cake_wallet/themes/theme_base.dart';
3 import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
4 import 'package:cake_wallet/utils/share_util.dart';
5 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
6 import 'package:cake_wallet/utils/show_bar.dart';
7 import 'package:cake_wallet/utils/show_pop_up.dart';
8 import 'package:flutter/material.dart';
@@ -52,7 +53,7 @@ class WalletSeedPage extends BasePage {
53
54 @override
55 Widget? leading(BuildContext context) =>
55 - isNewWalletCreated ? Offstage() : super.leading(context);
56 + isNewWalletCreated ? null: super.leading(context);
57
58 @override
59 Widget trailing(BuildContext context) {
@@ -85,114 +86,119 @@ class WalletSeedPage extends BasePage {
86
87 return WillPopScope(onWillPop: () async => false, child: Container(
88 padding: EdgeInsets.all(24),
88 - child: Column(
89 - children: <Widget>[
90 - Flexible(
91 - flex: 2,
92 - child: AspectRatio(
93 - aspectRatio: 1,
94 - child: FittedBox(child: image, fit: BoxFit.fill))),
95 - Flexible(
96 - flex: 3,
97 - child: Column(
98 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
99 - children: <Widget>[
100 - Padding(
101 - padding: EdgeInsets.only(top: 33),
102 - child: Observer(builder: (_) {
103 - return Column(
104 - crossAxisAlignment: CrossAxisAlignment.center,
105 - children: <Widget>[
106 - Text(
107 - walletSeedViewModel.name,
108 - style: TextStyle(
109 - fontSize: 20,
110 - fontWeight: FontWeight.w600,
111 - color: Theme.of(context)
112 - .primaryTextTheme!
113 - .headline6!
114 - .color!),
115 - ),
116 - Padding(
117 - padding:
118 - EdgeInsets.only(top: 20, left: 16, right: 16),
119 - child: Text(
120 - walletSeedViewModel.seed,
121 - textAlign: TextAlign.center,
89 + alignment: Alignment.center,
90 + child: ConstrainedBox(
91 + constraints:
92 + BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
93 + child: Column(
94 + children: <Widget>[
95 + Flexible(
96 + flex: 2,
97 + child: AspectRatio(
98 + aspectRatio: 1,
99 + child: FittedBox(child: image, fit: BoxFit.fill))),
100 + Flexible(
101 + flex: 3,
102 + child: Column(
103 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
104 + children: <Widget>[
105 + Padding(
106 + padding: EdgeInsets.only(top: 33),
107 + child: Observer(builder: (_) {
108 + return Column(
109 + crossAxisAlignment: CrossAxisAlignment.center,
110 + children: <Widget>[
111 + Text(
112 + walletSeedViewModel.name,
113 style: TextStyle(
123 - fontSize: 14,
124 - fontWeight: FontWeight.normal,
114 + fontSize: 20,
115 + fontWeight: FontWeight.w600,
116 color: Theme.of(context)
117 .primaryTextTheme!
127 - .caption!
118 + .headline6!
119 .color!),
120 ),
130 - )
131 - ],
132 - );
133 - }),
134 - ),
135 - Column(
136 - children: <Widget>[
137 - isNewWalletCreated
138 - ? Padding(
139 - padding: EdgeInsets.only(
140 - bottom: 52, left: 43, right: 43),
121 + Padding(
122 + padding:
123 + EdgeInsets.only(top: 20, left: 16, right: 16),
124 child: Text(
142 - S.of(context).seed_reminder,
125 + walletSeedViewModel.seed,
126 textAlign: TextAlign.center,
127 style: TextStyle(
145 - fontSize: 12,
128 + fontSize: 14,
129 fontWeight: FontWeight.normal,
130 color: Theme.of(context)
131 .primaryTextTheme!
149 - .overline!
132 + .caption!
133 .color!),
134 ),
135 )
153 - : Offstage(),
154 - Row(
155 - mainAxisSize: MainAxisSize.max,
156 - children: <Widget>[
157 - Flexible(
158 - child: Container(
159 - padding: EdgeInsets.only(right: 8.0),
160 - child: PrimaryButton(
161 - onPressed: () {
162 - ShareUtil.share(
163 - text: walletSeedViewModel.seed,
164 - context: context,
165 - );
166 - },
167 - text: S.of(context).save,
168 - color: Colors.green,
169 - textColor: Colors.white),
170 - )),
171 - Flexible(
172 - child: Container(
173 - padding: EdgeInsets.only(left: 8.0),
174 - child: Builder(
175 - builder: (context) => PrimaryButton(
176 - onPressed: () {
177 - Clipboard.setData(ClipboardData(
178 - text: walletSeedViewModel.seed));
179 - showBar<void>(context,
180 - S.of(context).copied_to_clipboard);
181 - },
182 - text: S.of(context).copy,
183 - color: Theme.of(context)
184 - .accentTextTheme!
185 - .bodyText2!
186 - .color!,
187 - textColor: Colors.white)),
188 - ))
189 - ],
190 - )
191 - ],
192 - )
193 - ],
194 - ))
195 - ],
136 + ],
137 + );
138 + }),
139 + ),
140 + Column(
141 + children: <Widget>[
142 + isNewWalletCreated
143 + ? Padding(
144 + padding: EdgeInsets.only(
145 + bottom: 52, left: 43, right: 43),
146 + child: Text(
147 + S.of(context).seed_reminder,
148 + textAlign: TextAlign.center,
149 + style: TextStyle(
150 + fontSize: 12,
151 + fontWeight: FontWeight.normal,
152 + color: Theme.of(context)
153 + .primaryTextTheme!
154 + .overline!
155 + .color!),
156 + ),
157 + )
158 + : Offstage(),
159 + Row(
160 + mainAxisSize: MainAxisSize.max,
161 + children: <Widget>[
162 + Flexible(
163 + child: Container(
164 + padding: EdgeInsets.only(right: 8.0),
165 + child: PrimaryButton(
166 + onPressed: () {
167 + ShareUtil.share(
168 + text: walletSeedViewModel.seed,
169 + context: context,
170 + );
171 + },
172 + text: S.of(context).save,
173 + color: Colors.green,
174 + textColor: Colors.white),
175 + )),
176 + Flexible(
177 + child: Container(
178 + padding: EdgeInsets.only(left: 8.0),
179 + child: Builder(
180 + builder: (context) => PrimaryButton(
181 + onPressed: () {
182 + Clipboard.setData(ClipboardData(
183 + text: walletSeedViewModel.seed));
184 + showBar<void>(context,
185 + S.of(context).copied_to_clipboard);
186 + },
187 + text: S.of(context).copy,
188 + color: Theme.of(context)
189 + .accentTextTheme!
190 + .bodyText2!
191 + .color!,
192 + textColor: Colors.white)),
193 + ))
194 + ],
195 + )
196 + ],
197 + )
198 + ],
199 + ))
200 + ],
201 + ),
202 )));
203 }
204 }
lib/src/screens/send/send_page.dart
+145 -176
@@ -1,10 +1,12 @@
1 import 'package:cake_wallet/entities/fiat_currency.dart';
2 import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator_icon.dart';
3 import 'package:cake_wallet/src/screens/send/widgets/send_card.dart';
4 +import 'package:cake_wallet/src/widgets/add_template_button.dart';
5 import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
6 import 'package:cake_wallet/src/widgets/picker.dart';
7 import 'package:cake_wallet/src/widgets/template_tile.dart';
8 import 'package:cake_wallet/utils/payment_request.dart';
9 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
10 import 'package:cake_wallet/view_model/send/output.dart';
11 import 'package:flutter/material.dart';
12 import 'package:flutter_mobx/flutter_mobx.dart';
@@ -19,7 +21,6 @@ import 'package:cake_wallet/src/widgets/trail_button.dart';
21 import 'package:cake_wallet/utils/show_pop_up.dart';
22 import 'package:cake_wallet/view_model/send/send_view_model_state.dart';
23 import 'package:cake_wallet/generated/i18n.dart';
22 -import 'package:dotted_border/dotted_border.dart';
24 import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
25 import 'package:cake_wallet/src/screens/send/widgets/confirm_sending_alert.dart';
26 import 'package:smooth_page_indicator/smooth_page_indicator.dart';
@@ -50,9 +51,21 @@ class SendPage extends BasePage {
51 @override
52 bool get extendBodyBehindAppBar => true;
53
54 + @override
55 + bool get canUseCloseIcon => true;
56 +
57 @override
58 AppBarStyle get appBarStyle => AppBarStyle.transparent;
59
60 + double _sendCardHeight(BuildContext context) {
61 + final double initialHeight = sendViewModel.isElectrumWallet ? 490 : 465;
62 +
63 + if (!ResponsiveLayoutUtil.instance.isMobile(context)) {
64 + return initialHeight - 66;
65 + }
66 + return initialHeight;
67 + }
68 +
69 @override
70 void onClose(BuildContext context) {
71 sendViewModel.onClose();
@@ -104,178 +117,137 @@ class SendPage extends BasePage {
117 key: _formKey,
118 child: ScrollableWithBottomSection(
119 contentPadding: EdgeInsets.only(bottom: 24),
107 - content: Column(
108 - children: <Widget>[
109 - Container(
110 - height: sendViewModel.isElectrumWallet ? 490 : 465,
111 - child: Observer(
112 - builder: (_) {
113 - return PageView.builder(
114 - scrollDirection: Axis.horizontal,
115 - controller: controller,
116 - itemCount: sendViewModel.outputs.length,
117 - itemBuilder: (context, index) {
118 - final output = sendViewModel.outputs[index];
119 -
120 - return SendCard(
121 - key: output.key,
122 - output: output,
123 - sendViewModel: sendViewModel,
124 - initialPaymentRequest: initialPaymentRequest,
125 - );
126 - });
127 - },
128 - )),
129 - Padding(
130 - padding:
131 - EdgeInsets.only(top: 10, left: 24, right: 24, bottom: 10),
132 - child: Container(
133 - height: 10,
134 - child: Observer(
135 - builder: (_) {
136 - final count = sendViewModel.outputs.length;
137 -
138 - return count > 1
139 - ? SmoothPageIndicator(
140 - controller: controller,
141 - count: count,
142 - effect: ScrollingDotsEffect(
143 - spacing: 6.0,
144 - radius: 6.0,
145 - dotWidth: 6.0,
146 - dotHeight: 6.0,
147 - dotColor: Theme.of(context)
148 - .primaryTextTheme!
149 - .headline3!
150 - .backgroundColor!,
151 - activeDotColor: Theme.of(context)
152 - .primaryTextTheme!
153 - .headline2!
154 - .backgroundColor!),
155 - )
156 - : Offstage();
157 - },
158 - ),
159 - ),
160 - ),
161 - if (sendViewModel.hasMultiRecipient)
162 - Container(
163 - height: 40,
164 - width: double.infinity,
165 - padding: EdgeInsets.only(left: 24),
166 - child: SingleChildScrollView(
167 - scrollDirection: Axis.horizontal,
168 - child: Observer(
169 - builder: (_) {
170 - final templates = sendViewModel.templates;
171 - final itemCount = templates.length;
172 -
173 - return Row(
174 - children: <Widget>[
175 - GestureDetector(
176 - onTap: () => Navigator.of(context)
177 - .pushNamed(Routes.sendTemplate),
178 - child: Container(
179 - padding: EdgeInsets.only(left: 1, right: 10),
180 - child: DottedBorder(
181 - borderType: BorderType.RRect,
182 - dashPattern: [6, 4],
183 - color: Theme.of(context)
184 - .primaryTextTheme!
185 - .headline2!
186 - .decorationColor!,
187 - strokeWidth: 2,
188 - radius: Radius.circular(20),
189 - child: Container(
190 - height: 34,
191 - padding: EdgeInsets.only(left: 10, right: 10),
192 - alignment: Alignment.center,
193 - decoration: BoxDecoration(
194 - borderRadius:
195 - BorderRadius.all(Radius.circular(20)),
196 - color: Colors.transparent,
197 - ),
198 - child: templates.length >= 1
199 - ? Icon(
200 - Icons.add,
201 - color: Theme.of(context)
202 - .primaryTextTheme!
203 - .headline2!
204 - .color!,
205 - )
206 - : Text(
207 - S.of(context).new_template,
208 - style: TextStyle(
209 - fontSize: 14,
210 - fontWeight: FontWeight.w600,
211 - color: Theme.of(context)
212 - .primaryTextTheme!
213 - .headline2!
214 - .color!,
215 - ),
216 - ),
217 - ),
218 - ),
219 - ),
220 - ),
221 - ListView.builder(
120 + content: FocusTraversalGroup(
121 + policy: OrderedTraversalPolicy(),
122 + child: Column(
123 + children: <Widget>[
124 + Container(
125 + height: _sendCardHeight(context),
126 + child: Observer(
127 + builder: (_) {
128 + return PageView.builder(
129 scrollDirection: Axis.horizontal,
223 - shrinkWrap: true,
224 - physics: NeverScrollableScrollPhysics(),
225 - itemCount: itemCount,
130 + controller: controller,
131 + itemCount: sendViewModel.outputs.length,
132 itemBuilder: (context, index) {
227 - final template = templates[index];
228 - return TemplateTile(
229 - key: UniqueKey(),
230 - to: template.name,
231 - amount: template.isCurrencySelected ? template.amount : template.amountFiat,
232 - from: template.isCurrencySelected ? template.cryptoCurrency : template.fiatCurrency,
233 - onTap: () async {
234 - final fiatFromTemplate = FiatCurrency.all.singleWhere((element) => element.title == template.fiatCurrency);
235 - final output = _defineCurrentOutput();
236 - output.address = template.address;
237 - if(template.isCurrencySelected){
238 - output.setCryptoAmount(template.amount);
239 - }else{
240 - sendViewModel.setFiatCurrency(fiatFromTemplate);
241 - output.setFiatAmount(template.amountFiat);
242 - }
243 - output.resetParsedAddress();
244 - await output.fetchParsedAddress(context);
245 - },
246 - onRemove: () {
247 - showPopUp<void>(
248 - context: context,
249 - builder: (dialogContext) {
250 - return AlertWithTwoActions(
251 - alertTitle: S.of(context).template,
252 - alertContent: S
253 - .of(context)
254 - .confirm_delete_template,
255 - rightButtonText: S.of(context).delete,
256 - leftButtonText: S.of(context).cancel,
257 - actionRightButton: () {
258 - Navigator.of(dialogContext).pop();
259 - sendViewModel.sendTemplateViewModel
260 - .removeTemplate(
261 - template: template);
262 - },
263 - actionLeftButton: () =>
264 - Navigator.of(dialogContext)
265 - .pop());
266 - },
267 - );
268 - },
133 + final output = sendViewModel.outputs[index];
134 +
135 + return SendCard(
136 + key: output.key,
137 + output: output,
138 + sendViewModel: sendViewModel,
139 + initialPaymentRequest: initialPaymentRequest,
140 );
270 - },
271 - ),
272 - ],
273 - );
274 - },
141 + });
142 + },
143 + )),
144 + Padding(
145 + padding:
146 + EdgeInsets.only(top: 10, left: 24, right: 24, bottom: 10),
147 + child: Container(
148 + height: 10,
149 + child: Observer(
150 + builder: (_) {
151 + final count = sendViewModel.outputs.length;
152 +
153 + return count > 1
154 + ? SmoothPageIndicator(
155 + controller: controller,
156 + count: count,
157 + effect: ScrollingDotsEffect(
158 + spacing: 6.0,
159 + radius: 6.0,
160 + dotWidth: 6.0,
161 + dotHeight: 6.0,
162 + dotColor: Theme.of(context)
163 + .primaryTextTheme.headline3!
164 + .backgroundColor!,
165 + activeDotColor: Theme.of(context)
166 + .primaryTextTheme.headline2!
167 + .backgroundColor!),
168 + )
169 + : Offstage();
170 + },
171 + ),
172 ),
173 ),
277 - )
278 - ],
174 + if (sendViewModel.hasMultiRecipient)
175 + Container(
176 + height: 40,
177 + width: double.infinity,
178 + padding: EdgeInsets.only(left: 24),
179 + child: SingleChildScrollView(
180 + scrollDirection: Axis.horizontal,
181 + child: Observer(
182 + builder: (_) {
183 + final templates = sendViewModel.templates;
184 + final itemCount = templates.length;
185 +
186 + return Row(
187 + children: <Widget>[
188 + AddTemplateButton(
189 + onTap: () => Navigator.of(context).pushNamed(Routes.sendTemplate),
190 + currentTemplatesLength: templates.length,
191 + ),
192 + ListView.builder(
193 + scrollDirection: Axis.horizontal,
194 + shrinkWrap: true,
195 + physics: NeverScrollableScrollPhysics(),
196 + itemCount: itemCount,
197 + itemBuilder: (context, index) {
198 + final template = templates[index];
199 + return TemplateTile(
200 + key: UniqueKey(),
201 + to: template.name,
202 + amount: template.isCurrencySelected ? template.amount : template.amountFiat,
203 + from: template.isCurrencySelected ? template.cryptoCurrency : template.fiatCurrency,
204 + onTap: () async {
205 + final fiatFromTemplate = FiatCurrency.all.singleWhere((element) => element.title == template.fiatCurrency);
206 + final output = _defineCurrentOutput();
207 + output.address = template.address;
208 + if(template.isCurrencySelected){
209 + output.setCryptoAmount(template.amount);
210 + }else{
211 + sendViewModel.setFiatCurrency(fiatFromTemplate);
212 + output.setFiatAmount(template.amountFiat);
213 + }
214 + output.resetParsedAddress();
215 + await output.fetchParsedAddress(context);
216 + },
217 + onRemove: () {
218 + showPopUp<void>(
219 + context: context,
220 + builder: (dialogContext) {
221 + return AlertWithTwoActions(
222 + alertTitle: S.of(context).template,
223 + alertContent: S
224 + .of(context)
225 + .confirm_delete_template,
226 + rightButtonText: S.of(context).delete,
227 + leftButtonText: S.of(context).cancel,
228 + actionRightButton: () {
229 + Navigator.of(dialogContext).pop();
230 + sendViewModel.sendTemplateViewModel
231 + .removeTemplate(
232 + template: template);
233 + },
234 + actionLeftButton: () =>
235 + Navigator.of(dialogContext)
236 + .pop());
237 + },
238 + );
239 + },
240 + );
241 + },
242 + ),
243 + ],
244 + );
245 + },
246 + ),
247 + ),
248 + )
249 + ],
250 + ),
251 ),
252 bottomSectionPadding:
253 EdgeInsets.only(left: 24, right: 24, bottom: 24),
@@ -290,8 +262,7 @@ class SendPage extends BasePage {
262 text: 'Change your asset (${sendViewModel.selectedCryptoCurrency})',
263 color: Colors.transparent,
264 textColor: Theme.of(context)
293 - .accentTextTheme!
294 - .headline3!
265 + .accentTextTheme.headline3!
266 .decorationColor!,
267 )
268 )
@@ -309,13 +280,11 @@ class SendPage extends BasePage {
280 text: S.of(context).add_receiver,
281 color: Colors.transparent,
282 textColor: Theme.of(context)
312 - .accentTextTheme!
313 - .headline3!
283 + .accentTextTheme.headline3!
284 .decorationColor!,
285 isDottedBorder: true,
286 borderColor: Theme.of(context)
317 - .primaryTextTheme!
318 - .headline3!
287 + .primaryTextTheme.headline3!
288 .decorationColor!,
289 )),
290 Observer(
@@ -335,7 +304,7 @@ class SendPage extends BasePage {
304 item.address.isEmpty || item.cryptoAmount.isEmpty)
305 .toList();
306
338 - if (notValidItems?.isNotEmpty ?? false) {
307 + if (notValidItems.isNotEmpty ?? false) {
308 showErrorValidationAlert(context);
309 return;
310 }
@@ -344,7 +313,7 @@ class SendPage extends BasePage {
313
314 },
315 text: S.of(context).send,
347 - color: Theme.of(context).accentTextTheme!.bodyText1!.color!,
316 + color: Theme.of(context).accentTextTheme.bodyText1!.color!,
317 textColor: Colors.white,
318 isLoading: sendViewModel.state is IsExecutingState ||
319 sendViewModel.state is TransactionCommitting,
lib/src/screens/send/widgets/send_card.dart
+9 -3
@@ -1,6 +1,7 @@
1 import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
2 import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
3 import 'package:cake_wallet/utils/payment_request.dart';
4 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
5 import 'package:cw_core/transaction_priority.dart';
6 import 'package:cake_wallet/routes.dart';
7 import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
@@ -119,7 +120,7 @@ class SendCardState extends State<SendCard>
120 color: Colors.transparent,
121 )),
122 Container(
122 - decoration: BoxDecoration(
123 + decoration: ResponsiveLayoutUtil.instance.isMobile(context) ? BoxDecoration(
124 borderRadius: BorderRadius.only(
125 bottomLeft: Radius.circular(24),
126 bottomRight: Radius.circular(24)),
@@ -130,9 +131,14 @@ class SendCardState extends State<SendCard>
131 .subtitle1!
132 .decorationColor!,
133 ], begin: Alignment.topLeft, end: Alignment.bottomRight),
133 - ),
134 + ) : null,
135 child: Padding(
135 - padding: EdgeInsets.fromLTRB(24, 100, 24, 32),
136 + padding: EdgeInsets.fromLTRB(
137 + 24,
138 + ResponsiveLayoutUtil.instance.isMobile(context) ? 100 : 55,
139 + 24,
140 + ResponsiveLayoutUtil.instance.isMobile(context) ? 32 : 0,
141 + ),
142 child: SingleChildScrollView(
143 child: Observer(builder: (_) => Column(
144 mainAxisSize: MainAxisSize.min,
lib/src/screens/settings/desktop_settings/desktop_settings_page.dart new
+105
@@ -0,0 +1,105 @@
1 +import 'package:cake_wallet/generated/i18n.dart';
2 +import 'package:cake_wallet/routes.dart';
3 +import 'package:cake_wallet/src/widgets/setting_action_button.dart';
4 +import 'package:cake_wallet/src/widgets/setting_actions.dart';
5 +import 'package:cake_wallet/typography.dart';
6 +import 'package:flutter/material.dart';
7 +import 'package:cake_wallet/router.dart' as Router;
8 +
9 +final _settingsNavigatorKey = GlobalKey<NavigatorState>();
10 +
11 +class DesktopSettingsPage extends StatefulWidget {
12 + const DesktopSettingsPage({super.key});
13 +
14 + @override
15 + State<DesktopSettingsPage> createState() => _DesktopSettingsPageState();
16 +}
17 +
18 +class _DesktopSettingsPageState extends State<DesktopSettingsPage> {
19 + final int itemCount = SettingActions.desktopSettings.length;
20 +
21 + int? currentPage;
22 +
23 + void _onItemChange(int index) {
24 + setState(() {
25 + currentPage = index;
26 + });
27 + }
28 +
29 + @override
30 + Widget build(BuildContext context) {
31 + return Scaffold(
32 + body: Container(
33 + height: MediaQuery.of(context).size.height,
34 + child: Column(
35 + mainAxisSize: MainAxisSize.min,
36 + crossAxisAlignment: CrossAxisAlignment.start,
37 + children: [
38 + Padding(
39 + padding: const EdgeInsets.all(24),
40 + child: Text(
41 + S.current.settings,
42 + style: textXLarge(),
43 + ),
44 + ),
45 + Expanded(
46 + child: Row(
47 + children: [
48 + Expanded(
49 + flex: 1,
50 + child: ListView.separated(
51 + padding: EdgeInsets.only(top: 0),
52 + itemBuilder: (_, index) {
53 + final item = SettingActions.desktopSettings[index];
54 + final isLastTile = index == itemCount - 1;
55 + return SettingActionButton(
56 + isLastTile: isLastTile,
57 + selectionActive: currentPage != null,
58 + isSelected: currentPage == index,
59 + isArrowVisible: true,
60 + onTap: () {
61 + if (currentPage != index) {
62 + final settingContext =
63 + _settingsNavigatorKey.currentState?.context ?? context;
64 + item.onTap.call(settingContext);
65 + _onItemChange(index);
66 + }
67 + },
68 + image: item.image,
69 + title: item.name,
70 + );
71 + },
72 + separatorBuilder: (_, index) => Container(
73 + height: 1,
74 + color: Theme.of(context).primaryTextTheme.caption!.decorationColor!,
75 + ),
76 + itemCount: itemCount,
77 + ),
78 + ),
79 + Flexible(
80 + flex: 2,
81 + child: ConstrainedBox(
82 + constraints: BoxConstraints(maxWidth: 500),
83 + child: Navigator(
84 + key: _settingsNavigatorKey,
85 + initialRoute: Routes.empty_no_route,
86 + onGenerateRoute: (settings) => Router.createRoute(settings),
87 + onGenerateInitialRoutes:
88 + (NavigatorState navigator, String initialRouteName) {
89 + return [
90 + navigator
91 + .widget.onGenerateRoute!(RouteSettings(name: initialRouteName))!
92 + ];
93 + },
94 + ),
95 + ),
96 + )
97 + ],
98 + ),
99 + ),
100 + ],
101 + ),
102 + ),
103 + );
104 + }
105 +}
lib/src/screens/settings/display_settings_page.dart
+9 -8
@@ -7,9 +7,9 @@ import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.da
7 import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
8 import 'package:cake_wallet/themes/theme_base.dart';
9 import 'package:cake_wallet/themes/theme_list.dart';
10 +import 'package:cake_wallet/utils/device_info.dart';
11 import 'package:cake_wallet/view_model/settings/choices_list_item.dart';
12 import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart';
12 -import 'package:cake_wallet/wallet_type_utils.dart';
13 import 'package:flutter/material.dart';
14 import 'package:flutter_mobx/flutter_mobx.dart';
15
@@ -65,14 +65,15 @@ class DisplaySettingsPage extends BasePage {
65 return LanguageService.list[code]?.toLowerCase().contains(searchText) ?? false;
66 },
67 ),
68 - SettingsChoicesCell(
69 - ChoicesListItem<ThemeBase>(
70 - title: S.current.color_theme,
71 - items: ThemeList.all,
72 - selectedItem: _displaySettingsViewModel.theme,
73 - onItemSelected: (ThemeBase theme) => _displaySettingsViewModel.setTheme(theme),
68 + if (DeviceInfo.instance.isMobile)
69 + SettingsChoicesCell(
70 + ChoicesListItem<ThemeBase>(
71 + title: S.current.color_theme,
72 + items: ThemeList.all,
73 + selectedItem: _displaySettingsViewModel.theme,
74 + onItemSelected: (ThemeBase theme) => _displaySettingsViewModel.setTheme(theme),
75 + ),
76 ),
75 - ),
77 ],
78 ),
79 );
lib/src/screens/support/support_page.dart
+30 -27
@@ -1,6 +1,7 @@
1 import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
2 import 'package:cake_wallet/src/screens/settings/widgets/settings_link_provider_cell.dart';
3 import 'package:cake_wallet/src/widgets/standard_list.dart';
4 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
5 import 'package:cake_wallet/view_model/settings/link_list_item.dart';
6 import 'package:cake_wallet/view_model/settings/regular_list_item.dart';
7 import 'package:cake_wallet/view_model/support_view_model.dart';
@@ -18,32 +19,34 @@ class SupportPage extends BasePage {
19
20 @override
21 Widget body(BuildContext context) {
21 - final iconColor =
22 - Theme.of(context).accentTextTheme!.headline1!.backgroundColor!;
22 + final iconColor = Theme.of(context).accentTextTheme!.headline1!.backgroundColor!;
23 // FIX-ME: Added `context` it was not used here before, maby bug ?
24 - return SectionStandardList(
25 - context: context,
26 - sectionCount: 1,
27 - itemCounter: (int _) => supportViewModel.items.length,
28 - itemBuilder: (_, __, index) {
29 - final item = supportViewModel.items[index];
30 -
31 - if (item is RegularListItem) {
32 - return SettingsCellWithArrow(
33 - title: item.title, handler: item.handler);
34 - }
35 -
36 - if (item is LinkListItem) {
37 - return SettingsLinkProviderCell(
38 - title: item.title,
39 - icon: item.icon,
40 - iconColor: item.hasIconColor ? iconColor : null,
41 - link: item.link,
42 - linkTitle: item.linkTitle);
43 - }
44 -
45 - return Container();
46 - });
24 + return Center(
25 + child: ConstrainedBox(
26 + constraints: BoxConstraints(maxWidth: 500),
27 + child: SectionStandardList(
28 + context: context,
29 + sectionCount: 1,
30 + itemCounter: (int _) => supportViewModel.items.length,
31 + itemBuilder: (_, __, index) {
32 + final item = supportViewModel.items[index];
33 +
34 + if (item is RegularListItem) {
35 + return SettingsCellWithArrow(title: item.title, handler: item.handler);
36 + }
37 +
38 + if (item is LinkListItem) {
39 + return SettingsLinkProviderCell(
40 + title: item.title,
41 + icon: item.icon,
42 + iconColor: item.hasIconColor ? iconColor : null,
43 + link: item.link,
44 + linkTitle: item.linkTitle);
45 + }
46 +
47 + return Container();
48 + }),
49 + ),
50 + );
51 }
48 -
49 -}
\ No newline at end of file
52 +}
lib/src/screens/wallet_list/wallet_list_page.dart
+58 -66
@@ -1,5 +1,6 @@
1 import 'package:cake_wallet/src/screens/auth/auth_page.dart';
2 import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
3 +import 'package:cake_wallet/utils/device_info.dart';
4 import 'package:cake_wallet/utils/show_bar.dart';
5 import 'package:cake_wallet/utils/show_pop_up.dart';
6 import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
@@ -23,8 +24,7 @@ class WalletListPage extends BasePage {
24 final WalletListViewModel walletListViewModel;
25
26 @override
26 - Widget body(BuildContext context) =>
27 - WalletListBody(walletListViewModel: walletListViewModel);
27 + Widget body(BuildContext context) => WalletListBody(walletListViewModel: walletListViewModel);
28 }
29
30 class WalletListBody extends StatefulWidget {
@@ -37,28 +37,21 @@ class WalletListBody extends StatefulWidget {
37 }
38
39 class WalletListBodyState extends State<WalletListBody> {
40 - final moneroIcon =
41 - Image.asset('assets/images/monero_logo.png', height: 24, width: 24);
42 - final bitcoinIcon =
43 - Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
44 - final litecoinIcon =
45 - Image.asset('assets/images/litecoin_icon.png', height: 24, width: 24);
46 - final nonWalletTypeIcon =
47 - Image.asset('assets/images/close.png', height: 24, width: 24);
48 - final havenIcon =
49 - Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
40 + final moneroIcon = Image.asset('assets/images/monero_logo.png', height: 24, width: 24);
41 + final bitcoinIcon = Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
42 + final litecoinIcon = Image.asset('assets/images/litecoin_icon.png', height: 24, width: 24);
43 + final nonWalletTypeIcon = Image.asset('assets/images/close.png', height: 24, width: 24);
44 + final havenIcon = Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
45 final scrollController = ScrollController();
46 final double tileHeight = 60;
47 Flushbar<void>? _progressBar;
48
49 @override
50 Widget build(BuildContext context) {
56 - final newWalletImage = Image.asset('assets/images/new_wallet.png',
57 - height: 12, width: 12, color: Colors.white);
51 + final newWalletImage =
52 + Image.asset('assets/images/new_wallet.png', height: 12, width: 12, color: Colors.white);
53 final restoreWalletImage = Image.asset('assets/images/restore_wallet.png',
59 - height: 12,
60 - width: 12,
61 - color: Theme.of(context).primaryTextTheme!.headline6!.color!);
54 + height: 12, width: 12, color: Theme.of(context).primaryTextTheme.headline6!.color!);
55
56 return Container(
57 padding: EdgeInsets.only(top: 16),
@@ -69,16 +62,13 @@ class WalletListBodyState extends State<WalletListBody> {
62 builder: (_) => ListView.separated(
63 shrinkWrap: true,
64 physics: const NeverScrollableScrollPhysics(),
72 - separatorBuilder: (_, index) => Divider(
73 - color: Theme.of(context).backgroundColor, height: 32),
65 + separatorBuilder: (_, index) =>
66 + Divider(color: Theme.of(context).backgroundColor, height: 32),
67 itemCount: widget.walletListViewModel.wallets.length,
68 itemBuilder: (__, index) {
69 final wallet = widget.walletListViewModel.wallets[index];
70 final currentColor = wallet.isCurrent
78 - ? Theme.of(context)
79 - .accentTextTheme!
80 - .subtitle2!
81 - .decorationColor!
71 + ? Theme.of(context).accentTextTheme.subtitle2!.decorationColor!
72 : Theme.of(context).backgroundColor;
73 final row = GestureDetector(
74 onTap: () async {
@@ -90,19 +80,15 @@ class WalletListBodyState extends State<WalletListBody> {
80 context: context,
81 builder: (dialogContext) {
82 return AlertWithTwoActions(
93 - alertTitle: S
94 - .of(context)
95 - .change_wallet_alert_title,
96 - alertContent: S
97 - .of(context)
98 - .change_wallet_alert_content(
99 - wallet.name),
83 + alertTitle: S.of(context).change_wallet_alert_title,
84 + alertContent:
85 + S.of(context).change_wallet_alert_content(wallet.name),
86 leftButtonText: S.of(context).cancel,
87 rightButtonText: S.of(context).change,
88 actionLeftButton: () =>
103 - Navigator.of(context).pop(false),
89 + Navigator.of(dialogContext).pop(false),
90 actionRightButton: () =>
105 - Navigator.of(context).pop(true));
91 + Navigator.of(dialogContext).pop(true));
92 }) ??
93 false;
94
@@ -131,12 +117,11 @@ class WalletListBodyState extends State<WalletListBody> {
117 color: Theme.of(context).backgroundColor,
118 alignment: Alignment.centerLeft,
119 child: Row(
134 - crossAxisAlignment:
135 - CrossAxisAlignment.center,
120 + crossAxisAlignment: CrossAxisAlignment.center,
121 children: <Widget>[
122 wallet.isEnabled
138 - ? _imageFor(type: wallet.type)
139 - : nonWalletTypeIcon,
123 + ? _imageFor(type: wallet.type)
124 + : nonWalletTypeIcon,
125 SizedBox(width: 10),
126 Text(
127 wallet.name,
@@ -144,8 +129,7 @@ class WalletListBodyState extends State<WalletListBody> {
129 fontSize: 22,
130 fontWeight: FontWeight.w500,
131 color: Theme.of(context)
147 - .primaryTextTheme!
148 - .headline6!
132 + .primaryTextTheme.headline6!
133 .color!),
134 )
135 ],
@@ -163,43 +147,40 @@ class WalletListBodyState extends State<WalletListBody> {
147 startActionPane: _actionPane(wallet),
148 endActionPane: _actionPane(wallet),
149 child: row,
166 - );
150 + );
151 }),
152 ),
153 ),
170 - bottomSectionPadding:
171 - EdgeInsets.only(bottom: 24, right: 24, left: 24),
154 + bottomSectionPadding: EdgeInsets.only(bottom: 24, right: 24, left: 24),
155 bottomSection: Column(children: <Widget>[
156 PrimaryImageButton(
157 onPressed: () {
175 - if (isSingleCoin) {
176 - Navigator.of(context).pushNamed(Routes.newWallet, arguments: widget.walletListViewModel.currentWalletType);
177 - } else {
178 - Navigator.of(context).pushNamed(Routes.newWalletType);
179 - }
180 - },
158 + if (isSingleCoin) {
159 + Navigator.of(context).pushNamed(Routes.newWallet,
160 + arguments: widget.walletListViewModel.currentWalletType);
161 + } else {
162 + Navigator.of(context).pushNamed(Routes.newWalletType);
163 + }
164 + },
165 image: newWalletImage,
166 text: S.of(context).wallet_list_create_new_wallet,
183 - color: Theme.of(context).accentTextTheme!.bodyText1!.color!,
167 + color: Theme.of(context).accentTextTheme.bodyText1!.color!,
168 textColor: Colors.white,
169 ),
170 SizedBox(height: 10.0),
171 PrimaryImageButton(
172 onPressed: () {
189 - if (isSingleCoin) {
190 - Navigator
191 - .of(context)
192 - .pushNamed(
193 - Routes.restoreWallet,
194 - arguments: widget.walletListViewModel.currentWalletType);
195 - } else {
196 - Navigator.of(context).pushNamed(Routes.restoreWalletType);
197 - }
198 - },
173 + if (isSingleCoin) {
174 + Navigator.of(context).pushNamed(Routes.restoreWallet,
175 + arguments: widget.walletListViewModel.currentWalletType);
176 + } else {
177 + Navigator.of(context).pushNamed(Routes.restoreWalletType);
178 + }
179 + },
180 image: restoreWalletImage,
181 text: S.of(context).wallet_list_restore_wallet,
201 - color: Theme.of(context).accentTextTheme!.caption!.color!,
202 - textColor: Theme.of(context).primaryTextTheme!.headline6!.color!)
182 + color: Theme.of(context).accentTextTheme.caption!.color!,
183 + textColor: Theme.of(context).primaryTextTheme.headline6!.color!)
184 ])),
185 );
186 }
@@ -232,9 +213,13 @@ class WalletListBodyState extends State<WalletListBody> {
213 await widget.walletListViewModel.loadWallet(wallet);
214 auth.hideProgressText();
215 auth.close();
235 - WidgetsBinding.instance.addPostFrameCallback((_) {
236 - Navigator.of(context).pop();
237 - });
216 + // only pop the wallets route in mobile as it will go back to dashboard page
217 + // in desktop platforms the navigation tree is different
218 + if (DeviceInfo.instance.isMobile) {
219 + WidgetsBinding.instance.addPostFrameCallback((_) {
220 + Navigator.of(context).pop();
221 + });
222 + }
223 } catch (e) {
224 auth.changeProcessText(
225 S.of(context).wallet_list_failed_to_load(wallet.name, e.toString()));
@@ -245,7 +230,11 @@ class WalletListBodyState extends State<WalletListBody> {
230 changeProcessText(S.of(context).wallet_list_loading_wallet(wallet.name));
231 await widget.walletListViewModel.loadWallet(wallet);
232 hideProgressText();
248 - Navigator.of(context).pop();
233 + // only pop the wallets route in mobile as it will go back to dashboard page
234 + // in desktop platforms the navigation tree is different
235 + if (DeviceInfo.instance.isMobile) {
236 + Navigator.of(context).pop();
237 + }
238 } catch (e) {
239 changeProcessText(S.of(context).wallet_list_failed_to_load(wallet.name, e.toString()));
240 }
@@ -290,6 +279,7 @@ class WalletListBodyState extends State<WalletListBody> {
279 ? auth.changeProcessText(S.of(context).wallet_list_removing_wallet(wallet.name))
280 : changeProcessText(S.of(context).wallet_list_removing_wallet(wallet.name));
281 await widget.walletListViewModel.remove(wallet);
282 + hideProgressText();
283 } catch (e) {
284 auth != null
285 ? auth.changeProcessText(
@@ -309,8 +299,10 @@ class WalletListBodyState extends State<WalletListBody> {
299 }
300
301 void hideProgressText() {
312 - _progressBar?.dismiss();
313 - _progressBar = null;
302 + Future.delayed(Duration(milliseconds: 50), () {
303 + _progressBar?.dismiss();
304 + _progressBar = null;
305 + });
306 }
307
308 ActionPane _actionPane(WalletListItem wallet) => ActionPane(
lib/src/screens/welcome/welcome_page.dart
+111 -145
@@ -1,4 +1,5 @@
1 import 'package:cake_wallet/themes/theme_base.dart';
2 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
3 import 'package:flutter/material.dart';
4 import 'package:cake_wallet/routes.dart';
5 import 'package:cake_wallet/src/widgets/primary_button.dart';
@@ -19,7 +20,7 @@ class WelcomePage extends BasePage {
20 if (isHaven) {
21 return S.of(context).haven_app;
22 }
22 -
23 +
24 return S.of(context).cake_wallet;
25 }
26
@@ -31,172 +32,137 @@ class WelcomePage extends BasePage {
32 if (isHaven) {
33 return S.of(context).haven_app_wallet_text;
34 }
34 -
35 +
36 return S.of(context).first_wallet_text;
37 }
38
39 @override
40 Widget build(BuildContext context) {
41 return Scaffold(
41 - backgroundColor: Theme
42 - .of(context)
43 - .backgroundColor,
42 + backgroundColor: Theme.of(context).backgroundColor,
43 resizeToAvoidBottomInset: false,
44 body: body(context));
45 }
46
47 @override
48 Widget body(BuildContext context) {
50 - final welcomeImage = currentTheme.type == ThemeType.dark
51 - ? welcomeImageDark : welcomeImageLight;
49 + final welcomeImage = currentTheme.type == ThemeType.dark ? welcomeImageDark : welcomeImageLight;
50
51 final newWalletImage = Image.asset('assets/images/new_wallet.png',
52 height: 12,
53 width: 12,
56 - color: Theme
57 - .of(context)
58 - .accentTextTheme!
59 - .headline5!
60 - .decorationColor!);
54 + color: Theme.of(context).accentTextTheme!.headline5!.decorationColor!);
55 final restoreWalletImage = Image.asset('assets/images/restore_wallet.png',
62 - height: 12,
63 - width: 12,
64 - color: Theme.of(context)
65 - .primaryTextTheme!
66 - .headline6!
67 - .color!);
56 + height: 12, width: 12, color: Theme.of(context).primaryTextTheme!.headline6!.color!);
57
69 - return WillPopScope(onWillPop: () async => false, child: Container(
70 - padding: EdgeInsets.only(top: 64, bottom: 24, left: 24, right: 24),
71 - child: Column(
72 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
73 - children: <Widget>[
74 - Flexible(
75 - flex: 2,
76 - child: AspectRatio(
77 - aspectRatio: aspectRatioImage,
78 - child: FittedBox(child: welcomeImage, fit: BoxFit.fill)
79 - )
80 - ),
81 - Flexible(
82 - flex: 3,
58 + return WillPopScope(
59 + onWillPop: () async => false,
60 + child: Container(
61 + padding: EdgeInsets.only(top: 64, bottom: 24, left: 24, right: 24),
62 + child: Center(
63 + child: ConstrainedBox(
64 + constraints:
65 + BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
66 child: Column(
67 mainAxisAlignment: MainAxisAlignment.spaceBetween,
68 children: <Widget>[
86 - Column(
87 - children: <Widget>[
88 - Padding(
89 - padding: EdgeInsets.only(top: 24),
90 - child: Text(
91 - S
92 - .of(context)
93 - .welcome,
94 - style: TextStyle(
95 - fontSize: 18,
96 - fontWeight: FontWeight.w500,
97 - color: Theme
98 - .of(context)
99 - .accentTextTheme!
100 - .headline2!
101 - .color!,
102 - ),
103 - textAlign: TextAlign.center,
104 - ),
105 - ),
106 - Padding(
107 - padding: EdgeInsets.only(top: 5),
108 - child: Text(
109 - appTitle(context),
110 - style: TextStyle(
111 - fontSize: 36,
112 - fontWeight: FontWeight.bold,
113 - color: Theme.of(context)
114 - .primaryTextTheme!
115 - .headline6!
116 - .color!,
117 - ),
118 - textAlign: TextAlign.center,
119 - ),
120 - ),
121 - Padding(
122 - padding: EdgeInsets.only(top: 5),
123 - child: Text(
124 - appDescription(context),
125 - style: TextStyle(
126 - fontSize: 16,
127 - fontWeight: FontWeight.w500,
128 - color: Theme
129 - .of(context)
130 - .accentTextTheme!
131 - .headline2!
132 - .color!,
69 + Flexible(
70 + flex: 2,
71 + child: AspectRatio(
72 + aspectRatio: aspectRatioImage,
73 + child: FittedBox(child: welcomeImage, fit: BoxFit.fill))),
74 + Flexible(
75 + flex: 3,
76 + child: Column(
77 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
78 + children: <Widget>[
79 + Column(
80 + children: <Widget>[
81 + Padding(
82 + padding: EdgeInsets.only(top: 24),
83 + child: Text(
84 + S.of(context).welcome,
85 + style: TextStyle(
86 + fontSize: 18,
87 + fontWeight: FontWeight.w500,
88 + color: Theme.of(context).accentTextTheme!.headline2!.color!,
89 + ),
90 + textAlign: TextAlign.center,
91 + ),
92 + ),
93 + Padding(
94 + padding: EdgeInsets.only(top: 5),
95 + child: Text(
96 + appTitle(context),
97 + style: TextStyle(
98 + fontSize: 36,
99 + fontWeight: FontWeight.bold,
100 + color: Theme.of(context).primaryTextTheme!.headline6!.color!,
101 + ),
102 + textAlign: TextAlign.center,
103 + ),
104 + ),
105 + Padding(
106 + padding: EdgeInsets.only(top: 5),
107 + child: Text(
108 + appDescription(context),
109 + style: TextStyle(
110 + fontSize: 16,
111 + fontWeight: FontWeight.w500,
112 + color: Theme.of(context).accentTextTheme!.headline2!.color!,
113 + ),
114 + textAlign: TextAlign.center,
115 + ),
116 + ),
117 + ],
118 ),
134 - textAlign: TextAlign.center,
135 - ),
136 - ),
137 - ],
138 - ),
139 - Column(
140 - children: <Widget>[
141 - Text(
142 - S
143 - .of(context)
144 - .please_make_selection,
145 - style: TextStyle(
146 - fontSize: 12,
147 - fontWeight: FontWeight.normal,
148 - color: Theme.of(context)
149 - .accentTextTheme!
150 - .headline2!
151 - .color!,
152 - ),
153 - textAlign: TextAlign.center,
154 - ),
155 - Padding(
156 - padding: EdgeInsets.only(top: 24),
157 - child: PrimaryImageButton(
158 - onPressed: () =>
159 - Navigator.pushNamed(context,
160 - Routes.newWalletFromWelcome),
161 - image: newWalletImage,
162 - text: S.of(context).create_new,
163 - color: Theme.of(context)
164 - .accentTextTheme!
165 - .subtitle2!
166 - .decorationColor!,
167 - textColor: Theme
168 - .of(context)
169 - .accentTextTheme!
170 - .headline5!
171 - .decorationColor!,
172 - ),
173 - ),
174 - Padding(
175 - padding: EdgeInsets.only(top: 10),
176 - child: PrimaryImageButton(
177 - onPressed: () {
178 - Navigator.pushNamed(context, Routes.restoreOptions);
179 - },
180 - image: restoreWalletImage,
181 - text: S
182 - .of(context)
183 - .restore_wallet,
184 - color: Theme.of(context)
185 - .accentTextTheme!
186 - .caption!
187 - .color!,
188 - textColor: Theme.of(context)
189 - .primaryTextTheme!
190 - .headline6!
191 - .color!),
192 - )
193 - ],
194 - )
119 + Column(
120 + children: <Widget>[
121 + Text(
122 + S.of(context).please_make_selection,
123 + style: TextStyle(
124 + fontSize: 12,
125 + fontWeight: FontWeight.normal,
126 + color: Theme.of(context).accentTextTheme!.headline2!.color!,
127 + ),
128 + textAlign: TextAlign.center,
129 + ),
130 + Padding(
131 + padding: EdgeInsets.only(top: 24),
132 + child: PrimaryImageButton(
133 + onPressed: () =>
134 + Navigator.pushNamed(context, Routes.newWalletFromWelcome),
135 + image: newWalletImage,
136 + text: S.of(context).create_new,
137 + color: Theme.of(context)
138 + .accentTextTheme!
139 + .subtitle2!
140 + .decorationColor!,
141 + textColor: Theme.of(context)
142 + .accentTextTheme!
143 + .headline5!
144 + .decorationColor!,
145 + ),
146 + ),
147 + Padding(
148 + padding: EdgeInsets.only(top: 10),
149 + child: PrimaryImageButton(
150 + onPressed: () {
151 + Navigator.pushNamed(context, Routes.restoreOptions);
152 + },
153 + image: restoreWalletImage,
154 + text: S.of(context).restore_wallet,
155 + color: Theme.of(context).accentTextTheme!.caption!.color!,
156 + textColor:
157 + Theme.of(context).primaryTextTheme!.headline6!.color!),
158 + )
159 + ],
160 + )
161 + ],
162 + ))
163 ],
196 - )
197 - )
198 - ],
199 - )
200 - ));
164 + ),
165 + ),
166 + )));
167 }
168 }
lib/src/widgets/add_template_button.dart new
+52
@@ -0,0 +1,52 @@
1 +import 'package:cake_wallet/generated/i18n.dart';
2 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
3 +import 'package:dotted_border/dotted_border.dart';
4 +import 'package:flutter/material.dart';
5 +
6 +class AddTemplateButton extends StatelessWidget {
7 + final Function() onTap;
8 + final int currentTemplatesLength;
9 +
10 + const AddTemplateButton({Key? key, required this.onTap, required this.currentTemplatesLength})
11 + : super(key: key);
12 +
13 + @override
14 + Widget build(BuildContext context) {
15 + return GestureDetector(
16 + onTap: onTap,
17 + child: Container(
18 + padding: EdgeInsets.only(left: 1, right: 10),
19 + child: DottedBorder(
20 + borderType: BorderType.RRect,
21 + dashPattern: [6, 4],
22 + color: Theme.of(context).primaryTextTheme.headline3!.decorationColor!,
23 + strokeWidth: 2,
24 + radius: Radius.circular(20),
25 + child: Container(
26 + height: 34,
27 + padding: EdgeInsets.symmetric(
28 + horizontal: ResponsiveLayoutUtil.instance.isMobile(context) ? 10 : 30),
29 + alignment: Alignment.center,
30 + decoration: BoxDecoration(
31 + borderRadius: BorderRadius.all(Radius.circular(20)),
32 + color: Colors.transparent,
33 + ),
34 + child: currentTemplatesLength >= 1
35 + ? Icon(
36 + Icons.add,
37 + color: Theme.of(context).primaryTextTheme.headline2!.color!,
38 + )
39 + : Text(
40 + S.of(context).new_template,
41 + style: TextStyle(
42 + fontSize: 14,
43 + fontWeight: FontWeight.w600,
44 + color: Theme.of(context).primaryTextTheme.headline2!.color!,
45 + ),
46 + ),
47 + ),
48 + ),
49 + ),
50 + );
51 + }
52 +}
lib/src/widgets/address_text_field.dart
+16 -17
@@ -1,3 +1,6 @@
1 +import 'dart:io';
2 +
3 +import 'package:cake_wallet/utils/device_info.dart';
4 import 'package:flutter/services.dart';
5 import 'package:flutter/material.dart';
6 import 'package:cake_wallet/routes.dart';
@@ -65,7 +68,7 @@ class AddressTextField extends StatelessWidget {
68 style: textStyle ??
69 TextStyle(
70 fontSize: 16,
68 - color: Theme.of(context).primaryTextTheme!.headline6!.color!),
71 + color: Theme.of(context).primaryTextTheme.headline6!.color!),
72 decoration: InputDecoration(
73 suffixIcon: SizedBox(
74 width: prefixIconWidth * options.length +
@@ -102,7 +105,8 @@ class AddressTextField extends StatelessWidget {
105 width: prefixIconWidth * options.length +
106 (spaceBetweenPrefixIcons * options.length),
107 child: Row(
105 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
108 + mainAxisAlignment: DeviceInfo.instance.isMobile
109 + ? MainAxisAlignment.spaceBetween : MainAxisAlignment.end,
110 children: [
111 SizedBox(width: 5),
112 if (this.options.contains(AddressTextFieldOption.paste)) ...[
@@ -117,8 +121,7 @@ class AddressTextField extends StatelessWidget {
121 decoration: BoxDecoration(
122 color: buttonColor ??
123 Theme.of(context)
120 - .accentTextTheme!
121 - .headline6!
124 + .accentTextTheme.headline6!
125 .color!,
126 borderRadius:
127 BorderRadius.all(Radius.circular(6))),
@@ -126,13 +129,13 @@ class AddressTextField extends StatelessWidget {
129 'assets/images/paste_ios.png',
130 color: iconColor ??
131 Theme.of(context)
129 - .primaryTextTheme!
130 - .headline4!
132 + .primaryTextTheme.headline4!
133 .decorationColor!,
134 )),
135 )),
136 ],
135 - if (this.options.contains(AddressTextFieldOption.qrCode)) ...[
137 + if (this.options.contains(AddressTextFieldOption.qrCode) && DeviceInfo.instance.isMobile)
138 + ...[
139 Container(
140 width: prefixIconWidth,
141 height: prefixIconHeight,
@@ -144,8 +147,7 @@ class AddressTextField extends StatelessWidget {
147 decoration: BoxDecoration(
148 color: buttonColor ??
149 Theme.of(context)
147 - .accentTextTheme!
148 - .headline6!
150 + .accentTextTheme.headline6!
151 .color!,
152 borderRadius:
153 BorderRadius.all(Radius.circular(6))),
@@ -153,12 +155,11 @@ class AddressTextField extends StatelessWidget {
155 'assets/images/qr_code_icon.png',
156 color: iconColor ??
157 Theme.of(context)
156 - .primaryTextTheme!
157 - .headline4!
158 + .primaryTextTheme.headline4!
159 .decorationColor!,
160 )),
161 ))
161 - ],
162 + ] else SizedBox(width: 5),
163 if (this
164 .options
165 .contains(AddressTextFieldOption.addressBook)) ...[
@@ -173,8 +174,7 @@ class AddressTextField extends StatelessWidget {
174 decoration: BoxDecoration(
175 color: buttonColor ??
176 Theme.of(context)
176 - .accentTextTheme!
177 - .headline6!
177 + .accentTextTheme.headline6!
178 .color!,
179 borderRadius:
180 BorderRadius.all(Radius.circular(6))),
@@ -182,8 +182,7 @@ class AddressTextField extends StatelessWidget {
182 'assets/images/open_book.png',
183 color: iconColor ??
184 Theme.of(context)
185 - .primaryTextTheme!
186 - .headline4!
185 + .primaryTextTheme.headline4!
186 .decorationColor!,
187 )),
188 ))
@@ -211,7 +210,7 @@ class AddressTextField extends StatelessWidget {
210 }
211
212 Future<void> _presetAddressBookPicker(BuildContext context) async {
214 - final contact = await Navigator.of(context, rootNavigator: true)
213 + final contact = await Navigator.of(context)
214 .pushNamed(Routes.pickerAddressBook,arguments: selectedCurrency);
215
216 if (contact is ContactBase && contact.address != null) {
lib/src/widgets/alert_background.dart
+8 -3
@@ -1,5 +1,5 @@
1 import 'dart:ui';
2 -import 'package:flutter/cupertino.dart';
2 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
3 import 'package:flutter/material.dart';
4 import 'package:cake_wallet/palette.dart';
5
@@ -21,10 +21,15 @@ class AlertBackground extends StatelessWidget {
21 filter: ImageFilter.blur(sigmaX: 3.0, sigmaY: 3.0),
22 child: Container(
23 decoration: BoxDecoration(color: PaletteDark.darkNightBlue.withOpacity(0.75)),
24 - child: child,
24 + child: Center(
25 + child: Container(
26 + width: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint,
27 + child: child,
28 + ),
29 + ),
30 ),
31 ),
32 ),
33 );
34 }
30 -}
\ No newline at end of file
35 +}
lib/src/widgets/alert_close_button.dart
+1 -4
@@ -13,9 +13,7 @@ class AlertCloseButton extends StatelessWidget {
13
14 @override
15 Widget build(BuildContext context) {
16 - return Positioned(
17 - bottom: 60,
18 - child: GestureDetector(
16 + return GestureDetector(
17 onTap: () => Navigator.of(context).pop(),
18 child: Container(
19 height: 42,
@@ -28,7 +26,6 @@ class AlertCloseButton extends StatelessWidget {
26 child: image ?? closeButton,
27 ),
28 ),
31 - )
29 );
30 }
31 }
\ No newline at end of file
lib/src/widgets/base_text_form_field.dart
+7 -4
@@ -27,6 +27,7 @@ class BaseTextFormField extends StatelessWidget {
27 this.maxLength,
28 this.focusNode,
29 this.initialValue,
30 + this.onSubmit,
31 this.borderWidth = 1.0});
32
33 final TextEditingController? controller;
@@ -54,6 +55,7 @@ class BaseTextFormField extends StatelessWidget {
55 final bool? enableInteractiveSelection;
56 final String? initialValue;
57 final double borderWidth;
58 + final void Function(String)? onSubmit;
59
60 @override
61 Widget build(BuildContext context) {
@@ -71,11 +73,12 @@ class BaseTextFormField extends StatelessWidget {
73 inputFormatters: inputFormatters,
74 enabled: enabled,
75 maxLength: maxLength,
76 + onFieldSubmitted: onSubmit,
77 style: textStyle ??
78 TextStyle(
79 fontSize: 16.0,
80 color:
78 - textColor ?? Theme.of(context).primaryTextTheme!.headline6!.color!),
81 + textColor ?? Theme.of(context).primaryTextTheme.headline6!.color!),
82 decoration: InputDecoration(
83 prefix: prefix,
84 prefixIcon: prefixIcon,
@@ -89,17 +92,17 @@ class BaseTextFormField extends StatelessWidget {
92 focusedBorder: UnderlineInputBorder(
93 borderSide: BorderSide(
94 color: borderColor ??
92 - Theme.of(context).primaryTextTheme!.headline6!.backgroundColor!,
95 + Theme.of(context).primaryTextTheme.headline6!.backgroundColor!,
96 width: borderWidth)),
97 disabledBorder: UnderlineInputBorder(
98 borderSide: BorderSide(
99 color: borderColor ??
97 - Theme.of(context).primaryTextTheme!.headline6!.backgroundColor!,
100 + Theme.of(context).primaryTextTheme.headline6!.backgroundColor!,
101 width: borderWidth)),
102 enabledBorder: UnderlineInputBorder(
103 borderSide: BorderSide(
104 color: borderColor ??
102 - Theme.of(context).primaryTextTheme!.headline6!.backgroundColor!,
105 + Theme.of(context).primaryTextTheme.headline6!.backgroundColor!,
106 width: borderWidth))),
107 validator: validator,
108 );
lib/src/widgets/check_box_picker.dart
+50 -50
@@ -1,4 +1,5 @@
1 import 'package:cake_wallet/palette.dart';
2 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
3 import 'package:flutter/material.dart';
4 import 'package:cake_wallet/src/widgets/alert_background.dart';
5 import 'package:cake_wallet/src/widgets/alert_close_button.dart';
@@ -32,63 +33,62 @@ class CheckBoxPickerState extends State<CheckBoxPicker> {
33 @override
34 Widget build(BuildContext context) {
35 return AlertBackground(
35 - child: Stack(
36 - alignment: Alignment.center,
37 - children: <Widget>[
38 - Column(
39 - mainAxisSize: MainAxisSize.min,
40 - children: <Widget>[
41 - if (widget.title.isNotEmpty)
42 - Container(
43 - padding: EdgeInsets.symmetric(horizontal: 24),
44 - child: Text(
45 - widget.title,
46 - textAlign: TextAlign.center,
47 - style: TextStyle(
48 - fontSize: 18,
49 - fontFamily: 'Lato',
50 - fontWeight: FontWeight.bold,
51 - decoration: TextDecoration.none,
52 - color: Colors.white,
36 + child: Center(
37 + child: Column(
38 + mainAxisSize: MainAxisSize.min,
39 + children: <Widget>[
40 + if (widget.title.isNotEmpty)
41 + Container(
42 + padding: EdgeInsets.symmetric(horizontal: 24),
43 + child: Text(
44 + widget.title,
45 + textAlign: TextAlign.center,
46 + style: TextStyle(
47 + fontSize: 18,
48 + fontFamily: 'Lato',
49 + fontWeight: FontWeight.bold,
50 + decoration: TextDecoration.none,
51 + color: Colors.white,
52 + ),
53 ),
54 ),
55 - ),
56 - Padding(
57 - padding: EdgeInsets.only(left: 24, right: 24, top: 24),
58 - child: ClipRRect(
59 - borderRadius: BorderRadius.all(Radius.circular(30)),
60 - child: Container(
61 - color: Theme.of(context).accentTextTheme.headline6!.color!,
62 - child: ConstrainedBox(
63 - constraints: BoxConstraints(
64 - maxHeight: MediaQuery.of(context).size.height * 0.65,
65 - ),
66 - child: Column(
67 - mainAxisSize: MainAxisSize.min,
68 - children: [
69 - Flexible(
70 - child: Stack(
71 - alignment: Alignment.center,
72 - children: <Widget>[
73 - (items.length) > 3
74 - ? Scrollbar(
75 - controller: controller,
76 - child: itemsList(),
77 - )
78 - : itemsList(),
79 - ],
55 + Padding(
56 + padding: EdgeInsets.only(left: 24, right: 24, top: 24),
57 + child: ClipRRect(
58 + borderRadius: BorderRadius.all(Radius.circular(30)),
59 + child: Container(
60 + color: Theme.of(context).accentTextTheme.headline6!.color!,
61 + child: ConstrainedBox(
62 + constraints: BoxConstraints(
63 + maxHeight: MediaQuery.of(context).size.height * 0.65,
64 + maxWidth: ResponsiveLayoutUtil.kPopupWidth,
65 + ),
66 + child: Column(
67 + mainAxisSize: MainAxisSize.min,
68 + children: [
69 + Flexible(
70 + child: Stack(
71 + alignment: Alignment.center,
72 + children: <Widget>[
73 + items.length > 3
74 + ? Scrollbar(
75 + controller: controller,
76 + child: itemsList(),
77 + )
78 + : itemsList(),
79 + ],
80 + ),
81 ),
81 - ),
82 - ],
82 + ],
83 + ),
84 ),
85 ),
86 ),
87 ),
87 - )
88 - ],
89 - ),
90 - AlertCloseButton(),
91 - ],
88 + SizedBox(height: ResponsiveLayoutUtil.kPopupSpaceHeight),
89 + AlertCloseButton(),
90 + ],
91 + ),
92 ),
93 );
94 }
lib/src/widgets/market_place_item.dart
+3
@@ -17,6 +17,9 @@ class MarketPlaceItem extends StatelessWidget {
17 Widget build(BuildContext context) {
18 return InkWell(
19 onTap: onTap,
20 + hoverColor: Colors.transparent,
21 + splashColor: Colors.transparent,
22 + highlightColor: Colors.transparent,
23 child: Stack(
24 children: [
25 Container(
lib/src/widgets/nav_bar.dart
+16 -21
@@ -1,13 +1,7 @@
1 import 'package:flutter/cupertino.dart';
2 -import 'package:flutter/material.dart';
2
3 class NavBar extends StatelessWidget implements ObstructingPreferredSizeWidget {
5 - factory NavBar(
6 - {Widget? leading,
7 - Widget? middle,
8 - Widget? trailing,
9 - Color? backgroundColor}) {
10 -
4 + factory NavBar({Widget? leading, Widget? middle, Widget? trailing, Color? backgroundColor}) {
5 return NavBar._internal(
6 leading: leading,
7 middle: middle,
@@ -17,11 +11,7 @@ class NavBar extends StatelessWidget implements ObstructingPreferredSizeWidget {
11 }
12
13 factory NavBar.withShadow(
20 - {Widget? leading,
21 - Widget? middle,
22 - Widget? trailing,
23 - Color? backgroundColor}) {
24 -
14 + {Widget? leading, Widget? middle, Widget? trailing, Color? backgroundColor}) {
15 return NavBar._internal(
16 leading: leading,
17 middle: middle,
@@ -29,13 +19,15 @@ class NavBar extends StatelessWidget implements ObstructingPreferredSizeWidget {
19 height: 80,
20 backgroundColor: backgroundColor,
21 decoration: BoxDecoration(
32 - color: backgroundColor,
33 - boxShadow: [
34 - BoxShadow(
35 - color: Color.fromRGBO(132, 141, 198, 0.11),
36 - blurRadius: 8,
37 - offset: Offset(0, 2))
38 - ]),
22 + color: backgroundColor,
23 + boxShadow: [
24 + BoxShadow(
25 + color: Color.fromRGBO(132, 141, 198, 0.11),
26 + blurRadius: 8,
27 + offset: Offset(0, 2),
28 + ),
29 + ],
30 + ),
31 );
32 }
33
@@ -59,14 +51,17 @@ class NavBar extends StatelessWidget implements ObstructingPreferredSizeWidget {
51
52 @override
53 Widget build(BuildContext context) {
54 + if (leading == null && middle == null && trailing == null) {
55 + return const SizedBox();
56 + }
57 +
58 final pad = height - _originalHeight;
59 final paddingTop = pad / 2;
60 final _paddingBottom = (pad / 2);
61
62 return Container(
63 decoration: decoration ?? BoxDecoration(color: backgroundColor),
68 - padding:
69 - EdgeInsetsDirectional.only(bottom: _paddingBottom, top: paddingTop),
64 + padding: EdgeInsetsDirectional.only(bottom: _paddingBottom, top: paddingTop),
65 child: CupertinoNavigationBar(
66 leading: leading,
67 automaticallyImplyLeading: false,
lib/src/widgets/picker.dart
+91 -92
@@ -1,5 +1,6 @@
1 // ignore_for_file: deprecated_member_use
2
3 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
4 import 'package:flutter/material.dart';
5 import 'package:cake_wallet/src/widgets/alert_background.dart';
6 import 'package:cake_wallet/src/widgets/alert_close_button.dart';
@@ -70,108 +71,106 @@ class _PickerState<Item> extends State<Picker<Item>> {
71 @override
72 Widget build(BuildContext context) {
73 return AlertBackground(
73 - child: Stack(
74 - alignment: Alignment.center,
74 + child: Column(
75 + mainAxisSize: MainAxisSize.min,
76 + mainAxisAlignment: MainAxisAlignment.center,
77 children: <Widget>[
76 - Column(
77 - mainAxisSize: MainAxisSize.min,
78 - children: <Widget>[
79 - if (widget.title?.isNotEmpty ?? false)
80 - Container(
81 - padding: EdgeInsets.symmetric(horizontal: 24),
82 - child: Text(
83 - widget.title!,
84 - textAlign: TextAlign.center,
85 - style: TextStyle(
86 - fontSize: 18,
87 - fontFamily: 'Lato',
88 - fontWeight: FontWeight.bold,
89 - decoration: TextDecoration.none,
90 - color: Colors.white,
91 - ),
92 - ),
78 + if (widget.title?.isNotEmpty ?? false)
79 + Container(
80 + padding: EdgeInsets.symmetric(horizontal: 24),
81 + child: Text(
82 + widget.title!,
83 + textAlign: TextAlign.center,
84 + style: TextStyle(
85 + fontSize: 18,
86 + fontFamily: 'Lato',
87 + fontWeight: FontWeight.bold,
88 + decoration: TextDecoration.none,
89 + color: Colors.white,
90 ),
94 - Padding(
95 - padding: EdgeInsets.only(left: 24, right: 24, top: 24),
96 - child: ClipRRect(
97 - borderRadius: BorderRadius.all(Radius.circular(30)),
98 - child: Container(
99 - color: Theme.of(context).accentTextTheme.headline6!.color!,
100 - child: ConstrainedBox(
101 - constraints: BoxConstraints(
102 - maxHeight: MediaQuery.of(context).size.height * 0.65,
103 - ),
104 - child: Column(
105 - mainAxisSize: MainAxisSize.min,
106 - children: [
107 - if (widget.hintText != null)
108 - Padding(
109 - padding: const EdgeInsets.all(16),
110 - child: TextFormField(
111 - controller: searchController,
112 - style: TextStyle(color: Theme.of(context).primaryTextTheme.headline6!.color!),
113 - decoration: InputDecoration(
114 - hintText: widget.hintText,
115 - prefixIcon: Image.asset("assets/images/search_icon.png"),
116 - filled: true,
117 - fillColor: Theme.of(context).accentTextTheme.headline3!.color!,
118 - alignLabelWithHint: false,
119 - contentPadding: const EdgeInsets.symmetric(vertical: 4, horizontal: 16),
120 - enabledBorder: OutlineInputBorder(
121 - borderRadius: BorderRadius.circular(14),
122 - borderSide: const BorderSide(
123 - color: Colors.transparent,
124 - )),
125 - focusedBorder: OutlineInputBorder(
126 - borderRadius: BorderRadius.circular(14),
127 - borderSide: const BorderSide(
128 - color: Colors.transparent,
129 - )),
130 - ),
91 + ),
92 + ),
93 + Padding(
94 + padding: EdgeInsets.only(left: 24, right: 24, top: 24),
95 + child: ClipRRect(
96 + borderRadius: BorderRadius.all(Radius.circular(30)),
97 + child: Container(
98 + color: Theme.of(context).accentTextTheme.headline6!.color!,
99 + child: ConstrainedBox(
100 + constraints: BoxConstraints(
101 + maxHeight: MediaQuery.of(context).size.height * 0.65,
102 + maxWidth: ResponsiveLayoutUtil.kPopupWidth,
103 + ),
104 + child: Column(
105 + mainAxisSize: MainAxisSize.min,
106 + children: [
107 + if (widget.hintText != null)
108 + Padding(
109 + padding: const EdgeInsets.all(16),
110 + child: TextFormField(
111 + controller: searchController,
112 + style: TextStyle(color: Theme.of(context).primaryTextTheme.headline6!.color!),
113 + decoration: InputDecoration(
114 + hintText: widget.hintText,
115 + prefixIcon: Image.asset("assets/images/search_icon.png"),
116 + filled: true,
117 + fillColor: Theme.of(context).accentTextTheme.headline3!.color!,
118 + alignLabelWithHint: false,
119 + contentPadding: const EdgeInsets.symmetric(vertical: 4, horizontal: 16),
120 + enabledBorder: OutlineInputBorder(
121 + borderRadius: BorderRadius.circular(14),
122 + borderSide: const BorderSide(
123 + color: Colors.transparent,
124 + )),
125 + focusedBorder: OutlineInputBorder(
126 + borderRadius: BorderRadius.circular(14),
127 + borderSide: const BorderSide(
128 + color: Colors.transparent,
129 + )),
130 ),
131 ),
133 - Divider(
134 - color: Theme.of(context).accentTextTheme.headline6!.backgroundColor!,
135 - height: 1,
132 ),
137 - if (widget.selectedAtIndex != -1) buildSelectedItem(),
138 - Flexible(
139 - child: Stack(
140 - alignment: Alignment.center,
141 - children: <Widget>[
142 - items.length > 3 ? Scrollbar(
143 - controller: controller,
144 - child: itemsList(),
145 - ) : itemsList(),
146 - (widget.description?.isNotEmpty ?? false)
147 - ? Positioned(
148 - bottom: 24,
149 - left: 24,
150 - right: 24,
151 - child: Text(
152 - widget.description!,
153 - textAlign: TextAlign.center,
154 - style: TextStyle(
155 - fontSize: 12,
156 - fontWeight: FontWeight.w500,
157 - fontFamily: 'Lato',
158 - decoration: TextDecoration.none,
159 - color: Theme.of(context).primaryTextTheme.headline6!.color!,
160 - ),
133 + Divider(
134 + color: Theme.of(context).accentTextTheme.headline6!.backgroundColor!,
135 + height: 1,
136 + ),
137 + if (widget.selectedAtIndex != -1) buildSelectedItem(),
138 + Flexible(
139 + child: Stack(
140 + alignment: Alignment.center,
141 + children: <Widget>[
142 + items.length > 3 ? Scrollbar(
143 + controller: controller,
144 + child: itemsList(),
145 + ) : itemsList(),
146 + (widget.description?.isNotEmpty ?? false)
147 + ? Positioned(
148 + bottom: 24,
149 + left: 24,
150 + right: 24,
151 + child: Text(
152 + widget.description!,
153 + textAlign: TextAlign.center,
154 + style: TextStyle(
155 + fontSize: 12,
156 + fontWeight: FontWeight.w500,
157 + fontFamily: 'Lato',
158 + decoration: TextDecoration.none,
159 + color: Theme.of(context).primaryTextTheme.headline6!.color!,
160 ),
162 - )
163 - : Offstage(),
164 - ],
165 - ),
161 + ),
162 + )
163 + : Offstage(),
164 + ],
165 ),
167 - ],
168 - ),
169 - ),
166 + ),
167 + ],
168 ),
169 ),
172 - )
173 - ],
170 + ),
171 + ),
172 ),
173 + SizedBox(height: ResponsiveLayoutUtil.kPopupSpaceHeight),
174 AlertCloseButton(),
175 ],
176 ),
lib/src/widgets/primary_button.dart
+121 -108
@@ -1,3 +1,4 @@
1 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
2 import 'package:dotted_border/dotted_border.dart';
3 import 'package:flutter/cupertino.dart';
4 import 'package:flutter/material.dart';
@@ -24,28 +25,31 @@ class PrimaryButton extends StatelessWidget {
25
26 @override
27 Widget build(BuildContext context) {
27 - final content = SizedBox(
28 - width: double.infinity,
29 - height: 52.0,
30 - child: TextButton(
31 - onPressed: isDisabled
32 - ? (onDisabledPressed != null ? onDisabledPressed : null) : onPressed,
33 - style: ButtonStyle(backgroundColor: MaterialStateProperty.all(isDisabled ? color.withOpacity(0.5) : color),
34 - shape: MaterialStateProperty.all<RoundedRectangleBorder>(
35 - RoundedRectangleBorder(
36 - borderRadius: BorderRadius.circular(26.0),
28 + final content = ConstrainedBox(
29 + constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
30 + child: SizedBox(
31 + width: double.infinity,
32 + height: 52.0,
33 + child: TextButton(
34 + onPressed: isDisabled
35 + ? (onDisabledPressed != null ? onDisabledPressed : null) : onPressed,
36 + style: ButtonStyle(backgroundColor: MaterialStateProperty.all(isDisabled ? color.withOpacity(0.5) : color),
37 + shape: MaterialStateProperty.all<RoundedRectangleBorder>(
38 + RoundedRectangleBorder(
39 + borderRadius: BorderRadius.circular(26.0),
40 + ),
41 ),
38 - ),
39 - overlayColor: MaterialStateProperty.all(Colors.transparent)),
40 - child: Text(text,
41 - textAlign: TextAlign.center,
42 - style: TextStyle(
43 - fontSize: 15.0,
44 - fontWeight: FontWeight.w600,
45 - color: isDisabled
46 - ? textColor.withOpacity(0.5)
47 - : textColor)),
48 - ));
42 + overlayColor: MaterialStateProperty.all(Colors.transparent)),
43 + child: Text(text,
44 + textAlign: TextAlign.center,
45 + style: TextStyle(
46 + fontSize: 15.0,
47 + fontWeight: FontWeight.w600,
48 + color: isDisabled
49 + ? textColor.withOpacity(0.5)
50 + : textColor)),
51 + )),
52 + );
53
54 return isDottedBorder
55 ? DottedBorder(
@@ -77,29 +81,32 @@ class LoadingPrimaryButton extends StatelessWidget {
81
82 @override
83 Widget build(BuildContext context) {
80 - return SizedBox(
81 - width: double.infinity,
82 - height: 52.0,
83 - child: TextButton(
84 - onPressed: (isLoading || isDisabled) ? null : onPressed,
85 - style: ButtonStyle(backgroundColor: MaterialStateProperty.all(isDisabled ? color.withOpacity(0.5) : color),
86 - shape: MaterialStateProperty.all<RoundedRectangleBorder>(
87 - RoundedRectangleBorder(
88 - borderRadius: BorderRadius.circular(26.0),
89 - ),
90 - )),
91 -
92 - child: isLoading
93 - ? CupertinoActivityIndicator(animating: true)
94 - : Text(text,
95 - style: TextStyle(
96 - fontSize: 15.0,
97 - fontWeight: FontWeight.w600,
98 - color: isDisabled
99 - ? textColor.withOpacity(0.5)
100 - : textColor
84 + return ConstrainedBox(
85 + constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
86 + child: SizedBox(
87 + width: double.infinity,
88 + height: 52.0,
89 + child: TextButton(
90 + onPressed: (isLoading || isDisabled) ? null : onPressed,
91 + style: ButtonStyle(backgroundColor: MaterialStateProperty.all(isDisabled ? color.withOpacity(0.5) : color),
92 + shape: MaterialStateProperty.all<RoundedRectangleBorder>(
93 + RoundedRectangleBorder(
94 + borderRadius: BorderRadius.circular(26.0),
95 + ),
96 )),
102 - ));
97 +
98 + child: isLoading
99 + ? CupertinoActivityIndicator(animating: true)
100 + : Text(text,
101 + style: TextStyle(
102 + fontSize: 15.0,
103 + fontWeight: FontWeight.w600,
104 + color: isDisabled
105 + ? textColor.withOpacity(0.5)
106 + : textColor
107 + )),
108 + )),
109 + );
110 }
111 }
112
@@ -130,45 +137,48 @@ class PrimaryIconButton extends StatelessWidget {
137
138 @override
139 Widget build(BuildContext context) {
133 - return SizedBox(
134 - width: double.infinity,
135 - height: 52.0,
136 - child: TextButton(
137 - onPressed: onPressed,
138 - style: ButtonStyle(backgroundColor: MaterialStateProperty.all(color),
139 - shape: MaterialStateProperty.all<RoundedRectangleBorder>(
140 - RoundedRectangleBorder(
141 - borderRadius: BorderRadius.circular(radius),
142 - ),
143 - )),
144 - child: Stack(
145 - children: <Widget>[
146 - Row(
147 - mainAxisAlignment: mainAxisAlignment,
148 - children: <Widget>[
149 - Container(
150 - width: 26.0,
151 - height: 52.0,
152 - decoration: BoxDecoration(
153 - shape: BoxShape.circle, color: iconBackgroundColor),
154 - child: Center(
155 - child: Icon(iconData, color: iconColor, size: 22.0)
156 - ),
140 + return ConstrainedBox(
141 + constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
142 + child: SizedBox(
143 + width: double.infinity,
144 + height: 52.0,
145 + child: TextButton(
146 + onPressed: onPressed,
147 + style: ButtonStyle(backgroundColor: MaterialStateProperty.all(color),
148 + shape: MaterialStateProperty.all<RoundedRectangleBorder>(
149 + RoundedRectangleBorder(
150 + borderRadius: BorderRadius.circular(radius),
151 ),
158 - ],
159 - ),
160 - Container(
161 - height: 52.0,
162 - child: Center(
163 - child: Text(text,
164 - style: TextStyle(
165 - fontSize: 16.0,
166 - color: textColor)),
152 + )),
153 + child: Stack(
154 + children: <Widget>[
155 + Row(
156 + mainAxisAlignment: mainAxisAlignment,
157 + children: <Widget>[
158 + Container(
159 + width: 26.0,
160 + height: 52.0,
161 + decoration: BoxDecoration(
162 + shape: BoxShape.circle, color: iconBackgroundColor),
163 + child: Center(
164 + child: Icon(iconData, color: iconColor, size: 22.0)
165 + ),
166 + ),
167 + ],
168 ),
168 - )
169 - ],
170 - ),
171 - ));
169 + Container(
170 + height: 52.0,
171 + child: Center(
172 + child: Text(text,
173 + style: TextStyle(
174 + fontSize: 16.0,
175 + color: textColor)),
176 + ),
177 + )
178 + ],
179 + ),
180 + )),
181 + );
182 }
183 }
184
@@ -190,34 +200,37 @@ class PrimaryImageButton extends StatelessWidget {
200
201 @override
202 Widget build(BuildContext context) {
193 - return SizedBox(
194 - width: double.infinity,
195 - height: 52.0,
196 - child: TextButton(
197 - onPressed: onPressed,
198 - style: ButtonStyle(backgroundColor: MaterialStateProperty.all(color),
199 - shape: MaterialStateProperty.all<RoundedRectangleBorder>(
200 - RoundedRectangleBorder(
201 - borderRadius: BorderRadius.circular(26.0),
202 - ),
203 - )),
204 - child:Center(
205 - child: Row(
206 - mainAxisSize: MainAxisSize.min,
207 - children: <Widget>[
208 - image,
209 - SizedBox(width: 15),
210 - Text(
211 - text,
212 - style: TextStyle(
213 - fontSize: 15,
214 - fontWeight: FontWeight.w600,
215 - color: textColor
203 + return ConstrainedBox(
204 + constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
205 + child: SizedBox(
206 + width: double.infinity,
207 + height: 52.0,
208 + child: TextButton(
209 + onPressed: onPressed,
210 + style: ButtonStyle(backgroundColor: MaterialStateProperty.all(color),
211 + shape: MaterialStateProperty.all<RoundedRectangleBorder>(
212 + RoundedRectangleBorder(
213 + borderRadius: BorderRadius.circular(26.0),
214 ),
217 - )
218 - ],
219 - ),
220 - )
221 - ));
215 + )),
216 + child:Center(
217 + child: Row(
218 + mainAxisSize: MainAxisSize.min,
219 + children: <Widget>[
220 + image,
221 + SizedBox(width: 15),
222 + Text(
223 + text,
224 + style: TextStyle(
225 + fontSize: 15,
226 + fontWeight: FontWeight.w600,
227 + color: textColor
228 + ),
229 + )
230 + ],
231 + ),
232 + )
233 + )),
234 + );
235 }
236 }
lib/src/widgets/setting_action_button.dart new
+81
@@ -0,0 +1,81 @@
1 +import 'package:cake_wallet/palette.dart';
2 +import 'package:flutter/material.dart';
3 +
4 +class SettingActionButton extends StatelessWidget {
5 + final bool isLastTile;
6 + final bool isSelected;
7 + final bool isArrowVisible;
8 + final bool selectionActive;
9 + final VoidCallback onTap;
10 + final String image;
11 + final String title;
12 + final double fromBottomEdge;
13 + final double fromTopEdge;
14 + final double tileHeight;
15 + const SettingActionButton({
16 + super.key,
17 + this.isLastTile = false,
18 + this.isSelected = false,
19 + this.selectionActive = true,
20 + this.isArrowVisible = false,
21 + required this.onTap,
22 + required this.image,
23 + required this.title,
24 + this.tileHeight = 60,
25 + this.fromTopEdge = 50,
26 + this.fromBottomEdge = 25,
27 + });
28 +
29 + @override
30 + Widget build(BuildContext context) {
31 + Color? color = isSelected
32 + ? Theme.of(context).textTheme.headline3!.color
33 + : selectionActive
34 + ? Palette.darkBlue
35 + : Theme.of(context).textTheme.headline3!.color;
36 + return InkWell(
37 + onTap: onTap,
38 + hoverColor: Colors.transparent,
39 + child: Container(
40 + height: tileHeight,
41 + padding: isLastTile
42 + ? EdgeInsets.only(
43 + left: 24,
44 + right: 24,
45 + top: fromBottomEdge,
46 + )
47 + : EdgeInsets.only(left: 24, right: 24),
48 + alignment: isLastTile ? Alignment.topLeft : null,
49 + child: Row(
50 + mainAxisAlignment: MainAxisAlignment.start,
51 + crossAxisAlignment: CrossAxisAlignment.center,
52 + children: <Widget>[
53 + Image.asset(
54 + image,
55 + height: 16,
56 + width: 16,
57 + color: Palette.darkBlue,
58 + ),
59 + SizedBox(width: 16),
60 + Expanded(
61 + child: Text(
62 + title,
63 + style: TextStyle(
64 + color: color,
65 + fontSize: 16,
66 + fontWeight: FontWeight.bold,
67 + ),
68 + ),
69 + ),
70 + if (isArrowVisible)
71 + Icon(
72 + Icons.arrow_forward_ios,
73 + color: color,
74 + size: 16,
75 + )
76 + ],
77 + ),
78 + ),
79 + );
80 + }
81 +}
lib/src/widgets/setting_actions.dart new
+109
@@ -0,0 +1,109 @@
1 +import 'package:cake_wallet/generated/i18n.dart';
2 +import 'package:cake_wallet/routes.dart';
3 +import 'package:flutter/material.dart';
4 +
5 +class SettingActions {
6 + final String name;
7 + final String image;
8 + final void Function(BuildContext) onTap;
9 +
10 + SettingActions._({
11 + required this.name,
12 + required this.image,
13 + required this.onTap,
14 + });
15 +
16 + static List<SettingActions> all = [
17 + connectionSettingAction,
18 + walletSettingAction,
19 + addressBookSettingAction,
20 + securityBackupSettingAction,
21 + privacySettingAction,
22 + displaySettingAction,
23 + otherSettingAction,
24 + supportSettingAction,
25 + ];
26 +
27 + static List<SettingActions> desktopSettings = [
28 + connectionSettingAction,
29 + walletSettingAction,
30 + addressBookSettingAction,
31 + securityBackupSettingAction,
32 + privacySettingAction,
33 + displaySettingAction,
34 + otherSettingAction,
35 + supportSettingAction,
36 + ];
37 +
38 + static SettingActions connectionSettingAction = SettingActions._(
39 + name: S.current.connection_sync,
40 + image: 'assets/images/nodes_menu.png',
41 + onTap: (BuildContext context) {
42 + Navigator.pop(context);
43 + Navigator.of(context).pushNamed(Routes.connectionSync);
44 + },
45 + );
46 +
47 + static SettingActions walletSettingAction = SettingActions._(
48 + name: S.current.wallets,
49 + image: 'assets/images/wallet_menu.png',
50 + onTap: (BuildContext context) {
51 + Navigator.pop(context);
52 + Navigator.of(context).pushNamed(Routes.walletList);
53 + },
54 + );
55 +
56 + static SettingActions addressBookSettingAction = SettingActions._(
57 + name: S.current.address_book_menu,
58 + image: 'assets/images/open_book_menu.png',
59 + onTap: (BuildContext context) {
60 + Navigator.pop(context);
61 + Navigator.of(context).pushNamed(Routes.addressBook);
62 + },
63 + );
64 +
65 + static SettingActions securityBackupSettingAction = SettingActions._(
66 + name: S.current.security_and_backup,
67 + image: 'assets/images/key_menu.png',
68 + onTap: (BuildContext context) {
69 + Navigator.pop(context);
70 + Navigator.of(context).pushNamed(Routes.securityBackupPage);
71 + },
72 + );
73 +
74 + static SettingActions privacySettingAction = SettingActions._(
75 + name: S.current.privacy,
76 + image: 'assets/images/privacy_menu.png',
77 + onTap: (BuildContext context) {
78 + Navigator.pop(context);
79 + Navigator.of(context).pushNamed(Routes.privacyPage);
80 + },
81 + );
82 +
83 + static SettingActions displaySettingAction = SettingActions._(
84 + name: S.current.display_settings,
85 + image: 'assets/images/eye_menu.png',
86 + onTap: (BuildContext context) {
87 + Navigator.pop(context);
88 + Navigator.of(context).pushNamed(Routes.displaySettingsPage);
89 + },
90 + );
91 +
92 + static SettingActions otherSettingAction = SettingActions._(
93 + name: S.current.other_settings,
94 + image: 'assets/images/settings_menu.png',
95 + onTap: (BuildContext context) {
96 + Navigator.pop(context);
97 + Navigator.of(context).pushNamed(Routes.otherSettingsPage);
98 + },
99 + );
100 +
101 + static SettingActions supportSettingAction = SettingActions._(
102 + name: S.current.settings_support,
103 + image: 'assets/images/question_mark.png',
104 + onTap: (BuildContext context) {
105 + Navigator.pop(context);
106 + Navigator.of(context).pushNamed(Routes.support);
107 + },
108 + );
109 +}
lib/store/settings_store.dart
+3 -3
@@ -241,8 +241,8 @@ abstract class SettingsStoreBase with Store {
241 {required Box<Node> nodeSource,
242 required bool isBitcoinBuyEnabled,
243 FiatCurrency initialFiatCurrency = FiatCurrency.usd,
244 - BalanceDisplayMode initialBalanceDisplayMode =
245 - BalanceDisplayMode.availableBalance}) async {
244 + BalanceDisplayMode initialBalanceDisplayMode = BalanceDisplayMode.availableBalance,
245 + ThemeBase? initialTheme}) async {
246
247 final sharedPreferences = await getIt.getAsync<SharedPreferences>();
248 final currentFiatCurrency = FiatCurrency.deserialize(raw:
@@ -292,7 +292,7 @@ abstract class SettingsStoreBase with Store {
292 (sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false)
293 ? ThemeType.dark.index
294 : ThemeType.bright.index;
295 - final savedTheme = ThemeList.deserialize(
295 + final savedTheme = initialTheme ?? ThemeList.deserialize(
296 raw: sharedPreferences.getInt(PreferencesKey.currentTheme) ??
297 legacyTheme);
298 final actionListDisplayMode = ObservableList<ActionListDisplayMode>();
lib/utils/device_info.dart new
+11
@@ -0,0 +1,11 @@
1 +import 'dart:io';
2 +
3 +class DeviceInfo {
4 + DeviceInfo._();
5 +
6 + static DeviceInfo get instance => DeviceInfo._();
7 +
8 + bool get isMobile => Platform.isAndroid || Platform.isIOS;
9 +
10 + bool get isDesktop => Platform.isMacOS || Platform.isWindows || Platform.isLinux;
11 +}
\ No newline at end of file
lib/utils/exception_handler.dart
+1
@@ -69,6 +69,7 @@ class ExceptionHandler {
69 static void onError(FlutterErrorDetails errorDetails) async {
70 if (kDebugMode) {
71 FlutterError.presentError(errorDetails);
72 + debugPrint(errorDetails.toString());
73 return;
74 }
75
lib/utils/responsive_layout_util.dart new
+34
@@ -0,0 +1,34 @@
1 +import 'package:flutter/material.dart';
2 +
3 +class ResponsiveLayoutUtil {
4 + static const double _kMobileThreshold = 900;
5 + static const double kDesktopMaxWidthConstraint = 400;
6 + static const double kPopupWidth = 400;
7 + static const double kPopupSpaceHeight = 100;
8 +
9 +
10 + const ResponsiveLayoutUtil._();
11 +
12 + static final instance = ResponsiveLayoutUtil._();
13 +
14 + bool isMobile(BuildContext context) {
15 + final MediaQueryData mediaQueryData = MediaQuery.of(context);
16 + return mediaQueryData.size.width < _kMobileThreshold;
17 + }
18 +
19 + /// Returns dynamic size.
20 + ///
21 + /// If screen size is mobile, it returns 66% ([scale]) of the [originalValue].
22 + double getDynamicSize(
23 + BuildContext context,
24 + double originalValue, {
25 + double? mobileSize,
26 + double? scale,
27 + }) {
28 + scale ??= 2 / 3;
29 + mobileSize ??= originalValue * scale;
30 + final value = isMobile(context) ? mobileSize : originalValue;
31 +
32 + return value.roundToDouble();
33 + }
34 +}
lib/view_model/dashboard/dashboard_view_model.dart
-8
@@ -1,13 +1,9 @@
1 import 'package:cake_wallet/entities/exchange_api_mode.dart';
2 -import 'package:cake_wallet/entities/fiat_api_mode.dart';
2 import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart';
3 import 'package:cake_wallet/view_model/dashboard/anonpay_transaction_list_item.dart';
4 import 'package:cake_wallet/wallet_type_utils.dart';
5 import 'package:cw_core/transaction_history.dart';
6 import 'package:cw_core/balance.dart';
8 -import 'package:cake_wallet/buy/order.dart';
9 -import 'package:cake_wallet/entities/transaction_history.dart';
10 -import 'package:cake_wallet/exchange/trade_state.dart';
7 import 'package:cake_wallet/entities/balance_display_mode.dart';
8 import 'package:cw_core/transaction_info.dart';
9 import 'package:cake_wallet/exchange/exchange_provider_description.dart';
@@ -21,10 +17,6 @@ import 'package:cake_wallet/view_model/dashboard/order_list_item.dart';
17 import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart';
18 import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
19 import 'package:cake_wallet/view_model/dashboard/action_list_item.dart';
24 -import 'package:cake_wallet/view_model/dashboard/action_list_display_mode.dart';
25 -import 'package:crypto/crypto.dart';
26 -import 'package:flutter/services.dart';
27 -import 'package:hive/hive.dart';
20 import 'package:mobx/mobx.dart';
21 import 'package:cw_core/wallet_base.dart';
22 import 'package:cw_core/sync_status.dart';
lib/view_model/dashboard/desktop_sidebar_view_model.dart new
+34
@@ -0,0 +1,34 @@
1 +import 'package:mobx/mobx.dart';
2 +
3 +part 'desktop_sidebar_view_model.g.dart';
4 +
5 +enum SidebarItem {
6 + dashboard,
7 + support,
8 + settings,
9 + transactions;
10 +}
11 +
12 +class DesktopSidebarViewModel = DesktopSidebarViewModelBase with _$DesktopSidebarViewModel;
13 +
14 +abstract class DesktopSidebarViewModelBase with Store {
15 + DesktopSidebarViewModelBase();
16 +
17 + @observable
18 + SidebarItem currentPage = SidebarItem.dashboard;
19 +
20 + @action
21 + void onPageChange(SidebarItem item) {
22 + if (currentPage == item) {
23 + resetSidebar();
24 +
25 + return;
26 + }
27 + currentPage = item;
28 + }
29 +
30 + @action
31 + void resetSidebar() {
32 + currentPage = SidebarItem.dashboard;
33 + }
34 +}
lib/view_model/node_list/node_list_view_model.dart
+27 -13
@@ -1,4 +1,6 @@
1 import 'package:cake_wallet/generated/i18n.dart';
2 +import 'package:cake_wallet/store/app_store.dart';
3 +import 'package:cake_wallet/utils/mobx.dart';
4 import 'package:hive/hive.dart';
5 import 'package:mobx/mobx.dart';
6 import 'package:cw_core/wallet_base.dart';
@@ -7,25 +9,28 @@ import 'package:cw_core/node.dart';
9 import 'package:cake_wallet/entities/node_list.dart';
10 import 'package:cake_wallet/entities/default_settings_migration.dart';
11 import 'package:cw_core/wallet_type.dart';
10 -import 'package:cake_wallet/utils/mobx.dart';
12
13 part 'node_list_view_model.g.dart';
14
15 class NodeListViewModel = NodeListViewModelBase with _$NodeListViewModel;
16
17 abstract class NodeListViewModelBase with Store {
17 - NodeListViewModelBase(this._nodeSource, this.wallet, this.settingsStore)
18 - : nodes = ObservableList<Node>() {
19 - _nodeSource.bindToList(nodes,
20 - filter: (Node val) => val?.type == wallet.type, initialFire: true);
18 + NodeListViewModelBase(this._nodeSource, this._appStore)
19 + : nodes = ObservableList<Node>(),
20 + settingsStore = _appStore.settingsStore {
21 + _bindNodes();
22 +
23 + reaction((_) => _appStore.wallet, (WalletBase? _wallet) {
24 + _bindNodes();
25 + });
26 }
27
28 @computed
29 Node get currentNode {
25 - final node = settingsStore.nodes[wallet.type];
30 + final node = settingsStore.nodes[_appStore.wallet!.type];
31
32 if (node == null) {
28 - throw Exception('No node for wallet type: ${wallet.type}');
33 + throw Exception('No node for wallet type: ${_appStore.wallet!.type}');
34 }
35
36 return node;
@@ -33,19 +38,19 @@ abstract class NodeListViewModelBase with Store {
38
39 String getAlertContent(String uri) =>
40 S.current.change_current_node(uri) +
36 - '${uri.endsWith('.onion') || uri.contains('.onion:') ? '\n' + S.current.orbot_running_alert : ''}';
41 + '${uri.endsWith('.onion') || uri.contains('.onion:') ? '\n' + S.current.orbot_running_alert : ''}';
42
43 final ObservableList<Node> nodes;
44 final SettingsStore settingsStore;
40 - final WalletBase wallet;
45 final Box<Node> _nodeSource;
46 + final AppStore _appStore;
47
48 Future<void> reset() async {
49 await resetToDefault(_nodeSource);
50
51 Node node;
52
48 - switch (wallet.type) {
53 + switch (_appStore.wallet!.type) {
54 case WalletType.bitcoin:
55 node = getBitcoinDefaultElectrumServer(nodes: _nodeSource)!;
56 break;
@@ -59,7 +64,7 @@ abstract class NodeListViewModelBase with Store {
64 node = getHavenDefaultNode(nodes: _nodeSource)!;
65 break;
66 default:
62 - throw Exception('Unexpected wallet type: ${wallet.type}');
67 + throw Exception('Unexpected wallet type: ${_appStore.wallet!.type}');
68 }
69
70 await setAsCurrent(node);
@@ -68,6 +73,15 @@ abstract class NodeListViewModelBase with Store {
73 @action
74 Future<void> delete(Node node) async => node.delete();
75
71 - Future<void> setAsCurrent(Node node) async =>
72 - settingsStore.nodes[wallet.type] = node;
76 + Future<void> setAsCurrent(Node node) async => settingsStore.nodes[_appStore.wallet!.type] = node;
77 +
78 + @action
79 + void _bindNodes() {
80 + nodes.clear();
81 + _nodeSource.bindToList(
82 + nodes,
83 + filter: (val) => val.type == _appStore.wallet!.type,
84 + initialFire: true,
85 + );
86 + }
87 }
lib/view_model/wallet_keys_view_model.dart
+39 -25
@@ -1,3 +1,4 @@
1 +import 'package:cake_wallet/store/app_store.dart';
2 import 'package:cw_core/wallet_type.dart';
3 import 'package:mobx/mobx.dart';
4 import 'package:cake_wallet/generated/i18n.dart';
@@ -12,15 +13,34 @@ part 'wallet_keys_view_model.g.dart';
13 class WalletKeysViewModel = WalletKeysViewModelBase with _$WalletKeysViewModel;
14
15 abstract class WalletKeysViewModelBase with Store {
15 - WalletKeysViewModelBase(WalletBase wallet)
16 - : title = wallet.type == WalletType.bitcoin || wallet.type == WalletType.litecoin
16 + WalletKeysViewModelBase(this._appStore)
17 + : title = _appStore.wallet!.type == WalletType.bitcoin ||
18 + _appStore.wallet!.type == WalletType.litecoin
19 ? S.current.wallet_seed
20 : S.current.wallet_keys,
19 - _wallet = wallet,
20 - _restoreHeight = wallet.walletInfo.restoreHeight,
21 + _restoreHeight = _appStore.wallet!.walletInfo.restoreHeight,
22 items = ObservableList<StandartListItem>() {
22 - if (wallet.type == WalletType.monero) {
23 - final keys = monero!.getKeys(wallet);
23 + _populateItems();
24 +
25 + reaction((_) => _appStore.wallet, (WalletBase? _wallet) {
26 + _populateItems();
27 + });
28 + }
29 +
30 + final ObservableList<StandartListItem> items;
31 +
32 + final String title;
33 +
34 + final AppStore _appStore;
35 +
36 + final int _restoreHeight;
37 +
38 + void _populateItems() {
39 + items.clear();
40 +
41 + if (_appStore.wallet!.type == WalletType.monero) {
42 + final keys = monero!.getKeys(_appStore.wallet!);
43 +
44 items.addAll([
45 if (keys['publicSpendKey'] != null)
46 StandartListItem(title: S.current.spend_key_public, value: keys['publicSpendKey']!),
@@ -30,12 +50,13 @@ abstract class WalletKeysViewModelBase with Store {
50 StandartListItem(title: S.current.view_key_public, value: keys['publicViewKey']!),
51 if (keys['privateViewKey'] != null)
52 StandartListItem(title: S.current.view_key_private, value: keys['privateViewKey']!),
33 - StandartListItem(title: S.current.wallet_seed, value: wallet.seed),
53 + StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed),
54 ]);
55 }
56
37 - if (wallet.type == WalletType.haven) {
38 - final keys = haven!.getKeys(wallet);
57 + if (_appStore.wallet!.type == WalletType.haven) {
58 + final keys = haven!.getKeys(_appStore.wallet!);
59 +
60 items.addAll([
61 if (keys['publicSpendKey'] != null)
62 StandartListItem(title: S.current.spend_key_public, value: keys['publicSpendKey']!),
@@ -45,37 +66,30 @@ abstract class WalletKeysViewModelBase with Store {
66 StandartListItem(title: S.current.view_key_public, value: keys['publicViewKey']!),
67 if (keys['privateViewKey'] != null)
68 StandartListItem(title: S.current.view_key_private, value: keys['privateViewKey']!),
48 - StandartListItem(title: S.current.wallet_seed, value: wallet.seed),
69 + StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed),
70 ]);
71 }
72
52 - if (wallet.type == WalletType.bitcoin || wallet.type == WalletType.litecoin) {
73 + if (_appStore.wallet!.type == WalletType.bitcoin ||
74 + _appStore.wallet!.type == WalletType.litecoin) {
75 items.addAll([
54 - StandartListItem(title: S.current.wallet_seed, value: wallet.seed),
76 + StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed),
77 ]);
78 }
79 }
80
59 - final ObservableList<StandartListItem> items;
60 -
61 - final String title;
62 -
63 - final WalletBase _wallet;
64 -
65 - final int _restoreHeight;
66 -
81 Future<int?> currentHeight() async {
68 - if (_wallet.type == WalletType.haven) {
82 + if (_appStore.wallet!.type == WalletType.haven) {
83 return await haven!.getCurrentHeight();
84 }
71 - if (_wallet.type == WalletType.monero) {
85 + if (_appStore.wallet!.type == WalletType.monero) {
86 return monero_wallet.getCurrentHeight();
87 }
88 return null;
89 }
90
91 String get _path {
78 - switch (_wallet.type) {
92 + switch (_appStore.wallet!.type) {
93 case WalletType.monero:
94 return 'monero_wallet:';
95 case WalletType.bitcoin:
@@ -85,7 +99,7 @@ abstract class WalletKeysViewModelBase with Store {
99 case WalletType.haven:
100 return 'haven_wallet:';
101 default:
88 - throw Exception('Unexpected wallet type: ${_wallet.toString()}');
102 + throw Exception('Unexpected wallet type: ${_appStore.wallet!.toString()}');
103 }
104 }
105
@@ -103,7 +117,7 @@ abstract class WalletKeysViewModelBase with Store {
117 Future<Map<String, String>> get _queryParams async {
118 final restoreHeightResult = await restoreHeight;
119 return {
106 - 'seed': _wallet.seed,
120 + 'seed': _appStore.wallet!.seed,
121 if (restoreHeightResult != null) ...{'height': restoreHeightResult}
122 };
123 }
lib/view_model/wallet_list/wallet_list_item.dart
+7 -7
@@ -1,13 +1,13 @@
1 -import 'package:flutter/foundation.dart';
1 import 'package:cw_core/wallet_type.dart';
2
3 class WalletListItem {
5 - const WalletListItem(
6 - {required this.name,
7 - required this.type,
8 - required this.key,
9 - this.isCurrent = false,
10 - this.isEnabled = true});
4 + const WalletListItem({
5 + required this.name,
6 + required this.type,
7 + required this.key,
8 + this.isCurrent = false,
9 + this.isEnabled = true,
10 + });
11
12 final String name;
13 final WalletType type;
lib/view_model/wallet_list/wallet_list_view_model.dart
+1
@@ -22,6 +22,7 @@ abstract class WalletListViewModelBase with Store {
22 this._authService,
23 ) : wallets = ObservableList<WalletListItem>() {
24 _updateList();
25 + reaction((_) => _appStore.wallet, (_) => _updateList());
26 }
27
28 @observable
macos/.gitignore new
+7
@@ -0,0 +1,7 @@
1 +# Flutter-related
2 +**/Flutter/ephemeral/
3 +**/Pods/
4 +
5 +# Xcode-related
6 +**/dgph
7 +**/xcuserdata/
macos/CakeWallet/secRandom.swift new
+12
@@ -0,0 +1,12 @@
1 +import Foundation
2 +
3 +func secRandom(count: Int) -> Data? {
4 + var bytes = [Int8](repeating: 0, count: count)
5 + let status = SecRandomCopyBytes(kSecRandomDefault, bytes.count, &bytes)
6 +
7 + if status == errSecSuccess {
8 + return Data(bytes: bytes, count: bytes.count)
9 + }
10 +
11 + return nil
12 +}
macos/Flutter/Flutter-Debug.xcconfig new
+2
@@ -0,0 +1,2 @@
1 +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 +#include "ephemeral/Flutter-Generated.xcconfig"
macos/Flutter/Flutter-Release.xcconfig new
+2
@@ -0,0 +1,2 @@
1 +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 +#include "ephemeral/Flutter-Generated.xcconfig"
macos/Flutter/GeneratedPluginRegistrant.swift new
+36
@@ -0,0 +1,36 @@
1 +//
2 +// Generated file. Do not edit.
3 +//
4 +
5 +import FlutterMacOS
6 +import Foundation
7 +
8 +import connectivity_macos
9 +import cw_monero
10 +import device_info_plus
11 +import devicelocale
12 +import flutter_secure_storage_macos
13 +import package_info
14 +import path_provider_foundation
15 +import platform_device_id
16 +import platform_device_id_macos
17 +import share_plus_macos
18 +import shared_preferences_foundation
19 +import url_launcher_macos
20 +import wakelock_macos
21 +
22 +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
23 + ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin"))
24 + CwMoneroPlugin.register(with: registry.registrar(forPlugin: "CwMoneroPlugin"))
25 + DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
26 + DevicelocalePlugin.register(with: registry.registrar(forPlugin: "DevicelocalePlugin"))
27 + FlutterSecureStorageMacosPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageMacosPlugin"))
28 + FLTPackageInfoPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlugin"))
29 + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
30 + PlatformDeviceIdMacosPlugin.register(with: registry.registrar(forPlugin: "PlatformDeviceIdMacosPlugin"))
31 + PlatformDeviceIdMacosPlugin.register(with: registry.registrar(forPlugin: "PlatformDeviceIdMacosPlugin"))
32 + SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
33 + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
34 + UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
35 + WakelockMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockMacosPlugin"))
36 +}
macos/Podfile new
+40
@@ -0,0 +1,40 @@
1 +platform :osx, '12.0'
2 +
3 +# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
4 +ENV['COCOAPODS_DISABLE_STATS'] = 'true'
5 +
6 +project 'Runner', {
7 + 'Debug' => :debug,
8 + 'Profile' => :release,
9 + 'Release' => :release,
10 +}
11 +
12 +def flutter_root
13 + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)
14 + unless File.exist?(generated_xcode_build_settings_path)
15 + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first"
16 + end
17 +
18 + File.foreach(generated_xcode_build_settings_path) do |line|
19 + matches = line.match(/FLUTTER_ROOT\=(.*)/)
20 + return matches[1].strip if matches
21 + end
22 + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\""
23 +end
24 +
25 +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
26 +
27 +flutter_macos_podfile_setup
28 +
29 +target 'Runner' do
30 + use_frameworks!
31 + use_modular_headers!
32 +
33 + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))
34 +end
35 +
36 +post_install do |installer|
37 + installer.pods_project.targets.each do |target|
38 + flutter_additional_macos_build_settings(target)
39 + end
40 +end
macos/Podfile.lock new
+118
@@ -0,0 +1,118 @@
1 +PODS:
2 + - connectivity_macos (0.0.1):
3 + - FlutterMacOS
4 + - Reachability
5 + - cw_monero (0.0.1):
6 + - cw_monero/Boost (= 0.0.1)
7 + - cw_monero/Monero (= 0.0.1)
8 + - cw_monero/OpenSSL (= 0.0.1)
9 + - cw_monero/Sodium (= 0.0.1)
10 + - cw_monero/Unbound (= 0.0.1)
11 + - FlutterMacOS
12 + - cw_monero/Boost (0.0.1):
13 + - FlutterMacOS
14 + - cw_monero/Monero (0.0.1):
15 + - FlutterMacOS
16 + - cw_monero/OpenSSL (0.0.1):
17 + - FlutterMacOS
18 + - cw_monero/Sodium (0.0.1):
19 + - FlutterMacOS
20 + - cw_monero/Unbound (0.0.1):
21 + - FlutterMacOS
22 + - device_info_plus (0.0.1):
23 + - FlutterMacOS
24 + - devicelocale (0.0.1):
25 + - FlutterMacOS
26 + - flutter_secure_storage_macos (3.3.1):
27 + - FlutterMacOS
28 + - FlutterMacOS (1.0.0)
29 + - package_info (0.0.1):
30 + - FlutterMacOS
31 + - path_provider_foundation (0.0.1):
32 + - Flutter
33 + - FlutterMacOS
34 + - platform_device_id (0.0.1):
35 + - FlutterMacOS
36 + - platform_device_id_macos (0.0.1):
37 + - FlutterMacOS
38 + - Reachability (3.2)
39 + - share_plus_macos (0.0.1):
40 + - FlutterMacOS
41 + - shared_preferences_foundation (0.0.1):
42 + - Flutter
43 + - FlutterMacOS
44 + - url_launcher_macos (0.0.1):
45 + - FlutterMacOS
46 + - wakelock_macos (0.0.1):
47 + - FlutterMacOS
48 +
49 +DEPENDENCIES:
50 + - connectivity_macos (from `Flutter/ephemeral/.symlinks/plugins/connectivity_macos/macos`)
51 + - cw_monero (from `Flutter/ephemeral/.symlinks/plugins/cw_monero/macos`)
52 + - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`)
53 + - devicelocale (from `Flutter/ephemeral/.symlinks/plugins/devicelocale/macos`)
54 + - flutter_secure_storage_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos`)
55 + - FlutterMacOS (from `Flutter/ephemeral`)
56 + - package_info (from `Flutter/ephemeral/.symlinks/plugins/package_info/macos`)
57 + - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/macos`)
58 + - platform_device_id (from `Flutter/ephemeral/.symlinks/plugins/platform_device_id/macos`)
59 + - platform_device_id_macos (from `Flutter/ephemeral/.symlinks/plugins/platform_device_id_macos/macos`)
60 + - share_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/share_plus_macos/macos`)
61 + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/macos`)
62 + - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
63 + - wakelock_macos (from `Flutter/ephemeral/.symlinks/plugins/wakelock_macos/macos`)
64 +
65 +SPEC REPOS:
66 + trunk:
67 + - Reachability
68 +
69 +EXTERNAL SOURCES:
70 + connectivity_macos:
71 + :path: Flutter/ephemeral/.symlinks/plugins/connectivity_macos/macos
72 + cw_monero:
73 + :path: Flutter/ephemeral/.symlinks/plugins/cw_monero/macos
74 + device_info_plus:
75 + :path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos
76 + devicelocale:
77 + :path: Flutter/ephemeral/.symlinks/plugins/devicelocale/macos
78 + flutter_secure_storage_macos:
79 + :path: Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos
80 + FlutterMacOS:
81 + :path: Flutter/ephemeral
82 + package_info:
83 + :path: Flutter/ephemeral/.symlinks/plugins/package_info/macos
84 + path_provider_foundation:
85 + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/macos
86 + platform_device_id:
87 + :path: Flutter/ephemeral/.symlinks/plugins/platform_device_id/macos
88 + platform_device_id_macos:
89 + :path: Flutter/ephemeral/.symlinks/plugins/platform_device_id_macos/macos
90 + share_plus_macos:
91 + :path: Flutter/ephemeral/.symlinks/plugins/share_plus_macos/macos
92 + shared_preferences_foundation:
93 + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/macos
94 + url_launcher_macos:
95 + :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
96 + wakelock_macos:
97 + :path: Flutter/ephemeral/.symlinks/plugins/wakelock_macos/macos
98 +
99 +SPEC CHECKSUMS:
100 + connectivity_macos: 5dae6ee11d320fac7c05f0d08bd08fc32b5514d9
101 + cw_monero: f8b7f104508efba2591548e76b5c058d05cba3f0
102 + device_info_plus: 5401765fde0b8d062a2f8eb65510fb17e77cf07f
103 + devicelocale: 9f0f36ac651cabae2c33f32dcff4f32b61c38225
104 + flutter_secure_storage_macos: 6ceee8fbc7f484553ad17f79361b556259df89aa
105 + FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
106 + package_info: 6eba2fd8d3371dda2d85c8db6fe97488f24b74b2
107 + path_provider_foundation: c68054786f1b4f3343858c1e1d0caaded73f0be9
108 + platform_device_id: 3e414428f45df149bbbfb623e2c0ca27c545b763
109 + platform_device_id_macos: f763bb55f088be804d61b96eb4710b8ab6598e94
110 + Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96
111 + share_plus_macos: 853ee48e7dce06b633998ca0735d482dd671ade4
112 + shared_preferences_foundation: 986fc17f3d3251412d18b0265f9c64113a8c2472
113 + url_launcher_macos: 5335912b679c073563f29d89d33d10d459f95451
114 + wakelock_macos: bc3f2a9bd8d2e6c89fee1e1822e7ddac3bd004a9
115 +
116 +PODFILE CHECKSUM: 505596d150d38022472859d890f709281982e016
117 +
118 +COCOAPODS: 1.11.3
macos/Runner.xcodeproj/project.pbxproj new
+663
@@ -0,0 +1,663 @@
1 +// !$*UTF8*$!
2 +{
3 + archiveVersion = 1;
4 + classes = {
5 + };
6 + objectVersion = 54;
7 + objects = {
8 +
9 +/* Begin PBXAggregateTarget section */
10 + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = {
11 + isa = PBXAggregateTarget;
12 + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */;
13 + buildPhases = (
14 + 33CC111E2044C6BF0003C045 /* ShellScript */,
15 + );
16 + dependencies = (
17 + );
18 + name = "Flutter Assemble";
19 + productName = FLX;
20 + };
21 +/* End PBXAggregateTarget section */
22 +
23 +/* Begin PBXBuildFile section */
24 + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };
25 + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };
26 + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
27 + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
28 + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
29 + 4171CB1F5A4EA2E4DC33F52F /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B38D1DBC56DBD386923BC063 /* Pods_Runner.framework */; };
30 + 9F565D5929954F53009A75FB /* secRandom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F565D5729954F53009A75FB /* secRandom.swift */; };
31 +/* End PBXBuildFile section */
32 +
33 +/* Begin PBXContainerItemProxy section */
34 + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = {
35 + isa = PBXContainerItemProxy;
36 + containerPortal = 33CC10E52044A3C60003C045 /* Project object */;
37 + proxyType = 1;
38 + remoteGlobalIDString = 33CC111A2044C6BA0003C045;
39 + remoteInfo = FLX;
40 + };
41 +/* End PBXContainerItemProxy section */
42 +
43 +/* Begin PBXCopyFilesBuildPhase section */
44 + 33CC110E2044A8840003C045 /* Bundle Framework */ = {
45 + isa = PBXCopyFilesBuildPhase;
46 + buildActionMask = 2147483647;
47 + dstPath = "";
48 + dstSubfolderSpec = 10;
49 + files = (
50 + );
51 + name = "Bundle Framework";
52 + runOnlyForDeploymentPostprocessing = 0;
53 + };
54 +/* End PBXCopyFilesBuildPhase section */
55 +
56 +/* Begin PBXFileReference section */
57 + 094BF982245FD1012D60A103 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
58 + 0C090639294D3AAC00954DC9 /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = usr/lib/libiconv.tbd; sourceTree = SDKROOT; };
59 + 2A820A13B0719E9E0CD6686F /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
60 + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
61 + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
62 + 33CC10ED2044A3C60003C045 /* Cake Wallet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Cake Wallet.app"; sourceTree = BUILT_PRODUCTS_DIR; };
63 + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
64 + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
65 + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
66 + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = "<group>"; };
67 + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = "<group>"; };
68 + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = "<group>"; };
69 + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = "<group>"; };
70 + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = "<group>"; };
71 + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
72 + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
73 + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
74 + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
75 + 9646C67C7114830A5ACFF5DF /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
76 + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
77 + 9F565D5729954F53009A75FB /* secRandom.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = secRandom.swift; path = CakeWallet/secRandom.swift; sourceTree = "<group>"; };
78 + 9F565D5829954F53009A75FB /* decrypt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = decrypt.swift; path = CakeWallet/decrypt.swift; sourceTree = "<group>"; };
79 + B38D1DBC56DBD386923BC063 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
80 +/* End PBXFileReference section */
81 +
82 +/* Begin PBXFrameworksBuildPhase section */
83 + 33CC10EA2044A3C60003C045 /* Frameworks */ = {
84 + isa = PBXFrameworksBuildPhase;
85 + buildActionMask = 2147483647;
86 + files = (
87 + 4171CB1F5A4EA2E4DC33F52F /* Pods_Runner.framework in Frameworks */,
88 + );
89 + runOnlyForDeploymentPostprocessing = 0;
90 + };
91 +/* End PBXFrameworksBuildPhase section */
92 +
93 +/* Begin PBXGroup section */
94 + 33BA886A226E78AF003329D5 /* Configs */ = {
95 + isa = PBXGroup;
96 + children = (
97 + 33E5194F232828860026EE4D /* AppInfo.xcconfig */,
98 + 9740EEB21CF90195004384FC /* Debug.xcconfig */,
99 + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
100 + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */,
101 + );
102 + path = Configs;
103 + sourceTree = "<group>";
104 + };
105 + 33CC10E42044A3C60003C045 = {
106 + isa = PBXGroup;
107 + children = (
108 + 9F565D5829954F53009A75FB /* decrypt.swift */,
109 + 9F565D5729954F53009A75FB /* secRandom.swift */,
110 + 33FAB671232836740065AC1E /* Runner */,
111 + 33CEB47122A05771004F2AC0 /* Flutter */,
112 + 33CC10EE2044A3C60003C045 /* Products */,
113 + D73912EC22F37F3D000D13A0 /* Frameworks */,
114 + 9B6E7CA3983216A9E173F00F /* Pods */,
115 + );
116 + sourceTree = "<group>";
117 + };
118 + 33CC10EE2044A3C60003C045 /* Products */ = {
119 + isa = PBXGroup;
120 + children = (
121 + 33CC10ED2044A3C60003C045 /* Cake Wallet.app */,
122 + );
123 + name = Products;
124 + sourceTree = "<group>";
125 + };
126 + 33CC11242044D66E0003C045 /* Resources */ = {
127 + isa = PBXGroup;
128 + children = (
129 + 33CC10F22044A3C60003C045 /* Assets.xcassets */,
130 + 33CC10F42044A3C60003C045 /* MainMenu.xib */,
131 + 33CC10F72044A3C60003C045 /* Info.plist */,
132 + );
133 + name = Resources;
134 + path = ..;
135 + sourceTree = "<group>";
136 + };
137 + 33CEB47122A05771004F2AC0 /* Flutter */ = {
138 + isa = PBXGroup;
139 + children = (
140 + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */,
141 + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */,
142 + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */,
143 + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */,
144 + );
145 + path = Flutter;
146 + sourceTree = "<group>";
147 + };
148 + 33FAB671232836740065AC1E /* Runner */ = {
149 + isa = PBXGroup;
150 + children = (
151 + 33CC10F02044A3C60003C045 /* AppDelegate.swift */,
152 + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */,
153 + 33E51913231747F40026EE4D /* DebugProfile.entitlements */,
154 + 33E51914231749380026EE4D /* Release.entitlements */,
155 + 33CC11242044D66E0003C045 /* Resources */,
156 + 33BA886A226E78AF003329D5 /* Configs */,
157 + );
158 + path = Runner;
159 + sourceTree = "<group>";
160 + };
161 + 9B6E7CA3983216A9E173F00F /* Pods */ = {
162 + isa = PBXGroup;
163 + children = (
164 + 9646C67C7114830A5ACFF5DF /* Pods-Runner.debug.xcconfig */,
165 + 2A820A13B0719E9E0CD6686F /* Pods-Runner.release.xcconfig */,
166 + 094BF982245FD1012D60A103 /* Pods-Runner.profile.xcconfig */,
167 + );
168 + path = Pods;
169 + sourceTree = "<group>";
170 + };
171 + D73912EC22F37F3D000D13A0 /* Frameworks */ = {
172 + isa = PBXGroup;
173 + children = (
174 + 0C090639294D3AAC00954DC9 /* libiconv.tbd */,
175 + B38D1DBC56DBD386923BC063 /* Pods_Runner.framework */,
176 + );
177 + name = Frameworks;
178 + sourceTree = "<group>";
179 + };
180 +/* End PBXGroup section */
181 +
182 +/* Begin PBXNativeTarget section */
183 + 33CC10EC2044A3C60003C045 /* Runner */ = {
184 + isa = PBXNativeTarget;
185 + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
186 + buildPhases = (
187 + 93B711AB4B96E7C8C5C5B844 /* [CP] Check Pods Manifest.lock */,
188 + 33CC10E92044A3C60003C045 /* Sources */,
189 + 33CC10EA2044A3C60003C045 /* Frameworks */,
190 + 33CC10EB2044A3C60003C045 /* Resources */,
191 + 33CC110E2044A8840003C045 /* Bundle Framework */,
192 + 3399D490228B24CF009A79C7 /* ShellScript */,
193 + 5592D00118C2EA3C5E0B5FDF /* [CP] Embed Pods Frameworks */,
194 + );
195 + buildRules = (
196 + );
197 + dependencies = (
198 + 33CC11202044C79F0003C045 /* PBXTargetDependency */,
199 + );
200 + name = Runner;
201 + productName = Runner;
202 + productReference = 33CC10ED2044A3C60003C045 /* Cake Wallet.app */;
203 + productType = "com.apple.product-type.application";
204 + };
205 +/* End PBXNativeTarget section */
206 +
207 +/* Begin PBXProject section */
208 + 33CC10E52044A3C60003C045 /* Project object */ = {
209 + isa = PBXProject;
210 + attributes = {
211 + LastSwiftUpdateCheck = 0920;
212 + LastUpgradeCheck = 1300;
213 + ORGANIZATIONNAME = "";
214 + TargetAttributes = {
215 + 33CC10EC2044A3C60003C045 = {
216 + CreatedOnToolsVersion = 9.2;
217 + LastSwiftMigration = 1100;
218 + SystemCapabilities = {
219 + com.apple.Sandbox = {
220 + enabled = 1;
221 + };
222 + };
223 + };
224 + 33CC111A2044C6BA0003C045 = {
225 + CreatedOnToolsVersion = 9.2;
226 + ProvisioningStyle = Manual;
227 + };
228 + };
229 + };
230 + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */;
231 + compatibilityVersion = "Xcode 9.3";
232 + developmentRegion = en;
233 + hasScannedForEncodings = 0;
234 + knownRegions = (
235 + en,
236 + Base,
237 + );
238 + mainGroup = 33CC10E42044A3C60003C045;
239 + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */;
240 + projectDirPath = "";
241 + projectRoot = "";
242 + targets = (
243 + 33CC10EC2044A3C60003C045 /* Runner */,
244 + 33CC111A2044C6BA0003C045 /* Flutter Assemble */,
245 + );
246 + };
247 +/* End PBXProject section */
248 +
249 +/* Begin PBXResourcesBuildPhase section */
250 + 33CC10EB2044A3C60003C045 /* Resources */ = {
251 + isa = PBXResourcesBuildPhase;
252 + buildActionMask = 2147483647;
253 + files = (
254 + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */,
255 + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */,
256 + );
257 + runOnlyForDeploymentPostprocessing = 0;
258 + };
259 +/* End PBXResourcesBuildPhase section */
260 +
261 +/* Begin PBXShellScriptBuildPhase section */
262 + 3399D490228B24CF009A79C7 /* ShellScript */ = {
263 + isa = PBXShellScriptBuildPhase;
264 + alwaysOutOfDate = 1;
265 + buildActionMask = 2147483647;
266 + files = (
267 + );
268 + inputFileListPaths = (
269 + );
270 + inputPaths = (
271 + );
272 + outputFileListPaths = (
273 + );
274 + outputPaths = (
275 + );
276 + runOnlyForDeploymentPostprocessing = 0;
277 + shellPath = /bin/sh;
278 + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n";
279 + };
280 + 33CC111E2044C6BF0003C045 /* ShellScript */ = {
281 + isa = PBXShellScriptBuildPhase;
282 + buildActionMask = 2147483647;
283 + files = (
284 + );
285 + inputFileListPaths = (
286 + Flutter/ephemeral/FlutterInputs.xcfilelist,
287 + );
288 + inputPaths = (
289 + Flutter/ephemeral/tripwire,
290 + );
291 + outputFileListPaths = (
292 + Flutter/ephemeral/FlutterOutputs.xcfilelist,
293 + );
294 + outputPaths = (
295 + );
296 + runOnlyForDeploymentPostprocessing = 0;
297 + shellPath = /bin/sh;
298 + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
299 + };
300 + 5592D00118C2EA3C5E0B5FDF /* [CP] Embed Pods Frameworks */ = {
301 + isa = PBXShellScriptBuildPhase;
302 + buildActionMask = 2147483647;
303 + files = (
304 + );
305 + inputFileListPaths = (
306 + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
307 + );
308 + name = "[CP] Embed Pods Frameworks";
309 + outputFileListPaths = (
310 + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
311 + );
312 + runOnlyForDeploymentPostprocessing = 0;
313 + shellPath = /bin/sh;
314 + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
315 + showEnvVarsInLog = 0;
316 + };
317 + 93B711AB4B96E7C8C5C5B844 /* [CP] Check Pods Manifest.lock */ = {
318 + isa = PBXShellScriptBuildPhase;
319 + buildActionMask = 2147483647;
320 + files = (
321 + );
322 + inputFileListPaths = (
323 + );
324 + inputPaths = (
325 + "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
326 + "${PODS_ROOT}/Manifest.lock",
327 + );
328 + name = "[CP] Check Pods Manifest.lock";
329 + outputFileListPaths = (
330 + );
331 + outputPaths = (
332 + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
333 + );
334 + runOnlyForDeploymentPostprocessing = 0;
335 + shellPath = /bin/sh;
336 + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
337 + showEnvVarsInLog = 0;
338 + };
339 +/* End PBXShellScriptBuildPhase section */
340 +
341 +/* Begin PBXSourcesBuildPhase section */
342 + 33CC10E92044A3C60003C045 /* Sources */ = {
343 + isa = PBXSourcesBuildPhase;
344 + buildActionMask = 2147483647;
345 + files = (
346 + 9F565D5929954F53009A75FB /* secRandom.swift in Sources */,
347 + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */,
348 + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */,
349 + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */,
350 + );
351 + runOnlyForDeploymentPostprocessing = 0;
352 + };
353 +/* End PBXSourcesBuildPhase section */
354 +
355 +/* Begin PBXTargetDependency section */
356 + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = {
357 + isa = PBXTargetDependency;
358 + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */;
359 + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */;
360 + };
361 +/* End PBXTargetDependency section */
362 +
363 +/* Begin PBXVariantGroup section */
364 + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = {
365 + isa = PBXVariantGroup;
366 + children = (
367 + 33CC10F52044A3C60003C045 /* Base */,
368 + );
369 + name = MainMenu.xib;
370 + path = Runner;
371 + sourceTree = "<group>";
372 + };
373 +/* End PBXVariantGroup section */
374 +
375 +/* Begin XCBuildConfiguration section */
376 + 338D0CE9231458BD00FA5F75 /* Profile */ = {
377 + isa = XCBuildConfiguration;
378 + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
379 + buildSettings = {
380 + ALWAYS_SEARCH_USER_PATHS = NO;
381 + CLANG_ANALYZER_NONNULL = YES;
382 + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
383 + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
384 + CLANG_CXX_LIBRARY = "libc++";
385 + CLANG_ENABLE_MODULES = YES;
386 + CLANG_ENABLE_OBJC_ARC = YES;
387 + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
388 + CLANG_WARN_BOOL_CONVERSION = YES;
389 + CLANG_WARN_CONSTANT_CONVERSION = YES;
390 + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
391 + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
392 + CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
393 + CLANG_WARN_EMPTY_BODY = YES;
394 + CLANG_WARN_ENUM_CONVERSION = YES;
395 + CLANG_WARN_INFINITE_RECURSION = YES;
396 + CLANG_WARN_INT_CONVERSION = YES;
397 + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
398 + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
399 + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
400 + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
401 + CLANG_WARN_SUSPICIOUS_MOVE = YES;
402 + CODE_SIGN_IDENTITY = "-";
403 + COPY_PHASE_STRIP = NO;
404 + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
405 + ENABLE_NS_ASSERTIONS = NO;
406 + ENABLE_STRICT_OBJC_MSGSEND = YES;
407 + GCC_C_LANGUAGE_STANDARD = gnu11;
408 + GCC_NO_COMMON_BLOCKS = YES;
409 + GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
410 + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
411 + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
412 + GCC_WARN_UNUSED_FUNCTION = YES;
413 + GCC_WARN_UNUSED_VARIABLE = YES;
414 + MACOSX_DEPLOYMENT_TARGET = 10.14;
415 + MTL_ENABLE_DEBUG_INFO = NO;
416 + SDKROOT = macosx;
417 + SWIFT_COMPILATION_MODE = wholemodule;
418 + SWIFT_OPTIMIZATION_LEVEL = "-O";
419 + };
420 + name = Profile;
421 + };
422 + 338D0CEA231458BD00FA5F75 /* Profile */ = {
423 + isa = XCBuildConfiguration;
424 + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
425 + buildSettings = {
426 + ARCHS = arm64;
427 + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
428 + CLANG_ENABLE_MODULES = YES;
429 + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
430 + CODE_SIGN_IDENTITY = "Apple Development";
431 + CODE_SIGN_STYLE = Automatic;
432 + COMBINE_HIDPI_IMAGES = YES;
433 + CURRENT_PROJECT_VERSION = 10;
434 + DEVELOPMENT_TEAM = 32J6BB6VUS;
435 + INFOPLIST_FILE = Runner/Info.plist;
436 + INFOPLIST_KEY_CFBundleDisplayName = "Cake Wallet";
437 + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.finance";
438 + LD_RUNPATH_SEARCH_PATHS = (
439 + "$(inherited)",
440 + "@executable_path/../Frameworks",
441 + );
442 + MACOSX_DEPLOYMENT_TARGET = 12;
443 + MARKETING_VERSION = 1.0.1;
444 + PROVISIONING_PROFILE_SPECIFIER = "";
445 + SWIFT_VERSION = 5.0;
446 + };
447 + name = Profile;
448 + };
449 + 338D0CEB231458BD00FA5F75 /* Profile */ = {
450 + isa = XCBuildConfiguration;
451 + buildSettings = {
452 + CODE_SIGN_STYLE = Manual;
453 + PRODUCT_NAME = "$(TARGET_NAME)";
454 + };
455 + name = Profile;
456 + };
457 + 33CC10F92044A3C60003C045 /* Debug */ = {
458 + isa = XCBuildConfiguration;
459 + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
460 + buildSettings = {
461 + ALWAYS_SEARCH_USER_PATHS = NO;
462 + CLANG_ANALYZER_NONNULL = YES;
463 + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
464 + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
465 + CLANG_CXX_LIBRARY = "libc++";
466 + CLANG_ENABLE_MODULES = YES;
467 + CLANG_ENABLE_OBJC_ARC = YES;
468 + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
469 + CLANG_WARN_BOOL_CONVERSION = YES;
470 + CLANG_WARN_CONSTANT_CONVERSION = YES;
471 + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
472 + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
473 + CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
474 + CLANG_WARN_EMPTY_BODY = YES;
475 + CLANG_WARN_ENUM_CONVERSION = YES;
476 + CLANG_WARN_INFINITE_RECURSION = YES;
477 + CLANG_WARN_INT_CONVERSION = YES;
478 + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
479 + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
480 + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
481 + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
482 + CLANG_WARN_SUSPICIOUS_MOVE = YES;
483 + CODE_SIGN_IDENTITY = "-";
484 + COPY_PHASE_STRIP = NO;
485 + DEBUG_INFORMATION_FORMAT = dwarf;
486 + ENABLE_STRICT_OBJC_MSGSEND = YES;
487 + ENABLE_TESTABILITY = YES;
488 + GCC_C_LANGUAGE_STANDARD = gnu11;
489 + GCC_DYNAMIC_NO_PIC = NO;
490 + GCC_NO_COMMON_BLOCKS = YES;
491 + GCC_OPTIMIZATION_LEVEL = 0;
492 + GCC_PREPROCESSOR_DEFINITIONS = (
493 + "DEBUG=1",
494 + "$(inherited)",
495 + );
496 + GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
497 + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
498 + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
499 + GCC_WARN_UNUSED_FUNCTION = YES;
500 + GCC_WARN_UNUSED_VARIABLE = YES;
501 + MACOSX_DEPLOYMENT_TARGET = 10.14;
502 + MTL_ENABLE_DEBUG_INFO = YES;
503 + ONLY_ACTIVE_ARCH = YES;
504 + SDKROOT = macosx;
505 + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
506 + SWIFT_OPTIMIZATION_LEVEL = "-Onone";
507 + };
508 + name = Debug;
509 + };
510 + 33CC10FA2044A3C60003C045 /* Release */ = {
511 + isa = XCBuildConfiguration;
512 + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
513 + buildSettings = {
514 + ALWAYS_SEARCH_USER_PATHS = NO;
515 + CLANG_ANALYZER_NONNULL = YES;
516 + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
517 + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
518 + CLANG_CXX_LIBRARY = "libc++";
519 + CLANG_ENABLE_MODULES = YES;
520 + CLANG_ENABLE_OBJC_ARC = YES;
521 + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
522 + CLANG_WARN_BOOL_CONVERSION = YES;
523 + CLANG_WARN_CONSTANT_CONVERSION = YES;
524 + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
525 + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
526 + CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
527 + CLANG_WARN_EMPTY_BODY = YES;
528 + CLANG_WARN_ENUM_CONVERSION = YES;
529 + CLANG_WARN_INFINITE_RECURSION = YES;
530 + CLANG_WARN_INT_CONVERSION = YES;
531 + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
532 + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
533 + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
534 + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
535 + CLANG_WARN_SUSPICIOUS_MOVE = YES;
536 + CODE_SIGN_IDENTITY = "-";
537 + COPY_PHASE_STRIP = NO;
538 + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
539 + ENABLE_NS_ASSERTIONS = NO;
540 + ENABLE_STRICT_OBJC_MSGSEND = YES;
541 + GCC_C_LANGUAGE_STANDARD = gnu11;
542 + GCC_NO_COMMON_BLOCKS = YES;
543 + GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
544 + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
545 + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
546 + GCC_WARN_UNUSED_FUNCTION = YES;
547 + GCC_WARN_UNUSED_VARIABLE = YES;
548 + MACOSX_DEPLOYMENT_TARGET = 10.14;
549 + MTL_ENABLE_DEBUG_INFO = NO;
550 + SDKROOT = macosx;
551 + SWIFT_COMPILATION_MODE = wholemodule;
552 + SWIFT_OPTIMIZATION_LEVEL = "-O";
553 + };
554 + name = Release;
555 + };
556 + 33CC10FC2044A3C60003C045 /* Debug */ = {
557 + isa = XCBuildConfiguration;
558 + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
559 + buildSettings = {
560 + ARCHS = arm64;
561 + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
562 + CLANG_ENABLE_MODULES = YES;
563 + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
564 + CODE_SIGN_IDENTITY = "Apple Development";
565 + CODE_SIGN_STYLE = Automatic;
566 + COMBINE_HIDPI_IMAGES = YES;
567 + CURRENT_PROJECT_VERSION = 10;
568 + DEVELOPMENT_TEAM = 32J6BB6VUS;
569 + INFOPLIST_FILE = Runner/Info.plist;
570 + INFOPLIST_KEY_CFBundleDisplayName = "Cake Wallet";
571 + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.finance";
572 + LD_RUNPATH_SEARCH_PATHS = (
573 + "$(inherited)",
574 + "@executable_path/../Frameworks",
575 + );
576 + MACOSX_DEPLOYMENT_TARGET = 12;
577 + MARKETING_VERSION = 1.0.1;
578 + PROVISIONING_PROFILE_SPECIFIER = "";
579 + SWIFT_OPTIMIZATION_LEVEL = "-Onone";
580 + SWIFT_VERSION = 5.0;
581 + };
582 + name = Debug;
583 + };
584 + 33CC10FD2044A3C60003C045 /* Release */ = {
585 + isa = XCBuildConfiguration;
586 + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
587 + buildSettings = {
588 + ARCHS = arm64;
589 + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
590 + CLANG_ENABLE_MODULES = YES;
591 + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;
592 + CODE_SIGN_IDENTITY = "Apple Development";
593 + CODE_SIGN_STYLE = Automatic;
594 + COMBINE_HIDPI_IMAGES = YES;
595 + CURRENT_PROJECT_VERSION = 10;
596 + DEVELOPMENT_TEAM = 32J6BB6VUS;
597 + INFOPLIST_FILE = Runner/Info.plist;
598 + INFOPLIST_KEY_CFBundleDisplayName = "Cake Wallet";
599 + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.finance";
600 + LD_RUNPATH_SEARCH_PATHS = (
601 + "$(inherited)",
602 + "@executable_path/../Frameworks",
603 + );
604 + MACOSX_DEPLOYMENT_TARGET = 12;
605 + MARKETING_VERSION = 1.0.1;
606 + PROVISIONING_PROFILE_SPECIFIER = "";
607 + SWIFT_VERSION = 5.0;
608 + };
609 + name = Release;
610 + };
611 + 33CC111C2044C6BA0003C045 /* Debug */ = {
612 + isa = XCBuildConfiguration;
613 + buildSettings = {
614 + CODE_SIGN_STYLE = Manual;
615 + PRODUCT_NAME = "$(TARGET_NAME)";
616 + };
617 + name = Debug;
618 + };
619 + 33CC111D2044C6BA0003C045 /* Release */ = {
620 + isa = XCBuildConfiguration;
621 + buildSettings = {
622 + CODE_SIGN_STYLE = Automatic;
623 + PRODUCT_NAME = "$(TARGET_NAME)";
624 + };
625 + name = Release;
626 + };
627 +/* End XCBuildConfiguration section */
628 +
629 +/* Begin XCConfigurationList section */
630 + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = {
631 + isa = XCConfigurationList;
632 + buildConfigurations = (
633 + 33CC10F92044A3C60003C045 /* Debug */,
634 + 33CC10FA2044A3C60003C045 /* Release */,
635 + 338D0CE9231458BD00FA5F75 /* Profile */,
636 + );
637 + defaultConfigurationIsVisible = 0;
638 + defaultConfigurationName = Release;
639 + };
640 + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = {
641 + isa = XCConfigurationList;
642 + buildConfigurations = (
643 + 33CC10FC2044A3C60003C045 /* Debug */,
644 + 33CC10FD2044A3C60003C045 /* Release */,
645 + 338D0CEA231458BD00FA5F75 /* Profile */,
646 + );
647 + defaultConfigurationIsVisible = 0;
648 + defaultConfigurationName = Release;
649 + };
650 + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = {
651 + isa = XCConfigurationList;
652 + buildConfigurations = (
653 + 33CC111C2044C6BA0003C045 /* Debug */,
654 + 33CC111D2044C6BA0003C045 /* Release */,
655 + 338D0CEB231458BD00FA5F75 /* Profile */,
656 + );
657 + defaultConfigurationIsVisible = 0;
658 + defaultConfigurationName = Release;
659 + };
660 +/* End XCConfigurationList section */
661 + };
662 + rootObject = 33CC10E52044A3C60003C045 /* Project object */;
663 +}
macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new
+8
@@ -0,0 +1,8 @@
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 +<plist version="1.0">
4 +<dict>
5 + <key>IDEDidComputeMac32BitWarning</key>
6 + <true/>
7 +</dict>
8 +</plist>
macos/Runner.xcodeproj/project_base.pbxproj new
+636
@@ -0,0 +1,636 @@
1 +// !$*UTF8*$!
2 +{
3 + archiveVersion = 1;
4 + classes = {
5 + };
6 + objectVersion = 51;
7 + objects = {
8 +
9 +/* Begin PBXAggregateTarget section */
10 + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = {
11 + isa = PBXAggregateTarget;
12 + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */;
13 + buildPhases = (
14 + 33CC111E2044C6BF0003C045 /* ShellScript */,
15 + );
16 + dependencies = (
17 + );
18 + name = "Flutter Assemble";
19 + productName = FLX;
20 + };
21 +/* End PBXAggregateTarget section */
22 +
23 +/* Begin PBXBuildFile section */
24 + 328F945957E1041662291EC5 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C84AA35EA80D710889C68D81 /* Pods_Runner.framework */; };
25 + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };
26 + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };
27 + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
28 + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
29 + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
30 +/* End PBXBuildFile section */
31 +
32 +/* Begin PBXContainerItemProxy section */
33 + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = {
34 + isa = PBXContainerItemProxy;
35 + containerPortal = 33CC10E52044A3C60003C045 /* Project object */;
36 + proxyType = 1;
37 + remoteGlobalIDString = 33CC111A2044C6BA0003C045;
38 + remoteInfo = FLX;
39 + };
40 +/* End PBXContainerItemProxy section */
41 +
42 +/* Begin PBXCopyFilesBuildPhase section */
43 + 33CC110E2044A8840003C045 /* Bundle Framework */ = {
44 + isa = PBXCopyFilesBuildPhase;
45 + buildActionMask = 2147483647;
46 + dstPath = "";
47 + dstSubfolderSpec = 10;
48 + files = (
49 + );
50 + name = "Bundle Framework";
51 + runOnlyForDeploymentPostprocessing = 0;
52 + };
53 +/* End PBXCopyFilesBuildPhase section */
54 +
55 +/* Begin PBXFileReference section */
56 + 0C090639294D3AAC00954DC9 /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = usr/lib/libiconv.tbd; sourceTree = SDKROOT; };
57 + 135D3AD0276D31F62BBEDDBF /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
58 + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
59 + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
60 + 33CC10ED2044A3C60003C045 /* cake_wallet_new.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = cake_wallet_new.app; sourceTree = BUILT_PRODUCTS_DIR; };
61 + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
62 + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
63 + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
64 + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = "<group>"; };
65 + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = "<group>"; };
66 + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = "<group>"; };
67 + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = "<group>"; };
68 + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = "<group>"; };
69 + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
70 + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
71 + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
72 + 359F2F22842E234537DED5E3 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
73 + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
74 + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
75 + C84AA35EA80D710889C68D81 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
76 + FF499CFF131B036E3C5638D0 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
77 +/* End PBXFileReference section */
78 +
79 +/* Begin PBXFrameworksBuildPhase section */
80 + 33CC10EA2044A3C60003C045 /* Frameworks */ = {
81 + isa = PBXFrameworksBuildPhase;
82 + buildActionMask = 2147483647;
83 + files = (
84 + 328F945957E1041662291EC5 /* Pods_Runner.framework in Frameworks */,
85 + );
86 + runOnlyForDeploymentPostprocessing = 0;
87 + };
88 +/* End PBXFrameworksBuildPhase section */
89 +
90 +/* Begin PBXGroup section */
91 + 33BA886A226E78AF003329D5 /* Configs */ = {
92 + isa = PBXGroup;
93 + children = (
94 + 33E5194F232828860026EE4D /* AppInfo.xcconfig */,
95 + 9740EEB21CF90195004384FC /* Debug.xcconfig */,
96 + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
97 + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */,
98 + );
99 + path = Configs;
100 + sourceTree = "<group>";
101 + };
102 + 33CC10E42044A3C60003C045 = {
103 + isa = PBXGroup;
104 + children = (
105 + 33FAB671232836740065AC1E /* Runner */,
106 + 33CEB47122A05771004F2AC0 /* Flutter */,
107 + 33CC10EE2044A3C60003C045 /* Products */,
108 + D73912EC22F37F3D000D13A0 /* Frameworks */,
109 + 9B6E7CA3983216A9E173F00F /* Pods */,
110 + );
111 + sourceTree = "<group>";
112 + };
113 + 33CC10EE2044A3C60003C045 /* Products */ = {
114 + isa = PBXGroup;
115 + children = (
116 + 33CC10ED2044A3C60003C045 /* cake_wallet_new.app */,
117 + );
118 + name = Products;
119 + sourceTree = "<group>";
120 + };
121 + 33CC11242044D66E0003C045 /* Resources */ = {
122 + isa = PBXGroup;
123 + children = (
124 + 33CC10F22044A3C60003C045 /* Assets.xcassets */,
125 + 33CC10F42044A3C60003C045 /* MainMenu.xib */,
126 + 33CC10F72044A3C60003C045 /* Info.plist */,
127 + );
128 + name = Resources;
129 + path = ..;
130 + sourceTree = "<group>";
131 + };
132 + 33CEB47122A05771004F2AC0 /* Flutter */ = {
133 + isa = PBXGroup;
134 + children = (
135 + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */,
136 + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */,
137 + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */,
138 + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */,
139 + );
140 + path = Flutter;
141 + sourceTree = "<group>";
142 + };
143 + 33FAB671232836740065AC1E /* Runner */ = {
144 + isa = PBXGroup;
145 + children = (
146 + 33CC10F02044A3C60003C045 /* AppDelegate.swift */,
147 + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */,
148 + 33E51913231747F40026EE4D /* DebugProfile.entitlements */,
149 + 33E51914231749380026EE4D /* Release.entitlements */,
150 + 33CC11242044D66E0003C045 /* Resources */,
151 + 33BA886A226E78AF003329D5 /* Configs */,
152 + );
153 + path = Runner;
154 + sourceTree = "<group>";
155 + };
156 + 9B6E7CA3983216A9E173F00F /* Pods */ = {
157 + isa = PBXGroup;
158 + children = (
159 + 359F2F22842E234537DED5E3 /* Pods-Runner.debug.xcconfig */,
160 + 135D3AD0276D31F62BBEDDBF /* Pods-Runner.release.xcconfig */,
161 + FF499CFF131B036E3C5638D0 /* Pods-Runner.profile.xcconfig */,
162 + );
163 + path = Pods;
164 + sourceTree = "<group>";
165 + };
166 + D73912EC22F37F3D000D13A0 /* Frameworks */ = {
167 + isa = PBXGroup;
168 + children = (
169 + 0C090639294D3AAC00954DC9 /* libiconv.tbd */,
170 + C84AA35EA80D710889C68D81 /* Pods_Runner.framework */,
171 + );
172 + name = Frameworks;
173 + sourceTree = "<group>";
174 + };
175 +/* End PBXGroup section */
176 +
177 +/* Begin PBXNativeTarget section */
178 + 33CC10EC2044A3C60003C045 /* Runner */ = {
179 + isa = PBXNativeTarget;
180 + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
181 + buildPhases = (
182 + 8AB41FC42599228A92F51A44 /* [CP] Check Pods Manifest.lock */,
183 + 33CC10E92044A3C60003C045 /* Sources */,
184 + 33CC10EA2044A3C60003C045 /* Frameworks */,
185 + 33CC10EB2044A3C60003C045 /* Resources */,
186 + 33CC110E2044A8840003C045 /* Bundle Framework */,
187 + 3399D490228B24CF009A79C7 /* ShellScript */,
188 + F015812745AAC61FF550BB30 /* [CP] Embed Pods Frameworks */,
189 + );
190 + buildRules = (
191 + );
192 + dependencies = (
193 + 33CC11202044C79F0003C045 /* PBXTargetDependency */,
194 + );
195 + name = Runner;
196 + productName = Runner;
197 + productReference = 33CC10ED2044A3C60003C045 /* cake_wallet_new.app */;
198 + productType = "com.apple.product-type.application";
199 + };
200 +/* End PBXNativeTarget section */
201 +
202 +/* Begin PBXProject section */
203 + 33CC10E52044A3C60003C045 /* Project object */ = {
204 + isa = PBXProject;
205 + attributes = {
206 + LastSwiftUpdateCheck = 0920;
207 + LastUpgradeCheck = 1300;
208 + ORGANIZATIONNAME = "";
209 + TargetAttributes = {
210 + 33CC10EC2044A3C60003C045 = {
211 + CreatedOnToolsVersion = 9.2;
212 + LastSwiftMigration = 1100;
213 + ProvisioningStyle = Automatic;
214 + SystemCapabilities = {
215 + com.apple.Sandbox = {
216 + enabled = 1;
217 + };
218 + };
219 + };
220 + 33CC111A2044C6BA0003C045 = {
221 + CreatedOnToolsVersion = 9.2;
222 + ProvisioningStyle = Manual;
223 + };
224 + };
225 + };
226 + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */;
227 + compatibilityVersion = "Xcode 9.3";
228 + developmentRegion = en;
229 + hasScannedForEncodings = 0;
230 + knownRegions = (
231 + en,
232 + Base,
233 + );
234 + mainGroup = 33CC10E42044A3C60003C045;
235 + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */;
236 + projectDirPath = "";
237 + projectRoot = "";
238 + targets = (
239 + 33CC10EC2044A3C60003C045 /* Runner */,
240 + 33CC111A2044C6BA0003C045 /* Flutter Assemble */,
241 + );
242 + };
243 +/* End PBXProject section */
244 +
245 +/* Begin PBXResourcesBuildPhase section */
246 + 33CC10EB2044A3C60003C045 /* Resources */ = {
247 + isa = PBXResourcesBuildPhase;
248 + buildActionMask = 2147483647;
249 + files = (
250 + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */,
251 + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */,
252 + );
253 + runOnlyForDeploymentPostprocessing = 0;
254 + };
255 +/* End PBXResourcesBuildPhase section */
256 +
257 +/* Begin PBXShellScriptBuildPhase section */
258 + 3399D490228B24CF009A79C7 /* ShellScript */ = {
259 + isa = PBXShellScriptBuildPhase;
260 + buildActionMask = 2147483647;
261 + files = (
262 + );
263 + inputFileListPaths = (
264 + );
265 + inputPaths = (
266 + );
267 + outputFileListPaths = (
268 + );
269 + outputPaths = (
270 + );
271 + runOnlyForDeploymentPostprocessing = 0;
272 + shellPath = /bin/sh;
273 + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n";
274 + };
275 + 33CC111E2044C6BF0003C045 /* ShellScript */ = {
276 + isa = PBXShellScriptBuildPhase;
277 + buildActionMask = 2147483647;
278 + files = (
279 + );
280 + inputFileListPaths = (
281 + Flutter/ephemeral/FlutterInputs.xcfilelist,
282 + );
283 + inputPaths = (
284 + Flutter/ephemeral/tripwire,
285 + );
286 + outputFileListPaths = (
287 + Flutter/ephemeral/FlutterOutputs.xcfilelist,
288 + );
289 + outputPaths = (
290 + );
291 + runOnlyForDeploymentPostprocessing = 0;
292 + shellPath = /bin/sh;
293 + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
294 + };
295 + 8AB41FC42599228A92F51A44 /* [CP] Check Pods Manifest.lock */ = {
296 + isa = PBXShellScriptBuildPhase;
297 + buildActionMask = 2147483647;
298 + files = (
299 + );
300 + inputFileListPaths = (
301 + );
302 + inputPaths = (
303 + "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
304 + "${PODS_ROOT}/Manifest.lock",
305 + );
306 + name = "[CP] Check Pods Manifest.lock";
307 + outputFileListPaths = (
308 + );
309 + outputPaths = (
310 + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
311 + );
312 + runOnlyForDeploymentPostprocessing = 0;
313 + shellPath = /bin/sh;
314 + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
315 + showEnvVarsInLog = 0;
316 + };
317 + F015812745AAC61FF550BB30 /* [CP] Embed Pods Frameworks */ = {
318 + isa = PBXShellScriptBuildPhase;
319 + buildActionMask = 2147483647;
320 + files = (
321 + );
322 + inputFileListPaths = (
323 + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
324 + );
325 + name = "[CP] Embed Pods Frameworks";
326 + outputFileListPaths = (
327 + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
328 + );
329 + runOnlyForDeploymentPostprocessing = 0;
330 + shellPath = /bin/sh;
331 + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
332 + showEnvVarsInLog = 0;
333 + };
334 +/* End PBXShellScriptBuildPhase section */
335 +
336 +/* Begin PBXSourcesBuildPhase section */
337 + 33CC10E92044A3C60003C045 /* Sources */ = {
338 + isa = PBXSourcesBuildPhase;
339 + buildActionMask = 2147483647;
340 + files = (
341 + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */,
342 + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */,
343 + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */,
344 + );
345 + runOnlyForDeploymentPostprocessing = 0;
346 + };
347 +/* End PBXSourcesBuildPhase section */
348 +
349 +/* Begin PBXTargetDependency section */
350 + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = {
351 + isa = PBXTargetDependency;
352 + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */;
353 + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */;
354 + };
355 +/* End PBXTargetDependency section */
356 +
357 +/* Begin PBXVariantGroup section */
358 + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = {
359 + isa = PBXVariantGroup;
360 + children = (
361 + 33CC10F52044A3C60003C045 /* Base */,
362 + );
363 + name = MainMenu.xib;
364 + path = Runner;
365 + sourceTree = "<group>";
366 + };
367 +/* End PBXVariantGroup section */
368 +
369 +/* Begin XCBuildConfiguration section */
370 + 338D0CE9231458BD00FA5F75 /* Profile */ = {
371 + isa = XCBuildConfiguration;
372 + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
373 + buildSettings = {
374 + ALWAYS_SEARCH_USER_PATHS = NO;
375 + CLANG_ANALYZER_NONNULL = YES;
376 + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
377 + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
378 + CLANG_CXX_LIBRARY = "libc++";
379 + CLANG_ENABLE_MODULES = YES;
380 + CLANG_ENABLE_OBJC_ARC = YES;
381 + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
382 + CLANG_WARN_BOOL_CONVERSION = YES;
383 + CLANG_WARN_CONSTANT_CONVERSION = YES;
384 + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
385 + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
386 + CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
387 + CLANG_WARN_EMPTY_BODY = YES;
388 + CLANG_WARN_ENUM_CONVERSION = YES;
389 + CLANG_WARN_INFINITE_RECURSION = YES;
390 + CLANG_WARN_INT_CONVERSION = YES;
391 + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
392 + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
393 + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
394 + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
395 + CLANG_WARN_SUSPICIOUS_MOVE = YES;
396 + CODE_SIGN_IDENTITY = "-";
397 + COPY_PHASE_STRIP = NO;
398 + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
399 + ENABLE_NS_ASSERTIONS = NO;
400 + ENABLE_STRICT_OBJC_MSGSEND = YES;
401 + GCC_C_LANGUAGE_STANDARD = gnu11;
402 + GCC_NO_COMMON_BLOCKS = YES;
403 + GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
404 + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
405 + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
406 + GCC_WARN_UNUSED_FUNCTION = YES;
407 + GCC_WARN_UNUSED_VARIABLE = YES;
408 + MACOSX_DEPLOYMENT_TARGET = 10.11;
409 + MTL_ENABLE_DEBUG_INFO = NO;
410 + SDKROOT = macosx;
411 + SWIFT_COMPILATION_MODE = wholemodule;
412 + SWIFT_OPTIMIZATION_LEVEL = "-O";
413 + };
414 + name = Profile;
415 + };
416 + 338D0CEA231458BD00FA5F75 /* Profile */ = {
417 + isa = XCBuildConfiguration;
418 + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
419 + buildSettings = {
420 + ARCHS = ;
421 + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
422 + CLANG_ENABLE_MODULES = YES;
423 + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
424 + CODE_SIGN_STYLE = Automatic;
425 + COMBINE_HIDPI_IMAGES = YES;
426 + INFOPLIST_FILE = Runner/Info.plist;
427 + LD_RUNPATH_SEARCH_PATHS = (
428 + "$(inherited)",
429 + "@executable_path/../Frameworks",
430 + );
431 + PROVISIONING_PROFILE_SPECIFIER = "";
432 + SWIFT_VERSION = 5.0;
433 + };
434 + name = Profile;
435 + };
436 + 338D0CEB231458BD00FA5F75 /* Profile */ = {
437 + isa = XCBuildConfiguration;
438 + buildSettings = {
439 + CODE_SIGN_STYLE = Manual;
440 + PRODUCT_NAME = "$(TARGET_NAME)";
441 + };
442 + name = Profile;
443 + };
444 + 33CC10F92044A3C60003C045 /* Debug */ = {
445 + isa = XCBuildConfiguration;
446 + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
447 + buildSettings = {
448 + ALWAYS_SEARCH_USER_PATHS = NO;
449 + CLANG_ANALYZER_NONNULL = YES;
450 + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
451 + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
452 + CLANG_CXX_LIBRARY = "libc++";
453 + CLANG_ENABLE_MODULES = YES;
454 + CLANG_ENABLE_OBJC_ARC = YES;
455 + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
456 + CLANG_WARN_BOOL_CONVERSION = YES;
457 + CLANG_WARN_CONSTANT_CONVERSION = YES;
458 + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
459 + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
460 + CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
461 + CLANG_WARN_EMPTY_BODY = YES;
462 + CLANG_WARN_ENUM_CONVERSION = YES;
463 + CLANG_WARN_INFINITE_RECURSION = YES;
464 + CLANG_WARN_INT_CONVERSION = YES;
465 + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
466 + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
467 + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
468 + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
469 + CLANG_WARN_SUSPICIOUS_MOVE = YES;
470 + CODE_SIGN_IDENTITY = "-";
471 + COPY_PHASE_STRIP = NO;
472 + DEBUG_INFORMATION_FORMAT = dwarf;
473 + ENABLE_STRICT_OBJC_MSGSEND = YES;
474 + ENABLE_TESTABILITY = YES;
475 + GCC_C_LANGUAGE_STANDARD = gnu11;
476 + GCC_DYNAMIC_NO_PIC = NO;
477 + GCC_NO_COMMON_BLOCKS = YES;
478 + GCC_OPTIMIZATION_LEVEL = 0;
479 + GCC_PREPROCESSOR_DEFINITIONS = (
480 + "DEBUG=1",
481 + "$(inherited)",
482 + );
483 + GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
484 + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
485 + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
486 + GCC_WARN_UNUSED_FUNCTION = YES;
487 + GCC_WARN_UNUSED_VARIABLE = YES;
488 + MACOSX_DEPLOYMENT_TARGET = 10.11;
489 + MTL_ENABLE_DEBUG_INFO = YES;
490 + ONLY_ACTIVE_ARCH = YES;
491 + SDKROOT = macosx;
492 + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
493 + SWIFT_OPTIMIZATION_LEVEL = "-Onone";
494 + };
495 + name = Debug;
496 + };
497 + 33CC10FA2044A3C60003C045 /* Release */ = {
498 + isa = XCBuildConfiguration;
499 + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
500 + buildSettings = {
501 + ALWAYS_SEARCH_USER_PATHS = NO;
502 + CLANG_ANALYZER_NONNULL = YES;
503 + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
504 + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
505 + CLANG_CXX_LIBRARY = "libc++";
506 + CLANG_ENABLE_MODULES = YES;
507 + CLANG_ENABLE_OBJC_ARC = YES;
508 + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
509 + CLANG_WARN_BOOL_CONVERSION = YES;
510 + CLANG_WARN_CONSTANT_CONVERSION = YES;
511 + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
512 + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
513 + CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
514 + CLANG_WARN_EMPTY_BODY = YES;
515 + CLANG_WARN_ENUM_CONVERSION = YES;
516 + CLANG_WARN_INFINITE_RECURSION = YES;
517 + CLANG_WARN_INT_CONVERSION = YES;
518 + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
519 + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
520 + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
521 + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
522 + CLANG_WARN_SUSPICIOUS_MOVE = YES;
523 + CODE_SIGN_IDENTITY = "-";
524 + COPY_PHASE_STRIP = NO;
525 + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
526 + ENABLE_NS_ASSERTIONS = NO;
527 + ENABLE_STRICT_OBJC_MSGSEND = YES;
528 + GCC_C_LANGUAGE_STANDARD = gnu11;
529 + GCC_NO_COMMON_BLOCKS = YES;
530 + GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
531 + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
532 + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
533 + GCC_WARN_UNUSED_FUNCTION = YES;
534 + GCC_WARN_UNUSED_VARIABLE = YES;
535 + MACOSX_DEPLOYMENT_TARGET = 10.11;
536 + MTL_ENABLE_DEBUG_INFO = NO;
537 + SDKROOT = macosx;
538 + SWIFT_COMPILATION_MODE = wholemodule;
539 + SWIFT_OPTIMIZATION_LEVEL = "-O";
540 + };
541 + name = Release;
542 + };
543 + 33CC10FC2044A3C60003C045 /* Debug */ = {
544 + isa = XCBuildConfiguration;
545 + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
546 + buildSettings = {
547 + ARCHS = ;
548 + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
549 + CLANG_ENABLE_MODULES = YES;
550 + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
551 + CODE_SIGN_STYLE = Automatic;
552 + COMBINE_HIDPI_IMAGES = YES;
553 + INFOPLIST_FILE = Runner/Info.plist;
554 + LD_RUNPATH_SEARCH_PATHS = (
555 + "$(inherited)",
556 + "@executable_path/../Frameworks",
557 + );
558 + PROVISIONING_PROFILE_SPECIFIER = "";
559 + SWIFT_OPTIMIZATION_LEVEL = "-Onone";
560 + SWIFT_VERSION = 5.0;
561 + };
562 + name = Debug;
563 + };
564 + 33CC10FD2044A3C60003C045 /* Release */ = {
565 + isa = XCBuildConfiguration;
566 + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
567 + buildSettings = {
568 + ARCHS = ;
569 + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
570 + CLANG_ENABLE_MODULES = YES;
571 + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;
572 + CODE_SIGN_STYLE = Automatic;
573 + COMBINE_HIDPI_IMAGES = YES;
574 + INFOPLIST_FILE = Runner/Info.plist;
575 + LD_RUNPATH_SEARCH_PATHS = (
576 + "$(inherited)",
577 + "@executable_path/../Frameworks",
578 + );
579 + PROVISIONING_PROFILE_SPECIFIER = "";
580 + SWIFT_VERSION = 5.0;
581 + };
582 + name = Release;
583 + };
584 + 33CC111C2044C6BA0003C045 /* Debug */ = {
585 + isa = XCBuildConfiguration;
586 + buildSettings = {
587 + CODE_SIGN_STYLE = Manual;
588 + PRODUCT_NAME = "$(TARGET_NAME)";
589 + };
590 + name = Debug;
591 + };
592 + 33CC111D2044C6BA0003C045 /* Release */ = {
593 + isa = XCBuildConfiguration;
594 + buildSettings = {
595 + CODE_SIGN_STYLE = Automatic;
596 + PRODUCT_NAME = "$(TARGET_NAME)";
597 + };
598 + name = Release;
599 + };
600 +/* End XCBuildConfiguration section */
601 +
602 +/* Begin XCConfigurationList section */
603 + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = {
604 + isa = XCConfigurationList;
605 + buildConfigurations = (
606 + 33CC10F92044A3C60003C045 /* Debug */,
607 + 33CC10FA2044A3C60003C045 /* Release */,
608 + 338D0CE9231458BD00FA5F75 /* Profile */,
609 + );
610 + defaultConfigurationIsVisible = 0;
611 + defaultConfigurationName = Release;
612 + };
613 + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = {
614 + isa = XCConfigurationList;
615 + buildConfigurations = (
616 + 33CC10FC2044A3C60003C045 /* Debug */,
617 + 33CC10FD2044A3C60003C045 /* Release */,
618 + 338D0CEA231458BD00FA5F75 /* Profile */,
619 + );
620 + defaultConfigurationIsVisible = 0;
621 + defaultConfigurationName = Release;
622 + };
623 + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = {
624 + isa = XCConfigurationList;
625 + buildConfigurations = (
626 + 33CC111C2044C6BA0003C045 /* Debug */,
627 + 33CC111D2044C6BA0003C045 /* Release */,
628 + 338D0CEB231458BD00FA5F75 /* Profile */,
629 + );
630 + defaultConfigurationIsVisible = 0;
631 + defaultConfigurationName = Release;
632 + };
633 +/* End XCConfigurationList section */
634 + };
635 + rootObject = 33CC10E52044A3C60003C045 /* Project object */;
636 +}
macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new
+87
@@ -0,0 +1,87 @@
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<Scheme
3 + LastUpgradeVersion = "1300"
4 + version = "1.3">
5 + <BuildAction
6 + parallelizeBuildables = "YES"
7 + buildImplicitDependencies = "YES">
8 + <BuildActionEntries>
9 + <BuildActionEntry
10 + buildForTesting = "YES"
11 + buildForRunning = "YES"
12 + buildForProfiling = "YES"
13 + buildForArchiving = "YES"
14 + buildForAnalyzing = "YES">
15 + <BuildableReference
16 + BuildableIdentifier = "primary"
17 + BlueprintIdentifier = "33CC10EC2044A3C60003C045"
18 + BuildableName = "Cake Wallet.app"
19 + BlueprintName = "Runner"
20 + ReferencedContainer = "container:Runner.xcodeproj">
21 + </BuildableReference>
22 + </BuildActionEntry>
23 + </BuildActionEntries>
24 + </BuildAction>
25 + <TestAction
26 + buildConfiguration = "Debug"
27 + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28 + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29 + shouldUseLaunchSchemeArgsEnv = "YES">
30 + <MacroExpansion>
31 + <BuildableReference
32 + BuildableIdentifier = "primary"
33 + BlueprintIdentifier = "33CC10EC2044A3C60003C045"
34 + BuildableName = "Cake Wallet.app"
35 + BlueprintName = "Runner"
36 + ReferencedContainer = "container:Runner.xcodeproj">
37 + </BuildableReference>
38 + </MacroExpansion>
39 + <Testables>
40 + </Testables>
41 + </TestAction>
42 + <LaunchAction
43 + buildConfiguration = "Debug"
44 + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
45 + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
46 + launchStyle = "0"
47 + useCustomWorkingDirectory = "NO"
48 + ignoresPersistentStateOnLaunch = "NO"
49 + debugDocumentVersioning = "YES"
50 + debugServiceExtension = "internal"
51 + allowLocationSimulation = "YES">
52 + <BuildableProductRunnable
53 + runnableDebuggingMode = "0">
54 + <BuildableReference
55 + BuildableIdentifier = "primary"
56 + BlueprintIdentifier = "33CC10EC2044A3C60003C045"
57 + BuildableName = "Cake Wallet.app"
58 + BlueprintName = "Runner"
59 + ReferencedContainer = "container:Runner.xcodeproj">
60 + </BuildableReference>
61 + </BuildableProductRunnable>
62 + </LaunchAction>
63 + <ProfileAction
64 + buildConfiguration = "Profile"
65 + shouldUseLaunchSchemeArgsEnv = "YES"
66 + savedToolIdentifier = ""
67 + useCustomWorkingDirectory = "NO"
68 + debugDocumentVersioning = "YES">
69 + <BuildableProductRunnable
70 + runnableDebuggingMode = "0">
71 + <BuildableReference
72 + BuildableIdentifier = "primary"
73 + BlueprintIdentifier = "33CC10EC2044A3C60003C045"
74 + BuildableName = "Cake Wallet.app"
75 + BlueprintName = "Runner"
76 + ReferencedContainer = "container:Runner.xcodeproj">
77 + </BuildableReference>
78 + </BuildableProductRunnable>
79 + </ProfileAction>
80 + <AnalyzeAction
81 + buildConfiguration = "Debug">
82 + </AnalyzeAction>
83 + <ArchiveAction
84 + buildConfiguration = "Release"
85 + revealArchiveInOrganizer = "YES">
86 + </ArchiveAction>
87 +</Scheme>
macos/Runner.xcworkspace/contents.xcworkspacedata new
+10
@@ -0,0 +1,10 @@
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<Workspace
3 + version = "1.0">
4 + <FileRef
5 + location = "group:Runner.xcodeproj">
6 + </FileRef>
7 + <FileRef
8 + location = "group:Pods/Pods.xcodeproj">
9 + </FileRef>
10 +</Workspace>
macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new
+8
@@ -0,0 +1,8 @@
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 +<plist version="1.0">
4 +<dict>
5 + <key>IDEDidComputeMac32BitWarning</key>
6 + <true/>
7 +</dict>
8 +</plist>
macos/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new
+8
@@ -0,0 +1,8 @@
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 +<plist version="1.0">
4 +<dict>
5 + <key>PreviewsEnabled</key>
6 + <false/>
7 +</dict>
8 +</plist>
macos/Runner/AppDelegate.swift new
+33
@@ -0,0 +1,33 @@
1 +import Cocoa
2 +import FlutterMacOS
3 +import IOKit.pwr_mgt
4 +
5 +@NSApplicationMain
6 +class AppDelegate: FlutterAppDelegate {
7 + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
8 + return true
9 + }
10 +
11 + override func applicationDidFinishLaunching(_ notification: Notification) {
12 + let controller : FlutterViewController = mainFlutterWindow?.contentViewController as! FlutterViewController
13 +
14 + let utilsChannel = FlutterMethodChannel(
15 + name: "com.cake_wallet/native_utils",
16 + binaryMessenger: controller.engine.binaryMessenger)
17 + utilsChannel.setMethodCallHandler({ [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
18 + switch call.method {
19 + case "sec_random":
20 + guard let args = call.arguments as? Dictionary<String, Any>,
21 + let count = args["count"] as? Int else {
22 + result(nil)
23 + return
24 + }
25 +
26 + result(secRandom(count: count))
27 +
28 + default:
29 + result(FlutterMethodNotImplemented)
30 + }
31 + })
32 + }
33 +}
macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new
+68
@@ -0,0 +1,68 @@
1 +{
2 + "info": {
3 + "version": 1,
4 + "author": "xcode"
5 + },
6 + "images": [
7 + {
8 + "size": "16x16",
9 + "idiom": "mac",
10 + "filename": "app_icon_16.png",
11 + "scale": "1x"
12 + },
13 + {
14 + "size": "16x16",
15 + "idiom": "mac",
16 + "filename": "app_icon_32.png",
17 + "scale": "2x"
18 + },
19 + {
20 + "size": "32x32",
21 + "idiom": "mac",
22 + "filename": "app_icon_32.png",
23 + "scale": "1x"
24 + },
25 + {
26 + "size": "32x32",
27 + "idiom": "mac",
28 + "filename": "app_icon_64.png",
29 + "scale": "2x"
30 + },
31 + {
32 + "size": "128x128",
33 + "idiom": "mac",
34 + "filename": "app_icon_128.png",
35 + "scale": "1x"
36 + },
37 + {
38 + "size": "128x128",
39 + "idiom": "mac",
40 + "filename": "app_icon_256.png",
41 + "scale": "2x"
42 + },
43 + {
44 + "size": "256x256",
45 + "idiom": "mac",
46 + "filename": "app_icon_256.png",
47 + "scale": "1x"
48 + },
49 + {
50 + "size": "256x256",
51 + "idiom": "mac",
52 + "filename": "app_icon_512.png",
53 + "scale": "2x"
54 + },
55 + {
56 + "size": "512x512",
57 + "idiom": "mac",
58 + "filename": "app_icon_512.png",
59 + "scale": "1x"
60 + },
61 + {
62 + "size": "512x512",
63 + "idiom": "mac",
64 + "filename": "app_icon_1024.png",
65 + "scale": "2x"
66 + }
67 + ]
68 +}
\ No newline at end of file
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png
Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png
Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png
Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ
macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png
Binary files /dev/null and b/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ
macos/Runner/Base.lproj/MainMenu.xib new
+344
@@ -0,0 +1,344 @@
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21507" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
3 + <dependencies>
4 + <deployment identifier="macosx"/>
5 + <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21507"/>
6 + <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
7 + </dependencies>
8 + <objects>
9 + <customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
10 + <connections>
11 + <outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
12 + </connections>
13 + </customObject>
14 + <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
15 + <customObject id="-3" userLabel="Application" customClass="NSObject"/>
16 + <customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Cake_Wallet" customModuleProvider="target">
17 + <connections>
18 + <outlet property="applicationMenu" destination="uQy-DD-JDr" id="XBo-yE-nKs"/>
19 + <outlet property="mainFlutterWindow" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
20 + </connections>
21 + </customObject>
22 + <customObject id="YLy-65-1bz" customClass="NSFontManager"/>
23 + <menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
24 + <items>
25 + <menuItem title="APP_NAME" id="1Xt-HY-uBw">
26 + <modifierMask key="keyEquivalentModifierMask"/>
27 + <menu key="submenu" title="APP_NAME" systemMenu="apple" id="uQy-DD-JDr">
28 + <items>
29 + <menuItem title="About APP_NAME" id="5kV-Vb-QxS">
30 + <modifierMask key="keyEquivalentModifierMask"/>
31 + <connections>
32 + <action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
33 + </connections>
34 + </menuItem>
35 + <menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
36 + <menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
37 + <menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
38 + <menuItem title="Services" id="NMo-om-nkz">
39 + <modifierMask key="keyEquivalentModifierMask"/>
40 + <menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
41 + </menuItem>
42 + <menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
43 + <menuItem title="Hide APP_NAME" keyEquivalent="h" id="Olw-nP-bQN">
44 + <connections>
45 + <action selector="hide:" target="-1" id="PnN-Uc-m68"/>
46 + </connections>
47 + </menuItem>
48 + <menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
49 + <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
50 + <connections>
51 + <action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
52 + </connections>
53 + </menuItem>
54 + <menuItem title="Show All" id="Kd2-mp-pUS">
55 + <modifierMask key="keyEquivalentModifierMask"/>
56 + <connections>
57 + <action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
58 + </connections>
59 + </menuItem>
60 + <menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
61 + <menuItem title="Quit APP_NAME" keyEquivalent="q" id="4sb-4s-VLi">
62 + <connections>
63 + <action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
64 + </connections>
65 + </menuItem>
66 + </items>
67 + </menu>
68 + </menuItem>
69 + <menuItem title="Edit" id="5QF-Oa-p0T">
70 + <modifierMask key="keyEquivalentModifierMask"/>
71 + <menu key="submenu" title="Edit" id="W48-6f-4Dl">
72 + <items>
73 + <menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
74 + <connections>
75 + <action selector="undo:" target="-1" id="M6e-cu-g7V"/>
76 + </connections>
77 + </menuItem>
78 + <menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
79 + <connections>
80 + <action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
81 + </connections>
82 + </menuItem>
83 + <menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
84 + <menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
85 + <connections>
86 + <action selector="cut:" target="-1" id="YJe-68-I9s"/>
87 + </connections>
88 + </menuItem>
89 + <menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
90 + <connections>
91 + <action selector="copy:" target="-1" id="G1f-GL-Joy"/>
92 + </connections>
93 + </menuItem>
94 + <menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
95 + <connections>
96 + <action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
97 + </connections>
98 + </menuItem>
99 + <menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
100 + <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
101 + <connections>
102 + <action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/>
103 + </connections>
104 + </menuItem>
105 + <menuItem title="Delete" id="pa3-QI-u2k">
106 + <modifierMask key="keyEquivalentModifierMask"/>
107 + <connections>
108 + <action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
109 + </connections>
110 + </menuItem>
111 + <menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
112 + <connections>
113 + <action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
114 + </connections>
115 + </menuItem>
116 + <menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
117 + <menuItem title="Find" id="4EN-yA-p0u">
118 + <modifierMask key="keyEquivalentModifierMask"/>
119 + <menu key="submenu" title="Find" id="1b7-l0-nxx">
120 + <items>
121 + <menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
122 + <connections>
123 + <action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/>
124 + </connections>
125 + </menuItem>
126 + <menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
127 + <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
128 + <connections>
129 + <action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/>
130 + </connections>
131 + </menuItem>
132 + <menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
133 + <connections>
134 + <action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/>
135 + </connections>
136 + </menuItem>
137 + <menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
138 + <connections>
139 + <action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/>
140 + </connections>
141 + </menuItem>
142 + <menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
143 + <connections>
144 + <action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/>
145 + </connections>
146 + </menuItem>
147 + <menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
148 + <connections>
149 + <action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/>
150 + </connections>
151 + </menuItem>
152 + </items>
153 + </menu>
154 + </menuItem>
155 + <menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
156 + <modifierMask key="keyEquivalentModifierMask"/>
157 + <menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
158 + <items>
159 + <menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
160 + <connections>
161 + <action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/>
162 + </connections>
163 + </menuItem>
164 + <menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
165 + <connections>
166 + <action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/>
167 + </connections>
168 + </menuItem>
169 + <menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
170 + <menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
171 + <modifierMask key="keyEquivalentModifierMask"/>
172 + <connections>
173 + <action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/>
174 + </connections>
175 + </menuItem>
176 + <menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
177 + <modifierMask key="keyEquivalentModifierMask"/>
178 + <connections>
179 + <action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/>
180 + </connections>
181 + </menuItem>
182 + <menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
183 + <modifierMask key="keyEquivalentModifierMask"/>
184 + <connections>
185 + <action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/>
186 + </connections>
187 + </menuItem>
188 + </items>
189 + </menu>
190 + </menuItem>
191 + <menuItem title="Substitutions" id="9ic-FL-obx">
192 + <modifierMask key="keyEquivalentModifierMask"/>
193 + <menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
194 + <items>
195 + <menuItem title="Show Substitutions" id="z6F-FW-3nz">
196 + <modifierMask key="keyEquivalentModifierMask"/>
197 + <connections>
198 + <action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/>
199 + </connections>
200 + </menuItem>
201 + <menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
202 + <menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
203 + <modifierMask key="keyEquivalentModifierMask"/>
204 + <connections>
205 + <action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/>
206 + </connections>
207 + </menuItem>
208 + <menuItem title="Smart Quotes" id="hQb-2v-fYv">
209 + <modifierMask key="keyEquivalentModifierMask"/>
210 + <connections>
211 + <action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/>
212 + </connections>
213 + </menuItem>
214 + <menuItem title="Smart Dashes" id="rgM-f4-ycn">
215 + <modifierMask key="keyEquivalentModifierMask"/>
216 + <connections>
217 + <action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/>
218 + </connections>
219 + </menuItem>
220 + <menuItem title="Smart Links" id="cwL-P1-jid">
221 + <modifierMask key="keyEquivalentModifierMask"/>
222 + <connections>
223 + <action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/>
224 + </connections>
225 + </menuItem>
226 + <menuItem title="Data Detectors" id="tRr-pd-1PS">
227 + <modifierMask key="keyEquivalentModifierMask"/>
228 + <connections>
229 + <action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/>
230 + </connections>
231 + </menuItem>
232 + <menuItem title="Text Replacement" id="HFQ-gK-NFA">
233 + <modifierMask key="keyEquivalentModifierMask"/>
234 + <connections>
235 + <action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/>
236 + </connections>
237 + </menuItem>
238 + </items>
239 + </menu>
240 + </menuItem>
241 + <menuItem title="Transformations" id="2oI-Rn-ZJC">
242 + <modifierMask key="keyEquivalentModifierMask"/>
243 + <menu key="submenu" title="Transformations" id="c8a-y6-VQd">
244 + <items>
245 + <menuItem title="Make Upper Case" id="vmV-6d-7jI">
246 + <modifierMask key="keyEquivalentModifierMask"/>
247 + <connections>
248 + <action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/>
249 + </connections>
250 + </menuItem>
251 + <menuItem title="Make Lower Case" id="d9M-CD-aMd">
252 + <modifierMask key="keyEquivalentModifierMask"/>
253 + <connections>
254 + <action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/>
255 + </connections>
256 + </menuItem>
257 + <menuItem title="Capitalize" id="UEZ-Bs-lqG">
258 + <modifierMask key="keyEquivalentModifierMask"/>
259 + <connections>
260 + <action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/>
261 + </connections>
262 + </menuItem>
263 + </items>
264 + </menu>
265 + </menuItem>
266 + <menuItem title="Speech" id="xrE-MZ-jX0">
267 + <modifierMask key="keyEquivalentModifierMask"/>
268 + <menu key="submenu" title="Speech" id="3rS-ZA-NoH">
269 + <items>
270 + <menuItem title="Start Speaking" id="Ynk-f8-cLZ">
271 + <modifierMask key="keyEquivalentModifierMask"/>
272 + <connections>
273 + <action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/>
274 + </connections>
275 + </menuItem>
276 + <menuItem title="Stop Speaking" id="Oyz-dy-DGm">
277 + <modifierMask key="keyEquivalentModifierMask"/>
278 + <connections>
279 + <action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/>
280 + </connections>
281 + </menuItem>
282 + </items>
283 + </menu>
284 + </menuItem>
285 + </items>
286 + </menu>
287 + </menuItem>
288 + <menuItem title="View" id="H8h-7b-M4v">
289 + <modifierMask key="keyEquivalentModifierMask"/>
290 + <menu key="submenu" title="View" id="HyV-fh-RgO">
291 + <items>
292 + <menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
293 + <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
294 + <connections>
295 + <action selector="toggleFullScreen:" target="-1" id="dU3-MA-1Rq"/>
296 + </connections>
297 + </menuItem>
298 + </items>
299 + </menu>
300 + </menuItem>
301 + <menuItem title="Window" id="aUF-d1-5bR">
302 + <modifierMask key="keyEquivalentModifierMask"/>
303 + <menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
304 + <items>
305 + <menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
306 + <connections>
307 + <action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
308 + </connections>
309 + </menuItem>
310 + <menuItem title="Zoom" id="R4o-n2-Eq4">
311 + <modifierMask key="keyEquivalentModifierMask"/>
312 + <connections>
313 + <action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
314 + </connections>
315 + </menuItem>
316 + <menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
317 + <menuItem title="Bring All to Front" id="LE2-aR-0XJ">
318 + <modifierMask key="keyEquivalentModifierMask"/>
319 + <connections>
320 + <action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
321 + </connections>
322 + </menuItem>
323 + </items>
324 + </menu>
325 + </menuItem>
326 + <menuItem title="Help" id="EPT-qC-fAb">
327 + <modifierMask key="keyEquivalentModifierMask"/>
328 + <menu key="submenu" title="Help" systemMenu="help" id="rJ0-wn-3NY"/>
329 + </menuItem>
330 + </items>
331 + <point key="canvasLocation" x="142" y="-258"/>
332 + </menu>
333 + <window title="APP_NAME" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g" customClass="MainFlutterWindow" customModule="Cake_Wallet" customModuleProvider="target">
334 + <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
335 + <rect key="contentRect" x="335" y="390" width="1163" height="755"/>
336 + <rect key="screenRect" x="0.0" y="0.0" width="1512" height="944"/>
337 + <view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
338 + <rect key="frame" x="0.0" y="0.0" width="1163" height="755"/>
339 + <autoresizingMask key="autoresizingMask"/>
340 + </view>
341 + <point key="canvasLocation" x="138.5" y="222.5"/>
342 + </window>
343 + </objects>
344 +</document>
macos/Runner/Configs/AppInfo.xcconfig new
+14
@@ -0,0 +1,14 @@
1 +// Application-level settings for the Runner target.
2 +//
3 +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the
4 +// future. If not, the values below would default to using the project name when this becomes a
5 +// 'flutter create' template.
6 +
7 +// The application's name. By default this is also the title of the Flutter window.
8 +PRODUCT_NAME = Cake Wallet
9 +
10 +// The application's bundle identifier
11 +PRODUCT_BUNDLE_IDENTIFIER = com.fotolockr.cakewallet
12 +
13 +// The copyright displayed in application information
14 +PRODUCT_COPYRIGHT = Copyright © 2022 com.fotolockr. All rights reserved.
macos/Runner/Configs/Debug.xcconfig new
+2
@@ -0,0 +1,2 @@
1 +#include "../../Flutter/Flutter-Debug.xcconfig"
2 +#include "Warnings.xcconfig"
macos/Runner/Configs/Release.xcconfig new
+2
@@ -0,0 +1,2 @@
1 +#include "../../Flutter/Flutter-Release.xcconfig"
2 +#include "Warnings.xcconfig"
macos/Runner/Configs/Warnings.xcconfig new
+13
@@ -0,0 +1,13 @@
1 +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings
2 +GCC_WARN_UNDECLARED_SELECTOR = YES
3 +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES
4 +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE
5 +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
6 +CLANG_WARN_PRAGMA_PACK = YES
7 +CLANG_WARN_STRICT_PROTOTYPES = YES
8 +CLANG_WARN_COMMA = YES
9 +GCC_WARN_STRICT_SELECTOR_MATCH = YES
10 +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES
11 +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
12 +GCC_WARN_SHADOW = YES
13 +CLANG_WARN_UNREACHABLE_CODE = YES
macos/Runner/DebugProfileBase.entitlements new
+18
@@ -0,0 +1,18 @@
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 +<plist version="1.0">
4 +<dict>
5 + <key>com.apple.security.app-sandbox</key>
6 + <true/>
7 + <key>com.apple.security.cs.allow-jit</key>
8 + <true/>
9 + <key>com.apple.security.network.server</key>
10 + <true/>
11 + <key>keychain-access-groups</key>
12 + <array>
13 + <string>$(AppIdentifierPrefix)${BUNDLE_ID}</string>
14 + </array>
15 + <key>com.apple.security.network.client</key>
16 + <true/>
17 +</dict>
18 +</plist>
macos/Runner/InfoBase.plist new
+34
@@ -0,0 +1,34 @@
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 +<plist version="1.0">
4 +<dict>
5 + <key>CFBundleDevelopmentRegion</key>
6 + <string>$(DEVELOPMENT_LANGUAGE)</string>
7 + <key>CFBundleExecutable</key>
8 + <string>$(EXECUTABLE_NAME)</string>
9 + <key>CFBundleIconFile</key>
10 + <string></string>
11 + <key>CFBundleIdentifier</key>
12 + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
13 + <key>CFBundleInfoDictionaryVersion</key>
14 + <string>6.0</string>
15 + <key>CFBundleName</key>
16 + <string>$(PRODUCT_NAME)</string>
17 + <key>CFBundlePackageType</key>
18 + <string>APPL</string>
19 + <key>CFBundleShortVersionString</key>
20 + <string>$(FLUTTER_BUILD_NAME)</string>
21 + <key>CFBundleVersion</key>
22 + <string>$(FLUTTER_BUILD_NUMBER)</string>
23 + <key>LSMinimumSystemVersion</key>
24 + <string>$(MACOSX_DEPLOYMENT_TARGET)</string>
25 + <key>NSHumanReadableCopyright</key>
26 + <string>$(PRODUCT_COPYRIGHT)</string>
27 + <key>NSMainNibFile</key>
28 + <string>MainMenu</string>
29 + <key>NSPrincipalClass</key>
30 + <string>NSApplication</string>
31 + <key>LSApplicationCategoryType</key>
32 + <string>public.app-category.finance</string>
33 +</dict>
34 +</plist>
macos/Runner/MainFlutterWindow.swift new
+15
@@ -0,0 +1,15 @@
1 +import Cocoa
2 +import FlutterMacOS
3 +
4 +class MainFlutterWindow: NSWindow {
5 + override func awakeFromNib() {
6 + let flutterViewController = FlutterViewController.init()
7 + let windowFrame = self.frame
8 + self.contentViewController = flutterViewController
9 + self.setFrame(windowFrame, display: true)
10 +
11 + RegisterGeneratedPlugins(registry: flutterViewController)
12 +
13 + super.awakeFromNib()
14 + }
15 +}
macos/Runner/ReleaseBase.entitlements new
+14
@@ -0,0 +1,14 @@
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 +<plist version="1.0">
4 +<dict>
5 + <key>com.apple.security.app-sandbox</key>
6 + <true/>
7 + <key>keychain-access-groups</key>
8 + <array>
9 + <string>$(AppIdentifierPrefix)${BUNDLE_ID}</string>
10 + </array>
11 + <key>com.apple.security.network.client</key>
12 + <true/>
13 +</dict>
14 +</plist>
pubspec_base.yaml
+10 -3
@@ -9,6 +9,7 @@ dependencies:
9 qr_flutter: ^4.0.0
10 uuid: 3.0.6
11 shared_preferences: ^2.0.15
12 + shared_preferences_android: 2.1.0
13 flutter_secure_storage:
14 git:
15 url: https://github.com/cake-tech/flutter_secure_storage.git
@@ -34,7 +35,9 @@ dependencies:
35 local_auth: ^2.1.0
36 package_info: ^2.0.0
37 #package_info_plus: ^1.4.2
37 - devicelocale: ^0.4.3
38 + devicelocale:
39 + git:
40 + url: https://github.com/OmarHatem28/flutter-devicelocale
41 auto_size_text: ^3.0.0
42 dotted_border: ^2.0.0+2
43 smooth_page_indicator: ^1.0.0+2
@@ -61,6 +64,7 @@ dependencies:
64 permission_handler: ^10.0.0
65 device_display_brightness: ^0.0.6
66 platform_device_id: ^1.0.1
67 + wakelock: ^0.6.2
68 flutter_mailer: ^2.0.2
69 device_info_plus: 8.1.0
70 cake_backup:
@@ -72,11 +76,11 @@ dependencies:
76 dev_dependencies:
77 flutter_test:
78 sdk: flutter
75 - build_runner: ^2.1.11
79 + build_runner: ^2.3.3
80 mobx_codegen: ^2.1.1
81 build_resolvers: ^2.0.9
82 hive_generator: ^1.1.3
79 - flutter_launcher_icons: ^0.9.3
83 + flutter_launcher_icons: ^0.11.0
84 # check flutter_launcher_icons for usage
85 pedantic: ^1.8.0
86 # replace https://github.com/dart-lang/lints#migrating-from-packagepedantic
@@ -85,6 +89,9 @@ flutter_icons:
89 image_path: "assets/images/app_logo.png"
90 android: true
91 ios: true
92 + macos:
93 + generate: true
94 + image_path: "assets/images/app_logo.png"
95
96 flutter:
97 uses-material-design: true
res/values/strings_ar.arb
+1
@@ -695,5 +695,6 @@
695 "optional_name": "اسم المستلم الاختياري",
696 "clearnet_link": "رابط Clearnet",
697 "onion_link": "رابط البصل",
698 + "settings": "إعدادات",
699 "sell_monero_com_alert_content": "بيع Monero غير مدعوم حتى الآن"
700 }
res/values/strings_de.arb
+1
@@ -697,5 +697,6 @@
697 "optional_name": "Optionaler Empfängername",
698 "clearnet_link": "Clearnet-Link",
699 "onion_link": "Zwiebel-Link",
700 + "settings": "Einstellungen",
701 "sell_monero_com_alert_content": "Der Verkauf von Monero wird noch nicht unterstützt"
702 }
res/values/strings_en.arb
+1
@@ -697,5 +697,6 @@
697 "onion_link": "Onion link",
698 "decimal_places_error": "Too many decimal places",
699 "edit_node": "Edit Node",
700 + "settings": "Settings",
701 "sell_monero_com_alert_content": "Selling Monero is not supported yet"
702 }
res/values/strings_es.arb
+1
@@ -697,5 +697,6 @@
697 "optional_name": "Nombre del destinatario opcional",
698 "clearnet_link": "enlace Clearnet",
699 "onion_link": "Enlace de cebolla",
700 + "settings": "Configuraciones",
701 "sell_monero_com_alert_content": "Aún no se admite la venta de Monero"
702 }
res/values/strings_fr.arb
+1
@@ -696,6 +696,7 @@
696 "optional_description": "Descriptif facultatif",
697 "optional_name": "Nom du destinataire facultatif",
698 "clearnet_link": "Lien Clearnet",
699 + "settings": "Paramètres",
700 "onion_link": "Lien .onion",
701 "sell_monero_com_alert_content": "La vente de Monero n'est pas encore prise en charge"
702 }
res/values/strings_hi.arb
+1
@@ -697,5 +697,6 @@
697 "optional_name": "वैकल्पिक प्राप्तकर्ता नाम",
698 "clearnet_link": "क्लियरनेट लिंक",
699 "onion_link": "प्याज का लिंक",
700 + "settings": "समायोजन",
701 "sell_monero_com_alert_content": "मोनेरो बेचना अभी तक समर्थित नहीं है"
702 }
res/values/strings_hr.arb
+1
@@ -697,5 +697,6 @@
697 "optional_name": "Izborno ime primatelja",
698 "clearnet_link": "Clearnet veza",
699 "onion_link": "Poveznica luka",
700 + "settings": "Postavke",
701 "sell_monero_com_alert_content": "Prodaja Monera još nije podržana"
702 }
res/values/strings_it.arb
+1
@@ -697,5 +697,6 @@
697 "optional_name": "Nome del destinatario facoltativo",
698 "clearnet_link": "Collegamento Clearnet",
699 "onion_link": "Collegamento a cipolla",
700 + "settings": "Impostazioni",
701 "sell_monero_com_alert_content": "La vendita di Monero non è ancora supportata"
702 }
res/values/strings_ja.arb
+1
@@ -697,5 +697,6 @@
697 "optional_name": "オプションの受信者名",
698 "clearnet_link": "クリアネット リンク",
699 "onion_link": "オニオンリンク",
700 + "settings": "設定",
701 "sell_monero_com_alert_content": "モネロの販売はまだサポートされていません"
702 }
res/values/strings_ko.arb
+1
@@ -697,5 +697,6 @@
697 "optional_name": "선택적 수신자 이름",
698 "clearnet_link": "클리어넷 링크",
699 "onion_link": "양파 링크",
700 + "settings": "설정",
701 "sell_monero_com_alert_content": "지원되지 않습니다."
702 }
res/values/strings_my.arb
+1
@@ -697,5 +697,6 @@
697 "optional_name": "ရွေးချယ်နိုင်သော လက်ခံသူအမည်",
698 "clearnet_link": "Clearnet လင့်ခ်",
699 "onion_link": "ကြက်သွန်လင့်",
700 + "settings": "ဆက်တင်များ",
701 "sell_monero_com_alert_content": "Monero ရောင်းချခြင်းကို မပံ့ပိုးရသေးပါ။"
702 }
res/values/strings_nl.arb
+1
@@ -697,5 +697,6 @@
697 "optional_name": "Optionele naam ontvanger",
698 "clearnet_link": "Clearnet-link",
699 "onion_link": "Ui koppeling",
700 + "settings": "Instellingen",
701 "sell_monero_com_alert_content": "Het verkopen van Monero wordt nog niet ondersteund"
702 }
res/values/strings_pl.arb
+1
@@ -697,5 +697,6 @@
697 "optional_name": "Opcjonalna nazwa odbiorcy",
698 "clearnet_link": "łącze Clearnet",
699 "onion_link": "Łącznik cebulowy",
700 + "settings": "Ustawienia",
701 "sell_monero_com_alert_content": "Sprzedaż Monero nie jest jeszcze obsługiwana"
702 }
res/values/strings_pt.arb
+1
@@ -696,5 +696,6 @@
696 "optional_name": "Nome do destinatário opcional",
697 "clearnet_link": "link clear net",
698 "onion_link": "ligação de cebola",
699 + "settings": "Configurações",
700 "sell_monero_com_alert_content": "A venda de Monero ainda não é suportada"
701 }
res/values/strings_ru.arb
+1
@@ -697,5 +697,6 @@
697 "optional_name": "Необязательное имя получателя",
698 "clearnet_link": "Клирнет ссылка",
699 "onion_link": "Луковая ссылка",
700 + "settings": "Настройки",
701 "sell_monero_com_alert_content": "Продажа Monero пока не поддерживается"
702 }
res/values/strings_th.arb
+1
@@ -695,5 +695,6 @@
695 "optional_name": "ชื่อผู้รับเพิ่มเติม",
696 "clearnet_link": "ลิงค์เคลียร์เน็ต",
697 "onion_link": "ลิงค์หัวหอม",
698 + "settings": "การตั้งค่า",
699 "sell_monero_com_alert_content": "ยังไม่รองรับการขาย Monero"
700 }
res/values/strings_tr.arb
+1
@@ -697,5 +697,6 @@
697 "optional_name": "İsteğe bağlı alıcı adı",
698 "clearnet_link": "Net bağlantı",
699 "onion_link": "soğan bağlantısı",
700 + "settings": "ayarlar",
701 "sell_monero_com_alert_content": "Monero satışı henüz desteklenmiyor"
702 }
res/values/strings_uk.arb
+1
@@ -696,5 +696,6 @@
696 "optional_name": "Додаткове ім'я одержувача",
697 "clearnet_link": "Посилання Clearnet",
698 "onion_link": "Посилання на цибулю",
699 + "settings": "Налаштування",
700 "sell_monero_com_alert_content": "Продаж Monero ще не підтримується"
701 }
res/values/strings_zh.arb
+1
@@ -696,5 +696,6 @@
696 "optional_name": "可选收件人姓名",
697 "clearnet_link": "明网链接",
698 "onion_link": "洋葱链接",
699 + "settings": "设置",
700 "sell_monero_com_alert_content": "尚不支持出售门罗币"
701 }
scripts/macos/app_config.sh new
+34
@@ -0,0 +1,34 @@
1 +#!/bin/bash
2 +
3 +CAKEWALLET="cakewallet"
4 +DIR=`pwd`
5 +
6 +if [ -z "$APP_MACOS_TYPE" ]; then
7 + echo "Please set APP_MACOS_TYPE"
8 + exit 1
9 +fi
10 +
11 +cd ../.. # go to root
12 +cp -rf ./macos/Runner/InfoBase.plist ./macos/Runner/Info.plist
13 +/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier ${APP_MACOS_BUNDLE_ID}" ./macos/Runner/Info.plist
14 +/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString ${APP_MACOS_VERSION}" ./macos/Runner/Info.plist
15 +/usr/libexec/PlistBuddy -c "Set :CFBundleVersion ${APP_MACOS_BUILD_NUMBER}" ./macos/Runner/Info.plist
16 +
17 +# Fill entitlements Bundle ID
18 +cp -rf ./macos/Runner/DebugProfileBase.entitlements ./macos/Runner/DebugProfile.entitlements
19 +cp -rf ./macos/Runner/ReleaseBase.entitlements ./macos/Runner/Release.entitlements
20 +sed -i '' "s/\${BUNDLE_ID}/${APP_MACOS_BUNDLE_ID}/g" ./macos/Runner/DebugProfile.entitlements
21 +sed -i '' "s/\${BUNDLE_ID}/${APP_MACOS_BUNDLE_ID}/g" ./macos/Runner/Release.entitlements
22 +CONFIG_ARGS=""
23 +
24 +case $APP_MACOS_TYPE in
25 + $CAKEWALLET)
26 + CONFIG_ARGS="--monero --bitcoin";; #--haven
27 +esac
28 +
29 +cp -rf pubspec_description.yaml pubspec.yaml
30 +flutter pub get
31 +flutter pub run tool/generate_pubspec.dart
32 +flutter pub get
33 +flutter packages pub run tool/configure.dart $CONFIG_ARGS
34 +cd $DIR
\ No newline at end of file
scripts/macos/app_env.sh new
+39
@@ -0,0 +1,39 @@
1 +#!/bin/sh
2 +
3 +APP_MACOS_NAME=""
4 +APP_MACOS_VERSION=""
5 +APP_MACOS_BUILD_VERSION=""
6 +APP_MACOS_BUNDLE_ID=""
7 +
8 +CAKEWALLET="cakewallet"
9 +
10 +TYPES=($CAKEWALLET)
11 +APP_MACOS_TYPE=$CAKEWALLET
12 +
13 +if [ -n "$1" ]; then
14 + APP_MACOS_TYPE=$1
15 +fi
16 +
17 +CAKEWALLET_NAME="Cake Wallet"
18 +CAKEWALLET_VERSION="1.0.1"
19 +CAKEWALLET_BUILD_NUMBER=11
20 +CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
21 +
22 +if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then
23 + echo "Wrong app type."
24 + exit 1
25 +fi
26 +
27 +case $APP_MACOS_TYPE in
28 + $CAKEWALLET)
29 + APP_MACOS_NAME=$CAKEWALLET_NAME
30 + APP_MACOS_VERSION=$CAKEWALLET_VERSION
31 + APP_MACOS_BUILD_NUMBER=$CAKEWALLET_BUILD_NUMBER
32 + APP_MACOS_BUNDLE_ID=$CAKEWALLET_BUNDLE_ID;;
33 +esac
34 +
35 +export APP_MACOS_TYPE
36 +export APP_MACOS_NAME
37 +export APP_MACOS_VERSION
38 +export APP_MACOS_BUILD_NUMBER
39 +export APP_MACOS_BUNDLE_ID
scripts/macos/build_all.sh new
+3
@@ -0,0 +1,3 @@
1 +#!/bin/sh
2 +
3 +./build_monero_all.sh
\ No newline at end of file
scripts/macos/build_boost_arm64.sh new
+4
@@ -0,0 +1,4 @@
1 +#!/bin/sh
2 +
3 +. ./build_boost_common.sh
4 +build_boost_arm64
\ No newline at end of file
scripts/macos/build_boost_common.sh new
+210
@@ -0,0 +1,210 @@
1 +#!/bin/sh
2 +
3 +. ./config.sh
4 +
5 +# Boost combined
6 +
7 +BOOST_CXXFLAGS_COMBINED="-arch x86_64 -arch arm64"
8 +BOOST_CFLAGS_COMBINED="-arch x86_64 -arch arm64"
9 +BOOST_LINKFLAGS_COMBINED="-arch x86_64 -arch arm64"
10 +
11 +# Boost arm64
12 +
13 +BOOST_CXXFLAGS_ARM64="-arch arm64"
14 +BOOST_CFLAGS_ARM64="-arch arm64"
15 +BOOST_LINKFLAGS_ARM64="-arch arm64"
16 +
17 +# Boost x86_64
18 +
19 +BOOST_CXXFLAGS_X86_64="-arch x86_64"
20 +BOOST_CFLAGS_X86_64="-arch x86_64"
21 +BOOST_LINKFLAGS_X86_64="-arch x86_64"
22 +
23 +# Boost B2 arm64
24 +
25 +BOOST_B2_CXXFLAGS_ARM_64="-arch arm64"
26 +BOOST_B2_CFLAGS_ARM_64="-arch arm64"
27 +BOOST_B2_LINKFLAGS_ARM_64="-arch arm64"
28 +BOOST_B2_BUILD_DIR_ARM_64=macos-arm64
29 +
30 +# Boost B2 x86_64
31 +
32 +BOOST_B2_CXXFLAGS_X86_64="-arch x86_64"
33 +BOOST_B2_CFLAGS_X86_64="-arch x86_64"
34 +BOOST_B2_LINKFLAGS_X86_64="-arch x86_64"
35 +BOOST_B2_BUILD_DIR_X86_64=macos-x86_64
36 +
37 +build_boost_init_common() {
38 + CXXFLAGS=$1
39 + CFLAGS=$2
40 + LINKFLAGS=$3
41 + BOOST_SRC_DIR=${EXTERNAL_MACOS_SOURCE_DIR}/boost_1_72_0
42 + BOOST_FILENAME=boost_1_72_0.tar.bz2
43 + BOOST_VERSION=1.72.0
44 + BOOST_FILE_PATH=${EXTERNAL_MACOS_SOURCE_DIR}/${BOOST_FILENAME}
45 + BOOST_SHA256="59c9b274bc451cf91a9ba1dd2c7fdcaf5d60b1b3aa83f2c9fa143417cc660722"
46 +
47 + if [ ! -e "$BOOST_FILE_PATH" ]; then
48 + curl -L http://downloads.sourceforge.net/project/boost/boost/${BOOST_VERSION}/${BOOST_FILENAME} > $BOOST_FILE_PATH
49 + fi
50 +
51 + echo $BOOST_SHA256 *$BOOST_FILE_PATH | shasum -a 256 -c - || exit 1
52 +
53 + cd $EXTERNAL_MACOS_SOURCE_DIR
54 + rm -rf $BOOST_SRC_DIR
55 + tar -xvf $BOOST_FILE_PATH -C $EXTERNAL_MACOS_SOURCE_DIR
56 + cd $BOOST_SRC_DIR
57 + ./bootstrap.sh --with-toolset=clang-darwin cxxflags="${CXXFLAGS}" cflags="${CFLAGS}" linkflags="${LINKFLAGS}"
58 +}
59 +
60 +build_boost_init_arm64() {
61 + CXXFLAGS="-arch arm64"
62 + CFLAGS="-arch arm64"
63 + LINKFLAGS="-arch arm64"
64 + build_boost_init_common "${CXXFLAGS}" "${CFLAGS}" "${LINKFLAGS}"
65 +}
66 +
67 +build_boost_init_x86_64() {
68 + CXXFLAGS="-arch x86_64"
69 + CFLAGS="-arch x86_64"
70 + LINKFLAGS="-arch x86_64"
71 + build_boost_init_common "${CXXFLAGS}" "${CFLAGS}" "${LINKFLAGS}"
72 +}
73 +
74 +build_boost_init_universal() {
75 + CXXFLAGS="-arch x86_64 -arch arm64"
76 + CFLAGS="-arch x86_64 -arch arm64"
77 + LINKFLAGS="-arch x86_64 -arch arm64"
78 + build_boost_init_common "${CXXFLAGS}" "${CFLAGS}" "${LINKFLAGS}"
79 +}
80 +
81 +build_boost_compile_common() {
82 + ARCH=$1
83 + ABI=$2
84 + CXXFLAGS=$3
85 + CFLAGS=$4
86 + LINKFLAGS=$5
87 + FLAGS=$6
88 + BUILD_DIR=$7
89 + ./b2 toolset=clang-darwin target-os=darwin architecture="${ARCH}" cxxflags="${CXXFLAGS}" cflags="${CFLAGS}" linkflags="${LINKFLAGS}" abi="${ABI}" "${FLAGS}" -a \
90 + --with-chrono \
91 + --with-date_time \
92 + --with-filesystem \
93 + --with-program_options \
94 + --with-regex \
95 + --with-serialization \
96 + --with-system \
97 + --with-thread \
98 + --with-locale \
99 + --build-dir=$BUILD_DIR \
100 + --stagedir=${BUILD_DIR}/stage \
101 + link=static
102 +}
103 +
104 +build_boost_compile_arm64() {
105 + ARCH="arm"
106 + ABI="aapcs"
107 + CXXFLAGS="-arch arm64"
108 + CFLAGS="-arch arm64"
109 + LINKFLAGS="-arch arm64"
110 + FLAGS=""
111 + BUILD_DIR="macos-arm64"
112 + build_boost_compile_common "${ARCH}" "${ABI}" "${CXXFLAGS}" "${CFLAGS}" "${LINKFLAGS}" "${FLAGS}" "${BUILD_DIR}"
113 +}
114 +
115 +build_boost_compile_x86_64() {
116 + ARCH="x86"
117 + ABI="sysv"
118 + CXXFLAGS="-arch x86_64"
119 + CFLAGS="-arch x86_64"
120 + LINKFLAGS="-arch x86_64"
121 + FLAGS="binary-format=mach-o"
122 + BUILD_DIR="macos-x86_64"
123 + build_boost_compile_common "${ARCH}" "${ABI}" "${CXXFLAGS}" "${CFLAGS}" "${LINKFLAGS}" "${FLAGS}" "${BUILD_DIR}"
124 +}
125 +
126 +build_boost_compile_universal() {
127 + ARCHES=(arm x86)
128 + for ARCH in ${ARCHES[@]}; do
129 + ABI=""
130 + CXXFLAGS=""
131 + CFLAGS=""
132 + LINKFLAGS=""
133 + FLAGS=""
134 + BUILD_DIR=""
135 +
136 + case $ARCH in
137 + arm)
138 + ABI="aapcs"
139 + CXXFLAGS="-arch arm64"
140 + CFLAGS="-arch arm64"
141 + LINKFLAGS="-arch arm64"
142 + FLAGS=""
143 + BUILD_DIR="macos-arm64";;
144 + x86)
145 + ABI="sysv"
146 + CXXFLAGS="-arch x86_64"
147 + CFLAGS="-arch x86_64"
148 + LINKFLAGS="-arch x86_64"
149 + FLAGS="binary-format=mach-o"
150 + BUILD_DIR="macos-x86_64"
151 + esac
152 +
153 + build_boost_compile_common "${ARCH}" "${ABI}" "${CXXFLAGS}" "${CFLAGS}" "${LINKFLAGS}" "${FLAGS}" "${BUILD_DIR}"
154 + done
155 +}
156 +
157 +build_boost_install_common() {
158 + ARCH=$1
159 + LIB_DIR=""
160 + mkdir $EXTERNAL_MACOS_LIB_DIR
161 + mkdir $EXTERNAL_MACOS_INCLUDE_DIR
162 +
163 + case $ARCH in
164 + arm64) LIB_DIR="${BOOST_B2_BUILD_DIR_ARM_64}/stage/lib";;
165 + x86_64) LIB_DIR="${BOOST_B2_BUILD_DIR_X86_64}/stage/lib";;
166 + *) LIB_DIR="lib";;
167 + esac
168 +
169 + cp -r ${LIB_DIR}/*.a ${EXTERNAL_MACOS_LIB_DIR}
170 + cp -r boost ${EXTERNAL_MACOS_INCLUDE_DIR}
171 +}
172 +
173 +build_boost_install_arm64() {
174 + ARCH="arm64"
175 + build_boost_install_common $ARCH
176 +}
177 +
178 +build_boost_install_x86_64() {
179 + ARCH="x86_64"
180 + build_boost_install_common $ARCH
181 +}
182 +
183 +build_boost_install_universal() {
184 + mkdir lib
185 +
186 + for blib in ${BOOST_B2_BUILD_DIR_ARM_64}/stage/lib/*.a; do
187 + lipo -create -arch arm64 $blib -arch x86_64 ${BOOST_B2_BUILD_DIR_X86_64}/stage/lib/$(basename $blib) -output lib/$(basename $blib);
188 + done
189 +
190 + cp -r lib/* ${EXTERNAL_MACOS_LIB_DIR}
191 + cp -r boost ${EXTERNAL_MACOS_INCLUDE_DIR}
192 +}
193 +
194 +build_boost_arm64() {
195 + build_boost_init_arm64
196 + build_boost_compile_arm64
197 + build_boost_install_arm64
198 +}
199 +
200 +build_boost_x86_64() {
201 + build_boost_init_x86_64
202 + build_boost_compile_x86_64
203 + build_boost_install_x86_64
204 +}
205 +
206 +build_boost_universal() {
207 + build_boost_init_universal
208 + build_boost_compile_universal
209 + build_boost_install_universal
210 +}
\ No newline at end of file
scripts/macos/build_boost_universal.sh new
+4
@@ -0,0 +1,4 @@
1 +#!/bin/sh
2 +
3 +. ./build_boost_common.sh
4 +build_boost_universal
\ No newline at end of file
scripts/macos/build_boost_x86_64.sh new
+4
@@ -0,0 +1,4 @@
1 +#!/bin/sh
2 +
3 +. ./build_boost_common.sh
4 +build_boost_x86_64
\ No newline at end of file
scripts/macos/build_expat.sh new
+17
@@ -0,0 +1,17 @@
1 +#!/bin/bash
2 +
3 +. ./config.sh
4 +
5 +EXPAT_VERSION=R_2_4_8
6 +EXPAT_HASH="3bab6c09bbe8bf42d84b81563ddbcf4cca4be838"
7 +EXPAT_SRC_DIR=${EXTERNAL_MACOS_SOURCE_DIR}/libexpat
8 +
9 +git clone https://github.com/libexpat/libexpat.git -b ${EXPAT_VERSION} ${EXPAT_SRC_DIR}
10 +cd $EXPAT_SRC_DIR
11 +test `git rev-parse HEAD` = ${EXPAT_HASH} || exit 1
12 +cd $EXPAT_SRC_DIR/expat
13 +
14 +./buildconf.sh
15 +./configure --enable-static --disable-shared --prefix=${EXTERNAL_MACOS_DIR}
16 +make
17 +make install
\ No newline at end of file
scripts/macos/build_haven.sh new
+50
@@ -0,0 +1,50 @@
1 +#!/bin/sh
2 +
3 +. ./config.sh
4 +
5 +HAVEN_URL="https://github.com/haven-protocol-org/haven-main.git"
6 +HAVEN_DIR_PATH="${EXTERNAL_MACOS_SOURCE_DIR}/haven"
7 +HAVEN_VERSION=tags/v3.0.0
8 +BUILD_TYPE=release
9 +PREFIX=${EXTERNAL_MACOS_DIR}
10 +DEST_LIB_DIR=${EXTERNAL_MACOS_LIB_DIR}/haven
11 +DEST_INCLUDE_DIR=${EXTERNAL_MACOS_INCLUDE_DIR}/haven
12 +ARCH=`uname -m`
13 +
14 +echo "Cloning haven from - $HAVEN_URL to - $HAVEN_DIR_PATH"
15 +git clone $HAVEN_URL $HAVEN_DIR_PATH
16 +cd $HAVEN_DIR_PATH
17 +git checkout $HAVEN_VERSION
18 +git submodule update --init --force
19 +mkdir -p build
20 +cd ..
21 +
22 +ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
23 +if [ -z $INSTALL_PREFIX ]; then
24 + INSTALL_PREFIX=${ROOT_DIR}/haven
25 +fi
26 +
27 +mkdir -p $DEST_LIB_DIR
28 +mkdir -p $DEST_INCLUDE_DIR
29 +
30 +echo "Building MACOS ${ARCH}"
31 +export CMAKE_INCLUDE_PATH="${PREFIX}/include"
32 +export CMAKE_LIBRARY_PATH="${PREFIX}/lib"
33 +rm -rf haven/build > /dev/null
34 +
35 +mkdir -p haven/build/${BUILD_TYPE}
36 +pushd haven/build/${BUILD_TYPE}
37 +cmake -DARCH=${ARCH} \
38 + -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
39 + -DSTATIC=ON \
40 + -DBUILD_GUI_DEPS=ON \
41 + -DINSTALL_VENDORED_LIBUNBOUND=ON \
42 + -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} \
43 + -DUSE_DEVICE_TREZOR=OFF \
44 + ../..
45 +make -j4 && make install
46 +find . -path ./lib -prune -o -name '*.a' -exec cp '{}' lib \;
47 +cp -r ./lib/* $DEST_LIB_DIR
48 +cp ../../src/wallet/api/wallet2_api.h $DEST_INCLUDE_DIR
49 +popd
50 +
scripts/macos/build_monero.sh new
+54
@@ -0,0 +1,54 @@
1 +#!/bin/sh
2 +
3 +. ./config.sh
4 +
5 +MONERO_URL="https://github.com/cake-tech/monero.git"
6 +MONERO_DIR_PATH="${EXTERNAL_MACOS_SOURCE_DIR}/monero"
7 +MONERO_VERSION=release-v0.18.0.0
8 +BUILD_TYPE=release
9 +PREFIX=${EXTERNAL_MACOS_DIR}
10 +DEST_LIB_DIR=${EXTERNAL_MACOS_LIB_DIR}/monero
11 +DEST_INCLUDE_DIR=${EXTERNAL_MACOS_INCLUDE_DIR}/monero
12 +ARCH=`uname -m`
13 +
14 +echo "Cloning monero from - $MONERO_URL to - $MONERO_DIR_PATH"
15 +git clone $MONERO_URL $MONERO_DIR_PATH
16 +cd $MONERO_DIR_PATH
17 +git checkout $MONERO_VERSION
18 +git submodule update --init --force
19 +mkdir -p build
20 +cd ..
21 +
22 +mkdir -p $DEST_LIB_DIR
23 +mkdir -p $DEST_INCLUDE_DIR
24 +
25 +ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
26 +if [ -z $INSTALL_PREFIX ]; then
27 + INSTALL_PREFIX=${ROOT_DIR}/monero
28 +fi
29 +
30 +echo "Building MACOS ${ARCH}"
31 +export CMAKE_INCLUDE_PATH="${PREFIX}/include"
32 +export CMAKE_LIBRARY_PATH="${PREFIX}/lib"
33 +rm -r monero/build > /dev/null
34 +
35 +if [ "${ARCH}" == "x86_64" ]; then
36 + ARCH="x86-64"
37 +fi
38 +
39 +mkdir -p monero/build/${BUILD_TYPE}
40 +pushd monero/build/${BUILD_TYPE}
41 +cmake -DARCH=${ARCH} \
42 + -DBUILD_64=ON \
43 + -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
44 + -DSTATIC=ON \
45 + -DBUILD_GUI_DEPS=ON \
46 + -DUNBOUND_INCLUDE_DIR=${EXTERNAL_MACOS_INCLUDE_DIR} \
47 + -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} \
48 + -DUSE_DEVICE_TREZOR=OFF \
49 + ../..
50 +make wallet_api -j4
51 +find . -path ./lib -prune -o -name '*.a' -exec cp '{}' lib \;
52 +cp -r ./lib/* $DEST_LIB_DIR
53 +cp ../../src/wallet/api/wallet2_api.h $DEST_INCLUDE_DIR
54 +popd
scripts/macos/build_monero_all.sh new
+20
@@ -0,0 +1,20 @@
1 +#!/bin/sh
2 +
3 +ARCH=`uname -m`
4 +
5 +. ./config.sh
6 +
7 +case $ARCH in
8 + arm64)
9 + ./build_openssl_arm64.sh
10 + ./build_boost_arm64.sh;;
11 + x86_64)
12 + ./build_openssl_x86_64.sh
13 + ./build_boost_x86_64.sh;;
14 +esac
15 +
16 +./build_zmq.sh
17 +./build_expat.sh
18 +./build_unbound.sh
19 +./build_sodium.sh
20 +./build_monero.sh
\ No newline at end of file
scripts/macos/build_openssl_arm64.sh new
+4
@@ -0,0 +1,4 @@
1 +#!/bin/sh
2 +
3 +. ./build_openssl_common.sh
4 +build_openssl_arm64
\ No newline at end of file
scripts/macos/build_openssl_common.sh new
+116
@@ -0,0 +1,116 @@
1 +#!/bin/sh
2 +
3 +. ./config.sh
4 +
5 +OPEN_SSL_DIR_NAME="OpenSSL"
6 +OPEN_SSL_x86_64_DIR_NAME="${OPEN_SSL_DIR_NAME}-x86_64"
7 +OPEN_SSL_ARM_DIR_NAME="${OPEN_SSL_DIR_NAME}-arm"
8 +OPEN_SSL_X86_64_DIR_PATH="${EXTERNAL_MACOS_SOURCE_DIR}/${OPEN_SSL_x86_64_DIR_NAME}"
9 +OPEN_SSL_ARM_DIR_PATH="${EXTERNAL_MACOS_SOURCE_DIR}/${OPEN_SSL_ARM_DIR_NAME}"
10 +
11 +build_openssl_init_common() {
12 + DIR=$1
13 + # Use 1.1.1s becasue of https://github.com/openssl/openssl/issues/18720
14 + OPENSSL_VERSION="1.1.1s"
15 +
16 + echo "============================ OpenSSL ============================"
17 +
18 + cd $EXTERNAL_MACOS_SOURCE_DIR
19 + curl -O https://www.openssl.org/source/openssl-$OPENSSL_VERSION.tar.gz
20 + tar -xvzf openssl-$OPENSSL_VERSION.tar.gz
21 + rm -rf $DIR
22 + rm -rf $OPEN_SSL_DIR_PATH
23 + mv openssl-$OPENSSL_VERSION $DIR
24 + tar -xvzf openssl-$OPENSSL_VERSION.tar.gz
25 + mv openssl-$OPENSSL_VERSION $OPEN_SSL_ARM_DIR_NAME
26 +}
27 +
28 +build_openssl_init_arm64() {
29 + DIR=$OPEN_SSL_ARM_DIR_PATH
30 + build_openssl_init_common ${DIR}
31 +}
32 +
33 +build_openssl_init_x86_64() {
34 + DIR=$OPEN_SSL_X86_64_DIR_PATH
35 + build_openssl_init_common ${DIR}
36 +}
37 +
38 +build_openssl_compile_common() {
39 + ARCH=$1
40 + DIR=""
41 + XARCH=""
42 + case $ARCH in
43 + arm64)
44 + DIR=$OPEN_SSL_ARM_DIR_PATH
45 + XARCH="darwin64-arm64-cc";;
46 + x86_64)
47 + DIR=$OPEN_SSL_X86_64_DIR_PATH
48 + XARCH="darwin64-x86_64-cc";;
49 + esac
50 +
51 + echo "Build OpenSSL for ${ARCH}"
52 + cd $DIR
53 + ./Configure $XARCH
54 + make
55 +
56 +}
57 +
58 +build_openssl_compile_arm64() {
59 + ARCH=arm64
60 + build_openssl_compile_common "${ARCH}"
61 +}
62 +
63 +build_openssl_compile_x86_64() {
64 + ARCH=x86_64
65 + build_openssl_compile_common "${ARCH}"
66 +}
67 +
68 +build_openssl_install_common() {
69 + DIR=$1
70 + mv ${DIR}/include/* $EXTERNAL_MACOS_INCLUDE_DIR
71 + mv ${DIR}/libcrypto.a ${EXTERNAL_MACOS_LIB_DIR}/libcrypto.a
72 + mv ${DIR}/libssl.a ${EXTERNAL_MACOS_LIB_DIR}/libssl.a
73 +}
74 +
75 +build_openssl_install_arm64() {
76 + build_openssl_install_common "${OPEN_SSL_ARM_DIR_PATH}"
77 +}
78 +
79 +build_openssl_install_x86_64() {
80 + build_openssl_install_common "${OPEN_SSL_X86_64_DIR_PATH}"
81 +}
82 +
83 +build_openssl_install_universal() {
84 + OPEN_SSL_DIR_PATH="${EXTERNAL_MACOS_SOURCE_DIR}/${OPEN_SSL_DIR_NAME}"
85 + mv ${OPEN_SSL_ARM_DIR_PATH}/include/* $OPEN_SSL_DIR_PATH/include
86 + build_openssl_install_common "${OPEN_SSL_DIR_PATH}"
87 +}
88 +
89 +build_openssl_arm64() {
90 + build_openssl_init_arm64
91 + build_openssl_compile_arm64
92 + build_openssl_install_arm64
93 +}
94 +
95 +build_openssl_x86_64() {
96 + build_openssl_init_x86_64
97 + build_openssl_compile_x86_64
98 + build_openssl_install_x86_64
99 +}
100 +
101 +build_openssl_combine() {
102 + OPEN_SSL_DIR_PATH="${EXTERNAL_MACOS_SOURCE_DIR}/${OPEN_SSL_DIR_NAME}"
103 + echo "Create universal bin"
104 + mkdir -p $OPEN_SSL_DIR_PATH/include
105 + lipo -create ${OPEN_SSL_ARM_DIR_PATH}/libcrypto.a ${OPEN_SSL_X86_64_DIR_PATH}/libcrypto.a -output ${OPEN_SSL_DIR_PATH}/libcrypto.a
106 + lipo -create ${OPEN_SSL_ARM_DIR_PATH}/libssl.a ${OPEN_SSL_X86_64_DIR_PATH}/libssl.a -output ${OPEN_SSL_DIR_PATH}/libssl.a
107 +}
108 +
109 +build_openssl_universal() {
110 + build_openssl_init_arm64
111 + build_openssl_compile_arm64
112 + build_openssl_init_x86_64
113 + build_openssl_compile_x86_64
114 + build_openssl_combine
115 + build_openssl_install_universal
116 +}
\ No newline at end of file
scripts/macos/build_openssl_universal.sh new
+4
@@ -0,0 +1,4 @@
1 +#!/bin/sh
2 +
3 +. ./build_openssl_common.sh
4 +build_openssl_universal
\ No newline at end of file
scripts/macos/build_openssl_x86_64.sh new
+4
@@ -0,0 +1,4 @@
1 +#!/bin/sh
2 +
3 +. ./build_openssl_common.sh
4 +build_openssl_x86_64
\ No newline at end of file
scripts/macos/build_sodium.sh new
+16
@@ -0,0 +1,16 @@
1 +#!/bin/sh
2 +
3 +. ./config.sh
4 +
5 +SODIUM_PATH="${EXTERNAL_MACOS_SOURCE_DIR}/libsodium"
6 +SODIUM_URL="https://github.com/jedisct1/libsodium.git"
7 +
8 +echo "============================ SODIUM ============================"
9 +
10 +echo "Cloning SODIUM from - $SODIUM_URL"
11 +git clone $SODIUM_URL $SODIUM_PATH --branch stable
12 +cd $SODIUM_PATH
13 +./dist-build/osx.sh
14 +
15 +mv ${SODIUM_PATH}/libsodium-osx/include/* $EXTERNAL_MACOS_INCLUDE_DIR
16 +mv ${SODIUM_PATH}/libsodium-osx/lib/* $EXTERNAL_MACOS_LIB_DIR
\ No newline at end of file
scripts/macos/build_unbound.sh new
+23
@@ -0,0 +1,23 @@
1 +#!/bin/sh
2 +
3 +. ./config.sh
4 +
5 +UNBOUND_VERSION=release-1.16.2
6 +UNBOUND_HASH="cbed768b8ff9bfcf11089a5f1699b7e5707f1ea5"
7 +UNBOUND_URL="https://www.nlnetlabs.nl/downloads/unbound/unbound-${UNBOUND_VERSION}.tar.gz"
8 +UNBOUND_DIR_PATH="${EXTERNAL_MACOS_SOURCE_DIR}/unbound-1.16.2"
9 +
10 +echo "============================ Unbound ============================"
11 +rm -rf ${UNBOUND_DIR_PATH}
12 +git clone https://github.com/NLnetLabs/unbound.git -b ${UNBOUND_VERSION} ${UNBOUND_DIR_PATH}
13 +cd $UNBOUND_DIR_PATH
14 +test `git rev-parse HEAD` = ${UNBOUND_HASH} || exit 1
15 +
16 +./configure --prefix="${EXTERNAL_MACOS_DIR}" \
17 + --with-ssl="${EXTERNAL_MACOS_DIR}" \
18 + --with-libexpat="${EXTERNAL_MACOS_DIR}" \
19 + --enable-static \
20 + --disable-shared \
21 + --disable-flto
22 +make
23 +make install
\ No newline at end of file
scripts/macos/build_zmq.sh new
+17
@@ -0,0 +1,17 @@
1 +#!/bin/sh
2 +
3 +. ./config.sh
4 +
5 +ZMQ_PATH="${EXTERNAL_MACOS_SOURCE_DIR}/libzmq"
6 +ZMQ_URL="https://github.com/zeromq/libzmq.git"
7 +
8 +echo "============================ ZMQ ============================"
9 +
10 +echo "Cloning ZMQ from - $ZMQ_URL"
11 +git clone $ZMQ_URL $ZMQ_PATH
12 +cd $ZMQ_PATH
13 +mkdir cmake-build
14 +cd cmake-build
15 +cmake .. -DCMAKE_INSTALL_PREFIX="${EXTERNAL_MACOS_DIR}"
16 +make
17 +make install
\ No newline at end of file
scripts/macos/cakewallet.sh new
+4
@@ -0,0 +1,4 @@
1 +#!/bin/sh
2 +
3 +. ./app_env.sh "cakewallet"
4 +. ./app_config.sh
\ No newline at end of file
scripts/macos/config.sh new
+13
@@ -0,0 +1,13 @@
1 +#!/bin/sh
2 +
3 +export MACOS_SCRIPTS_DIR=`pwd`
4 +export CW_ROOT=${MACOS_SCRIPTS_DIR}/../..
5 +export EXTERNAL_DIR=${CW_ROOT}/cw_shared_external/ios/External
6 +export EXTERNAL_MACOS_DIR=${EXTERNAL_DIR}/macos
7 +export EXTERNAL_MACOS_SOURCE_DIR=${EXTERNAL_MACOS_DIR}/sources
8 +export EXTERNAL_MACOS_LIB_DIR=${EXTERNAL_MACOS_DIR}/lib
9 +export EXTERNAL_MACOS_INCLUDE_DIR=${EXTERNAL_MACOS_DIR}/include
10 +
11 +mkdir -p $EXTERNAL_MACOS_LIB_DIR
12 +mkdir -p $EXTERNAL_MACOS_INCLUDE_DIR
13 +mkdir -p $EXTERNAL_MACOS_SOURCE_DIR
\ No newline at end of file
scripts/macos/gen_arm64.sh new
+5
@@ -0,0 +1,5 @@
1 +#!/bin/bash
2 +
3 +. ./gen_common.sh
4 +
5 +gen "arm64"
\ No newline at end of file
scripts/macos/gen_common.sh new
+31
@@ -0,0 +1,31 @@
1 +#!/bin/sh
2 +
3 +gen_podspec() {
4 + ARCH=$1
5 + CW_PLUGIN_DIR="`pwd`/../../cw_monero/macos"
6 + BASE_FILENAME="cw_monero_base.podspec"
7 + BASE_FILE_PATH="${CW_PLUGIN_DIR}/${BASE_FILENAME}"
8 + DEFAULT_FILENAME="cw_monero.podspec"
9 + DEFAULT_FILE_PATH="${CW_PLUGIN_DIR}/${DEFAULT_FILENAME}"
10 + rm -f $DEFAULT_FILE_PATH
11 + cp $BASE_FILE_PATH $DEFAULT_FILE_PATH
12 + sed -i '' "s/#___VALID_ARCHS___#/${ARCH}/g" $DEFAULT_FILE_PATH
13 +}
14 +
15 +gen_project() {
16 + ARCH=$1
17 + CW_DIR="`pwd`/../../macos/Runner.xcodeproj"
18 + BASE_FILENAME="project_base.pbxproj"
19 + BASE_FILE_PATH="${CW_DIR}/${BASE_FILENAME}"
20 + DEFAULT_FILENAME="project.pbxproj"
21 + DEFAULT_FILE_PATH="${CW_DIR}/${DEFAULT_FILENAME}"
22 + rm -f $DEFAULT_FILE_PATH
23 + cp $BASE_FILE_PATH $DEFAULT_FILE_PATH
24 + sed -i '' "s/ARCHS =.*/ARCHS = ${ARCH};/g" $DEFAULT_FILE_PATH
25 +}
26 +
27 +gen() {
28 + ARCH=$1
29 + gen_podspec "${ARCH}"
30 + gen_project "${ARCH}"
31 +}
\ No newline at end of file
scripts/macos/gen_universal.sh new
+5
@@ -0,0 +1,5 @@
1 +#!/bin/bash
2 +
3 +. ./gen_common.sh
4 +
5 +gen "arm64, x86_64"
\ No newline at end of file
scripts/macos/gen_x86_64.sh new
+5
@@ -0,0 +1,5 @@
1 +#!/bin/bash
2 +
3 +. ./gen_common.sh
4 +
5 +gen "x86_64"
\ No newline at end of file
scripts/macos/setup.sh new
+40
@@ -0,0 +1,40 @@
1 +#!/bin/sh
2 +
3 +. ./config.sh
4 +
5 +cd $EXTERNAL_MACOS_LIB_DIR
6 +
7 +
8 +# LIBRANDOMX_PATH=${EXTERNAL_MACOS_LIB_DIR}/monero/librandomx.a
9 +
10 +# if [ -f "$LIBRANDOMX_PATH" ]; then
11 +# cp $LIBRANDOMX_PATH ./haven
12 +# fi
13 +
14 +libtool -static -o libboost.a ./libboost_*.a
15 +libtool -static -o libmonero.a ./monero/*.a
16 +
17 +# CW_HAVEN_EXTERNAL_LIB=../../../../../cw_haven/macos/External/macos/lib
18 +# CW_HAVEN_EXTERNAL_INCLUDE=../../../../../cw_haven/macos/External/macos/include
19 +CW_MONERO_EXTERNAL_LIB=../../../../../cw_monero/macos/External/macos/lib
20 +CW_MONERO_EXTERNAL_INCLUDE=../../../../../cw_monero/macos/External/macos/include
21 +
22 +# mkdir -p $CW_HAVEN_EXTERNAL_INCLUDE
23 +mkdir -p $CW_MONERO_EXTERNAL_INCLUDE
24 +# mkdir -p $CW_HAVEN_EXTERNAL_LIB
25 +mkdir -p $CW_MONERO_EXTERNAL_LIB
26 +
27 +# ln ./libboost.a ${CW_HAVEN_EXTERNAL_LIB}/libboost.a
28 +# ln ./libcrypto.a ${CW_HAVEN_EXTERNAL_LIB}/libcrypto.a
29 +# ln ./libssl.a ${CW_HAVEN_EXTERNAL_LIB}/libssl.a
30 +# ln ./libsodium.a ${CW_HAVEN_EXTERNAL_LIB}/libsodium.a
31 +# cp ./libhaven.a $CW_HAVEN_EXTERNAL_LIB
32 +# cp ../include/haven/* $CW_HAVEN_EXTERNAL_INCLUDE
33 +
34 +ln ./libboost.a ${CW_MONERO_EXTERNAL_LIB}/libboost.a
35 +ln ./libcrypto.a ${CW_MONERO_EXTERNAL_LIB}/libcrypto.a
36 +ln ./libssl.a ${CW_MONERO_EXTERNAL_LIB}/libssl.a
37 +ln ./libsodium.a ${CW_MONERO_EXTERNAL_LIB}/libsodium.a
38 +ln ./libunbound.a ${CW_MONERO_EXTERNAL_LIB}/libunbound.a
39 +cp ./libmonero.a $CW_MONERO_EXTERNAL_LIB
40 +cp ../include/monero/* $CW_MONERO_EXTERNAL_INCLUDE
\ No newline at end of file
tool/utils/secret_key.dart
+2
@@ -13,6 +13,7 @@ class SecretKey {
13 SecretKey('backupSalt', () => hex.encode(encrypt.Key.fromSecureRandom(8).bytes)),
14 SecretKey('backupKeychainSalt', () => hex.encode(encrypt.Key.fromSecureRandom(12).bytes)),
15 SecretKey('changeNowApiKey', () => ''),
16 + SecretKey('changeNowApiKeyDesktop', () => ''),
17 SecretKey('wyreSecretKey', () => ''),
18 SecretKey('wyreApiKey', () => ''),
19 SecretKey('wyreAccountId', () => ''),
@@ -21,6 +22,7 @@ class SecretKey {
22 SecretKey('sideShiftAffiliateId', () => ''),
23 SecretKey('sideShiftApiKey', () => ''),
24 SecretKey('simpleSwapApiKey', () => ''),
25 + SecretKey('simpleSwapApiKeyDesktop', () => ''),
26 SecretKey('anypayToken', () => ''),
27 SecretKey('onramperApiKey', () => ''),
28 SecretKey('ioniaClientId', () => ''),