Desktop builds
This commit is contained in:
parent
41c0913dd3
commit
fa80d57b1e
47
BUILD.md
47
BUILD.md
|
@ -80,3 +80,50 @@ This will create a `root` directory will all the various apks (arm32, arm64, i32
|
|||
- Add arm64 to Excluded Architecture / Any IOS Simulator SDK
|
||||
- Build warp with x86_64-apple-ios target
|
||||
- debugShowCheckedModeBanner: false in MaterialApp()
|
||||
|
||||
## Desktop builds
|
||||
|
||||
Desktop builds must be made on their native platform, i.e. MacOX
|
||||
needs a Mac, etc.
|
||||
|
||||
First checkout how to use flutter desktop as there are requirements
|
||||
for each platform.
|
||||
|
||||
The repository does not include the project generated files.
|
||||
Run `flutter create --platform=windows,linux,macos .` to generate them.
|
||||
|
||||
First compile the rust code. In `native/warp_api_ffi`, edit `Cargo.toml`
|
||||
to change the library crate type to `cdylib`. Then `cargo build --release`.
|
||||
This should produce a dynamic library under `target/release` in the project root
|
||||
directory.
|
||||
|
||||
Depending on the platform, the output library has a different name and
|
||||
a different way to include in the build.
|
||||
|
||||
Build the flutter project: `flutter build windows` (macos or linux).
|
||||
The result is in `build/windows/runner/Release`.
|
||||
|
||||
### Linux
|
||||
Copy `libwarp_api_ffi.so` into the `lib/` directory. Then tar/gzip and that's it.
|
||||
|
||||
### Windows
|
||||
Copy `warp_api_ffi.dll` into the Release directory and also add:
|
||||
- `sqlite3.dll`
|
||||
- `msvcp140.dll`
|
||||
- `vcruntime140.dll`
|
||||
- `vcruntime140_1.dll`
|
||||
Then zip.
|
||||
|
||||
### MacOS
|
||||
On M1 macs, run rustup default stable-x86_64-apple-darwin
|
||||
MacOS is the trickiest one. Open the xcode workspace.
|
||||
Add in Signing & Capabilities: Network server & Client and R/W file access
|
||||
to user selected files
|
||||
Go to the Runner project, Build Stages
|
||||
Drag `libwarp_api_ffi.so` into Runner/Frameworks
|
||||
Remove it from the link stage (we don't want to statically link)
|
||||
Add to Bundle Framework, Code Sign
|
||||
Then exit xcode and run `flutter build macos`
|
||||
If you want to create a DMG, use the npm package appdmg
|
||||
|
||||
|
||||
|
|
|
@ -12,10 +12,14 @@ Future<void> showAbout(BuildContext context) async {
|
|||
final contentTemplate = await rootBundle.loadString('assets/about.md');
|
||||
final template = Template(contentTemplate);
|
||||
var content = template.renderString({'APP': APP_NAME});
|
||||
PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
||||
String version = packageInfo.version;
|
||||
String code = packageInfo.buildNumber;
|
||||
content += "`${S.of(context).version}: $version+$code`";
|
||||
if (isMobile()) {
|
||||
PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
||||
String version = packageInfo.version;
|
||||
String code = packageInfo.buildNumber;
|
||||
content += "`${S
|
||||
.of(context)
|
||||
.version}: $version+$code`";
|
||||
}
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
|
|
|
@ -205,7 +205,7 @@ class HomeState extends State<HomePageInner> with TickerProviderStateMixin {
|
|||
}
|
||||
|
||||
_backup() async {
|
||||
final didAuthenticate = await authenticate(context, S.of(context).pleaseAuthenticateToShowAccountSeed);
|
||||
final didAuthenticate = !isMobile() || await authenticate(context, S.of(context).pleaseAuthenticateToShowAccountSeed);
|
||||
if (didAuthenticate) {
|
||||
Navigator.of(context).pushNamed('/backup');
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'dart:ui';
|
|||
import 'package:csv/csv.dart';
|
||||
import 'package:currency_text_input_formatter/currency_text_input_formatter.dart';
|
||||
import 'package:decimal/decimal.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_barcode_scanner/flutter_barcode_scanner.dart';
|
||||
|
@ -17,6 +18,8 @@ import 'package:qr_flutter/qr_flutter.dart';
|
|||
import 'package:rate_my_app/rate_my_app.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
import 'package:sqflite_common/sqlite_api.dart';
|
||||
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
|
||||
import 'package:warp_api/warp_api.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
|
@ -213,12 +216,18 @@ class ZWalletAppState extends State<ZWalletApp> {
|
|||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance?.addPostFrameCallback((_) async {
|
||||
await rateMyApp.init();
|
||||
if (mounted && rateMyApp.shouldOpenDialog) {
|
||||
rateMyApp.showRateDialog(this.context);
|
||||
}
|
||||
});
|
||||
if (isMobile()) {
|
||||
WidgetsBinding.instance?.addPostFrameCallback((_) async {
|
||||
await rateMyApp.init();
|
||||
if (mounted && rateMyApp.shouldOpenDialog) {
|
||||
rateMyApp.showRateDialog(this.context);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
sqfliteFfiInit();
|
||||
databaseFactory = databaseFactoryFfi;
|
||||
}
|
||||
init = _init();
|
||||
}
|
||||
|
||||
|
@ -241,28 +250,30 @@ class ZWalletAppState extends State<ZWalletApp> {
|
|||
}
|
||||
}
|
||||
|
||||
await initUniLinks(this.context);
|
||||
final quickActions = QuickActions();
|
||||
quickActions.initialize((type) {
|
||||
handleQuickAction(this.context, type);
|
||||
});
|
||||
if (!settings.linkHooksInitialized) {
|
||||
Future.microtask(() {
|
||||
final s = S.of(this.context);
|
||||
List<ShortcutItem> shortcuts = [];
|
||||
for (var c in settings.coins) {
|
||||
final coin = c.coin;
|
||||
final ticker = c.def.ticker;
|
||||
shortcuts.add(ShortcutItem(type: '$coin.receive',
|
||||
localizedTitle: s.receive(ticker),
|
||||
icon: 'receive'));
|
||||
shortcuts.add(ShortcutItem(type: '$coin.send',
|
||||
localizedTitle: s.sendCointicker(ticker),
|
||||
icon: 'send'));
|
||||
}
|
||||
quickActions.setShortcutItems(shortcuts);
|
||||
if (isMobile()) {
|
||||
await initUniLinks(this.context);
|
||||
final quickActions = QuickActions();
|
||||
quickActions.initialize((type) {
|
||||
handleQuickAction(this.context, type);
|
||||
});
|
||||
await settings.setLinkHooksInitialized();
|
||||
if (!settings.linkHooksInitialized) {
|
||||
Future.microtask(() {
|
||||
final s = S.of(this.context);
|
||||
List<ShortcutItem> shortcuts = [];
|
||||
for (var c in settings.coins) {
|
||||
final coin = c.coin;
|
||||
final ticker = c.def.ticker;
|
||||
shortcuts.add(ShortcutItem(type: '$coin.receive',
|
||||
localizedTitle: s.receive(ticker),
|
||||
icon: 'receive'));
|
||||
shortcuts.add(ShortcutItem(type: '$coin.send',
|
||||
localizedTitle: s.sendCointicker(ticker),
|
||||
icon: 'send'));
|
||||
}
|
||||
quickActions.setShortcutItems(shortcuts);
|
||||
});
|
||||
await settings.setLinkHooksInitialized();
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -396,6 +407,7 @@ Future<bool> rescanDialog(BuildContext context) async {
|
|||
}
|
||||
|
||||
Future<bool> confirmWifi(BuildContext context) async {
|
||||
if (!isMobile()) return true;
|
||||
final connectivity = await Connectivity().checkConnectivity();
|
||||
if (connectivity == ConnectivityResult.mobile) {
|
||||
return await showDialog<bool?>(
|
||||
|
@ -576,10 +588,24 @@ Future<void> shieldTAddr(BuildContext context) async {
|
|||
Future<void> shareCsv(List<List> data, String filename, String title) async {
|
||||
final csvConverter = ListToCsvConverter();
|
||||
final csv = csvConverter.convert(data);
|
||||
Directory tempDir = await getTemporaryDirectory();
|
||||
String fn = "${tempDir.path}/$filename";
|
||||
final file = File(fn);
|
||||
await file.writeAsString(csv);
|
||||
await Share.shareFiles([fn], subject: title);
|
||||
await saveFile(csv, filename, title);
|
||||
}
|
||||
|
||||
Future<void> saveFile(String data, String filename, String title) async {
|
||||
if (isMobile()) {
|
||||
Directory tempDir = await getTemporaryDirectory();
|
||||
String fn = "${tempDir.path}/$filename";
|
||||
final file = File(fn);
|
||||
await file.writeAsString(data);
|
||||
return Share.shareFiles([filename], subject: title);
|
||||
}
|
||||
else {
|
||||
final fn = await FilePicker.platform.saveFile();
|
||||
if (fn != null) {
|
||||
final file = File(fn);
|
||||
await file.writeAsString(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool isMobile() => Platform.isAndroid || Platform.isIOS;
|
||||
|
|
|
@ -100,11 +100,7 @@ class FullBackupPage extends StatelessWidget {
|
|||
}
|
||||
|
||||
_onSave(BuildContext context) async {
|
||||
Directory tempDir = await getTemporaryDirectory();
|
||||
String filename = "${tempDir.path}/$APP_NAME.bak";
|
||||
final file = File(filename);
|
||||
await file.writeAsString(backup);
|
||||
Share.shareFiles([filename], subject: S.of(context).encryptedBackup(APP_NAME));
|
||||
await saveFile(backup, "$APP_NAME.bak", S.of(context).encryptedBackup(APP_NAME));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -451,18 +451,13 @@ Future<void> send(BuildContext context, List<Recipient> recipients, bool useTran
|
|||
rootScaffoldMessengerKey.currentState?.showSnackBar(snackBar2);
|
||||
await active.update();
|
||||
} else {
|
||||
Directory tempDir = await getTemporaryDirectory();
|
||||
String filename = "${tempDir.path}/tx.json";
|
||||
|
||||
final txjson = WarpApi.prepareTx(active.coin, active.id, recipients,
|
||||
useTransparent, settings.anchorOffset, filename);
|
||||
|
||||
final file = File(filename);
|
||||
await file.writeAsString(txjson);
|
||||
Share.shareFiles([filename], subject: s.unsignedTransactionFile);
|
||||
useTransparent, settings.anchorOffset);
|
||||
await saveFile(txjson, "tx.json", s.unsignedTransactionFile);
|
||||
|
||||
final snackBar2 = SnackBar(content: Text(s.fileSaved));
|
||||
rootScaffoldMessengerKey.currentState?.showSnackBar(snackBar2);
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ import 'package:http/http.dart' as http;
|
|||
import 'dart:convert' as convert;
|
||||
import 'package:convert/convert.dart';
|
||||
import 'package:flex_color_scheme/flex_color_scheme.dart';
|
||||
import 'package:sensors_plus/sensors_plus.dart';
|
||||
// import 'package:sensors_plus/sensors_plus.dart';
|
||||
|
||||
import 'coin/coin.dart';
|
||||
import 'generated/l10n.dart';
|
||||
|
@ -198,7 +198,7 @@ abstract class _Settings with Store {
|
|||
|
||||
_updateThemeData();
|
||||
Future.microtask(_loadCurrencies); // lazily
|
||||
accelerometerEvents.listen(_handleAccel);
|
||||
// accelerometerEvents.listen(_handleAccel);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,14 +18,14 @@ use zcash_multisig::{
|
|||
};
|
||||
use zcash_primitives::transaction::builder::Progress;
|
||||
|
||||
static RUNTIME: OnceCell<Mutex<Runtime>> = OnceCell::new();
|
||||
static YWALLET: OnceCell<Mutex<Wallet>> = OnceCell::new();
|
||||
static ZWALLET: OnceCell<Mutex<Wallet>> = OnceCell::new();
|
||||
static YMEMPOOL: OnceCell<Mutex<MemPool>> = OnceCell::new();
|
||||
static ZMEMPOOL: OnceCell<Mutex<MemPool>> = OnceCell::new();
|
||||
static SYNCLOCK: OnceCell<Mutex<()>> = OnceCell::new();
|
||||
static MULTISIG_AGG_LOCK: OnceCell<Mutex<MultisigAggregator>> = OnceCell::new();
|
||||
static MULTISIG_SIGN_LOCK: OnceCell<Mutex<MultisigClient>> = OnceCell::new();
|
||||
#[used] static RUNTIME: OnceCell<Mutex<Runtime>> = OnceCell::new();
|
||||
#[used] static YWALLET: OnceCell<Mutex<Wallet>> = OnceCell::new();
|
||||
#[used] static ZWALLET: OnceCell<Mutex<Wallet>> = OnceCell::new();
|
||||
#[used] static YMEMPOOL: OnceCell<Mutex<MemPool>> = OnceCell::new();
|
||||
#[used] static ZMEMPOOL: OnceCell<Mutex<MemPool>> = OnceCell::new();
|
||||
#[used] static SYNCLOCK: OnceCell<Mutex<()>> = OnceCell::new();
|
||||
#[used] static MULTISIG_AGG_LOCK: OnceCell<Mutex<MultisigAggregator>> = OnceCell::new();
|
||||
#[used] static MULTISIG_SIGN_LOCK: OnceCell<Mutex<MultisigClient>> = OnceCell::new();
|
||||
|
||||
fn get_lock<T>(cell: &OnceCell<Mutex<T>>) -> anyhow::Result<MutexGuard<T>> {
|
||||
cell.get()
|
||||
|
|
|
@ -81,6 +81,9 @@ class WarpApi {
|
|||
static open() {
|
||||
if (Platform.isAndroid) return DynamicLibrary.open('libwarp_api_ffi.so');
|
||||
if (Platform.isIOS) return DynamicLibrary.executable();
|
||||
if (Platform.isWindows) return DynamicLibrary.open('warp_api_ffi.dll');
|
||||
if (Platform.isLinux) return DynamicLibrary.open('./lib/libwarp_api_ffi.so');
|
||||
if (Platform.isMacOS) return DynamicLibrary.open('libwarp_api_ffi.dylib');
|
||||
throw UnsupportedError('This platform is not supported.');
|
||||
}
|
||||
|
||||
|
@ -194,8 +197,7 @@ class WarpApi {
|
|||
int account,
|
||||
List<Recipient> recipients,
|
||||
bool useTransparent,
|
||||
int anchorOffset,
|
||||
String txFilename) {
|
||||
int anchorOffset) {
|
||||
final recipientsJson = jsonEncode(recipients);
|
||||
final res = warp_api_lib.prepare_multi_payment(coin, account,
|
||||
recipientsJson.toNativeUtf8().cast<Int8>(),
|
||||
|
|
16
pubspec.lock
16
pubspec.lock
|
@ -990,7 +990,7 @@ packages:
|
|||
name: share_plus
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
version: "3.1.0"
|
||||
share_plus_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -1143,6 +1143,20 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
sqflite_common_ffi:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: sqflite_common_ffi
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.0+2"
|
||||
sqlite3:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqlite3
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.5.1"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -25,7 +25,8 @@ dependencies:
|
|||
sdk: flutter
|
||||
warp_api:
|
||||
path: packages/warp_api_ffi
|
||||
sqflite: ^2.0.0+4
|
||||
sqflite: ^2.0.2
|
||||
sqflite_common_ffi: ^2.1.0
|
||||
flutter_mobx: ^2.0.2
|
||||
qr_flutter: ^4.0.0
|
||||
http: ^0.13.3
|
||||
|
@ -51,9 +52,9 @@ dependencies:
|
|||
ref: 821f81681f8ee819cd721498f7b28d290f4ebe38
|
||||
grouped_list: ^4.1.0
|
||||
json_annotation: ^4.1.0
|
||||
share_plus: ^2.1.4
|
||||
share_plus: ^3.1.0
|
||||
path_provider: ^2.0.3
|
||||
file_picker: ^4.0.2
|
||||
file_picker: ^4.5.0
|
||||
mustache_template: ^2.0.0
|
||||
rate_my_app: ^1.1.1
|
||||
flutter_palette: ^1.1.0+1
|
||||
|
|
Loading…
Reference in New Issue