mirror of
https://github.com/lil-org/tokenary.git
synced 2025-01-07 14:10:28 +03:00
Merge pull request #69 from zeriontech/feature/safari-requests-queue
Safari requests queue
This commit is contained in:
commit
9970ad1977
@ -17,7 +17,6 @@ extension SafariRequest {
|
||||
case watchAsset
|
||||
case addEthereumChain
|
||||
case switchEthereumChain
|
||||
case switchAccount
|
||||
}
|
||||
|
||||
let method: Method
|
||||
@ -53,7 +52,7 @@ extension SafariRequest {
|
||||
|
||||
var responseUpdatesStoredConfiguration: Bool {
|
||||
switch method {
|
||||
case .switchEthereumChain, .addEthereumChain, .requestAccounts, .switchAccount:
|
||||
case .switchEthereumChain, .addEthereumChain, .requestAccounts:
|
||||
return true
|
||||
case .ecRecover, .signMessage, .signPersonalMessage, .signTransaction, .signTypedMessage, .watchAsset:
|
||||
return false
|
||||
|
@ -4,8 +4,7 @@ browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||
if (request.subject === "message-to-wallet") {
|
||||
browser.runtime.sendNativeMessage("mac.tokenary.io", request.message, function(response) {
|
||||
sendResponse(response);
|
||||
browser.tabs.update(sender.tab.id, { active: true });
|
||||
didCompleteRequest(request.message.id);
|
||||
didCompleteRequest(request.message.id, sender.tab.id);
|
||||
storeConfigurationIfNeeded(request.host, response);
|
||||
});
|
||||
} else if (request.subject === "getResponse") {
|
||||
|
File diff suppressed because one or more lines are too long
@ -105,7 +105,6 @@ class TokenaryEthereum extends EventEmitter {
|
||||
}
|
||||
|
||||
enable() {
|
||||
console.log('enable() is deprecated, please use window.ethereum.request({method: "eth_requestAccounts"}) instead.');
|
||||
if (!window.ethereum.address) { // avoid double accounts request in uniswap
|
||||
return this.request({ method: "eth_requestAccounts", params: [] });
|
||||
} else {
|
||||
@ -154,7 +153,7 @@ class TokenaryEthereum extends EventEmitter {
|
||||
}
|
||||
|
||||
_request(payload, wrapResult = true) {
|
||||
this.idMapping.tryIntifyId(payload);
|
||||
this.idMapping.tryFixId(payload);
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!payload.id) {
|
||||
payload.id = Utils.genId();
|
||||
|
@ -6,26 +6,21 @@
|
||||
import Utils from "./utils";
|
||||
|
||||
class IdMapping {
|
||||
|
||||
constructor() {
|
||||
this.intIds = new Map;
|
||||
}
|
||||
|
||||
tryIntifyId(payload) {
|
||||
tryFixId(payload) {
|
||||
if (!payload.id) {
|
||||
payload.id = Utils.genId();
|
||||
return;
|
||||
}
|
||||
if (typeof payload.id !== "number") {
|
||||
this.intIds.set(payload.id, payload.id);
|
||||
} else if (typeof payload.id !== "number" || this.intIds.has(payload.id) ) {
|
||||
let newId = Utils.genId();
|
||||
this.intIds.set(newId, payload.id);
|
||||
payload.id = newId;
|
||||
}
|
||||
}
|
||||
|
||||
tryRestoreId(payload) {
|
||||
let id = this.tryPopId(payload.id);
|
||||
if (id) {
|
||||
payload.id = id;
|
||||
} else {
|
||||
this.intIds.set(payload.id, payload.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ window.dispatchEvent(new Event('ethereum#initialized'));
|
||||
// - MARK: Solana
|
||||
|
||||
window.solana = new TokenarySolana();
|
||||
window.tokenarySolana = window.solana;
|
||||
window.phantom = {solana: window.solana};
|
||||
window.dispatchEvent(new Event("solana#initialized"));
|
||||
|
||||
|
@ -57,6 +57,7 @@ class TokenaryNear extends EventEmitter {
|
||||
}
|
||||
|
||||
request(payload) {
|
||||
this.idMapping.tryFixId(payload);
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!payload.id) {
|
||||
payload.id = Utils.genId();
|
||||
|
@ -59,8 +59,12 @@ class TokenarySolana extends EventEmitter {
|
||||
this.pendingPayloads = [];
|
||||
}
|
||||
|
||||
connect() {
|
||||
return this.request({method: "connect"});
|
||||
connect(params) {
|
||||
var payload = {method: "connect"};
|
||||
if (typeof params !== "undefined") {
|
||||
payload.params = params;
|
||||
}
|
||||
return this.request(payload);
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
@ -104,7 +108,7 @@ class TokenarySolana extends EventEmitter {
|
||||
}
|
||||
|
||||
request(payload) {
|
||||
this.idMapping.tryIntifyId(payload);
|
||||
this.idMapping.tryFixId(payload);
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!payload.id) {
|
||||
payload.id = Utils.genId();
|
||||
@ -143,7 +147,12 @@ class TokenarySolana extends EventEmitter {
|
||||
switch (payload.method) {
|
||||
case "connect":
|
||||
if (!this.publicKey) {
|
||||
return this.postMessage("connect", payload.id, {});
|
||||
if ("params" in payload && "onlyIfTrusted" in payload.params && payload.params.onlyIfTrusted) {
|
||||
this.sendError(payload.id, "Click a button to connect");
|
||||
return;
|
||||
} else {
|
||||
return this.postMessage("connect", payload.id, {});
|
||||
}
|
||||
} else {
|
||||
this.isConnected = true;
|
||||
this.emitConnect(this.publicKey);
|
||||
|
@ -1,6 +1,7 @@
|
||||
// Copyright © 2022 Tokenary. All rights reserved.
|
||||
|
||||
function didCompleteRequest(id) {
|
||||
function didCompleteRequest(id, tabId) {
|
||||
browser.tabs.update(tabId, { active: true });
|
||||
const request = {id: id, subject: "didCompleteRequest"};
|
||||
browser.runtime.sendNativeMessage("mac.tokenary.io", request);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Copyright © 2022 Tokenary. All rights reserved.
|
||||
|
||||
function didCompleteRequest(id) {
|
||||
function didCompleteRequest(id, tabId) {
|
||||
|
||||
}
|
||||
|
@ -11,6 +11,8 @@ enum EthereumChain: Int {
|
||||
case avalanche = 43114
|
||||
case gnosisChain = 100
|
||||
case fantomOpera = 250
|
||||
case celo = 42220
|
||||
case aurora = 1313161554
|
||||
|
||||
// Testnets
|
||||
case arbitrumRinkeby = 421611
|
||||
@ -34,7 +36,7 @@ enum EthereumChain: Int {
|
||||
return "0x" + String(id, radix: 16, uppercase: false)
|
||||
}
|
||||
|
||||
static let allMainnets: [EthereumChain] = [.ethereum, .polygon, .optimism, .binance, .arbitrum, .avalanche, .gnosisChain, .fantomOpera]
|
||||
static let allMainnets: [EthereumChain] = [.ethereum, .polygon, .optimism, .binance, .arbitrum, .avalanche, .gnosisChain, .fantomOpera, .celo, .aurora]
|
||||
static let allTestnets: [EthereumChain] = [.ethereumRopsten, .ethereumKovan, .ethereumRinkeby, .ethereumGoerli, .optimisticKovan, .arbitrumKovan, .arbitrumRinkeby, .polygonMumbai, .binanceTestnet, .avalancheFuji, .fantomTestnet, .neonDevnet]
|
||||
|
||||
var name: String {
|
||||
@ -47,6 +49,8 @@ enum EthereumChain: Int {
|
||||
case .avalanche: return "Avalanche"
|
||||
case .gnosisChain: return "Gnosis Chain"
|
||||
case .fantomOpera: return "Fantom Opera"
|
||||
case .celo: return "Celo"
|
||||
case .aurora: return "Aurora"
|
||||
|
||||
case .arbitrumRinkeby: return "Arbitrum Rinkeby"
|
||||
case .optimisticKovan: return "Optimistic Kovan"
|
||||
@ -69,7 +73,7 @@ enum EthereumChain: Int {
|
||||
return "BNB"
|
||||
case .polygon, .polygonMumbai:
|
||||
return "MATIC"
|
||||
case .arbitrum, .arbitrumKovan, .arbitrumRinkeby, .ethereum, .ethereumGoerli, .ethereumKovan, .ethereumRinkeby, .optimism, .optimisticKovan, .ethereumRopsten:
|
||||
case .arbitrum, .arbitrumKovan, .arbitrumRinkeby, .ethereum, .ethereumGoerli, .ethereumKovan, .ethereumRinkeby, .optimism, .optimisticKovan, .ethereumRopsten, .aurora:
|
||||
return "ETH"
|
||||
case .avalanche, .avalancheFuji:
|
||||
return "AVAX"
|
||||
@ -77,6 +81,8 @@ enum EthereumChain: Int {
|
||||
return "xDai"
|
||||
case .fantomOpera, .fantomTestnet:
|
||||
return "FTM"
|
||||
case .celo:
|
||||
return "CELO"
|
||||
case .neonDevnet:
|
||||
return "NEON"
|
||||
}
|
||||
@ -105,6 +111,8 @@ enum EthereumChain: Int {
|
||||
case .avalanche: return "https://api.avax.network/ext/bc/C/rpc"
|
||||
case .gnosisChain: return "https://rpc.gnosischain.com/"
|
||||
case .fantomOpera: return "https://rpc.ftm.tools/"
|
||||
case .celo: return "https://rpc.ankr.com/celo"
|
||||
case .aurora: return "https://mainnet.aurora.dev"
|
||||
|
||||
case .arbitrumRinkeby: return "https://rinkeby.arbitrum.io/rpc"
|
||||
case .arbitrumKovan: return "https://kovan5.arbitrum.io/rpc"
|
||||
|
@ -6,6 +6,7 @@ import WalletCore
|
||||
enum DappRequestAction {
|
||||
case none
|
||||
case justShowApp
|
||||
case switchAccount(SelectAccountAction)
|
||||
case selectAccount(SelectAccountAction)
|
||||
case approveMessage(SignMessageAction)
|
||||
case approveTransaction(SendTransactionAction)
|
||||
|
@ -51,7 +51,7 @@ struct DappRequestProcessor {
|
||||
respond(to: request, error: Strings.canceled, completion: completion)
|
||||
}
|
||||
}
|
||||
return .selectAccount(action)
|
||||
return .switchAccount(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -193,7 +193,7 @@ struct DappRequestProcessor {
|
||||
lazy var account = getAccount(coin: .ethereum, address: ethereumRequest.address)
|
||||
|
||||
switch ethereumRequest.method {
|
||||
case .switchAccount, .requestAccounts:
|
||||
case .requestAccounts:
|
||||
let action = SelectAccountAction(provider: .ethereum) { chain, wallet, account in
|
||||
if let chain = chain, let address = wallet?.ethereumAddress, account?.coin == .ethereum {
|
||||
let responseBody = ResponseToExtension.Ethereum(results: [address], chainId: chain.hexStringId, rpcURL: chain.nodeURLString)
|
||||
|
@ -151,7 +151,7 @@ class AccountsListViewController: UIViewController, DataStateContainer {
|
||||
switch action {
|
||||
case .none, .justShowApp:
|
||||
break
|
||||
case .selectAccount(let action):
|
||||
case .selectAccount(let action), .switchAccount(let action):
|
||||
let selectAccountViewController = instantiate(AccountsListViewController.self, from: .main)
|
||||
selectAccountViewController.onSelectedWallet = action.completion
|
||||
presentForSafariRequest(selectAccountViewController.inNavigationController, id: request.id)
|
||||
|
@ -54,13 +54,13 @@ class Agent: NSObject {
|
||||
self?.hasPassword = true
|
||||
self?.showInitialScreen(externalRequest: externalRequest)
|
||||
}
|
||||
let windowController = Window.showNew()
|
||||
let windowController = Window.showNew(closeOthers: true)
|
||||
windowController.contentViewController = welcomeViewController
|
||||
return
|
||||
}
|
||||
|
||||
guard didEnterPasswordOnStart else {
|
||||
askAuthentication(on: nil, onStart: true, reason: .start) { [weak self] success in
|
||||
askAuthentication(on: nil, browser: nil, onStart: true, reason: .start) { [weak self] success in
|
||||
if success {
|
||||
self?.didEnterPasswordOnStart = true
|
||||
self?.showInitialScreen(externalRequest: externalRequest)
|
||||
@ -76,22 +76,22 @@ class Agent: NSObject {
|
||||
if case let .safari(request) = request {
|
||||
processSafariRequest(request)
|
||||
} else {
|
||||
let windowController = Window.showNew()
|
||||
let accountsList = instantiate(AccountsListViewController.self)
|
||||
|
||||
if case let .wcSession(session) = request {
|
||||
accountsList.onSelectedWallet = onSelectedWallet(session: session)
|
||||
}
|
||||
|
||||
let windowController = Window.showNew(closeOthers: accountsList.onSelectedWallet == nil)
|
||||
windowController.contentViewController = accountsList
|
||||
}
|
||||
}
|
||||
|
||||
func showApprove(transaction: Transaction, chain: EthereumChain, peerMeta: PeerMeta?, completion: @escaping (Transaction?) -> Void) {
|
||||
let windowController = Window.showNew()
|
||||
let approveViewController = ApproveTransactionViewController.with(transaction: transaction, chain: chain, peerMeta: peerMeta) { [weak self] transaction in
|
||||
func showApprove(windowController: NSWindowController, browser: Browser?, transaction: Transaction, chain: EthereumChain, peerMeta: PeerMeta?, completion: @escaping (Transaction?) -> Void) {
|
||||
let window = windowController.window
|
||||
let approveViewController = ApproveTransactionViewController.with(transaction: transaction, chain: chain, peerMeta: peerMeta) { [weak self, weak window] transaction in
|
||||
if transaction != nil {
|
||||
self?.askAuthentication(on: windowController.window, onStart: false, reason: .sendTransaction) { success in
|
||||
self?.askAuthentication(on: window, browser: browser, onStart: false, reason: .sendTransaction) { success in
|
||||
completion(success ? transaction : nil)
|
||||
}
|
||||
} else {
|
||||
@ -101,13 +101,13 @@ class Agent: NSObject {
|
||||
windowController.contentViewController = approveViewController
|
||||
}
|
||||
|
||||
func showApprove(subject: ApprovalSubject, meta: String, peerMeta: PeerMeta?, completion: @escaping (Bool) -> Void) {
|
||||
let windowController = Window.showNew()
|
||||
let approveViewController = ApproveViewController.with(subject: subject, meta: meta, peerMeta: peerMeta) { [weak self] result in
|
||||
func showApprove(windowController: NSWindowController, browser: Browser?, subject: ApprovalSubject, meta: String, peerMeta: PeerMeta?, completion: @escaping (Bool) -> Void) {
|
||||
let window = windowController.window
|
||||
let approveViewController = ApproveViewController.with(subject: subject, meta: meta, peerMeta: peerMeta) { [weak self, weak window] result in
|
||||
if result {
|
||||
self?.askAuthentication(on: windowController.window, onStart: false, reason: subject.asAuthenticationReason) { success in
|
||||
self?.askAuthentication(on: window, getBackTo: window?.contentViewController, browser: browser, onStart: false, reason: subject.asAuthenticationReason) { success in
|
||||
completion(success)
|
||||
(windowController.contentViewController as? ApproveViewController)?.enableWaiting()
|
||||
(window?.contentViewController as? ApproveViewController)?.enableWaiting()
|
||||
}
|
||||
} else {
|
||||
completion(result)
|
||||
@ -116,11 +116,6 @@ class Agent: NSObject {
|
||||
windowController.contentViewController = approveViewController
|
||||
}
|
||||
|
||||
func showErrorMessage(_ message: String) {
|
||||
let windowController = Window.showNew()
|
||||
windowController.contentViewController = ErrorViewController.withMessage(message)
|
||||
}
|
||||
|
||||
func getWalletSelectionCompletionIfShouldSelect() -> ((EthereumChain?, TokenaryWallet?, Account?) -> Void)? {
|
||||
let session = getSessionFromPasteboard()
|
||||
return onSelectedWallet(session: session)
|
||||
@ -221,7 +216,7 @@ class Agent: NSObject {
|
||||
guard let session = session else { return nil }
|
||||
return { [weak self] chain, wallet, account in
|
||||
guard let chain = chain, let wallet = wallet, account?.coin == .ethereum else {
|
||||
Window.closeAllAndActivateBrowser(force: nil)
|
||||
Window.closeAllAndActivateBrowser(specific: nil)
|
||||
return
|
||||
}
|
||||
self?.connectWallet(session: session, chainId: chain.id, wallet: wallet)
|
||||
@ -250,19 +245,21 @@ class Agent: NSObject {
|
||||
showInitialScreen(externalRequest: request)
|
||||
}
|
||||
|
||||
func askAuthentication(on: NSWindow?, getBackTo: NSViewController? = nil, onStart: Bool, reason: AuthenticationReason, completion: @escaping (Bool) -> Void) {
|
||||
func askAuthentication(on: NSWindow?, getBackTo: NSViewController? = nil, browser: Browser?, onStart: Bool, reason: AuthenticationReason, completion: @escaping (Bool) -> Void) {
|
||||
let context = LAContext()
|
||||
var error: NSError?
|
||||
let policy = LAPolicy.deviceOwnerAuthenticationWithBiometrics
|
||||
let canDoLocalAuthentication = context.canEvaluatePolicy(policy, error: &error)
|
||||
|
||||
func showPasswordScreen() {
|
||||
let window = on ?? Window.showNew().window
|
||||
let window = on ?? Window.showNew(closeOthers: onStart).window
|
||||
let passwordViewController = PasswordViewController.with(mode: .enter, reason: reason) { [weak window] success in
|
||||
if let getBackTo = getBackTo {
|
||||
window?.contentViewController = getBackTo
|
||||
} else if let browser = browser {
|
||||
Window.closeWindowAndActivateNext(idToClose: window?.windowNumber, specificBrowser: browser)
|
||||
} else {
|
||||
Window.closeAll()
|
||||
Window.closeWindow(idToClose: window?.windowNumber)
|
||||
}
|
||||
completion(success)
|
||||
}
|
||||
@ -287,36 +284,50 @@ class Agent: NSObject {
|
||||
}
|
||||
|
||||
private func connectWallet(session: WCSession, chainId: Int, wallet: TokenaryWallet) {
|
||||
let windowController = Window.showNew()
|
||||
let windowController = Window.showNew(closeOthers: true)
|
||||
let window = windowController.window
|
||||
windowController.contentViewController = WaitingViewController.withReason(Strings.connecting)
|
||||
|
||||
walletConnect.connect(session: session, chainId: chainId, walletId: wallet.id) { [weak window] _ in
|
||||
if window?.isVisible == true {
|
||||
Window.closeAllAndActivateBrowser(force: nil)
|
||||
Window.closeAllAndActivateBrowser(specific: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func processSafariRequest(_ safariRequest: SafariRequest) {
|
||||
var windowNumber: Int?
|
||||
let action = DappRequestProcessor.processSafariRequest(safariRequest) {
|
||||
Window.closeAllAndActivateBrowser(force: .safari)
|
||||
Window.closeWindowAndActivateNext(idToClose: windowNumber, specificBrowser: .safari)
|
||||
}
|
||||
|
||||
switch action {
|
||||
case .none:
|
||||
break
|
||||
case .selectAccount(let action):
|
||||
let windowController = Window.showNew()
|
||||
case .selectAccount(let accountAction), .switchAccount(let accountAction):
|
||||
let closeOtherWindows: Bool
|
||||
if case .selectAccount = action {
|
||||
closeOtherWindows = false
|
||||
} else {
|
||||
closeOtherWindows = true
|
||||
}
|
||||
|
||||
let windowController = Window.showNew(closeOthers: closeOtherWindows)
|
||||
windowNumber = windowController.window?.windowNumber
|
||||
let accountsList = instantiate(AccountsListViewController.self)
|
||||
accountsList.onSelectedWallet = action.completion
|
||||
accountsList.onSelectedWallet = accountAction.completion
|
||||
windowController.contentViewController = accountsList
|
||||
case .approveMessage(let action):
|
||||
showApprove(subject: action.subject, meta: action.meta, peerMeta: action.peerMeta, completion: action.completion)
|
||||
let windowController = Window.showNew(closeOthers: false)
|
||||
windowNumber = windowController.window?.windowNumber
|
||||
showApprove(windowController: windowController, browser: .safari, subject: action.subject, meta: action.meta, peerMeta: action.peerMeta, completion: action.completion)
|
||||
case .approveTransaction(let action):
|
||||
showApprove(transaction: action.transaction, chain: action.chain, peerMeta: action.peerMeta, completion: action.completion)
|
||||
let windowController = Window.showNew(closeOthers: false)
|
||||
windowNumber = windowController.window?.windowNumber
|
||||
showApprove(windowController: windowController, browser: .safari, transaction: action.transaction, chain: action.chain, peerMeta: action.peerMeta, completion: action.completion)
|
||||
case .justShowApp:
|
||||
let windowController = Window.showNew()
|
||||
let windowController = Window.showNew(closeOthers: true)
|
||||
windowNumber = windowController.window?.windowNumber
|
||||
let accountsList = instantiate(AccountsListViewController.self)
|
||||
windowController.contentViewController = accountsList
|
||||
}
|
||||
|
@ -679,7 +679,7 @@
|
||||
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
|
||||
<customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="173" y="-44"/>
|
||||
<point key="canvasLocation" x="158" y="-43"/>
|
||||
</scene>
|
||||
<!--Window Controller-->
|
||||
<scene sceneID="R2V-B0-nI4">
|
||||
@ -1218,75 +1218,6 @@ DQ
|
||||
</objects>
|
||||
<point key="canvasLocation" x="75" y="1188"/>
|
||||
</scene>
|
||||
<!--Error View Controller-->
|
||||
<scene sceneID="LSi-74-yAS">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="ErrorViewController" id="Os3-h2-6sc" customClass="ErrorViewController" customModule="Tokenary" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" id="cFH-jd-zLP">
|
||||
<rect key="frame" x="0.0" y="0.0" width="250" height="350"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="T7q-cN-jjc">
|
||||
<rect key="frame" x="14" y="292" width="222" height="34"/>
|
||||
<textFieldCell key="cell" controlSize="large" alignment="center" title="Error" id="t7e-cO-oeN">
|
||||
<font key="font" metaFont="systemHeavy" size="29"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<stackView distribution="fill" orientation="horizontal" alignment="top" spacing="12" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="owz-dg-x2C">
|
||||
<rect key="frame" x="106" y="32" width="39" height="28"/>
|
||||
<subviews>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="bRK-Tb-oKu">
|
||||
<rect key="frame" x="-6" y="-6" width="51" height="40"/>
|
||||
<buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" controlSize="large" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="xDk-iz-zcw">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<string key="keyEquivalent" base64-UTF8="YES">
|
||||
DQ
|
||||
</string>
|
||||
<connections>
|
||||
<action selector="actionButtonTapped:" target="Os3-h2-6sc" id="1PU-4O-ljb"/>
|
||||
</connections>
|
||||
</buttonCell>
|
||||
</button>
|
||||
</subviews>
|
||||
<visibilityPriorities>
|
||||
<integer value="1000"/>
|
||||
</visibilityPriorities>
|
||||
<customSpacing>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
</customSpacing>
|
||||
</stackView>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="M1Q-Iu-4dD">
|
||||
<rect key="frame" x="34" y="175" width="182" height="25"/>
|
||||
<textFieldCell key="cell" controlSize="large" selectable="YES" alignment="center" title="Failed to connect" id="qy3-O0-p56">
|
||||
<font key="font" metaFont="systemBold" size="21"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="owz-dg-x2C" firstAttribute="centerX" secondItem="cFH-jd-zLP" secondAttribute="centerX" id="0OK-ZZ-1lf"/>
|
||||
<constraint firstItem="T7q-cN-jjc" firstAttribute="leading" secondItem="cFH-jd-zLP" secondAttribute="leading" constant="16" id="0mu-SM-Kvn"/>
|
||||
<constraint firstAttribute="trailing" secondItem="T7q-cN-jjc" secondAttribute="trailing" constant="16" id="AOT-En-wYh"/>
|
||||
<constraint firstItem="M1Q-Iu-4dD" firstAttribute="trailing" secondItem="T7q-cN-jjc" secondAttribute="trailing" constant="-20" id="Gbp-eZ-HHz"/>
|
||||
<constraint firstAttribute="bottom" secondItem="owz-dg-x2C" secondAttribute="bottom" constant="32" id="O7Z-WD-F1G"/>
|
||||
<constraint firstItem="M1Q-Iu-4dD" firstAttribute="centerY" secondItem="cFH-jd-zLP" secondAttribute="centerY" constant="-12" id="TQG-iy-bgb"/>
|
||||
<constraint firstItem="M1Q-Iu-4dD" firstAttribute="leading" secondItem="T7q-cN-jjc" secondAttribute="leading" constant="20" id="XO8-WA-SOb"/>
|
||||
<constraint firstItem="T7q-cN-jjc" firstAttribute="top" secondItem="cFH-jd-zLP" secondAttribute="top" constant="24" id="qQl-EG-gwj"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="messageLabel" destination="M1Q-Iu-4dD" id="s4z-1r-zIH"/>
|
||||
<outlet property="titleLabel" destination="T7q-cN-jjc" id="nXO-3X-Qbu"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<customObject id="gpa-4h-EjA" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="380" y="1177"/>
|
||||
</scene>
|
||||
<!--Password View Controller-->
|
||||
<scene sceneID="Riu-mP-tQs">
|
||||
<objects>
|
||||
@ -1671,7 +1602,7 @@ DQ
|
||||
</viewController>
|
||||
<customObject id="E6z-rT-Kks" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-219" y="1197"/>
|
||||
<point key="canvasLocation" x="380" y="1197"/>
|
||||
</scene>
|
||||
<!--Edit Accounts View Controller-->
|
||||
<scene sceneID="PtW-Bw-c7x">
|
||||
|
@ -12,6 +12,7 @@ enum Browser: String, CaseIterable {
|
||||
case firefox = "org.mozilla.firefox"
|
||||
case vivaldi = "com.vivaldi.Vivaldi"
|
||||
case yandex = "ru.yandex.desktop.yandex-browser"
|
||||
case unknown = "com.unknown.browser.stub"
|
||||
|
||||
static let allBundleIds = Set(Browser.allCases.map { $0.rawValue })
|
||||
}
|
||||
|
@ -67,6 +67,7 @@ class AccountsListViewController: NSViewController {
|
||||
reloadHeader()
|
||||
updateCellModels()
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(didBecomeActive), name: NSApplication.didBecomeActiveNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(walletsChanged), name: Notification.Name.walletsChanged, object: nil)
|
||||
}
|
||||
|
||||
override func viewDidAppear() {
|
||||
@ -120,6 +121,8 @@ class AccountsListViewController: NSViewController {
|
||||
menu.addItem(.separator())
|
||||
menu.addItem(submenuItem)
|
||||
networkButton.menu = menu
|
||||
} else if !canSelectAccount, !networkButton.isHidden {
|
||||
networkButton.isHidden = true
|
||||
}
|
||||
}
|
||||
|
||||
@ -178,9 +181,6 @@ class AccountsListViewController: NSViewController {
|
||||
private func createNewAccountAndShowSecretWords() {
|
||||
guard let wallet = try? walletsManager.createWallet() else { return }
|
||||
newWalletId = wallet.id
|
||||
reloadHeader()
|
||||
updateCellModels()
|
||||
tableView.reloadData()
|
||||
blinkNewWalletCellIfNeeded()
|
||||
showKey(wallet: wallet)
|
||||
}
|
||||
@ -280,8 +280,6 @@ class AccountsListViewController: NSViewController {
|
||||
|
||||
do {
|
||||
try walletsManager.update(wallet: wallet, removeAccounts: [account])
|
||||
updateCellModels()
|
||||
tableView.removeRows(at: [row], withAnimation: .slideUp)
|
||||
} catch {
|
||||
Alert.showWithMessage(Strings.somethingWentWrong, style: .informational)
|
||||
}
|
||||
@ -306,7 +304,7 @@ class AccountsListViewController: NSViewController {
|
||||
alert.addButton(withTitle: Strings.removeAnyway)
|
||||
alert.addButton(withTitle: Strings.cancel)
|
||||
if alert.runModal() == .alertFirstButtonReturn {
|
||||
agent.askAuthentication(on: view.window, getBackTo: self, onStart: false, reason: .removeWallet) { [weak self] allowed in
|
||||
agent.askAuthentication(on: view.window, getBackTo: self, browser: nil, onStart: false, reason: .removeWallet) { [weak self] allowed in
|
||||
Window.activateWindow(self?.view.window)
|
||||
if allowed {
|
||||
self?.removeWallet(wallet)
|
||||
@ -317,6 +315,9 @@ class AccountsListViewController: NSViewController {
|
||||
|
||||
private func removeWallet(_ wallet: TokenaryWallet) {
|
||||
try? walletsManager.delete(wallet: wallet)
|
||||
}
|
||||
|
||||
@objc private func walletsChanged() {
|
||||
reloadHeader()
|
||||
updateCellModels()
|
||||
tableView.reloadData()
|
||||
@ -336,7 +337,7 @@ class AccountsListViewController: NSViewController {
|
||||
alert.addButton(withTitle: Strings.cancel)
|
||||
if alert.runModal() == .alertFirstButtonReturn {
|
||||
let reason: AuthenticationReason = wallet.isMnemonic ? .showSecretWords : .showPrivateKey
|
||||
agent.askAuthentication(on: view.window, getBackTo: self, onStart: false, reason: reason) { [weak self] allowed in
|
||||
agent.askAuthentication(on: view.window, getBackTo: self, browser: nil, onStart: false, reason: reason) { [weak self] allowed in
|
||||
Window.activateWindow(self?.view.window)
|
||||
if allowed {
|
||||
self?.showKey(wallet: wallet)
|
||||
|
@ -1,27 +0,0 @@
|
||||
// Copyright © 2021 Tokenary. All rights reserved.
|
||||
|
||||
import Cocoa
|
||||
|
||||
class ErrorViewController: NSViewController {
|
||||
|
||||
static func withMessage(_ message: String) -> ErrorViewController {
|
||||
let new = instantiate(ErrorViewController.self)
|
||||
new.message = message
|
||||
return new
|
||||
}
|
||||
|
||||
private var message = ""
|
||||
|
||||
@IBOutlet weak var titleLabel: NSTextField!
|
||||
@IBOutlet weak var messageLabel: NSTextField!
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
messageLabel.stringValue = message
|
||||
}
|
||||
|
||||
@IBAction func actionButtonTapped(_ sender: Any) {
|
||||
Window.closeAllAndActivateBrowser(force: nil)
|
||||
}
|
||||
|
||||
}
|
@ -21,6 +21,7 @@ class PasswordViewController: NSViewController {
|
||||
private var reason: AuthenticationReason?
|
||||
private var passwordToRepeat: String?
|
||||
private var completion: ((Bool) -> Void)?
|
||||
private var didCallCompletion = false
|
||||
|
||||
@IBOutlet weak var reasonLabel: NSTextField!
|
||||
@IBOutlet weak var cancelButton: NSButton!
|
||||
@ -43,6 +44,11 @@ class PasswordViewController: NSViewController {
|
||||
}
|
||||
}
|
||||
|
||||
override func viewDidAppear() {
|
||||
super.viewDidAppear()
|
||||
view.window?.delegate = self
|
||||
}
|
||||
|
||||
func switchToMode(_ mode: Mode) {
|
||||
self.mode = mode
|
||||
switch mode {
|
||||
@ -67,11 +73,11 @@ class PasswordViewController: NSViewController {
|
||||
let repeated = passwordTextField.stringValue
|
||||
if repeated == passwordToRepeat {
|
||||
keychain.save(password: repeated)
|
||||
completion?(true)
|
||||
callCompletion(result: true)
|
||||
}
|
||||
case .enter:
|
||||
if keychain.password == passwordTextField.stringValue {
|
||||
completion?(true)
|
||||
callCompletion(result: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -83,7 +89,14 @@ class PasswordViewController: NSViewController {
|
||||
case .repeatAfterCreate:
|
||||
switchToMode(.create)
|
||||
case .enter:
|
||||
completion?(false)
|
||||
callCompletion(result: false)
|
||||
}
|
||||
}
|
||||
|
||||
private func callCompletion(result: Bool) {
|
||||
if !didCallCompletion {
|
||||
didCallCompletion = true
|
||||
completion?(result)
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,3 +109,11 @@ extension PasswordViewController: NSTextFieldDelegate {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension PasswordViewController: NSWindowDelegate {
|
||||
|
||||
func windowWillClose(_ notification: Notification) {
|
||||
callCompletion(result: false)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ class WaitingViewController: NSViewController {
|
||||
}
|
||||
|
||||
@IBAction func actionButtonTapped(_ sender: Any) {
|
||||
Window.closeAll()
|
||||
Window.closeWindowAndActivateNext(idToClose: view.window?.windowNumber, specificBrowser: nil)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -133,12 +133,14 @@ class WalletConnect {
|
||||
|
||||
let peer = PeerMeta(wcPeerMeta: getPeerOfInteractor(interactor))
|
||||
let transaction = Transaction(from: wct.from, to: to, nonce: wct.nonce, gasPrice: wct.gasPrice, gas: wct.gas, value: wct.value, data: wct.data)
|
||||
agent.showApprove(transaction: transaction, chain: chain, peerMeta: peer) { [weak self, weak interactor] transaction in
|
||||
let windowController = Window.showNew(closeOthers: false)
|
||||
let windowNumber = windowController.window?.windowNumber
|
||||
agent.showApprove(windowController: windowController, browser: .unknown, transaction: transaction, chain: chain, peerMeta: peer) { [weak self, weak interactor] transaction in
|
||||
if let transaction = transaction {
|
||||
self?.sendTransaction(transaction, walletId: walletId, chainId: chainId, requestId: id, interactor: interactor)
|
||||
Window.closeAllAndActivateBrowser(force: nil)
|
||||
Window.closeWindowAndActivateNext(idToClose: windowNumber, specificBrowser: nil)
|
||||
} else {
|
||||
Window.closeAllAndActivateBrowser(force: nil)
|
||||
Window.closeWindowAndActivateNext(idToClose: windowNumber, specificBrowser: nil)
|
||||
self?.rejectRequest(id: id, interactor: interactor, message: Strings.canceled)
|
||||
}
|
||||
}
|
||||
@ -162,12 +164,14 @@ class WalletConnect {
|
||||
}
|
||||
|
||||
let peer = PeerMeta(wcPeerMeta: getPeerOfInteractor(interactor))
|
||||
agent.showApprove(subject: approvalSubject, meta: message ?? "", peerMeta: peer) { [weak self, weak interactor] approved in
|
||||
let windowController = Window.showNew(closeOthers: false)
|
||||
let windowNumber = windowController.window?.windowNumber
|
||||
agent.showApprove(windowController: windowController, browser: .unknown, subject: approvalSubject, meta: message ?? "", peerMeta: peer) { [weak self, weak interactor] approved in
|
||||
if approved {
|
||||
self?.sign(id: id, payload: payload, walletId: walletId, interactor: interactor)
|
||||
Window.closeAllAndActivateBrowser(force: nil)
|
||||
Window.closeWindowAndActivateNext(idToClose: windowNumber, specificBrowser: nil)
|
||||
} else {
|
||||
Window.closeAllAndActivateBrowser(force: nil)
|
||||
Window.closeWindowAndActivateNext(idToClose: windowNumber, specificBrowser: nil)
|
||||
self?.rejectRequest(id: id, interactor: interactor, message: Strings.canceled)
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,10 @@ import Cocoa
|
||||
|
||||
struct Window {
|
||||
|
||||
static func showNew() -> NSWindowController {
|
||||
closeAll()
|
||||
static func showNew(closeOthers: Bool) -> NSWindowController {
|
||||
if closeOthers {
|
||||
closeAll()
|
||||
}
|
||||
let windowController = new
|
||||
activate(windowController)
|
||||
return windowController
|
||||
@ -21,20 +23,36 @@ struct Window {
|
||||
window?.makeKeyAndOrderFront(nil)
|
||||
}
|
||||
|
||||
static func closeAllAndActivateBrowser(force browser: Browser?) {
|
||||
closeAll()
|
||||
activateBrowser(force: browser)
|
||||
}
|
||||
|
||||
static func closeAll(updateStatusBarItem: Bool = true) {
|
||||
NSApplication.shared.windows.forEach { $0.close() }
|
||||
if updateStatusBarItem {
|
||||
Agent.shared.setupStatusBarItem()
|
||||
static func closeWindow(idToClose: Int?) {
|
||||
if let id = idToClose, let windowToClose = NSApplication.shared.windows.first(where: { $0.windowNumber == id }) {
|
||||
windowToClose.close()
|
||||
}
|
||||
}
|
||||
|
||||
static func activateBrowser(force browser: Browser?) {
|
||||
if let browser = browser {
|
||||
static func closeWindowAndActivateNext(idToClose: Int?, specificBrowser: Browser?) {
|
||||
closeWindow(idToClose: idToClose)
|
||||
|
||||
if let window = NSApplication.shared.windows.last(where: { $0.windowNumber != idToClose && $0.isOnActiveSpace && $0.contentViewController != nil }) {
|
||||
activateWindow(window)
|
||||
} else {
|
||||
activateBrowser(specific: specificBrowser)
|
||||
}
|
||||
}
|
||||
|
||||
static func closeAllAndActivateBrowser(specific browser: Browser?) {
|
||||
closeAll()
|
||||
activateBrowser(specific: browser)
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private static func closeAll() {
|
||||
NSApplication.shared.windows.forEach { $0.close() }
|
||||
Agent.shared.setupStatusBarItem()
|
||||
}
|
||||
|
||||
private static func activateBrowser(specific browser: Browser?) {
|
||||
if let browser = browser, browser != .unknown {
|
||||
activateBrowser(browser)
|
||||
return
|
||||
}
|
||||
@ -64,11 +82,7 @@ struct Window {
|
||||
NSWorkspace.shared.runningApplications.first(where: { $0.bundleIdentifier == browser.rawValue })?.activate(options: .activateIgnoringOtherApps)
|
||||
}
|
||||
|
||||
static var current: NSWindowController? {
|
||||
return NSApplication.shared.windows.first?.windowController
|
||||
}
|
||||
|
||||
static var new: NSWindowController {
|
||||
private static var new: NSWindowController {
|
||||
return NSStoryboard.main.instantiateController(withIdentifier: "initial") as! NSWindowController
|
||||
}
|
||||
|
||||
|
@ -123,7 +123,6 @@
|
||||
2C8A09D726751A0C00993638 /* WalletConnect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C8A09D626751A0C00993638 /* WalletConnect.swift */; };
|
||||
2C8A09DF267579EA00993638 /* AccountsListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C8A09DE267579EA00993638 /* AccountsListViewController.swift */; };
|
||||
2C8A09E326757FC000993638 /* AccountCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C8A09E226757FC000993638 /* AccountCellView.swift */; };
|
||||
2C8A09E82675960D00993638 /* ErrorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C8A09E72675960D00993638 /* ErrorViewController.swift */; };
|
||||
2C8A09EB2675964700993638 /* ApproveViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C8A09EA2675964700993638 /* ApproveViewController.swift */; };
|
||||
2C8A09EE2675965F00993638 /* WaitingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C8A09ED2675965F00993638 /* WaitingViewController.swift */; };
|
||||
2C8E47A326A322E8007B8354 /* RightClickTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C8E47A226A322E8007B8354 /* RightClickTableView.swift */; };
|
||||
@ -352,7 +351,6 @@
|
||||
2C8A09D626751A0C00993638 /* WalletConnect.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletConnect.swift; sourceTree = "<group>"; };
|
||||
2C8A09DE267579EA00993638 /* AccountsListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsListViewController.swift; sourceTree = "<group>"; };
|
||||
2C8A09E226757FC000993638 /* AccountCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountCellView.swift; sourceTree = "<group>"; };
|
||||
2C8A09E72675960D00993638 /* ErrorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorViewController.swift; sourceTree = "<group>"; };
|
||||
2C8A09EA2675964700993638 /* ApproveViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApproveViewController.swift; sourceTree = "<group>"; };
|
||||
2C8A09ED2675965F00993638 /* WaitingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaitingViewController.swift; sourceTree = "<group>"; };
|
||||
2C8E47A226A322E8007B8354 /* RightClickTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RightClickTableView.swift; sourceTree = "<group>"; };
|
||||
@ -678,7 +676,6 @@
|
||||
2C1995412674C4B900A8E370 /* ImportViewController.swift */,
|
||||
2C797E7D267BB88800F2CE2D /* WelcomeViewController.swift */,
|
||||
2CDAB3712675B3F0009F8B97 /* PasswordViewController.swift */,
|
||||
2C8A09E72675960D00993638 /* ErrorViewController.swift */,
|
||||
2C901C462689E6D400D0926A /* ApproveTransactionViewController.swift */,
|
||||
2C8A09EA2675964700993638 /* ApproveViewController.swift */,
|
||||
2C8A09ED2675965F00993638 /* WaitingViewController.swift */,
|
||||
@ -1380,7 +1377,6 @@
|
||||
2C4768A9282598C5005E8D4D /* CoinDerivationCellView.swift in Sources */,
|
||||
2CB4031D281D745D00BAEBEE /* NSTableView.swift in Sources */,
|
||||
2CD0B3F726AC619900488D92 /* AddAccountOptionCellView.swift in Sources */,
|
||||
2C8A09E82675960D00993638 /* ErrorViewController.swift in Sources */,
|
||||
0D059AD226C2796200EE3023 /* ApprovalSubject.swift in Sources */,
|
||||
2C264BCB27B2F2FF00234393 /* TezosSafariRequest.swift in Sources */,
|
||||
2C1995422674C4B900A8E370 /* ImportViewController.swift in Sources */,
|
||||
|
Loading…
Reference in New Issue
Block a user