Compare commits

...

No commits in common. "main" and "manymen" have entirely different histories.

312 changed files with 51790 additions and 20707 deletions

View file

@ -1,26 +0,0 @@
# You can override the included template(s) by including variable overrides
# SAST customization: https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings
# Secret Detection customization: https://docs.gitlab.com/ee/user/application_security/secret_detection/pipeline/#customization
# Dependency Scanning customization: https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#customizing-the-dependency-scanning-settings
# Container Scanning customization: https://docs.gitlab.com/ee/user/application_security/container_scanning/#customizing-the-container-scanning-settings
# Note that environment variables can be set in several places
# See https://docs.gitlab.com/ee/ci/variables/#cicd-variable-precedence
stages:
- build
- test
- deploy
- review
- dast
- staging
- canary
- production
- incremental rollout 10%
- incremental rollout 25%
- incremental rollout 50%
- incremental rollout 100%
- performance
- cleanup
sast:
stage: test
include:
- template: Auto-DevOps.gitlab-ci.yml

25
.vscode/launch.json vendored Normal file
View file

@ -0,0 +1,25 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "haveno",
"request": "launch",
"type": "dart"
},
{
"name": "haveno (profile mode)",
"request": "launch",
"type": "dart",
"flutterMode": "profile"
},
{
"name": "haveno (release mode)",
"request": "launch",
"type": "dart",
"flutterMode": "release"
}
]
}

View file

@ -1,3 +1,4 @@
{
"cmake.configureOnOpen": false,
"java.configuration.updateBuildConfiguration": "interactive"
}

View file

@ -1 +0,0 @@
* @KewbitXMR

42
LICENSE
View file

@ -617,3 +617,45 @@ Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<https://www.gnu.org/licenses/>.

View file

@ -48,9 +48,9 @@ The Haveno Plus app is available as alpha pre-release builds for Android and Win
- **Windows:** (Coming soon)
- **MacOS:** (Coming soon)
- **Android** Alpha (testing)
- **Android** (Coming soon)
- **iOS** (Coming soon)
- **Linux:** Alpha (testing)
- **Linux:** (Coming soon)
- **Docker:** (Coming soon)
@ -63,29 +63,27 @@ The Haveno Plus app is available as alpha pre-release builds for Android and Win
## Project Status
Milestone 1: Protocol Interface ✅
Milestone 2: Complete UI + Providers + lots more ✅
Extras not in CCS:
- Caching system to ease the load on the daemon SQLite
- AES encryption on shared shared preferences and DB (not tested, will including on wallet too if nessesary)
The project is currently currently in the testing peroid of Milestone 2 having completed it.
The project is currently on **Milestone 2** which is creating and releasing the **App UI**.
### Network Endorsements
Haveno does not endorse or denounce any particular network. The choice of network will be available upon official release.
## Project Activity
The project is actively developed full-time for at least the next 2 months. Continued support may require sponsorships or feature bounties. The goal is to provide significant value to the XMR community.
## Roadmap
- Dart SDK API ✅ [Haveno Dart SDK](https://pub.dev/packages/haveno)
- Complete UI ✅ (tweaks needed)
- Linux desktop support ✅
- Complete and release UI - Currently milestone
- Windows desktop Support
- MacOS desktop support
- Android mobile Support
- Complete full arbitration scope.
- Add client authentication for onion-hosted daemons.
- iOS support.
- Linux desktop support.
- Easy whitelisting and fund transfers to Cake Wallet or similar.
- Biometric security for mobile devices, with PIN or password protection for those without biometric options.
- Standalone version not requiring desktop or server (considerable work; community support may be needed).
@ -95,7 +93,5 @@ Haveno does not endorse or denounce any particular network. The choice of networ
Testing on old phones or laptops and providing high-quality feedback is the best way to contribute. A discussion section will be set up for initial feedback and contributions.
## Disclaimer
Kewbit the maintainers blog is at [Kewbit.org](https://kewbit.org/) official sources for this are located at [Haveno.com's Gitlab](https://git.haveno.com/haveno/). **HAVENO.COM represents the official haveno app website and services as a client to a Haveno Daemon only**, and **HAVENO.EXCHANGE represents everything else, including not not limited to the p2p server network protocol, daemon nodes and pricenodes**, there are now also lots of app-specific guides located at [haveno documentation](https://haveno.com/documentation/) section of the site, which are atuned towards the new app.
None of the code in this repository (haveno-app) is intrinically holding custody of philosophy in what may be considered 'crypto-assets' OR transmitting any such 'crypto-assets' or other financial services across the the wire, network or the general internet.
## Additional Resources
Kewbit the maintainers blog is at [Kewbit.org](https://kewbit.org/) official source and binaries for this are located at [https://haveno.com](Haveno.com) only, there are now also lots of guides located at [haveno documentation](https://haveno.com/documentation/) secion of the site, which are atuned towards the new app.

View file

@ -28,15 +28,9 @@ android {
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
splits {
abi {
enable false
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
defaultConfig {
@ -62,12 +56,6 @@ android {
}
}
configurations {
all {
exclude group: 'com.google.android.play', module: 'play-core'
}
}
flutter {
source = "../.."
}

View file

@ -2,4 +2,3 @@ org.gradle.jvmargs=-Xmx4G -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
android.enableJetifier=true
android.bundle.enableUncompressedNativeLibs=false
dev.steenbakker.mobile_scanner.useUnbundled=true

View file

@ -19,7 +19,7 @@ pluginManagement {
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "7.3.0" apply false
id "org.jetbrains.kotlin.android" version "1.9.20" apply false
id "org.jetbrains.kotlin.android" version "1.7.10" apply false
}
include ":app"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

View file

@ -1,94 +0,0 @@
## Configuration file for a typical i2pd user
## See https://i2pd.readthedocs.io/en/latest/user-guide/configuration/
## for more options you can use in this file.
#logfile = /sdcard/i2pd/i2pd.log
loglevel = none
#tunnelsdir = /sdcard/i2pd/tunnels.d
# host = 1.2.3.4
# port = 4567
ipv4 = true
ipv6 = false
ssu = false
bandwidth = L
# share = 100
# notransit = true
# floodfill = true
[ntcp2]
enabled = true
[ssu2]
enabled = true
published = true
[http]
enabled = true
address = 127.0.0.1
port = 7070
# auth = true
# user = i2pd
# pass = changeme
[httpproxy]
enabled = true
address = 127.0.0.1
port = 4444
inbound.length = 1
inbound.quantity = 5
outbound.length = 1
outbound.quantity = 5
signaturetype=7
i2cp.leaseSetType=3
i2cp.leaseSetEncType=0,4
keys = proxy-keys.dat
# addresshelper = true
# outproxy = http://false.i2p
## httpproxy section also accepts I2CP parameters, like "inbound.length" etc.
[socksproxy]
enabled = true
address = 127.0.0.1
port = 4447
keys = proxy-keys.dat
# outproxy.enabled = false
# outproxy = 127.0.0.1
# outproxyport = 9050
## socksproxy section also accepts I2CP parameters, like "inbound.length" etc.
[sam]
enabled = false
# address = 127.0.0.1
# port = 7656
[precomputation]
elgamal = false
[upnp]
enabled = true
# name = I2Pd
[reseed]
verify = true
## Path to local reseed data file (.su3) for manual reseeding
# file = /path/to/i2pseeds.su3
## or HTTPS URL to reseed from
# file = https://legit-website.com/i2pseeds.su3
## Path to local ZIP file or HTTPS URL to reseed from
# zipfile = /path/to/netDb.zip
## If you run i2pd behind a proxy server, set proxy server for reseeding here
## Should be http://address:port or socks://address:port
# proxy = http://127.0.0.1:8118
## Minimum number of known routers, below which i2pd triggers reseeding. 25 by default
# threshold = 25
[limits]
transittunnels = 50
[persist]
profiles = false

View file

@ -1,33 +0,0 @@
#[IRC-IRC2P]
#type = client
#address = 127.0.0.1
#port = 6668
#destination = irc.postman.i2p
#destinationport = 6667
#keys = irc-keys.dat
#[IRC-ILITA]
#type = client
#address = 127.0.0.1
#port = 6669
#destination = irc.ilita.i2p
#destinationport = 6667
#keys = irc-keys.dat
#[SMTP]
#type = client
#address = 127.0.0.1
#port = 7659
#destination = smtp.postman.i2p
#destinationport = 25
#keys = smtp-keys.dat
#[POP3]
#type = client
#address = 127.0.0.1
#port = 7660
#destination = pop.postman.i2p
#destinationport = 110
#keys = pop3-keys.dat
# see more examples at https://i2pd.readthedocs.io/en/latest/user-guide/tunnels/

View file

@ -1,22 +0,0 @@
DataDirectory ./data
HiddenServiceDir ../daemon_service
HiddenServicePort 80 127.0.0.1:3201
HTTPTunnelPort 8888
SocksPort 9066
ControlPort 9077
HashedControlPassword 16:7FD95C8D50BA159760AA90C98DEA2924F0539C6B939F8A07AA68265FF4
Log notice stdout
#Log notice file ./logs/notice.log
KeepalivePeriod 60
ConstrainedSockets 1
ConstrainedSockSize 8192
#GeoIPFile ./lib/geoip
#GeoIPv6File ./lib/geoip6
ClientDNSRejectInternalAddresses 1
Nickname HAx000000
ContactInfo uuidv4@something.com
UseEntryGuards 1
NumEntryGuards 3
### EXPERIMENTAL FUTURE STUFF DONT ENABLE THESE YET IT COULD BE DISASTEROUS
#HiddenServiceSingleHopMode 1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

View file

@ -1,17 +0,0 @@
{
"haveno-core": {
"default": ""
},
"tor": {
"default": "14.5a1",
"otherwise_default_model": "tor_find_latest"
},
"monero": {
"default": "0.18.3.4",
"otherwise_default_model": ""
},
"java": {
"default": "21.0.4+7",
"otherwise_default_model": ""
}
}

BIN
flutter_01.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

34
ios/.gitignore vendored Normal file
View file

@ -0,0 +1,34 @@
**/dgph
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
**/DerivedData/
Icon?
**/Pods/
**/.symlinks/
profile
xcuserdata
**/.generated/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/ephemeral/
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>12.0</string>
</dict>
</plist>

View file

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

View file

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

44
ios/Podfile Executable file
View file

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

View file

@ -0,0 +1,616 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
proxyType = 1;
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
remoteInfo = Runner;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
331C8082294A63A400263BE5 /* RunnerTests */ = {
isa = PBXGroup;
children = (
331C807B294A618700263BE5 /* RunnerTests.swift */,
);
path = RunnerTests;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
);
path = Runner;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
331C8080294A63A400263BE5 /* RunnerTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
331C807D294A63A400263BE5 /* Sources */,
331C807F294A63A400263BE5 /* Resources */,
);
buildRules = (
);
dependencies = (
331C8086294A63A400263BE5 /* PBXTargetDependency */,
);
name = RunnerTests;
productName = RunnerTests;
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
331C8080294A63A400263BE5 = {
CreatedOnToolsVersion = 14.0;
TestTargetID = 97C146ED1CF9000F007C117D;
};
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
331C8080294A63A400263BE5 /* RunnerTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
331C807F294A63A400263BE5 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
331C807D294A63A400263BE5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 97C146ED1CF9000F007C117D /* Runner */;
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.haveno.havenoFlutterApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
331C8088294A63A400263BE5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.haveno.havenoFlutterApp.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Debug;
};
331C8089294A63A400263BE5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.haveno.havenoFlutterApp.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Release;
};
331C808A294A63A400263BE5 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.haveno.havenoFlutterApp.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.haveno.havenoFlutterApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.haveno.havenoFlutterApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
331C8088294A63A400263BE5 /* Debug */,
331C8089294A63A400263BE5 /* Release */,
331C808A294A63A400263BE5 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View file

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "331C8080294A63A400263BE5"
BuildableName = "RunnerTests.xctest"
BlueprintName = "RunnerTests"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View file

@ -0,0 +1,13 @@
import Flutter
import UIKit
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}

View file

@ -0,0 +1,122 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 762 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

View file

@ -0,0 +1,5 @@
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.

View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>

49
ios/Runner/Info.plist Normal file
View file

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Haveno Flutter App</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>haveno</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
</plist>

View file

@ -0,0 +1 @@
#import "GeneratedPluginRegistrant.h"

View file

@ -0,0 +1,12 @@
import Flutter
import UIKit
import XCTest
class RunnerTests: XCTestCase {
func testExample() {
// If you add code to the Runner application, consider adding tests here.
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
}
}

View file

@ -1,304 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import 'dart:async';
import 'dart:convert';
import 'package:flutter_background_service/flutter_background_service.dart';
import 'package:haveno/enums.dart';
import 'package:haveno/haveno_client.dart';
import 'package:haveno/haveno_service.dart';
import 'package:haveno_app/models/haveno_daemon_config.dart';
import 'package:haveno_app/models/schema.dart';
import 'package:haveno_app/services/local_notification_service.dart';
import 'package:haveno_app/services/secure_storage_service.dart';
// This is for Mobile background services only (for now) fuck off if you wanted something else. But we could run native Tor on Desktop too!
class BackgroundServiceListener {
final FlutterBackgroundService service = FlutterBackgroundService();
final EventDispatcher dispatcher;
BackgroundServiceListener(this.dispatcher);
Future<void> startListening() async {
service.on('updateTorStatus').listen((event) {
if (event != null) {
dispatcher.dispatch(BackgroundEvent(
type: BackgroundEventType.updateTorStatus,
data: event,
));
}
});
service.on('updateDaemonStatus').listen((event) {
if (event != null) {
dispatcher.dispatch(BackgroundEvent(
type: BackgroundEventType.updateDaemonStatus,
data: event,
));
}
});
service.on('torStdOutLog').listen((event) {
if (event != null) {
dispatcher.dispatch(BackgroundEvent(
type: BackgroundEventType.torStdOutLog,
data: event,
));
}
});
service.on('torStdErrLog').listen((event) {
if (event != null) {
dispatcher.dispatch(BackgroundEvent(
type: BackgroundEventType.torStdErrLog,
data: event,
));
}
});
}
}
void startBackgroundService() {
final service = FlutterBackgroundService();
service.startService();
}
void stopBackgroundService() {
final service = FlutterBackgroundService();
service.invoke("stop");
}
void markServiceNotificationSeen() {
final service = FlutterBackgroundService(); // just notify the UI to show the notificiation instead???
service.invoke("mark_notification_as_seen");
}
Future<void> startLongRunningForegroundService(ServiceInstance service) async {
//await _startTor(service);
LocalNotificationsService localNotificationsService = LocalNotificationsService();
localNotificationsService.init();
NotificationsService notificationsService =
NotificationsService();
notificationsService.addListener(
NotificationMessage_NotificationType.APP_INITIALIZED,
(object) {
localNotificationsService.updateForegroundServiceNotification(
title: 'Status',
body: 'Connected',
);
},
);
notificationsService.addListener(
NotificationMessage_NotificationType.TRADE_UPDATE,
(object) {
localNotificationsService.showNotification(
id: object.hashCode,
title: 'Trade Update',
body: object.message,
payload: jsonEncode({
'action': 'route_to_active_trades_screen',
'tradeProtobufAsJson': jsonEncode(object.trade.toProto3Json())
}));
},
);
notificationsService.addListener(
NotificationMessage_NotificationType.CHAT_MESSAGE,
(object) {
var payload = {
'action': 'route_to_chat_screen',
'chatMessageProtobufAsJson':
jsonEncode(object.chatMessage.toProto3Json())
};
print(jsonEncode(object.trade.toProto3Json()));
localNotificationsService.showNotification(
id: object.hashCode,
title: object.chatMessage.type == SupportType.TRADE
? 'New Message'
: 'New Support Message',
body: object.chatMessage.message,
payload: jsonEncode(payload));
},
);
notificationsService.listen();
localNotificationsService.updateForegroundServiceNotification(
title: 'Status',
body: 'Attempting to connect...',
);
//_connectToHavenoDaemonHeadless(service);
service.on("stop").listen((event) {
// We may need to just trigger this when the app is opened, and when its closed, enable it again
service.stopSelf();
// Set something in database for this or in secure storage, if it stops we need to make sure ios background fetch is running at least
});
}
// For iOS to update notifications and state (mainly notifications)
Future<void> startShortLivedBackgroundFetch(ServiceInstance service) async {
LocalNotificationsService localNotificationsService = LocalNotificationsService();
localNotificationsService.init(); // This whole thing might not complete in time for iOS
// if (!Tor.instance.enabled) {
// await _startTor(service);
// } else {
//
// }
// await _connectToHavenoDaemonHeadless(service, retryUntilSuccess: true, failWhenNoDaemonConfig: true);
// Check for new trades and chat messages only then send notification
// TODO
}
//Future<void> _startTor(ServiceInstance service) async {
// try {
// if (!Tor.instance.started) {
// service.invoke("updateTorStatus", {
// "status": "intializing",
// "details": "Tor is is now initializing..."
// });
// await Tor.init();
// service.invoke("updateTorStatus", {
// "status": "initialized",
// "details": "Tor has now been initialized. (Not yet started)"
// });
// service.invoke("updateTorStatus", {
// "status": "starting",
// "details": "Start is now starting..."
// }
// );
// if (!Tor.instance.enabled) {
// await Tor.instance.enable();
// }
// await Tor.instance.start();
// while (!Tor.instance.bootstrapped) {
// await Future.delayed(const Duration(seconds: 1));
// }
// service.invoke("updateTorStatus", {
// "status": "started",
// "port": Tor.instance.port,
// "details": "Tor service successfully started on port ${Tor.instance.port}"
// });
// } else {
// service.invoke("updateTorStatus", {
// "status": "started",
// "port": Tor.instance.port,
// "details": "Tor service successfully started on port ${Tor.instance.port}"
// });
// }
// } catch (e) {
// service.invoke("updateTorStatus", {
// "status": "error",
// "details": e.toString()
// });
// rethrow;
// }
//
// StreamSubscription<dynamic> subscription = Tor.instance.events.stream.listen( /// might have to make sure this is close or reopenable on closure automatically
// (event) {
// // Handle each event
// service.invoke("torStdOutLog", {
// "details": event.toString(),
// });
// },
// onError: (error) {
// // Handle any errors that occur during the stream
// service.invoke("torStdErrLog", {
// "details": error.toString(),
// });
// },
// onDone: () {
// // Handle when the stream is closed or completed
// service.invoke("updateTorStatus", {
// "status": "Tor stream closed",
// });
// },
// cancelOnError: false, // If true, the stream will cancel on the first error
// );
//}
Future<void> _connectToHavenoDaemonHeadless(ServiceInstance service, {bool retryUntilSuccess = true, bool failWhenNoDaemonConfig = false}) async {
HavenoChannel havenoService = HavenoChannel();
HavenoDaemonConfig? daemonConfig;
while (daemonConfig == null && retryUntilSuccess) {
service.invoke("updateDaemonStatus", {
"status": "aquiringRemoteDaemonConfig",
"details": "Aquiring remote daemon configuration from shared preferences..."
});
daemonConfig = await SecureStorageService().readHavenoDaemonConfig();
if (daemonConfig == null) {
service.invoke("updateDaemonStatus", {
"status": "remoteDaemonConfigNotFound",
"details": "No remote daemon configuration in shared preferences..."
});
if (failWhenNoDaemonConfig) {
service.invoke("updateDaemonStatus", {
"status": "stopped",
"details": "No daemon config found and it is configured to fail in this case and not retry..."
});
} else {
service.invoke("updateDaemonStatus", {
"status": "retryingConfig",
"details": "Scheduled to check for config again in 20 seconds..."
});
await Future.delayed(const Duration(seconds: 10));
}
} else {
service.invoke("updateDaemonStatus", {
"status": "foundDaemonConfig",
"details": "Found remote daemon configuration from shared preferences..."
});
if (havenoService.isConnected) {
break;
} else {
try {
service.invoke("updateDaemonStatus", {
"status": "connecting",
"details": "Connecting to the daemon..."
});
await havenoService.connect(daemonConfig.host, daemonConfig.port,
daemonConfig.clientAuthPassword);
service.invoke("updateDaemonStatus", {
"status": "connected",
"details": "Connects to the daemon..."
});
} catch (e) {
service.invoke("updateDaemonStatus", {
"status": "unknownError",
"details": "Failure: ${e.toString()}"
});
await Future.delayed(const Duration(seconds: 10));
}
}
}
}
}

View file

@ -1,20 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

View file

@ -1,20 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

View file

@ -1,20 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

View file

@ -1,20 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

View file

@ -1,20 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

View file

@ -1,20 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

View file

@ -1,20 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

View file

@ -1,61 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/* import 'package:haveno_app/background_tasks/mobile_notification_workers/schema.dart';
import 'package:haveno_app/proto/compiled/pb.pb.dart';
import 'package:haveno_app/proto/compiled/grpc.pb.dart';
import 'package:haveno_app/services/haveno_grpc_clients/trades_client_service.dart';
class CheckNewTradeMessagesTask extends MobileTask {
@override
Future<void> run() async {
TradesClientService tradesClient = TradesClientService(havenoService: havenoService);
List<TradeInfo>? trades = await tradesClient.getTrades();
if (trades != null) {
for (var trade in trades) {
List<ChatMessage>? chatMessages = await tradesClient.getChatMessages(trade.tradeId);
for (var message in chatMessages!) {
bool isNewMessage = await db.isTradeChatMessageNew(message.uid);
await db.insertTradeChatMessage(message, trade.tradeId);
if (!trade.role.contains('buyer') && (trade.tradePeerNodeAddress != trade.contract.buyerNodeAddress)) {
if (isNewMessage) {
await sendNotification(
id: message.uid.hashCode,
title: 'New Trade Message',
body: message.message,
);
}
}
}
//await Future.delayed(const Duration(minutes: 1));
}
}
}
@override
Future<void> updateState() {
// Implement state update logic if needed
throw UnimplementedError();
}
}
*/

View file

@ -1,61 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/* // mobile_tasks/check_new_trades.dart
import 'package:haveno_app/background_tasks/mobile_notification_workers/schema.dart';
import 'package:haveno_app/proto/compiled/grpc.pb.dart';
import 'package:haveno_app/services/haveno_grpc_clients/trades_client_service.dart';
import 'package:haveno_app/utils/payment_utils.dart';
class CheckNewTradesTask extends MobileTask {
CheckNewTradesTask() : super(minIntervalDuration: const Duration(minutes: 10));
@override
Future<void> run() async {
TradesClientService tradesClient = TradesClientService(havenoService: havenoService);
List<TradeInfo>? trades = await tradesClient.getTrades();
if (trades != null) {
for (var trade in trades) {
bool isNewTrade = await db.isTradeNew(trade.tradeId);
await db.insertTrade(trade);
if (isNewTrade) {
await sendNotification(
id: trade.tradeId.hashCode,
title: 'New Trade',
body: 'You have a new trade for ${formatXmr(trade.amount)} XMR',
);
}
}
}
}
@override
Future<void> updateState() {
// Implement state update logic if needed
throw UnimplementedError();
}
}
*/

View file

@ -1,20 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

View file

@ -1,20 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

View file

@ -1,20 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

View file

@ -1,20 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

View file

@ -1,106 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import 'package:haveno/haveno_client.dart';
import 'package:haveno_app/models/haveno_daemon_config.dart';
import 'package:haveno_app/services/connection_checker_service.dart';
import 'package:haveno_app/services/secure_storage_service.dart';
import 'package:haveno_app/services/local_notification_service.dart';
import 'package:haveno_app/utils/database_helper.dart';
abstract class AbstractMobileTask {
late Duration minIntervalDuration;
Future<void> run();
Future<void> sendNotification({required int id, required String title, required String body});
Future<void> updateState();
}
class MobileTask implements AbstractMobileTask {
final SecureStorageService secureStorage = SecureStorageService();
final HavenoChannel havenoChannel = HavenoChannel();
late final DatabaseHelper db;
HavenoDaemonConfig? havenoDaemonConfig;
@override
Duration minIntervalDuration;
// Constructor with a default value for minIntervalDuration
MobileTask({this.minIntervalDuration = const Duration(minutes: 5)}) {
init();
}
// Common initialization logic
Future<void> init() async {
// Get remote daemon config
havenoDaemonConfig = await secureStorage.readHavenoDaemonConfig();
// Init database
db = DatabaseHelper.instance;
// Check if connected to Tor
while (true) {
try {
if ((!await ConnectionCheckerService().isTorConnected())) {
throw Exception("Not yet connected to Tor...");
}
} catch (e) {
print(e.toString());
}
break;
}
while (true) {
try {
if ((!havenoChannel.isConnected)) {
await havenoChannel.connect(
havenoDaemonConfig!.host,
havenoDaemonConfig!.port,
havenoDaemonConfig!.clientAuthPassword,
);
}
} catch (e) {
print("Failed to connect to Haveno instance: $e");
}
break;
}
}
@override
Future<void> run() async {
throw UnimplementedError("Subclasses should implement this method.");
}
@override
Future<void> sendNotification({required int id, required String title, required String body}) async {
// Default implementation of sendNotification
LocalNotificationsService().showNotification(
id: id,
title: title,
body: body,
);
}
@override
Future<void> updateState() async {
// Default implementation of updateState
// Can be overridden by subclasses if needed
}
}

View file

@ -1,645 +0,0 @@
import 'package:interactive_chart/interactive_chart.dart';
class MockDataTesla {
static const List<dynamic> _rawData = [
// (Price data for Tesla Inc, taken from Yahoo Finance)
// timestamp, open, high, low, close, volume
[1555939800, 53.80, 53.94, 52.50, 52.55, 60735500],
[1556026200, 52.03, 53.12, 51.15, 52.78, 54719500],
[1556112600, 52.77, 53.06, 51.60, 51.73, 53637500],
[1556199000, 51.00, 51.80, 49.21, 49.53, 109247000],
[1556285400, 49.30, 49.34, 46.23, 47.03, 111803500],
[1556544600, 47.17, 48.80, 46.43, 48.29, 83572500],
[1556631000, 48.41, 48.84, 47.40, 47.74, 47323000],
[1556717400, 47.77, 48.00, 46.30, 46.80, 53522000],
[1556803800, 49.10, 49.43, 47.54, 48.82, 90796500],
[1556890200, 48.77, 51.32, 48.70, 51.01, 118534000],
[1557149400, 50.00, 51.67, 49.70, 51.07, 54169500],
[1557235800, 51.36, 51.44, 49.02, 49.41, 50657000],
[1557322200, 49.39, 50.12, 48.84, 48.97, 30882000],
[1557408600, 48.40, 48.74, 47.39, 48.40, 33557000],
[1557495000, 47.95, 48.40, 47.20, 47.90, 35041500],
[1557754200, 46.40, 46.49, 44.90, 45.40, 54174000],
[1557840600, 45.86, 46.90, 45.60, 46.46, 36262000],
[1557927000, 45.86, 46.49, 45.05, 46.39, 36480000],
[1558013400, 45.90, 46.20, 45.30, 45.67, 37416500],
[1558099800, 44.39, 44.45, 41.78, 42.21, 88933500],
[1558359000, 40.56, 41.20, 39.05, 41.07, 102631000],
[1558445400, 39.55, 41.48, 39.21, 41.02, 90019500],
[1558531800, 39.82, 40.79, 38.36, 38.55, 93426000],
[1558618200, 38.87, 39.89, 37.24, 39.10, 132735500],
[1558704600, 39.97, 40.00, 37.75, 38.13, 70683000],
[1559050200, 38.24, 39.00, 37.57, 37.74, 51564500],
[1559136600, 37.42, 38.48, 37.01, 37.97, 59843000],
[1559223000, 37.75, 38.45, 37.40, 37.64, 39632500],
[1559309400, 37.02, 37.98, 36.82, 37.03, 52033500],
[1559568600, 37.10, 37.34, 35.40, 35.79, 65322000],
[1559655000, 36.22, 38.80, 35.92, 38.72, 69037500],
[1559741400, 39.74, 40.26, 38.37, 39.32, 67554000],
[1559827800, 40.89, 42.20, 40.36, 41.19, 101211000],
[1559914200, 41.00, 42.17, 40.70, 40.90, 80017500],
[1560173400, 42.05, 43.39, 41.80, 42.58, 52925000],
[1560259800, 43.83, 44.18, 42.70, 43.42, 58267500],
[1560346200, 44.59, 44.68, 41.80, 41.85, 75987500],
[1560432600, 42.08, 42.98, 41.50, 42.78, 40841500],
[1560519000, 42.25, 43.33, 42.08, 42.98, 37167000],
[1560778200, 43.10, 45.40, 42.85, 45.01, 61584000],
[1560864600, 45.74, 46.95, 44.51, 44.95, 63579000],
[1560951000, 45.02, 45.55, 44.21, 45.29, 32875500],
[1561037400, 44.60, 45.38, 43.27, 43.92, 59317500],
[1561123800, 43.24, 44.44, 43.10, 44.37, 41010500],
[1561383000, 44.65, 45.17, 44.20, 44.73, 28754000],
[1561469400, 44.88, 45.07, 43.90, 43.95, 30910500],
[1561555800, 44.06, 45.45, 43.62, 43.85, 42536000],
[1561642200, 43.89, 44.58, 43.47, 44.57, 31698500],
[1561728600, 44.20, 45.03, 44.16, 44.69, 34257000],
[1561987800, 46.04, 46.62, 45.26, 45.43, 41067000],
[1562074200, 45.78, 45.83, 44.44, 44.91, 46295000],
[1562160600, 47.88, 48.31, 46.90, 46.98, 71005500],
[1562333400, 46.91, 47.09, 46.16, 46.62, 35328500],
[1562592600, 46.25, 46.45, 45.73, 46.07, 29402500],
[1562679000, 45.79, 46.20, 45.46, 46.01, 30954000],
[1562765400, 46.83, 47.79, 46.63, 47.78, 45728500],
[1562851800, 47.63, 48.30, 47.16, 47.72, 37572000],
[1562938200, 47.95, 49.08, 47.94, 49.02, 46002500],
[1563197400, 49.60, 50.88, 48.97, 50.70, 55000500],
[1563283800, 49.86, 50.71, 49.59, 50.48, 40745000],
[1563370200, 51.13, 51.66, 50.67, 50.97, 48823500],
[1563456600, 51.01, 51.15, 50.38, 50.71, 23793000],
[1563543000, 51.14, 51.99, 50.92, 51.64, 35242000],
[1563802200, 51.75, 52.43, 50.84, 51.14, 34212000],
[1563888600, 51.34, 52.10, 50.90, 52.03, 25115500],
[1563975000, 51.83, 53.21, 51.63, 52.98, 55364000],
[1564061400, 46.70, 46.90, 45.11, 45.76, 112091500],
[1564147800, 45.38, 46.05, 44.45, 45.61, 50138500],
[1564407000, 45.42, 47.19, 45.21, 47.15, 46366500],
[1564493400, 46.58, 48.67, 46.44, 48.45, 40545000],
[1564579800, 48.60, 49.34, 47.33, 48.32, 45891000],
[1564666200, 48.53, 48.90, 46.35, 46.77, 41297500],
[1564752600, 46.27, 47.25, 45.85, 46.87, 30682500],
[1565011800, 45.92, 46.27, 45.16, 45.66, 35141500],
[1565098200, 46.38, 46.50, 45.15, 46.15, 27821000],
[1565184600, 45.30, 46.71, 45.16, 46.68, 23882500],
[1565271000, 46.89, 47.96, 46.53, 47.66, 26371500],
[1565357400, 47.21, 47.79, 46.76, 47.00, 19491000],
[1565616600, 46.60, 47.15, 45.75, 45.80, 23319500],
[1565703000, 45.76, 47.20, 45.51, 47.00, 24240500],
[1565789400, 46.24, 46.30, 43.34, 43.92, 47813000],
[1565875800, 44.17, 44.31, 42.31, 43.13, 40798000],
[1565962200, 43.33, 44.45, 43.20, 43.99, 25492500],
[1566221400, 44.84, 45.57, 44.34, 45.37, 26548000],
[1566307800, 45.52, 45.82, 44.91, 45.17, 20626000],
[1566394200, 44.40, 44.64, 43.52, 44.17, 38971500],
[1566480600, 44.56, 45.08, 43.64, 44.43, 32795000],
[1566567000, 43.99, 44.23, 42.20, 42.28, 42693000],
[1566826200, 42.72, 43.00, 42.31, 43.00, 25259500],
[1566912600, 43.15, 43.76, 42.41, 42.82, 27081000],
[1566999000, 42.74, 43.45, 42.46, 43.12, 16127500],
[1567085400, 43.80, 44.68, 43.60, 44.34, 25897500],
[1567171800, 45.83, 46.49, 44.84, 45.12, 46603000],
[1567517400, 44.82, 45.79, 44.63, 45.00, 26770500],
[1567603800, 45.38, 45.69, 43.84, 44.14, 28805000],
[1567690200, 44.50, 45.96, 44.17, 45.92, 36976500],
[1567776600, 45.44, 45.93, 45.03, 45.49, 20947000],
[1568035800, 46.00, 46.75, 45.85, 46.36, 24013500],
[1568122200, 46.16, 47.11, 45.79, 47.11, 24418500],
[1568208600, 47.48, 49.63, 47.20, 49.42, 50214000],
[1568295000, 49.54, 50.70, 48.88, 49.17, 42906000],
[1568381400, 49.39, 49.69, 48.97, 49.04, 26565500],
[1568640600, 49.20, 49.49, 48.23, 48.56, 23640500],
[1568727000, 48.49, 49.12, 48.07, 48.96, 19327000],
[1568813400, 49.00, 49.63, 48.47, 48.70, 20851000],
[1568899800, 49.20, 49.59, 48.97, 49.32, 23979000],
[1568986200, 49.30, 49.39, 47.63, 48.12, 31765000],
[1569245400, 48.00, 49.04, 47.84, 48.25, 21701000],
[1569331800, 48.30, 48.40, 44.52, 44.64, 64457500],
[1569418200, 44.91, 45.80, 43.67, 45.74, 47135500],
[1569504600, 46.13, 48.66, 45.48, 48.51, 59422500],
[1569591000, 48.44, 49.74, 47.75, 48.43, 55582000],
[1569850200, 48.60, 48.80, 47.22, 48.17, 29399000],
[1569936600, 48.30, 49.19, 47.83, 48.94, 30813000],
[1570023000, 48.66, 48.93, 47.89, 48.63, 28157000],
[1570109400, 46.37, 46.90, 44.86, 46.61, 75422500],
[1570195800, 46.32, 46.96, 45.61, 46.29, 39975000],
[1570455000, 45.96, 47.71, 45.71, 47.54, 40321000],
[1570541400, 47.17, 48.79, 46.90, 48.01, 43391000],
[1570627800, 48.26, 49.46, 48.13, 48.91, 34472000],
[1570714200, 49.06, 49.86, 48.32, 48.95, 31416500],
[1570800600, 49.43, 50.22, 49.36, 49.58, 42377000],
[1571059800, 49.58, 51.71, 49.43, 51.39, 51025000],
[1571146200, 51.54, 52.00, 50.82, 51.58, 32164000],
[1571232600, 51.48, 52.42, 51.38, 51.95, 33420500],
[1571319000, 52.50, 52.96, 52.03, 52.39, 23846500],
[1571405400, 52.14, 52.56, 51.02, 51.39, 28749000],
[1571664600, 51.67, 51.90, 50.04, 50.70, 25101500],
[1571751000, 50.86, 51.67, 50.17, 51.12, 23004000],
[1571837400, 50.90, 51.23, 50.27, 50.94, 26305500],
[1571923800, 59.67, 60.99, 57.84, 59.94, 148604500],
[1572010200, 59.54, 66.00, 59.22, 65.63, 150030500],
[1572269400, 65.51, 68.17, 64.52, 65.54, 94351500],
[1572355800, 64.00, 64.86, 62.95, 63.24, 63421500],
[1572442200, 62.60, 63.76, 61.99, 63.00, 48209000],
[1572528600, 62.62, 63.80, 62.60, 62.98, 25335000],
[1572615000, 63.26, 63.30, 61.96, 62.66, 31919500],
[1572877800, 62.96, 64.39, 61.85, 63.49, 43935000],
[1572964200, 63.92, 64.70, 63.22, 63.44, 34717000],
[1573050600, 63.60, 65.34, 62.90, 65.32, 39704500],
[1573137000, 65.83, 68.30, 65.60, 67.11, 72336500],
[1573223400, 66.90, 67.49, 66.50, 67.43, 30346000],
[1573482600, 68.79, 69.84, 68.40, 69.02, 49933500],
[1573569000, 69.38, 70.07, 68.81, 69.99, 36797000],
[1573655400, 71.00, 71.27, 69.04, 69.22, 42100500],
[1573741800, 69.22, 70.77, 68.58, 69.87, 32324500],
[1573828200, 70.13, 70.56, 69.67, 70.43, 24045000],
[1574087400, 70.58, 70.63, 69.22, 70.00, 22002000],
[1574173800, 70.35, 72.00, 69.56, 71.90, 38624000],
[1574260200, 72.00, 72.24, 69.91, 70.44, 33625500],
[1574346600, 70.90, 72.17, 70.80, 70.97, 30550000],
[1574433000, 68.03, 68.20, 66.00, 66.61, 84353000],
[1574692200, 68.86, 68.91, 66.89, 67.27, 61697500],
[1574778600, 67.05, 67.10, 65.42, 65.78, 39737000],
[1574865000, 66.22, 66.79, 65.71, 66.26, 27778000],
[1575037800, 66.22, 66.25, 65.50, 65.99, 12328000],
[1575297000, 65.88, 67.28, 65.74, 66.97, 30372500],
[1575383400, 66.52, 67.58, 66.44, 67.24, 32868500],
[1575469800, 67.55, 67.57, 66.57, 66.61, 27665000],
[1575556200, 66.57, 66.88, 65.45, 66.07, 18623000],
[1575642600, 67.00, 67.77, 66.95, 67.18, 38062000],
[1575901800, 67.32, 68.89, 67.02, 67.91, 45115500],
[1575988200, 67.99, 70.15, 67.86, 69.77, 44141500],
[1576074600, 70.38, 71.44, 70.22, 70.54, 34489000],
[1576161000, 70.98, 72.55, 70.65, 71.94, 38819500],
[1576247400, 72.21, 73.04, 70.93, 71.68, 32854500],
[1576506600, 72.51, 76.72, 72.50, 76.30, 90871000],
[1576593000, 75.80, 77.10, 75.18, 75.80, 42484000],
[1576679400, 76.13, 79.04, 76.12, 78.63, 70605000],
[1576765800, 79.46, 81.37, 79.30, 80.81, 90535500],
[1576852200, 82.06, 82.60, 80.04, 81.12, 73763500],
[1577111400, 82.36, 84.40, 82.00, 83.84, 66598000],
[1577197800, 83.67, 85.09, 82.54, 85.05, 40273500],
[1577370600, 85.58, 86.70, 85.27, 86.19, 53169500],
[1577457000, 87.00, 87.06, 85.22, 86.08, 49728500],
[1577716200, 85.76, 85.80, 81.85, 82.94, 62932000],
[1577802600, 81.00, 84.26, 80.42, 83.67, 51428500],
[1577975400, 84.90, 86.14, 84.34, 86.05, 47660500],
[1578061800, 88.10, 90.80, 87.38, 88.60, 88892500],
[1578321000, 88.09, 90.31, 88.00, 90.31, 50665000],
[1578407400, 92.28, 94.33, 90.67, 93.81, 89410500],
[1578493800, 94.74, 99.70, 93.65, 98.43, 155721500],
[1578580200, 99.42, 99.76, 94.57, 96.27, 142202000],
[1578666600, 96.36, 96.99, 94.74, 95.63, 64797500],
[1578925800, 98.70, 105.13, 98.40, 104.97, 132588000],
[1579012200, 108.85, 109.48, 104.98, 107.58, 144981000],
[1579098600, 105.95, 107.57, 103.36, 103.70, 86844000],
[1579185000, 98.75, 102.89, 98.43, 102.70, 108683500],
[1579271400, 101.52, 103.13, 100.63, 102.10, 68145500],
[1579617000, 106.05, 109.72, 105.68, 109.44, 89017500],
[1579703400, 114.38, 118.90, 111.82, 113.91, 156845000],
[1579789800, 112.85, 116.40, 111.12, 114.44, 98255000],
[1579876200, 114.13, 114.77, 110.85, 112.96, 71768000],
[1580135400, 108.40, 112.89, 107.86, 111.60, 68040500],
[1580221800, 113.70, 115.36, 111.62, 113.38, 58942500],
[1580308200, 115.14, 117.96, 113.49, 116.20, 89007500],
[1580394600, 126.48, 130.18, 123.60, 128.16, 145028500],
[1580481000, 128.00, 130.60, 126.50, 130.11, 78596500],
[1580740200, 134.74, 157.23, 134.70, 156.00, 235325000],
[1580826600, 176.59, 193.80, 166.78, 177.41, 304694000],
[1580913000, 164.65, 169.20, 140.82, 146.94, 242119000],
[1580999400, 139.98, 159.17, 137.40, 149.79, 199404000],
[1581085800, 146.11, 153.95, 146.00, 149.61, 85317500],
[1581345000, 160.00, 164.00, 150.48, 154.26, 123446000],
[1581431400, 153.76, 156.70, 151.60, 154.88, 58487500],
[1581517800, 155.57, 157.95, 152.67, 153.46, 60112500],
[1581604200, 148.37, 163.60, 147.00, 160.80, 131446500],
[1581690600, 157.44, 162.59, 157.10, 160.01, 78468500],
[1582036200, 168.32, 172.00, 166.47, 171.68, 81908500],
[1582122600, 184.70, 188.96, 180.20, 183.48, 127115000],
[1582209000, 182.39, 182.40, 171.99, 179.88, 88174500],
[1582295400, 181.40, 182.61, 176.09, 180.20, 71574000],
[1582554600, 167.80, 172.70, 164.44, 166.76, 75961000],
[1582641000, 169.80, 171.32, 157.40, 159.98, 86452500],
[1582727400, 156.50, 162.66, 155.22, 155.76, 70427500],
[1582813800, 146.00, 147.95, 133.80, 135.80, 121386000],
[1582900200, 125.94, 138.10, 122.30, 133.60, 121114500],
[1583159400, 142.25, 148.74, 137.33, 148.72, 100975000],
[1583245800, 161.00, 161.40, 143.22, 149.10, 128920000],
[1583332200, 152.79, 153.30, 144.95, 149.90, 75245000],
[1583418600, 144.75, 149.15, 143.61, 144.91, 54263500],
[1583505000, 138.00, 141.40, 136.85, 140.70, 63314500],
[1583760600, 121.08, 132.60, 121.00, 121.60, 85368500],
[1583847000, 131.89, 133.60, 121.60, 129.07, 77972000],
[1583933400, 128.04, 130.72, 122.60, 126.85, 66612500],
[1584019800, 116.18, 118.90, 109.25, 112.11, 94545500],
[1584106200, 119.00, 121.51, 100.40, 109.32, 113201500],
[1584365400, 93.90, 98.97, 88.43, 89.01, 102447500],
[1584451800, 88.00, 94.37, 79.20, 86.04, 119973000],
[1584538200, 77.80, 80.97, 70.10, 72.24, 118931000],
[1584624600, 74.94, 90.40, 71.69, 85.53, 150977500],
[1584711000, 87.64, 95.40, 85.16, 85.51, 141427500],
[1584970200, 86.72, 88.40, 82.10, 86.86, 82272500],
[1585056600, 95.46, 102.74, 94.80, 101.00, 114476000],
[1585143000, 109.05, 111.40, 102.22, 107.85, 106113500],
[1585229400, 109.48, 112.00, 102.45, 105.63, 86903500],
[1585315800, 101.00, 105.16, 98.81, 102.87, 71887000],
[1585575000, 102.05, 103.33, 98.25, 100.43, 59990500],
[1585661400, 100.25, 108.59, 99.40, 104.80, 88857500],
[1585747800, 100.80, 102.79, 95.02, 96.31, 66766000],
[1585834200, 96.21, 98.85, 89.28, 90.89, 99292000],
[1585920600, 101.90, 103.10, 93.68, 96.00, 112810500],
[1586179800, 102.24, 104.20, 99.59, 103.25, 74509000],
[1586266200, 109.00, 113.00, 106.47, 109.09, 89599000],
[1586352600, 110.84, 111.44, 106.67, 109.77, 63280000],
[1586439000, 112.42, 115.04, 111.42, 114.60, 68250000],
[1586784600, 118.03, 130.40, 116.11, 130.19, 112377000],
[1586871000, 139.79, 148.38, 138.49, 141.98, 152882500],
[1586957400, 148.40, 150.63, 142.00, 145.97, 117885000],
[1587043800, 143.39, 151.89, 141.34, 149.04, 103289500],
[1587130200, 154.46, 154.99, 149.53, 150.78, 65641000],
[1587389400, 146.54, 153.11, 142.44, 149.27, 73733000],
[1587475800, 146.02, 150.67, 134.76, 137.34, 101045500],
[1587562200, 140.80, 146.80, 137.74, 146.42, 70827500],
[1587648600, 145.52, 146.80, 140.63, 141.13, 66183500],
[1587735000, 142.16, 146.15, 139.64, 145.03, 66060000],
[1587994200, 147.52, 159.90, 147.00, 159.75, 103407000],
[1588080600, 159.13, 161.00, 151.34, 153.82, 76110000],
[1588167000, 158.03, 160.64, 156.63, 160.10, 81080000],
[1588253400, 171.04, 173.96, 152.70, 156.38, 142359500],
[1588339800, 151.00, 154.55, 136.61, 140.26, 162659000],
[1588599000, 140.20, 152.40, 139.60, 152.24, 96185500],
[1588685400, 157.96, 159.78, 152.44, 153.64, 84958500],
[1588771800, 155.30, 157.96, 152.22, 156.52, 55616000],
[1588858200, 155.44, 159.28, 154.47, 156.01, 57638500],
[1588944600, 158.75, 164.80, 157.40, 163.88, 80432500],
[1589203800, 158.10, 164.80, 157.00, 162.26, 82598000],
[1589290200, 165.40, 168.66, 161.60, 161.88, 79534500],
[1589376600, 164.17, 165.20, 152.66, 158.19, 95327500],
[1589463000, 156.00, 160.67, 152.80, 160.67, 68411000],
[1589549400, 158.07, 161.01, 157.31, 159.83, 52592000],
[1589808600, 165.56, 166.94, 160.78, 162.73, 58329000],
[1589895000, 163.03, 164.41, 161.22, 161.60, 48182500],
[1589981400, 164.10, 165.20, 162.36, 163.11, 36546500],
[1590067800, 163.20, 166.50, 159.20, 165.52, 61273000],
[1590154200, 164.43, 166.36, 162.40, 163.38, 49937500],
[1590499800, 166.90, 166.92, 163.14, 163.77, 40448500],
[1590586200, 164.17, 165.54, 157.00, 164.05, 57747500],
[1590672600, 162.70, 164.95, 160.34, 161.16, 36278000],
[1590759000, 161.75, 167.00, 160.84, 167.00, 58822500],
[1591018200, 171.60, 179.80, 170.82, 179.62, 74697500],
[1591104600, 178.94, 181.73, 174.20, 176.31, 67828000],
[1591191000, 177.62, 179.59, 176.02, 176.59, 39747500],
[1591277400, 177.98, 179.15, 171.69, 172.88, 44438500],
[1591363800, 175.57, 177.30, 173.24, 177.13, 39059500],
[1591623000, 183.80, 190.00, 181.83, 189.98, 70873500],
[1591709400, 188.00, 190.89, 184.79, 188.13, 56941000],
[1591795800, 198.38, 205.50, 196.50, 205.01, 92817000],
[1591882200, 198.04, 203.79, 194.40, 194.57, 79582500],
[1591968600, 196.00, 197.60, 182.52, 187.06, 83817000],
[1592227800, 183.56, 199.77, 181.70, 198.18, 78486000],
[1592314200, 202.37, 202.58, 192.48, 196.43, 70255500],
[1592400600, 197.54, 201.00, 196.51, 198.36, 49454000],
[1592487000, 200.60, 203.84, 198.89, 200.79, 48759500],
[1592573400, 202.56, 203.19, 198.27, 200.18, 43398500],
[1592832600, 199.99, 201.78, 198.00, 198.86, 31812000],
[1592919000, 199.78, 202.40, 198.80, 200.36, 31826500],
[1593005400, 198.82, 200.18, 190.63, 192.17, 54798000],
[1593091800, 190.85, 197.20, 187.43, 197.20, 46272500],
[1593178200, 198.96, 199.00, 190.97, 191.95, 44274500],
[1593437400, 193.80, 202.00, 189.70, 201.87, 45132000],
[1593523800, 201.30, 217.54, 200.75, 215.96, 84592500],
[1593610200, 216.60, 227.07, 216.10, 223.93, 66634500],
[1593696600, 244.30, 245.60, 237.12, 241.73, 86250500],
[1594042200, 255.34, 275.56, 253.21, 274.32, 102849500],
[1594128600, 281.00, 285.90, 267.34, 277.97, 107448500],
[1594215000, 281.00, 283.45, 262.27, 273.18, 81556500],
[1594301400, 279.40, 281.71, 270.26, 278.86, 58588000],
[1594387800, 279.20, 309.78, 275.20, 308.93, 116688000],
[1594647000, 331.80, 359.00, 294.22, 299.41, 194927000],
[1594733400, 311.20, 318.00, 286.20, 303.36, 117090500],
[1594819800, 308.60, 310.00, 291.40, 309.20, 81839000],
[1594906200, 295.43, 306.34, 293.20, 300.13, 71504000],
[1594992600, 302.69, 307.50, 298.00, 300.17, 46650000],
[1595251800, 303.80, 330.00, 297.60, 328.60, 85607000],
[1595338200, 327.99, 335.00, 311.60, 313.67, 80536000],
[1595424600, 319.80, 325.28, 312.40, 318.47, 70805500],
[1595511000, 335.79, 337.80, 296.15, 302.61, 121642500],
[1595597400, 283.20, 293.00, 273.31, 283.40, 96983000],
[1595856600, 287.00, 309.59, 282.60, 307.92, 80243500],
[1595943000, 300.80, 312.94, 294.88, 295.30, 79043500],
[1596029400, 300.20, 306.96, 297.40, 299.82, 47134500],
[1596115800, 297.60, 302.65, 294.20, 297.50, 38105000],
[1596202200, 303.00, 303.41, 284.20, 286.15, 61041000],
[1596461400, 289.84, 301.96, 288.88, 297.00, 44046500],
[1596547800, 299.00, 305.48, 292.40, 297.40, 42075000],
[1596634200, 298.60, 299.97, 293.66, 297.00, 24739000],
[1596720600, 298.17, 303.46, 295.45, 297.92, 29961500],
[1596807000, 299.91, 299.95, 283.00, 290.54, 44482000],
[1597066200, 289.60, 291.50, 277.17, 283.71, 37611500],
[1597152600, 279.20, 284.00, 273.00, 274.88, 43129000],
[1597239000, 294.00, 317.00, 287.00, 310.95, 109147000],
[1597325400, 322.20, 330.24, 313.45, 324.20, 102126500],
[1597411800, 333.00, 333.76, 325.33, 330.14, 62888000],
[1597671000, 335.40, 369.17, 334.57, 367.13, 101211500],
[1597757400, 379.80, 384.78, 369.02, 377.42, 82372500],
[1597843800, 373.00, 382.20, 368.24, 375.71, 61026500],
[1597930200, 372.14, 404.40, 371.41, 400.37, 103059000],
[1598016600, 408.95, 419.10, 405.01, 410.00, 107448000],
[1598275800, 425.26, 425.80, 385.50, 402.84, 100318000],
[1598362200, 394.98, 405.59, 393.60, 404.67, 53294500],
[1598448600, 412.00, 433.20, 410.73, 430.63, 71197000],
[1598535000, 436.09, 459.12, 428.50, 447.75, 118465000],
[1598621400, 459.02, 463.70, 437.30, 442.68, 100406000],
[1598880600, 444.61, 500.14, 440.11, 498.32, 118374400],
[1598967000, 502.14, 502.49, 470.51, 475.05, 89841100],
[1599053400, 478.99, 479.04, 405.12, 447.37, 96176100],
[1599139800, 407.23, 431.80, 402.00, 407.00, 87596100],
[1599226200, 402.81, 428.00, 372.02, 418.32, 110321900],
[1599571800, 356.00, 368.74, 329.88, 330.21, 115465700],
[1599658200, 356.60, 369.00, 341.51, 366.28, 79465800],
[1599744600, 386.21, 398.99, 360.56, 371.34, 84930600],
[1599831000, 381.94, 382.50, 360.50, 372.72, 60717500],
[1600090200, 380.95, 420.00, 373.30, 419.62, 83020600],
[1600176600, 436.56, 461.94, 430.70, 449.76, 97298200],
[1600263000, 439.87, 457.79, 435.31, 441.76, 72279300],
[1600349400, 415.60, 437.79, 408.00, 423.43, 76779200],
[1600435800, 447.94, 451.00, 428.80, 442.15, 86406800],
[1600695000, 453.13, 455.68, 407.07, 449.39, 109476800],
[1600781400, 429.60, 437.76, 417.60, 424.23, 79580800],
[1600867800, 405.16, 412.15, 375.88, 380.36, 95074200],
[1600954200, 363.80, 399.50, 351.30, 387.79, 96561100],
[1601040600, 393.47, 408.73, 391.30, 407.34, 67208500],
[1601299800, 424.62, 428.08, 415.55, 421.20, 49719600],
[1601386200, 416.00, 428.50, 411.60, 419.07, 50219300],
[1601472600, 421.32, 433.93, 420.47, 429.01, 48145600],
[1601559000, 440.76, 448.88, 434.42, 448.16, 50741500],
[1601645400, 421.39, 439.13, 415.00, 415.09, 71430000],
[1601904600, 423.35, 433.64, 419.33, 425.68, 44722800],
[1601991000, 423.79, 428.78, 406.05, 413.98, 49146300],
[1602077400, 419.87, 429.90, 413.85, 425.30, 43127700],
[1602163800, 438.44, 439.00, 425.30, 425.92, 40421100],
[1602250200, 430.13, 434.59, 426.46, 434.00, 28925700],
[1602509400, 442.00, 448.74, 438.58, 442.30, 38791100],
[1602595800, 443.35, 448.89, 436.60, 446.65, 34463700],
[1602682200, 449.78, 465.90, 447.35, 461.30, 47879700],
[1602768600, 450.31, 456.57, 442.50, 448.88, 35672400],
[1602855000, 454.44, 455.95, 438.85, 439.67, 32775900],
[1603114200, 446.24, 447.00, 428.87, 430.83, 36287800],
[1603200600, 431.75, 431.75, 419.05, 421.94, 31656300],
[1603287000, 422.70, 432.95, 421.25, 422.64, 32370500],
[1603373400, 441.92, 445.23, 424.51, 425.79, 39993200],
[1603459800, 421.84, 422.89, 407.38, 420.63, 33717000],
[1603719000, 411.63, 425.76, 410.00, 420.28, 28239200],
[1603805400, 423.76, 430.50, 420.10, 424.68, 22686500],
[1603891800, 416.48, 418.60, 406.00, 406.02, 25451400],
[1603978200, 409.96, 418.06, 406.46, 410.83, 22655300],
[1604064600, 406.90, 407.59, 379.11, 388.04, 42511300],
[1604327400, 394.00, 406.98, 392.30, 400.51, 29021100],
[1604413800, 409.73, 427.77, 406.69, 423.90, 34351700],
[1604500200, 430.62, 435.40, 417.10, 420.98, 32143100],
[1604586600, 428.30, 440.00, 424.00, 438.09, 28414500],
[1604673000, 436.10, 436.57, 424.28, 429.95, 21706000],
[1604932200, 439.50, 452.50, 421.00, 421.26, 34833000],
[1605018600, 420.09, 420.09, 396.03, 410.36, 30284200],
[1605105000, 416.45, 418.70, 410.58, 417.13, 17357700],
[1605191400, 415.05, 423.00, 409.52, 411.76, 19855100],
[1605277800, 410.85, 412.53, 401.66, 408.50, 19771100],
[1605537000, 408.93, 412.45, 404.09, 408.09, 26838600],
[1605623400, 460.17, 462.00, 433.01, 441.61, 61188300],
[1605709800, 448.35, 496.00, 443.50, 486.64, 78044000],
[1605796200, 492.00, 508.61, 487.57, 499.27, 62475300],
[1605882600, 497.99, 502.50, 489.06, 489.61, 32911900],
[1606141800, 503.50, 526.00, 501.79, 521.85, 50260300],
[1606228200, 540.40, 559.99, 526.20, 555.38, 53648500],
[1606314600, 550.06, 574.00, 545.37, 574.00, 48930200],
[1606487400, 581.16, 598.78, 578.45, 585.76, 37561100],
[1606746600, 602.21, 607.80, 554.51, 567.60, 63003100],
[1606833000, 597.59, 597.85, 572.05, 584.76, 40103500],
[1606919400, 556.44, 571.54, 541.21, 568.82, 47775700],
[1607005800, 590.02, 598.97, 582.43, 593.38, 42552000],
[1607092200, 591.01, 599.04, 585.50, 599.04, 29401300],
[1607351400, 604.92, 648.79, 603.05, 641.76, 56309700],
[1607437800, 625.51, 651.28, 618.50, 649.88, 64265000],
[1607524200, 653.69, 654.32, 588.00, 604.48, 71291200],
[1607610600, 574.37, 627.75, 566.34, 627.07, 67083200],
[1607697000, 615.01, 624.00, 596.80, 609.99, 46475000],
[1607956200, 619.00, 642.75, 610.20, 639.83, 52040600],
[1608042600, 643.28, 646.90, 623.80, 633.25, 45071500],
[1608129000, 628.23, 632.50, 605.00, 622.77, 42095800],
[1608215400, 628.19, 658.82, 619.50, 655.90, 56270100],
[1608301800, 668.90, 695.00, 628.54, 695.00, 222126200],
[1608561000, 666.24, 668.50, 646.07, 649.86, 58045300],
[1608647400, 648.00, 649.88, 614.23, 640.34, 51716000],
[1608733800, 632.20, 651.50, 622.57, 645.98, 33173000],
[1608820200, 642.99, 666.09, 641.00, 661.77, 22865600],
[1609165800, 674.51, 681.40, 660.80, 663.69, 32278600],
[1609252200, 661.00, 669.90, 655.00, 665.99, 22910800],
[1609338600, 672.00, 696.60, 668.36, 694.78, 42846000],
[1609425000, 699.99, 718.72, 691.12, 705.67, 49649900],
[1609770600, 719.46, 744.49, 717.19, 729.77, 48638200],
[1609857000, 723.66, 740.84, 719.20, 735.11, 32245200],
[1609943400, 758.49, 774.00, 749.10, 755.98, 44700000],
[1610029800, 777.63, 816.99, 775.20, 816.04, 51498900],
[1610116200, 856.00, 884.49, 838.39, 880.02, 75055500],
[1610375400, 849.40, 854.43, 803.62, 811.19, 59301600],
[1610461800, 831.00, 868.00, 827.34, 849.44, 46270700],
[1610548200, 852.76, 860.47, 832.00, 854.41, 33312500],
[1610634600, 843.39, 863.00, 838.75, 845.00, 31266300],
[1610721000, 852.00, 859.90, 819.10, 826.16, 38777600],
[1611066600, 837.80, 850.00, 833.00, 844.55, 25367000],
[1611153000, 858.74, 859.50, 837.28, 850.45, 25665900],
[1611239400, 855.00, 855.72, 841.42, 844.99, 20521100],
[1611325800, 834.31, 848.00, 828.62, 846.64, 20066500],
[1611585000, 855.00, 900.40, 838.82, 880.80, 41173400],
[1611671400, 891.38, 895.90, 871.60, 883.09, 23131600],
[1611757800, 870.35, 891.50, 858.66, 864.16, 27334000],
[1611844200, 820.00, 848.00, 801.00, 835.43, 26378000],
[1611930600, 830.00, 842.41, 780.10, 793.53, 34990800],
[1612189800, 814.29, 842.00, 795.56, 839.81, 25391400],
[1612276200, 844.68, 880.50, 842.20, 872.79, 24346200],
[1612362600, 877.02, 878.08, 853.06, 854.69, 18343500],
[1612449000, 855.00, 856.50, 833.42, 849.99, 15812700],
[1612535400, 845.00, 864.77, 838.97, 852.23, 18566600],
[1612794600, 869.67, 877.77, 854.75, 863.42, 20161700],
[1612881000, 855.12, 859.80, 841.75, 849.46, 15157700],
[1612967400, 843.64, 844.82, 800.02, 804.82, 36216100],
[1613053800, 812.44, 829.88, 801.73, 811.66, 21622800],
[1613140200, 801.26, 817.33, 785.33, 816.12, 23768300],
[1613485800, 818.00, 821.00, 792.44, 796.22, 19802300],
[1613572200, 779.09, 799.84, 762.01, 798.15, 25996500],
[1613658600, 780.90, 794.69, 776.27, 787.38, 17957100],
[1613745000, 795.00, 796.79, 777.37, 781.30, 18958300],
[1614004200, 762.64, 768.50, 710.20, 714.50, 37269700],
[1614090600, 662.13, 713.61, 619.00, 698.84, 66606900],
[1614177000, 711.85, 745.00, 694.17, 742.02, 36767000],
[1614263400, 726.15, 737.21, 670.58, 682.22, 39023900],
[1614349800, 700.00, 706.70, 659.51, 675.50, 41089200],
[1614609000, 690.11, 719.00, 685.05, 718.43, 27136200],
[1614695400, 718.28, 721.11, 685.00, 686.44, 23732200],
[1614781800, 687.99, 700.70, 651.71, 653.20, 30208000],
[1614868200, 655.80, 668.45, 600.00, 621.44, 65919500],
[1614954600, 626.06, 627.84, 539.49, 597.95, 89396500],
[1615213800, 600.55, 620.13, 558.79, 563.00, 51787000],
[1615300200, 608.18, 678.09, 595.21, 673.58, 67523300],
[1615386600, 700.30, 717.85, 655.06, 668.06, 60605700],
[1615473000, 699.40, 702.50, 677.18, 699.60, 36253900],
[1615559400, 670.00, 694.88, 666.14, 693.73, 33583800],
[1615815000, 694.09, 713.18, 684.04, 707.94, 29335600],
[1615901400, 703.35, 707.92, 671.00, 676.88, 32195700],
[1615987800, 656.87, 703.73, 651.01, 701.81, 40372500],
[1616074200, 684.29, 689.23, 652.00, 653.16, 33224800],
[1616160600, 646.60, 657.23, 624.62, 654.87, 42894000],
[1616419800, 684.59, 699.62, 668.75, 670.00, 39512200],
[1616506200, 675.77, 677.80, 657.51, 662.16, 30491900],
[1616592600, 667.91, 668.02, 630.11, 630.27, 33795200],
[1616679000, 613.00, 645.50, 609.50, 640.39, 39224900],
[1616765400, 641.87, 643.82, 599.89, 618.71, 33852800],
[1617024600, 615.64, 616.48, 596.02, 611.29, 28637000],
[1617111000, 601.75, 637.66, 591.01, 635.62, 39432400],
[1617197400, 646.62, 672.00, 641.11, 667.93, 33337300],
[1617283800, 688.37, 692.42, 659.42, 661.75, 35298400],
[1617629400, 707.71, 708.16, 684.70, 691.05, 41842800],
[1617715800, 690.30, 696.55, 681.37, 691.62, 28271800],
[1617802200, 687.00, 691.38, 667.84, 670.97, 26309400],
[1617888600, 677.38, 689.55, 671.65, 683.80, 23924300],
[1617975000, 677.77, 680.97, 669.43, 677.02, 21437100],
[1618234200, 685.70, 704.80, 682.09, 701.98, 29135700],
[1618320600, 712.70, 763.00, 710.66, 762.32, 44652800],
[1618407000, 770.70, 780.79, 728.03, 732.23, 49017400],
[1618493400, 743.10, 743.69, 721.31, 738.85, 27848900],
[1618579800, 728.65, 749.41, 724.60, 739.78, 27979500],
[1618839000, 719.60, 725.40, 691.80, 714.63, 39686200],
[1618925400, 717.42, 737.25, 710.69, 718.99, 35609000],
[1619011800, 704.77, 744.84, 698.00, 744.12, 31215500],
[1619098200, 741.50, 753.77, 718.04, 719.69, 35590300],
[1619184600, 719.80, 737.36, 715.46, 729.40, 28370000],
[1619443800, 741.00, 749.30, 732.61, 738.20, 31038500],
[1619530200, 717.96, 724.00, 703.35, 704.74, 29437000],
[1619616600, 696.41, 708.50, 693.60, 694.40, 22271000],
[1619703000, 699.51, 702.25, 668.50, 677.00, 28845400],
[1619789400, 667.59, 715.47, 666.14, 709.44, 40758700],
[1620048600, 703.80, 706.00, 680.50, 684.90, 27043100],
[1620135000, 678.94, 683.45, 657.70, 673.60, 29739300],
[1620221400, 681.06, 685.30, 667.34, 670.94, 21901900],
[1620307800, 680.76, 681.02, 650.00, 663.54, 27784600],
[1620394200, 665.80, 690.00, 660.22, 672.37, 23469200],
[1620653400, 664.90, 665.05, 627.61, 629.04, 31392400],
[1620739800, 599.24, 627.10, 595.60, 617.20, 46503900],
[1620826200, 602.49, 620.41, 586.77, 589.89, 33823600],
[1620912600, 601.54, 606.46, 559.65, 571.69, 44184900],
[1620999000, 583.41, 592.87, 570.46, 589.74, 33370900],
[1621258200, 575.55, 589.73, 561.20, 576.83, 32390400],
[1621344600, 568.00, 596.25, 563.38, 577.87, 36830600],
[1621431000, 552.55, 566.21, 546.98, 563.46, 39578400],
[1621517400, 575.00, 588.85, 571.07, 586.78, 30821100],
[1621603800, 596.11, 596.68, 580.00, 580.88, 26030600],
[1621863000, 581.60, 614.48, 573.65, 606.44, 34558100],
[1621949400, 607.31, 613.99, 595.71, 604.69, 28005900],
[1622035800, 607.56, 626.17, 601.50, 619.13, 28639300],
[1622122200, 620.24, 631.13, 616.21, 630.85, 26370600],
[1622208600, 628.50, 635.59, 622.38, 625.22, 22737000],
[1622554200, 627.80, 633.80, 620.55, 623.90, 18084900],
[1622640600, 620.13, 623.36, 599.14, 605.12, 23302800],
[1622727000, 601.80, 604.55, 571.22, 572.84, 30111900],
[1622813400, 579.71, 600.61, 577.20, 599.05, 24036900],
[1623072600, 591.83, 610.00, 582.88, 605.13, 22543700],
[1623159000, 623.01, 623.09, 595.50, 603.59, 26053400],
[1623245400, 602.17, 611.79, 597.63, 598.78, 16584600],
[1623331800, 603.88, 616.59, 600.50, 610.12, 23919600],
[1623418200, 610.23, 612.56, 601.52, 609.89, 16205300],
[1623677400, 612.23, 625.49, 609.18, 617.69, 20424000],
[1623763800, 616.69, 616.79, 598.23, 599.36, 17764100],
[1623850200, 597.54, 608.50, 593.50, 604.87, 22144100],
[1623936600, 601.89, 621.47, 601.34, 616.60, 22701400],
[1624023000, 613.37, 628.35, 611.80, 623.31, 24560900],
[1624282200, 624.48, 631.39, 608.88, 620.83, 24812700],
[1624368600, 618.25, 628.57, 615.50, 623.71, 19158900],
[1624455000, 632.00, 657.20, 630.04, 656.57, 31099200],
[1624541400, 674.99, 697.62, 667.61, 679.82, 45982400],
[1624627800, 689.58, 693.81, 668.70, 671.87, 32496700],
[1624887000, 671.64, 694.70, 670.32, 688.72, 21628200],
[1624973400, 684.65, 687.51, 675.89, 680.76, 17381300],
[1625059800, 679.77, 692.81, 678.14, 679.70, 18924900],
[1625146200, 683.92, 687.99, 672.80, 677.92, 18634500],
[1625232600, 678.98, 700.00, 673.26, 678.90, 27054500],
[1625578200, 681.71, 684.00, 651.40, 659.58, 23284500],
[1625664600, 664.27, 665.70, 638.32, 644.65, 18792000],
[1625751000, 628.37, 654.43, 620.46, 652.81, 22773300],
[1625837400, 653.18, 658.91, 644.69, 656.95, 18140500],
[1626096600, 662.20, 687.24, 662.16, 685.70, 25927000],
[1626183000, 686.32, 693.28, 666.30, 668.54, 20966100],
[1626269400, 670.75, 678.61, 652.84, 653.38, 21641200],
[1626355800, 658.39, 666.14, 637.88, 650.60, 20209600],
[1626442200, 654.68, 656.70, 642.20, 644.22, 16371000],
[1626701400, 629.89, 647.20, 621.29, 646.22, 21297100],
[1626787800, 651.99, 662.39, 640.50, 660.50, 15487100],
[1626874200, 659.61, 664.86, 650.29, 655.29, 13953300],
[1626960600, 656.44, 662.17, 644.60, 649.26, 15105700],
[1627047000, 646.36, 648.80, 637.30, 643.38, 14604900],
[1627306200, 650.97, 668.20, 647.11, 657.62, 25336600],
[1627392600, 663.40, 666.50, 627.24, 644.78, 32813300],
[1627479000, 647.00, 654.97, 639.40, 646.98, 16006600],
[1627565400, 649.79, 683.69, 648.80, 677.35, 30394600],
[1627651800, 671.76, 697.53, 669.00, 687.20, 29600500],
[1627911000, 700.00, 726.94, 698.40, 709.67, 33615800],
[1627997400, 719.00, 722.65, 701.01, 709.74, 21620300],
[1628083800, 711.00, 724.90, 708.93, 710.92, 17002600],
[1628170200, 716.00, 720.95, 711.41, 714.63, 12919600],
[1628256600, 711.90, 716.33, 697.63, 699.10, 15576200],
[1628515800, 710.17, 719.03, 705.13, 713.76, 14715300],
[1628602200, 713.99, 716.59, 701.88, 709.99, 13432300],
[1628688600, 712.71, 715.18, 704.21, 707.82, 9800600],
[1628775000, 706.34, 722.80, 699.40, 722.25, 17459100],
[1628861400, 723.71, 729.90, 714.34, 717.17, 16698900],
[1629120600, 705.07, 709.50, 676.40, 686.17, 22677400],
[1629207000, 672.66, 674.58, 648.84, 665.71, 23721300],
[1629293400, 669.75, 695.77, 669.35, 688.99, 20349400],
[1629379800, 678.21, 686.55, 667.59, 673.47, 14313500],
[1629466200, 682.85, 692.13, 673.70, 680.26, 14781800],
[1629725400, 685.44, 712.13, 680.75, 706.30, 20264900],
[1629811800, 710.68, 715.22, 702.64, 708.49, 13083100],
[1629898200, 707.03, 716.97, 704.00, 711.20, 12645600],
[1629984600, 708.31, 715.40, 697.62, 701.16, 13214300],
[1630071000, 705.00, 715.00, 702.10, 711.92, 13762100],
[1630330200, 714.72, 731.00, 712.73, 730.91, 18604200],
[1630416600, 733.00, 740.39, 726.44, 735.72, 20855400],
[1630503000, 734.08, 741.99, 731.27, 734.09, 13204300],
[1630589400, 734.50, 740.97, 730.54, 732.39, 12777300],
[1630675800, 732.25, 734.00, 724.20, 733.57, 15246100],
[1631021400, 740.00, 760.20, 739.26, 752.92, 20039800],
[1631107800, 761.58, 764.45, 740.77, 753.87, 18793000],
[1631194200, 753.41, 762.10, 751.63, 754.86, 14077700],
[1631280600, 759.60, 762.61, 734.52, 736.27, 15114300],
[1631539800, 740.21, 744.78, 708.85, 743.00, 22952500],
[1631626200, 742.57, 754.47, 736.40, 744.49, 18524900],
[1631712600, 745.00, 756.86, 738.36, 755.83, 15357700],
[1631799000, 752.83, 758.91, 747.61, 756.99, 13923400],
[1631885400, 757.15, 761.04, 750.00, 759.49, 28204200],
[1632144600, 734.56, 742.00, 718.62, 730.17, 24757700],
[1632231000, 734.79, 744.74, 730.44, 739.38, 16330700],
[1632317400, 743.53, 753.67, 739.12, 751.94, 15126300],
[1632403800, 755.00, 758.20, 747.92, 753.64, 11947500],
[1632490200, 745.89, 774.80, 744.56, 774.39, 21373000],
[1632749400, 773.12, 799.00, 769.31, 791.36, 28070700],
[1632835800, 787.20, 795.64, 766.18, 777.56, 25381400],
[1632922200, 779.80, 793.50, 770.68, 781.31, 20942900],
[1633008600, 781.00, 789.13, 775.00, 775.48, 17956000],
[1633095000, 778.40, 780.78, 763.59, 775.22, 17031400],
[1633354200, 796.50, 806.97, 776.12, 781.53, 30483300],
[1633440600, 784.80, 797.31, 774.20, 780.59, 18432600],
[1633527000, 776.20, 786.66, 773.22, 782.75, 14632800],
[1633613400, 785.46, 805.00, 783.38, 793.61, 19195800],
[1633699800, 796.21, 796.38, 780.91, 785.49, 16711100],
[1633959000, 787.65, 801.24, 785.50, 791.94, 14175800],
[1634064472, 800.93, 812.32, 796.57, 811.41, 17289281],
];
static List<CandleData> get candles => _rawData
.map((row) => CandleData(
timestamp: row[0] * 1000,
open: row[1]?.toDouble(),
high: row[2]?.toDouble(),
low: row[3]?.toDouble(),
close: row[4]?.toDouble(),
volume: row[5]?.toDouble(),
))
.toList();
}

View file

@ -1,155 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_background_service/flutter_background_service.dart';
import 'package:haveno_app/main.dart';
import 'package:haveno_app/services/secure_storage_service.dart';
import 'package:haveno_app/views/desktop_lifecycle.dart';
import 'package:haveno_app/views/mobile_lifecycle.dart';
import 'package:haveno_app/views/screens/onboarding_screen.dart';
import 'package:haveno_app/views/screens/seednode_setup_screen.dart';
class HavenoApp extends StatefulWidget {
const HavenoApp({super.key});
@override
_HavenoAppState createState() => _HavenoAppState();
}
class _HavenoAppState extends State<HavenoApp> with WidgetsBindingObserver {
bool? _onboardingComplete; // Nullable
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
// Load the onboarding status asynchronously and update the state
SecureStorageService().readOnboardingStatus().then((onboardingComplete) {
setState(() {
_onboardingComplete = onboardingComplete ?? false;
});
});
}
Widget _buildAppContent() {
// Check if _onboardingComplete is null (while loading)
if (_onboardingComplete == null) {
return const Center(child: CircularProgressIndicator());
}
return MaterialApp(
debugShowCheckedModeBanner: false,
navigatorKey: navigatorKey,
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
primary: const Color(0xFFF4511E),
seedColor: const Color(0xFFF4511E),
brightness: Brightness.dark,
),
scaffoldBackgroundColor: const Color(0xFF303030),
appBarTheme: const AppBarTheme(
backgroundColor: Color(0xFF303030),
),
drawerTheme: const DrawerThemeData(
backgroundColor: Color(0xFF303030),
),
navigationBarTheme: NavigationBarThemeData(
backgroundColor: const Color(0xFF303030).withOpacity(0.5),
indicatorShape: const StadiumBorder(),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFF4511E),
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
),
),
cardTheme: const CardTheme(
color: Color(0xFF424242),
),
),
// Use _onboardingComplete to decide the home widget
home: _onboardingComplete == true ? SeedNodeSetupScreen() : OnboardingScreen(),
);
}
@override
Widget build(BuildContext context) {
if (Platform.isAndroid || Platform.isIOS) {
return MobileLifecycleWidget(
child: _buildAppContent(),
builder: (context, child) => child,
);
} else if (Platform.isMacOS || Platform.isLinux || Platform.isWindows) {
return DesktopLifecycleWidget(
child: _buildAppContent(),
builder: (context, child) => child,
);
} else {
return const Center(child: CircularProgressIndicator());
}
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
Future<void> didChangeAppLifecycleState(AppLifecycleState state) async {
switch (state) {
case AppLifecycleState.resumed:
if (Platform.isAndroid || Platform.isIOS) {
final service = FlutterBackgroundService();
bool isRunning = await service.isRunning();
if (!isRunning) {
service.startService();
}
}
print("App resumed");
break;
case AppLifecycleState.paused:
print("App paused");
break;
case AppLifecycleState.inactive:
print("App inactive");
break;
case AppLifecycleState.detached:
print("App detached");
break;
case AppLifecycleState.hidden:
print("App hidden");
break;
}
// Ensure the method always returns a Future
return Future.value();
}
}

View file

@ -0,0 +1,20 @@
import 'package:haveno/proto/compiled/grpc.pbgrpc.dart';
import 'package:haveno/services/haveno_service.dart';
class AccountServiceClient {
final AccountClient _accountClient;
AccountServiceClient(HavenoService service)
: _accountClient = service.accountClient;
Future<bool> accountExists() async {
try {
final response =
await _accountClient.accountExists(AccountExistsRequest());
return response.accountExists;
} catch (e) {
print('Caught error: $e');
rethrow;
}
}
}

File diff suppressed because one or more lines are too long

View file

@ -1,195 +1,322 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import 'dart:io';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_background_service/flutter_background_service.dart';
import 'package:haveno/haveno_client.dart';
import 'package:haveno_app/haveno_app.dart';
import 'package:haveno_app/background_services.dart';
import 'package:haveno_app/models/schema.dart';
import 'package:haveno_app/providers/haveno_client_providers/xmr_connections_provider.dart';
import 'package:haveno_app/providers/haveno_daemon_provider.dart';
import 'package:haveno_app/providers/haveno_client_providers/dispute_agents_provider.dart';
import 'package:haveno_app/providers/haveno_client_providers/disputes_provider.dart';
import 'package:haveno_app/providers/haveno_client_providers/offers_provider.dart';
import 'package:haveno_app/providers/haveno_client_providers/payment_accounts_provider.dart';
import 'package:haveno_app/providers/haveno_client_providers/price_provider.dart';
import 'package:haveno_app/providers/haveno_client_providers/trade_statistics_provider.dart';
import 'package:haveno_app/providers/haveno_providers/settings_provider.dart';
import 'package:haveno_app/providers/haveno_client_providers/trades_provider.dart';
import 'package:haveno_app/providers/haveno_client_providers/wallets_provider.dart';
import 'package:haveno_app/services/local_notification_service.dart';
import 'package:haveno_app/services/secure_storage_service.dart';
import 'package:haveno_app/system_tray.dart';
import 'package:haveno_app/versions.dart';
import 'package:provider/provider.dart';
import 'package:haveno_app/providers/haveno_client_providers/version_provider.dart';
import 'package:haveno_app/providers/haveno_client_providers/account_provider.dart';
import 'dart:async';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:flutter_socks_proxy/socks_proxy.dart';
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
import 'package:flutter/material.dart';
import 'package:haveno/providers/offers_provider.dart';
import 'package:haveno/providers/payment_accounts_provider.dart';
import 'package:haveno/providers/prices_provider.dart';
import 'package:haveno/providers/trades_provider.dart';
import 'package:haveno/providers/wallets_provider.dart';
import 'package:haveno/screens/drawer/payment_accounts_screen.dart';
import 'package:haveno/screens/drawer/settings_screen.dart';
import 'package:haveno/tabs/trades_tab.dart';
import 'package:haveno/tabs/buy_tab.dart';
import 'package:haveno/tabs/sell_tab.dart';
import 'package:haveno/screens/drawer/wallet_screen.dart';
import 'package:logging/logging.dart';
import 'package:path_provider/path_provider.dart';
import 'package:provider/provider.dart';
import 'package:haveno/services/haveno_service.dart';
import 'package:haveno/services/http_service.dart';
import 'package:haveno/services/monero_service.dart';
import 'package:haveno/providers/get_version_provider.dart';
import 'package:haveno/providers/account_provider.dart';
import 'dart:async';
import 'package:badges/badges.dart' as badges;
//import 'package:tor/tor.dart'; // Import the badges package
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Versions().load();
// Initialize event dispatcher
final eventDispatcher = EventDispatcher();
// Initialize the tor status service
//final torStatusService = TorStatusService();
//torStatusService.startListening(eventDispatcher);
// Initialise the tor log service
//final torLogService = TorLogService();
//torLogService.startListening(eventDispatcher);
// Initializt notifications
await LocalNotificationsService().init();
// Set the default for desktop (overrites later when connected for mobile)
if (!Platform.isIOS) {
SocksProxy.initProxy(proxy: 'SOCKS5 127.0.0.1:9050');
}
// Start Orbot on iOS
//if (Platform.isIOS) {
// await OrbotApi().startOrbot();
//}
// Setup logging
_setupLogging();
if (Platform.isLinux || Platform.isMacOS || Platform.isWindows) {
intializeSystemTray();
}
final httpService = HttpService();
final moneroService = MoneroService();
// Setup background/foreground services (for fetching data for notifications and state updates in SQL)
if (Platform.isIOS || Platform.isAndroid) {
FlutterBackgroundService? mobileBackgroundService;
mobileBackgroundService = FlutterBackgroundService();
final havenoService = HavenoService('192.168.0.72', 3201, 'apitest');
// Start the background service listener
final backgroundServiceListener = BackgroundServiceListener(eventDispatcher);
backgroundServiceListener.startListening();
runApp(
MultiProvider(
providers: [
//Provider(create: (_) => torService),
Provider(create: (_) => httpService),
Provider(create: (_) => moneroService),
Provider(create: (_) => havenoService),
ChangeNotifierProvider(
create: (context) => GetVersionProvider(havenoService),
),
ChangeNotifierProvider(
create: (context) => AccountProvider(havenoService),
),
ChangeNotifierProvider(
create: (context) => WalletsProvider(havenoService),
),
ChangeNotifierProvider(
create: (context) => OffersProvider(havenoService),
),
ChangeNotifierProvider(
create: (context) => TradesProvider(havenoService),
),
ChangeNotifierProvider(
create: (context) => PaymentAccountsProvider(havenoService),
),
ChangeNotifierProvider(
create: (context) => PricesProvider(havenoService),
),
],
child: MyApp(),
),
);
}
await mobileBackgroundService.configure(
iosConfiguration: IosConfiguration(
autoStart: true,
//onForeground: onStart,
onBackground: onIosBackground,
Future<void> _setupLogging() async {
Logger.root.level = Level.ALL; // Capture all log levels
// Get the application documents directory
final directory = await getApplicationDocumentsDirectory();
final logFile = File('${directory.path}/app.log');
// Setup the logger to write to the file and print to console
Logger.root.onRecord.listen((record) {
final logMessage =
'${record.level.name}: ${record.time}: ${record.loggerName}: ${record.message}\n';
logFile.writeAsStringSync(logMessage,
mode: FileMode.append, flush: true); // Ensure it's flushed to file
print(logMessage); // Also print to console
});
}
final Logger _logger = Logger('Haveno');
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
primary: Color(0xFFF4511E),
seedColor: Color(0xFFF4511E), // Reddish-orange primary color
brightness: Brightness.dark,
// Ensures dark mode with light text
),
scaffoldBackgroundColor: Color(0xFF303030),
appBarTheme: const AppBarTheme(
backgroundColor: Color(0xFF303030),
),
drawerTheme: const DrawerThemeData(
backgroundColor: Color(0xFF303030),
),
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
backgroundColor: Color(0xFF303030),
selectedItemColor: Color(0xFFF4511E),
unselectedItemColor: Colors.white,
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFFF4511E), // Button background color
foregroundColor: Colors.white, // Button text color
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5), // Button border radius
),
),
),
cardTheme: const CardTheme(
color: Color(0xFF424242), // Card background color
),
),
androidConfiguration: AndroidConfiguration(
autoStart: true,
onStart: onStart,
isForegroundMode: true,
autoStartOnBoot: true,
home: HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
String _statusMessage = "Connecting to Tor...";
Timer? _timer;
int _selectedIndex = 0;
int _notificationCount = 5; // Mock notification count
static final List<Widget> _widgetOptions = <Widget>[
BuyTab(),
SellTab(),
TradesTab(),
];
@override
void initState() {
super.initState();
// final torService = context.read<TorService>();
// torService.statusStream.listen((String status) {
// print(status);
// setState(() {
// if (status.contains("started")) {
// _statusMessage = "Connecting to the Monero network...";
// } else {
// _statusMessage = status;
// }
// });
// });
_initializeServices();
}
Future<void> _initializeServices() async {
try {
await context.read<GetVersionProvider>().fetchVersion();
await context.read<AccountProvider>().checkAccountExists();
} catch (e) {
setState(() {
_statusMessage = "Initialization failed: ${e.toString()}";
});
}
}
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
Future<void> checkMoneroConnection() async {
try {
final info = await context.read<MoneroService>().getInfo();
setState(() {
_statusMessage =
"Connected to Monero Mainnet (via Tor) at block ${info['height']}";
});
} catch (e) {
setState(() {
_statusMessage =
"Failed to connect to the Monero network: ${e.toString()}";
});
}
}
@override
void dispose() {
//context.read<TorService>().dispose();
context.read<HttpService>().close();
context.read<MoneroService>().close();
_timer?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: AppBar(
title: const Text('Haveno'),
actions: [
Padding(
padding: const EdgeInsets.only(right: 15.0), // Adjust padding to move the bell and badge
child: badges.Badge(
position: badges.BadgePosition.topEnd(top: 5, end: 5),
badgeContent: Text(
'$_notificationCount',
style: TextStyle(color: Colors.white, fontSize: 10),
),
child: IconButton(
icon: Icon(Icons.notifications),
onPressed: () {
// Handle notification bell tap
},
),
),
),
],
),
drawer: _buildDrawer(context),
body: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
bottomNavigationBar: NavigationBar(
selectedIndex: _selectedIndex,
onDestinationSelected: _onItemTapped,
destinations: const <NavigationDestination>[
NavigationDestination(
icon: Icon(Icons.shopping_cart),
label: 'Buy',
),
NavigationDestination(
icon: Icon(Icons.sell),
label: 'Sell',
),
NavigationDestination(
icon: Icon(Icons.swap_vert),
label: 'Trades',
),
],
),
);
}
final secureStorageService = SecureStorageService();
final havenoChannel = HavenoChannel();
await SentryFlutter.init((options) {
options.dsn =
'https://ddf883d1a885ae8d619a923d1c80350f@o4507901830299648.ingest.us.sentry.io/4507901840457728';
options.tracesSampleRate = 1.0;
options.profilesSampleRate = 1.0;
if (Platform.isAndroid || Platform.isIOS) {
options.proxy = SentryProxy(type: SentryProxyType.socks, host: '127.0.0.1', port: 9050);
} else {
options.proxy = SentryProxy(type: SentryProxyType.socks, host: '127.0.0.1', port: 9066);
}
},
appRunner: () => runApp(
MultiProvider(
providers: [
Provider(create: (_) => havenoChannel),
//ChangeNotifierProvider(
// create: (context) => TorStatusProvider(torStatusService),
//),
//ChangeNotifierProvider(
// create: (context) => TorLogProvider(torLogService),
//),
ChangeNotifierProvider(
create: (context) =>
HavenoDaemonProvider(secureStorageService),
),
ChangeNotifierProvider(
create: (context) => SettingsProvider(secureStorageService),
),
ChangeNotifierProvider(
create: (context) => GetVersionProvider(havenoChannel),
),
ChangeNotifierProvider(
create: (context) => AccountProvider(),
),
ChangeNotifierProvider(
create: (context) => WalletsProvider(havenoChannel),
),
ChangeNotifierProvider(
create: (context) => OffersProvider(havenoChannel),
),
ChangeNotifierProvider(
create: (context) => TradesProvider(havenoChannel),
),
ChangeNotifierProvider(
create: (context) => PaymentAccountsProvider(havenoChannel),
),
ChangeNotifierProvider(
create: (context) => PricesProvider(havenoChannel),
),
ChangeNotifierProvider(
create: (context) => TradeStatisticsProvider(havenoChannel),
),
ChangeNotifierProvider(
create: (context) => DisputesProvider(),
),
ChangeNotifierProvider(
create: (context) => DisputeAgentsProvider(),
),
ChangeNotifierProvider(
create: (context) => XmrConnectionsProvider(),
),
],
child: HavenoApp(),
Widget _buildDrawer(BuildContext context) {
return Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Center(
child: Image.asset(
'assets/haveno-logo.png',
height: 60,
),
),
));
}
@pragma('vm:entry-point')
Future<bool> onIosBackground(ServiceInstance service) async {
WidgetsFlutterBinding.ensureInitialized();
DartPluginRegistrant.ensureInitialized();
startShortLivedBackgroundFetch(service);
return true;
}
@pragma('vm:entry-point')
void onStart(ServiceInstance service) async {
WidgetsFlutterBinding.ensureInitialized();
startLongRunningForegroundService(service);
decoration: BoxDecoration(
color: Color(0xFF303030), // Header background color
),
),
ListTile(
leading: Icon(Icons.account_balance_wallet, color: Colors.white),
title: Text('Wallet', style: TextStyle(color: Colors.white)),
onTap: () {
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(builder: (context) => WalletScreen()),
);
},
),
ListTile(
leading: Icon(Icons.account_circle, color: Colors.white),
title:
Text('Payment Accounts', style: TextStyle(color: Colors.white)),
onTap: () {
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(builder: (context) => PaymentAccountsScreen()),
);
},
),
ListTile(
leading: Icon(Icons.settings, color: Colors.white),
title: Text('Settings', style: TextStyle(color: Colors.white)),
onTap: () {
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SettingsScreen()),
);
},
),
ListTile(
leading: Icon(Icons.sync, color: Colors.white),
title: Text('Daemons', style: TextStyle(color: Colors.white)),
onTap: () {
// Handle logout
},
),
],
),
);
}
}

View file

@ -1,138 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/* import 'dart:convert';
import 'package:fixnum/fixnum.dart';
import 'package:haveno_app/proto/compiled/pb.pb.dart';
class CandlestickData {
final int timestamp;
final int open;
final int high;
final int low;
final int close;
final int volume;
CandlestickData({
required this.timestamp,
required this.open,
required this.high,
required this.low,
required this.close,
required this.volume,
});
}
Future<List<CandlestickData>> getCandlestickData(String period) async {
final db = await instance.database;
// Determine the start and end timestamps for the specified period
int startTime;
int endTime;
DateTime now = DateTime.now();
switch (period.toLowerCase()) {
case 'daily':
startTime = DateTime(now.year, now.month, now.day).millisecondsSinceEpoch;
endTime = DateTime(now.year, now.month, now.day + 1).millisecondsSinceEpoch - 1;
break;
case 'weekly':
startTime = DateTime(now.year, now.month, now.day - now.weekday + 1).millisecondsSinceEpoch;
endTime = DateTime(now.year, now.month, now.day - now.weekday + 8).millisecondsSinceEpoch - 1;
break;
case 'monthly':
startTime = DateTime(now.year, now.month, 1).millisecondsSinceEpoch;
endTime = DateTime(now.year, now.month + 1, 1).millisecondsSinceEpoch - 1;
break;
case 'yearly':
startTime = DateTime(now.year, 1, 1).millisecondsSinceEpoch;
endTime = DateTime(now.year + 1, 1, 1).millisecondsSinceEpoch - 1;
break;
default:
throw ArgumentError('Invalid period specified: $period');
}
// Query the database for trade statistics within the specified period
final List<Map<String, dynamic>> maps = await db.query(
'trade_statistics',
where: 'date >= ? AND date <= ?',
whereArgs: [startTime, endTime],
);
// Group the trade statistics by the period and calculate OHLC data
Map<int, List<TradeStatistics3>> groupedData = {};
for (var map in maps) {
final tradeStatisticJson = map['data'];
final tradeStatistic = TradeStatistics3.create()
..mergeFromProto3Json(jsonDecode(tradeStatisticJson));
// Determine the period timestamp (e.g., start of the day, week, etc.)
DateTime date = DateTime.fromMillisecondsSinceEpoch(tradeStatistic.date.toInt());
int periodTimestamp;
switch (period.toLowerCase()) {
case 'daily':
periodTimestamp = DateTime(date.year, date.month, date.day).millisecondsSinceEpoch;
break;
case 'weekly':
periodTimestamp = DateTime(date.year, date.month, date.day - date.weekday + 1).millisecondsSinceEpoch;
break;
case 'monthly':
periodTimestamp = DateTime(date.year, date.month, 1).millisecondsSinceEpoch;
break;
case 'yearly':
periodTimestamp = DateTime(date.year, 1, 1).millisecondsSinceEpoch;
break;
default:
throw ArgumentError('Invalid period specified: $period');
}
groupedData.putIfAbsent(periodTimestamp, () => []).add(tradeStatistic);
}
// Calculate OHLC data for each group
List<CandlestickData> candlestickData = groupedData.entries.map((entry) {
final trades = entry.value;
final sortedTrades = trades..sort((a, b) => a.date.compareTo(b.date));
Int64 open = sortedTrades.first.price;
Int64 close = sortedTrades.last.price;
Int64 high = sortedTrades.map((trade) => trade.price).reduce((a, b) => a > b ? a : b);
Int64 low = sortedTrades.map((trade) => trade.price).reduce((a, b) => a < b ? a : b);
Int64 volume = sortedTrades.map((trade) => trade.amount).reduce((a, b) => a + b);
return CandlestickData(
timestamp: entry.key,
open: open.toInt(),
high: open.,
high: ,
low: low,
close: close,
volume: volume,
);
}).toList();
return candlestickData;
}
*/

View file

@ -1,48 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
//
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
class HavenoNetwork {
final String name;
final String description;
HavenoNetwork({
required this.name,
required this.description,
});
Map<String, dynamic> toJson() {
return {
'name': name,
'description': description,
};
}
factory HavenoNetwork.fromJson(Map<String, dynamic> json) {
return HavenoNetwork(
name: json['name'],
description: json['description'],
);
}
factory HavenoNetwork.getDefault() {
return HavenoNetwork(
name: '',
description: 'A new Haveno network',
);
}
}

View file

@ -1,17 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
//
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

View file

@ -1,20 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

View file

@ -1,57 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
//
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import 'package:haveno_app/models/haveno/p2p/haveno_network';
class HavenoSeedNode {
final String onionHost;
final int port;
final HavenoNetwork network;
HavenoSeedNode({
required this.onionHost,
required this.port,
required this.network,
}) {
_validateOnionAddress(onionHost);
}
static void _validateOnionAddress(String host) {
final pattern = RegExp(r'^[a-zA-Z0-9]{56}\.onion$');
if (!pattern.hasMatch(host)) {
throw const FormatException('Invalid v3 onion address');
}
}
Map<String, dynamic> toJson() {
return {
'onionHost': onionHost,
'port': port,
'network': network.toJson(),
};
}
factory HavenoSeedNode.fromJson(Map<String, dynamic> json) {
return HavenoSeedNode(
onionHost: json['onionHost'],
port: json['port'],
network: HavenoNetwork.fromJson(json['network']),
);
}
}

View file

@ -1,83 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
class HavenoDaemonConfig {
final String host;
final int port;
final String clientAuthPassword;
final Uri fullUri;
bool isVerified; // Has had at least one successful GRPC call
HavenoDaemonConfig({
required this.fullUri,
String? clientAuthPassword,
}) : clientAuthPassword = clientAuthPassword ?? _parsePassword(fullUri),
host = _parseHost(fullUri),
port = _parsePort(fullUri),
isVerified = false {
_validateOnionAddress(fullUri);
}
static String _parseHost(Uri uri) {
return uri.host;
}
static int _parsePort(Uri uri) {
return uri.hasPort ? uri.port : 80;
}
static String _parsePassword(Uri uri) {
final password = uri.queryParameters['password'];
if (password == null) {
throw const FormatException('Missing password query parameter');
}
return password;
}
static void _validateOnionAddress(Uri uri) {
final pattern = RegExp(r'^[a-zA-Z0-9]{56}\.onion$');
if (!pattern.hasMatch(uri.host)) {
throw const FormatException('Invalid v3 onion address');
}
}
void setVerified(bool verified) {
isVerified = verified;
}
Map<String, dynamic> toJson() {
return {
'host': host,
'port': port,
'fullUri': fullUri.toString(),
'clientAuthPassword': clientAuthPassword,
'isVerified': isVerified
};
}
factory HavenoDaemonConfig.fromJson(Map<String, dynamic> json) {
return HavenoDaemonConfig(
fullUri: Uri.parse(json['fullUri']),
clientAuthPassword: json['clientAuthPassword'],
);
}
}

View file

@ -1,24 +1,3 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
class MoneroNode {
final int adjustedTime;
final int altBlocksCount;

View file

@ -1,248 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:haveno/grpc_models.dart';
import 'package:haveno/profobuf_models.dart';
import 'package:shared_preferences/shared_preferences.dart';
abstract class DeviceManagerAutoInitialization {
Future<void> init();
}
abstract class PollingProvider with ChangeNotifier {
Timer? _timer;
bool _isPolling = false;
final Duration maxPollingInterval;
PollingProvider(this.maxPollingInterval);
// Method to be implemented by subclasses to define the polling action
Future<void> pollAction();
// Method to start polling with a custom interval
void startPolling([Duration? interval]) {
if (_isPolling) return; // Prevent multiple polling tasks
_isPolling = true;
_timer = Timer.periodic(interval ?? maxPollingInterval, (Timer t) async {
await pollAction();
});
}
// Method to stop polling
void stopPolling() {
_timer?.cancel();
_isPolling = false;
}
@override
void dispose() {
stopPolling();
super.dispose();
}
}
class SyncTask {
final Future<void> Function() taskFunction;
final Duration cooldown;
final List<SyncTask> dependencies;
DateTime _lastRun;
SyncTask({
required this.taskFunction,
required this.cooldown,
this.dependencies = const [], // Default to no dependencies
}) : _lastRun = DateTime.fromMillisecondsSinceEpoch(0); // Initialize to a time far in the past
bool shouldRun() {
// Check if all dependencies have been run
bool dependenciesMet = dependencies.every((task) => task.hasRun);
// Check if cooldown period has passed and dependencies are met
return dependenciesMet && DateTime.now().difference(_lastRun) >= cooldown;
}
Future<void> run() async {
if (shouldRun()) {
await taskFunction();
_lastRun = DateTime.now();
}
}
bool get hasRun => _lastRun.isAfter(DateTime.fromMillisecondsSinceEpoch(0));
}
class SyncManager {
final List<SyncTask> _tasks = [];
final Duration checkInterval;
Timer? _timer;
SyncManager({required this.checkInterval});
void addTask(SyncTask task) {
_tasks.add(task);
}
void start() {
_timer = Timer.periodic(checkInterval, (timer) async {
// Iterate over tasks, making sure dependencies are resolved
for (var task in _tasks) {
await task.run();
}
});
}
void stop() {
_timer?.cancel();
}
}
mixin CooldownMixin {
final Map<String, Duration> _cooldownDurations = {};
// Initialize cooldown durations
void setCooldownDurations(Map<String, Duration> durations) {
_cooldownDurations.addAll(durations);
}
// Check if the cooldown is valid by comparing the current time with the stored last run time
Future<bool> isCooldownValid(String key) async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
final lastRunTimestamp = prefs.getInt('cooldown_$key');
if (lastRunTimestamp == null) return false; // No previous run recorded, so it's invalid.
final lastRunTime = DateTime.fromMillisecondsSinceEpoch(lastRunTimestamp);
final duration = _cooldownDurations[key] ?? const Duration(minutes: 5);
return DateTime.now().isBefore(lastRunTime.add(duration)); // Valid if current time is before cooldown expires.
}
// Update the cooldown with the current time and store it in shared_preferences
Future<void> updateCooldown(String key) async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
final now = DateTime.now();
final duration = _cooldownDurations[key] ?? const Duration(minutes: 5); // Default to 5 minutes if not defined
final cooldownEndTime = now.add(duration);
await prefs.setInt('cooldown_$key', cooldownEndTime.millisecondsSinceEpoch); // Store the expiration time
}
// Optionally, you can add a method to clear cooldowns for testing or reset purposes
Future<void> clearCooldown(String key) async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.remove('cooldown_$key');
}
}
abstract class PlatformLifecycleWidget extends StatefulWidget {
final Widget child;
final Widget Function(BuildContext context, Widget child) builder;
const PlatformLifecycleWidget({
super.key,
required this.child,
required this.builder,
});
}
abstract class PlatformLifecycleState<T extends PlatformLifecycleWidget> extends State<T> {
Future<void> initPlatform();
@override
void initState() {
super.initState();
initPlatform();
}
@override
Widget build(BuildContext context) {
return widget.builder(context, widget.child);
}
}
enum BackgroundEventType {
updateTorStatus,
updateDaemonStatus,
torStdOutLog,
torStdErrLog,
}
class BackgroundEvent {
final BackgroundEventType type;
final Map<String, dynamic> data;
BackgroundEvent({required this.type, required this.data});
}
class EventDispatcher {
final Map<BackgroundEventType, List<Function(Map<String, dynamic>)>> _listeners = {};
void subscribe(BackgroundEventType eventType, Function(Map<String, dynamic>) callback) {
_listeners[eventType] ??= [];
_listeners[eventType]!.add(callback);
}
void unsubscribe(BackgroundEventType eventType, Function(Map<String, dynamic>) callback) {
_listeners[eventType]?.remove(callback);
}
void dispatch(BackgroundEvent event) {
if (_listeners[event.type] != null) {
for (var listener in _listeners[event.type]!) {
listener(event.data);
}
}
}
}
mixin StreamListenerProviderMixin on ChangeNotifier {
StreamSubscription? _subscription;
// A helper function to manage stream subscriptions
void listenToStream(Stream<void> stream, VoidCallback onData) {
_subscription = stream.listen((_) {
onData(); // Perform action when data arrives (e.g., notifyListeners)
});
}
@override
void dispose() {
_subscription?.cancel();
super.dispose();
}
}
// Notification callbacks
typedef NewChatMessageCallback = void Function(ChatMessage chatMessage);
typedef TradeUpdateCallback = void Function(TradeInfo trade, bool isNewTrade);
// Background service callbacks
typedef UpdateTorStatusBackgroundCallback = void Function(String status, String detail);
typedef UpdateDaemonStatusBackgroundCallback = void Function(String status, String detail);
typedef TorStdOutLogBackgroundCallback = void Function(String details);
typedef TorStdErrLogBackgroundCallback = void Function(String details);

View file

@ -1,377 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import 'dart:async';
import 'dart:io';
import 'package:archive/archive_io.dart';
import 'package:flutter/services.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';
abstract class SystemProcess {
final String key;
final String displayName;
final String? bundleAssetKey;
final String? windowsInstallationPath;
final String? linuxInstallationPath;
final String? macOsInstallationPath;
final bool useInstallationPathAsWorkingDirectory;
final String? windowsExecutableName;
final String? linuxExecutableName;
final String? macOsExecutableName;
final bool startOnLaunch;
final String versionMinor;
final String versionMajor;
List<String>? executionArgs = [''];
final Uri downloadUrl;
final bool runAsDaemon;
final int? internalPort;
final int? externalPort;
final bool installedByDistribution;
final String? pidFilePath;
Process? process;
String? processStartPath;
SystemProcess(
{required this.key,
required this.displayName,
required this.bundleAssetKey,
required this.windowsInstallationPath,
required this.linuxInstallationPath,
required this.macOsInstallationPath,
required this.useInstallationPathAsWorkingDirectory,
required this.windowsExecutableName,
required this.linuxExecutableName,
required this.macOsExecutableName,
required this.startOnLaunch,
required this.versionMinor,
required this.versionMajor,
required this.executionArgs,
required this.downloadUrl,
required this.runAsDaemon,
required this.internalPort,
required this.externalPort,
required this.installedByDistribution,
required this.pidFilePath});
Future<Directory> getApplicationDirectory() async {
Directory appDir = await getApplicationSupportDirectory();
if (Platform.isWindows) {
appDir = Directory('${appDir.path}\\$key');
} else if (Platform.isMacOS) {
appDir = Directory('${appDir.path}/$key');
} else if (Platform.isLinux) {
appDir = Directory('${appDir.path}/$key');
}
if (!await appDir.exists()) {
await appDir.create(recursive: true);
}
return appDir;
}
String? get executableName {
if (Platform.isWindows) {
return windowsExecutableName;
} else if (Platform.isLinux) {
return linuxExecutableName;
} else if (Platform.isMacOS) {
return macOsExecutableName;
} else {
throw Exception("Operating system not supported for this service.");
}
}
String? get installationPath {
if (Platform.isWindows) {
return windowsInstallationPath;
} else if (Platform.isLinux) {
return linuxInstallationPath;
} else if (Platform.isMacOS) {
return macOsInstallationPath;
} else {
throw Exception("Operating system not supported for this service.");
}
}
Future<bool> isInstalled() async {
print("Is installed was called");
final directory = await getApplicationDirectory();
final defaultSystemProcessDirectory = path.join(directory.path, key);
String executablePath;
if (Platform.isWindows) {
executablePath = windowsInstallationPath != null &&
windowsInstallationPath!.isNotEmpty
? path.join(windowsInstallationPath!, windowsExecutableName!)
: path.join(defaultSystemProcessDirectory, windowsExecutableName!);
} else if (Platform.isLinux) {
executablePath =
linuxInstallationPath != null && linuxInstallationPath!.isNotEmpty
? path.join(linuxInstallationPath!, linuxExecutableName!)
: path.join(defaultSystemProcessDirectory, linuxExecutableName!);
} else if (Platform.isMacOS) {
executablePath =
macOsInstallationPath != null && macOsInstallationPath!.isNotEmpty
? path.join(macOsInstallationPath!, macOsExecutableName!)
: path.join(defaultSystemProcessDirectory, macOsExecutableName!);
} else {
throw Exception("Operating system not supported for this service.");
}
print("Path to system process $executablePath");
return File(executablePath).existsSync();
}
Future<bool> install() async {
if (installedByDistribution) {
throw Exception(
"Installation is not supported where installed by distribution, you may try to upgrade.");
}
if (downloadUrl.toString().isNotEmpty ||
(bundleAssetKey != null && bundleAssetKey!.isNotEmpty)) {
String? specifiedInstallPath;
if (Platform.isWindows) {
if (windowsInstallationPath != null &&
windowsInstallationPath!.isNotEmpty) {
specifiedInstallPath = windowsInstallationPath;
}
} else if (Platform.isMacOS) {
if (macOsInstallationPath != null &&
macOsInstallationPath!.isNotEmpty) {
specifiedInstallPath = macOsInstallationPath;
}
} else if (Platform.isLinux) {
if (linuxInstallationPath != null &&
linuxInstallationPath!.isNotEmpty) {
specifiedInstallPath = linuxInstallationPath;
}
}
final Directory installPath;
if (specifiedInstallPath == null || specifiedInstallPath.isEmpty) {
final directory = await getApplicationDirectory();
final defaultInstallPath = path.join(directory.path, key);
installPath = Directory(defaultInstallPath);
} else {
installPath = Directory(specifiedInstallPath);
}
final filePath = path.join(installPath.path, executableName!);
// Check if the main executable already exists
final file = File(filePath);
if (file.existsSync()) {
print('$displayName is already installed.');
print('Main executable was found at $filePath');
throw Exception("Already installed");
} else {
// Either download or extract from rootBundle
if (downloadUrl.isScheme('HTTP') || downloadUrl.isScheme('HTTPS')) {
// Handle file download (you need to implement this part)
await _downloadAndExtractFile(downloadUrl, installPath);
} else if (bundleAssetKey != null && bundleAssetKey!.isNotEmpty) {
await _extractAssetBundle(bundleAssetKey!, installPath);
}
}
} else {
throw Exception("No source or remote file defined for install");
}
return true;
}
Future<void> _downloadAndExtractFile(
Uri downloadUrl, Directory installPath) async {
// Implement the download and extraction logic
}
Future<void> _extractAssetBundle(
String assetKey, Directory installPath) async {
ByteData byteData;
try {
byteData = await rootBundle.load(assetKey);
} catch (e) {
throw Exception(
"Invalid bundle asset key supplied, the file could not be found. $e");
}
String? archiveType;
if (assetKey.endsWith('.zip')) {
archiveType = 'ZIP';
} else if (assetKey.endsWith('.7z')) {
throw Exception("The installer cannot support .7z files currently");
} else if (assetKey.endsWith('.tar.gz')) {
archiveType = 'TARGZ';
}
if (archiveType != null) {
await _extractArchive(byteData, archiveType, installPath);
} else {
await _writeSingleFile(byteData, installPath, path.basename(assetKey));
}
}
Future<void> _extractArchive(
ByteData byteData, String archiveType, Directory installPath) async {
if (archiveType == 'ZIP') {
final archive = ZipDecoder().decodeBytes(byteData.buffer
.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes));
extractArchiveToDisk(archive, installPath.absolute.path);
} else if (archiveType == 'TARGZ') {
final tarBytes = GZipDecoder().decodeBytes(byteData.buffer
.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes));
final archive = TarDecoder().decodeBytes(tarBytes);
extractArchiveToDisk(archive, installPath.absolute.path);
} else {
throw Exception("Unsupported archive type: $archiveType");
}
}
Future<void> _writeSingleFile(
ByteData byteData, Directory installPath, String fileName) async {
final file = File(path.join(installPath.path, fileName));
try {
await file.writeAsBytes(byteData.buffer
.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes));
print("Successfully installed ${file.absolute.path}");
} catch (e) {
print(
"Failed to write a single binary file as bytes to the installation path ${file.absolute.path}");
rethrow;
}
}
Future<void> update() async {
// #TODO
}
Future<Process?> start() async {
print("$displayName service is starting...");
final defaultApplicationDirectory = await getApplicationDirectory();
final defaultSystemProcessDirectory = defaultApplicationDirectory.path;
process = null;
File pidFile;
if (Platform.isWindows) {
if (windowsInstallationPath != null &&
windowsInstallationPath!.isNotEmpty &&
windowsExecutableName != null) {
processStartPath =
path.join(windowsInstallationPath!, windowsExecutableName!);
if (useInstallationPathAsWorkingDirectory) {
process = await Process.start(processStartPath!, executionArgs!,
mode: ProcessStartMode.detachedWithStdio,
workingDirectory: windowsInstallationPath);
} else {
process = await Process.start(processStartPath!, executionArgs!,
mode: ProcessStartMode.detachedWithStdio);
}
pidFile = File(path.join(windowsInstallationPath!, "$key.pid"));
await pidFile.writeAsString(process!.pid.toString());
} else {
processStartPath =
path.join(defaultSystemProcessDirectory, windowsExecutableName!);
if (useInstallationPathAsWorkingDirectory) {
process = await Process.start(processStartPath!, executionArgs!,
mode: ProcessStartMode.detachedWithStdio,
workingDirectory: defaultSystemProcessDirectory);
} else {
process = await Process.start(processStartPath!, executionArgs!,
mode: ProcessStartMode.detachedWithStdio);
}
pidFile = File(path.join(defaultSystemProcessDirectory, "$key.pid"));
await pidFile.writeAsString(process!.pid.toString());
}
} else if (Platform.isLinux) {
if (linuxInstallationPath != null &&
linuxInstallationPath!.isNotEmpty &&
linuxExecutableName != null) {
processStartPath =
path.join(linuxInstallationPath!, linuxExecutableName!);
if (useInstallationPathAsWorkingDirectory) {
process = await Process.start(processStartPath!, executionArgs!,
mode: ProcessStartMode.detachedWithStdio,
workingDirectory: linuxInstallationPath);
} else {
process = await Process.start(processStartPath!, executionArgs!,
mode: ProcessStartMode.detachedWithStdio);
}
pidFile = File(path.join(linuxInstallationPath!, "$key.pid"));
await pidFile.writeAsString(process!.pid.toString());
} else {
processStartPath =
path.join(defaultSystemProcessDirectory, linuxExecutableName!);
if (useInstallationPathAsWorkingDirectory) {
process = await Process.start(processStartPath!, executionArgs!,
mode: ProcessStartMode.detachedWithStdio,
workingDirectory: defaultSystemProcessDirectory);
} else {
process = await Process.start(processStartPath!, executionArgs!,
mode: ProcessStartMode.detachedWithStdio);
}
pidFile = File(path.join(defaultSystemProcessDirectory, "$key.pid"));
await pidFile.writeAsString(process!.pid.toString());
}
} else if (Platform.isMacOS) {
if (macOsInstallationPath != null &&
macOsInstallationPath!.isNotEmpty &&
macOsExecutableName != null) {
processStartPath =
path.join(macOsInstallationPath!, macOsExecutableName!);
if (useInstallationPathAsWorkingDirectory) {
process = await Process.start(processStartPath!, executionArgs!,
mode: ProcessStartMode.detachedWithStdio,
workingDirectory: macOsInstallationPath);
} else {
process = await Process.start(processStartPath!, executionArgs!,
mode: ProcessStartMode.detachedWithStdio);
}
pidFile = File(path.join(macOsInstallationPath!, "$key.pid"));
await pidFile.writeAsString(process!.pid.toString());
} else {
processStartPath =
path.join(defaultSystemProcessDirectory, macOsExecutableName!);
if (useInstallationPathAsWorkingDirectory) {
process = await Process.start(processStartPath!, executionArgs!,
mode: ProcessStartMode.normal,
workingDirectory: defaultSystemProcessDirectory);
} else {
process = await Process.start(processStartPath!, executionArgs!,
mode: ProcessStartMode.normal);
}
pidFile = File(path.join(defaultSystemProcessDirectory, "$key.pid"));
await pidFile.writeAsString(process!.pid.toString());
}
} else {
throw Exception(
"Operating system not supported for running this service, desktops only.");
}
if (process != null) {
print(
"The start script for $displayName was created with PID ${process?.pid.toString()} using command '$processStartPath ${executionArgs!.join(' ').trimRight()}'");
return process;
} else {
print("The process for $displayName was not created");
return null;
}
}
}

View file

@ -1,181 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import 'dart:io';
import 'package:haveno_app/utils/nssm_manager.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as path;
import 'base_system_process.dart';
class HavenoDaemonSystemProcess extends SystemProcess {
final String? password;
HavenoDaemonSystemProcess({this.password})
: super(
key: 'Haveno Daemon',
displayName: 'Haveno Daemon',
bundleAssetKey: '', // Specify the correct asset path here
windowsInstallationPath:
'', // Define specific installation paths if required
linuxInstallationPath:
'', // Define specific installation paths if required
macOsInstallationPath:
'', // Define specific installation paths if required
useInstallationPathAsWorkingDirectory: true,
windowsExecutableName: 'daemon-all.jar',
linuxExecutableName: 'daemon-all.jar',
macOsExecutableName: 'daemon-all.jar',
startOnLaunch: true,
versionMinor: '0.17.1.9',
versionMajor: '0.17',
executionArgs: [
'--baseCurrencyNetwork=XMR_STAGENET',
'--useLocalhostForP2P=false',
'--useDevPrivilegeKeys=false',
'--nodePort=9999',
'--apiPort=3201',
'--appName=haveno_app_stagenet',
'--useNativeXmrWallet=false',
'--torControlHost=127.0.0.1',
'--torControlPort=9077',
'--torControlPassword=boner',
'--appDataDir=data/'
],
downloadUrl: Uri.parse(''), // Specify the download URL if required
runAsDaemon: true,
internalPort: 9050,
externalPort: null,
installedByDistribution: false,
pidFilePath: null) {
if (password != null && password!.isNotEmpty) {
executionArgs!.add('--apiPassword=$password');
//executionArgs!.add('--passwordRequired=true');
} else {
//executionArgs!.add('--passwordRequired=false');
}
}
@override
Future<Process?> start() async {
print("$displayName service is starting...");
final defaultApplicationDirectory = await getApplicationDirectory();
final defaultSystemProcessDirectory = defaultApplicationDirectory.path;
process = null;
File? javaBinaryFile = await getJavaBinaryDirectory();
File? havenoDaemonJarFile = await getHavenoDaemonJarFile();
if (javaBinaryFile == null) {
print("The java binary file was not found, cannot start the daemon");
return null;
}
if (havenoDaemonJarFile == null) {
print(
"The haveno daemon file was not found, cannot start the daemon.");
return null;
}
// Get the paths
String javaPath = javaBinaryFile.path;
String jarPath = havenoDaemonJarFile.path;
Map<String, String> environment = {
'JAVA_HOME': path.dirname(path.dirname(javaPath)),
'PATH': Platform.environment['PATH'] ?? '',
};
if (Platform.isWindows) {
Directory appSupportDirectory = await getApplicationSupportDirectory();
String nssmPath = path.join(appSupportDirectory.path, 'nssm.exe');
print("We are trying to load NSSM from: $nssmPath");
var nssmManager = NSSMServiceManager(nssmPath);
try {
await nssmManager.setServiceParameters('HavenoPlusDaemonService',
['-jar', '"$jarPath"', ...executionArgs!]);
print("Set service parameters for HavenoPlusDaemonService");
await Future.delayed(Duration(seconds: 2));
await nssmManager.serviceStop('HavenoPlusDaemonService');
// Wait 5 seconds
await Future.delayed(Duration(seconds: 2)); // Added wait period
await nssmManager.serviceStart('HavenoPlusDaemonService');
print("Restarted HavenoPlusDaemonService");
} catch (e) {
print("Error setting service parameters or restarting: $e");
}
return null;
}
if (Platform.isLinux) {
process = await Process.start(
javaPath,
['-jar', jarPath, ...executionArgs!],
mode: ProcessStartMode.normal,
environment: environment,
);
} else if (Platform.isMacOS) {
process = await Process.start(
javaPath,
['-jar', jarPath, ...executionArgs!],
mode: ProcessStartMode.normal,
workingDirectory: defaultSystemProcessDirectory,
environment: environment,
);
}
return process;
}
Future<void> stop() async {
if (Platform.isWindows) {
Directory appSupportDirectory = await getApplicationSupportDirectory();
String nssmPath = path.join(appSupportDirectory.path, 'nssm.exe');
await NSSMServiceManager(nssmPath).serviceStop('HavenoPlusDaemonService');
}
}
Future<File?> getJavaBinaryDirectory() async {
Directory appSupportDirectory = await getApplicationSupportDirectory();
File javaBinaryFile;
if (Platform.isWindows) {
javaBinaryFile = File(path.join(
appSupportDirectory.path, 'Java', 'jdk-21.0.4', 'bin', 'java.exe'));
} else if (Platform.isMacOS) {
javaBinaryFile = File(path.join(appSupportDirectory.path, 'Java',
'21.0.4+7', 'Contents', 'Home', 'bin', 'java'));
} else if (Platform.isLinux) {
return null;
} else {
return null;
}
return await javaBinaryFile.exists() ? javaBinaryFile : null;
}
Future<File?> getHavenoDaemonJarFile() async {
Directory havenoHomeDirectory = await getApplicationDirectory();
String havenoJarFile = path.join(havenoHomeDirectory.path, executableName);
File file = File(havenoJarFile);
return await file.exists() ? file : null;
}
}

View file

@ -1,48 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import 'base_system_process.dart';
class JavaSystemProcess extends SystemProcess {
JavaSystemProcess()
: super(
key: 'Java',
displayName: 'Java',
bundleAssetKey: null,
windowsInstallationPath: '',
linuxInstallationPath: '',
macOsInstallationPath: '',
useInstallationPathAsWorkingDirectory: false,
windowsExecutableName: 'java.exe',
linuxExecutableName: 'java',
macOsExecutableName: 'java',
startOnLaunch: false,
versionMinor: '21.0.4+7',
versionMajor: '21',
executionArgs: [''],
downloadUrl: Uri.parse(''), // Add the appropriate download URL if needed
runAsDaemon: false,
internalPort: null,
externalPort: null,
installedByDistribution: true,
pidFilePath: null
);
}

View file

@ -1,48 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import 'base_system_process.dart';
class TorSystemProcess extends SystemProcess {
TorSystemProcess()
: super(
key: 'Tor',
displayName: 'Tor Daemon',
bundleAssetKey: '', // Specify the correct asset path here
windowsInstallationPath: '', // Define specific installation paths if required
linuxInstallationPath: '', // Define specific installation paths if required
macOsInstallationPath: '', // Define specific installation paths if required
useInstallationPathAsWorkingDirectory: true, // Assuming the working directory should be the installation path
windowsExecutableName: 'tor.exe',
linuxExecutableName: 'tor',
macOsExecutableName: 'tor',
startOnLaunch: true,
versionMinor: '0.17.1.9',
versionMajor: '0.17',
executionArgs: ['-f', 'torrc'],
downloadUrl: Uri.parse(''), // Specify the download URL if required
runAsDaemon: true,
internalPort: 9050,
externalPort: null,
installedByDistribution: true,
pidFilePath: 'tor.pid'
);
}

View file

@ -1,54 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import 'package:cryptography/cryptography.dart';
class HSV3OnionConfig {
final List<int> privateKeyBytes;
final SimplePublicKey publicKey;
final int internalPort;
final int externalPort;
HSV3OnionConfig(
{required this.privateKeyBytes,
required this.publicKey,
required this.internalPort,
required this.externalPort});
get privateKey => null;
Map<String, dynamic> toJson() {
return {
'privateKeyBytes': privateKeyBytes,
'publicKey': publicKey,
'internalPort': internalPort,
'externalPort': externalPort
};
}
factory HSV3OnionConfig.fromJson(Map<String, dynamic> json) {
return HSV3OnionConfig(
privateKeyBytes: json['privateKeyBytes'],
publicKey: json['publicKey'],
internalPort: json['internalPort'],
externalPort: json['externalPortal']);
}
}

View file

@ -1,75 +0,0 @@
// Haveno App extends the features of Haveno, supporting mobile devices and more.
// Copyright (C) 2024 Kewbit (https://kewbit.org)
// Source Code: https://git.haveno.com/haveno/haveno-app.git
//
// Author: Kewbit
// Website: https://kewbit.org
// Contact Email: me@kewbit.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
class TorDaemonConfig {
final String host;
final int controlPort;
final List<int> socks5ProxyPorts;
final List<int> httpProxyPorts;
final String? hashedPassword;
TorDaemonConfig({
required this.host,
required this.controlPort,
this.socks5ProxyPorts = const [9050],
this.httpProxyPorts = const [8118],
this.hashedPassword,
}) {
_validateOnionAddress(host);
}
static void _validateOnionAddress(String host) {
print(host);
final pattern = RegExp(r'^[a-zA-Z0-9]{56}\.onion$');
if (!pattern.hasMatch(host)) {
throw const FormatException('Invalid v3 onion address');
}
}
Map<String, dynamic> toJson() {
return {
'host': host,
'controlPort': controlPort,
'socks5ProxyPorts': socks5ProxyPorts,
'httpProxyPorts': httpProxyPorts,
'hashedPassword': hashedPassword,
};
}
factory TorDaemonConfig.fromJson(Map<String, dynamic> json) {
return TorDaemonConfig(
host: json['host'],
controlPort: json['controlPort'],
socks5ProxyPorts: List<int>.from(json['socks5ProxyPorts'] ?? [9050]),
httpProxyPorts: List<int>.from(json['httpProxyPorts'] ?? [8118]),
hashedPassword: json['hashedPassword'],
);
}
factory TorDaemonConfig.getDefault() {
return TorDaemonConfig(
host: '127.0.0.1',
controlPort: 9051,
socks5ProxyPorts: [9050],
httpProxyPorts: [8118],
);
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,90 @@
//
// Generated code. Do not modify.
// source: grpc.proto
//
// @dart = 2.12
// ignore_for_file: annotate_overrides, camel_case_types, comment_references
// ignore_for_file: constant_identifier_names, library_prefixes
// ignore_for_file: non_constant_identifier_names, prefer_final_fields
// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
import 'dart:core' as $core;
import 'package:protobuf/protobuf.dart' as $pb;
class NotificationMessage_NotificationType extends $pb.ProtobufEnum {
static const NotificationMessage_NotificationType ERROR = NotificationMessage_NotificationType._(0, _omitEnumNames ? '' : 'ERROR');
static const NotificationMessage_NotificationType APP_INITIALIZED = NotificationMessage_NotificationType._(1, _omitEnumNames ? '' : 'APP_INITIALIZED');
static const NotificationMessage_NotificationType KEEP_ALIVE = NotificationMessage_NotificationType._(2, _omitEnumNames ? '' : 'KEEP_ALIVE');
static const NotificationMessage_NotificationType TRADE_UPDATE = NotificationMessage_NotificationType._(3, _omitEnumNames ? '' : 'TRADE_UPDATE');
static const NotificationMessage_NotificationType CHAT_MESSAGE = NotificationMessage_NotificationType._(4, _omitEnumNames ? '' : 'CHAT_MESSAGE');
static const $core.List<NotificationMessage_NotificationType> values = <NotificationMessage_NotificationType> [
ERROR,
APP_INITIALIZED,
KEEP_ALIVE,
TRADE_UPDATE,
CHAT_MESSAGE,
];
static final $core.Map<$core.int, NotificationMessage_NotificationType> _byValue = $pb.ProtobufEnum.initByValue(values);
static NotificationMessage_NotificationType? valueOf($core.int value) => _byValue[value];
const NotificationMessage_NotificationType._($core.int v, $core.String n) : super(v, n);
}
class UrlConnection_OnlineStatus extends $pb.ProtobufEnum {
static const UrlConnection_OnlineStatus UNKNOWN = UrlConnection_OnlineStatus._(0, _omitEnumNames ? '' : 'UNKNOWN');
static const UrlConnection_OnlineStatus ONLINE = UrlConnection_OnlineStatus._(1, _omitEnumNames ? '' : 'ONLINE');
static const UrlConnection_OnlineStatus OFFLINE = UrlConnection_OnlineStatus._(2, _omitEnumNames ? '' : 'OFFLINE');
static const $core.List<UrlConnection_OnlineStatus> values = <UrlConnection_OnlineStatus> [
UNKNOWN,
ONLINE,
OFFLINE,
];
static final $core.Map<$core.int, UrlConnection_OnlineStatus> _byValue = $pb.ProtobufEnum.initByValue(values);
static UrlConnection_OnlineStatus? valueOf($core.int value) => _byValue[value];
const UrlConnection_OnlineStatus._($core.int v, $core.String n) : super(v, n);
}
class UrlConnection_AuthenticationStatus extends $pb.ProtobufEnum {
static const UrlConnection_AuthenticationStatus NO_AUTHENTICATION = UrlConnection_AuthenticationStatus._(0, _omitEnumNames ? '' : 'NO_AUTHENTICATION');
static const UrlConnection_AuthenticationStatus AUTHENTICATED = UrlConnection_AuthenticationStatus._(1, _omitEnumNames ? '' : 'AUTHENTICATED');
static const UrlConnection_AuthenticationStatus NOT_AUTHENTICATED = UrlConnection_AuthenticationStatus._(2, _omitEnumNames ? '' : 'NOT_AUTHENTICATED');
static const $core.List<UrlConnection_AuthenticationStatus> values = <UrlConnection_AuthenticationStatus> [
NO_AUTHENTICATION,
AUTHENTICATED,
NOT_AUTHENTICATED,
];
static final $core.Map<$core.int, UrlConnection_AuthenticationStatus> _byValue = $pb.ProtobufEnum.initByValue(values);
static UrlConnection_AuthenticationStatus? valueOf($core.int value) => _byValue[value];
const UrlConnection_AuthenticationStatus._($core.int v, $core.String n) : super(v, n);
}
/// Rpc method GetTrades parameter determining what category of trade list is is being requested.
class GetTradesRequest_Category extends $pb.ProtobufEnum {
static const GetTradesRequest_Category OPEN = GetTradesRequest_Category._(0, _omitEnumNames ? '' : 'OPEN');
static const GetTradesRequest_Category CLOSED = GetTradesRequest_Category._(1, _omitEnumNames ? '' : 'CLOSED');
static const GetTradesRequest_Category FAILED = GetTradesRequest_Category._(2, _omitEnumNames ? '' : 'FAILED');
static const $core.List<GetTradesRequest_Category> values = <GetTradesRequest_Category> [
OPEN,
CLOSED,
FAILED,
];
static final $core.Map<$core.int, GetTradesRequest_Category> _byValue = $pb.ProtobufEnum.initByValue(values);
static GetTradesRequest_Category? valueOf($core.int value) => _byValue[value];
const GetTradesRequest_Category._($core.int v, $core.String n) : super(v, n);
}
const _omitEnumNames = $core.bool.fromEnvironment('protobuf.omit_enum_names');

Some files were not shown because too many files have changed in this diff Show more