REF: watchOS app code optimization

This commit is contained in:
Marcos Rodriguez Velez 2024-01-25 00:39:01 -04:00
parent b060c21e89
commit cfabf827fc
No known key found for this signature in database
GPG Key ID: 6030B2F48CCE86D7
16 changed files with 164 additions and 158 deletions

View File

@ -3,7 +3,7 @@
// BlueWalletWatch Extension
//
// Created by Marcos Rodriguez on 3/6/19.
// Copyright © 2019 Facebook. All rights reserved.
//
import WatchKit

View File

@ -3,79 +3,72 @@
// BlueWalletWatch Extension
//
// Created by Marcos Rodriguez on 3/6/19.
// Copyright © 2019 Facebook. All rights reserved.
//
import WatchKit
import WatchConnectivity
import Foundation
class InterfaceController: WKInterfaceController {
class InterfaceController: WKInterfaceController, WCSessionDelegate {
@IBOutlet weak var walletsTable: WKInterfaceTable!
@IBOutlet weak var noWalletsAvailableLabel: WKInterfaceLabel!
override func awake(withContext context: Any?) {
super.awake(withContext: context)
if let contextUnwrapped = context as? [String: Any] {
WatchDataSource.shared.processData(data: contextUnwrapped)
}
if WCSession.isSupported() {
print("Activating watch session")
WCSession.default.delegate = self
WCSession.default.activate()
}
setupSession()
processContextData(context)
}
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
if (WatchDataSource.shared.wallets.isEmpty) {
noWalletsAvailableLabel.setHidden(false)
} else {
processWalletsTable()
}
NotificationCenter.default.addObserver(self, selector: #selector(processWalletsTable), name: WatchDataSource.NotificationName.dataUpdated, object: nil)
updateUI()
NotificationCenter.default.addObserver(self, selector: #selector(updateUI), name: WatchDataSource.NotificationName.dataUpdated, object: nil)
}
@objc private func processWalletsTable() {
walletsTable.setNumberOfRows(WatchDataSource.shared.wallets.count, withRowType: WalletInformation.identifier)
private func setupSession() {
guard WCSession.isSupported() else { return }
WCSession.default.delegate = self
WCSession.default.activate()
}
private func processContextData(_ context: Any?) {
guard let contextUnwrapped = context as? [String: Any] else { return }
WatchDataSource.shared.processData(data: contextUnwrapped)
}
@objc private func updateUI() {
let wallets = WatchDataSource.shared.wallets
let isEmpty = wallets.isEmpty
noWalletsAvailableLabel.setHidden(!isEmpty)
walletsTable.setHidden(isEmpty)
for index in 0..<walletsTable.numberOfRows {
guard let controller = walletsTable.rowController(at: index) as? WalletInformation else { continue }
let wallet = WatchDataSource.shared.wallets[index]
if wallet.identifier == nil {
WatchDataSource.shared.wallets[index].identifier = index
}
controller.walletBalanceLabel.setHidden(wallet.hideBalance)
controller.name = wallet.label
controller.balance = wallet.hideBalance ? "" : wallet.balance
controller.type = WalletGradient(rawValue: wallet.type) ?? .SegwitHD
if isEmpty { return }
walletsTable.setNumberOfRows(wallets.count, withRowType: WalletInformation.identifier)
for index in 0..<wallets.count {
updateRow(at: index, with: wallets[index])
}
noWalletsAvailableLabel.setHidden(!WatchDataSource.shared.wallets.isEmpty)
walletsTable.setHidden(WatchDataSource.shared.wallets.isEmpty)
}
private func updateRow(at index: Int, with wallet: Wallet) {
guard let controller = walletsTable.rowController(at: index) as? WalletInformation else { return }
controller.configure(with: wallet)
}
override func contextForSegue(withIdentifier segueIdentifier: String, in table: WKInterfaceTable, rowIndex: Int) -> Any? {
return rowIndex;
return rowIndex
}
}
extension InterfaceController: WCSessionDelegate {
func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) {
WatchDataSource.shared.processData(data: applicationContext)
}
func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {
WatchDataSource.shared.processData(data: userInfo)
}
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
WatchDataSource.shared.companionWalletsInitialized = activationState == .activated
if activationState == .activated {
WatchDataSource.shared.processWalletsData(walletsInfo: WCSession.default.applicationContext)
}
@ -90,3 +83,13 @@ extension InterfaceController: WCSessionDelegate {
}
}
// WalletInformation extension for configuration
extension WalletInformation {
func configure(with wallet: Wallet) {
walletBalanceLabel.setHidden(wallet.hideBalance)
name = wallet.label
balance = wallet.hideBalance ? "" : wallet.balance
type = WalletGradient(rawValue: wallet.type) ?? .SegwitHD
}
}

View File

@ -3,7 +3,7 @@
// BlueWalletWatch Extension
//
// Created by Marcos Rodriguez on 3/6/19.
// Copyright © 2019 Facebook. All rights reserved.
//
import WatchKit

View File

@ -3,7 +3,7 @@
// BlueWalletWatch Extension
//
// Created by Marcos Rodriguez on 3/23/19.
// Copyright © 2019 Facebook. All rights reserved.
//
import WatchKit

View File

@ -3,7 +3,7 @@
// BlueWalletWatch Extension
//
// Created by Marcos Rodriguez on 3/13/19.
// Copyright © 2019 Facebook. All rights reserved.
//
import Foundation

View File

@ -3,7 +3,7 @@
// BlueWalletWatch Extension
//
// Created by Marcos Rodriguez on 3/10/19.
// Copyright © 2019 Facebook. All rights reserved.
//
import WatchKit
@ -50,3 +50,13 @@ class TransactionTableRow: NSObject {
}
}
// TransactionTableRow extension for configuration
extension TransactionTableRow {
func configure(with transaction: Transaction) {
amount = transaction.amount
type = transaction.type
memo = transaction.memo
time = transaction.time
}
}

View File

@ -3,7 +3,7 @@
// BlueWalletWatch Extension
//
// Created by Marcos Rodriguez on 3/13/19.
// Copyright © 2019 Facebook. All rights reserved.
//
import Foundation

View File

@ -3,7 +3,7 @@
// BlueWalletWatch Extension
//
// Created by Marcos Rodriguez on 3/23/19.
// Copyright © 2019 Facebook. All rights reserved.
//
import Foundation

View File

@ -3,7 +3,7 @@
// BlueWalletWatch Extension
//
// Created by Marcos Rodriguez on 3/10/19.
// Copyright © 2019 Facebook. All rights reserved.
//
import WatchKit

View File

@ -3,7 +3,7 @@
// BlueWalletWatch Extension
//
// Created by Marcos Rodriguez on 3/20/19.
// Copyright © 2019 Facebook. All rights reserved.
//

View File

@ -3,7 +3,7 @@
// BlueWalletWatch Extension
//
// Created by Marcos Rodriguez on 3/12/19.
// Copyright © 2019 Facebook. All rights reserved.
//
import WatchKit

View File

@ -3,7 +3,7 @@
// BlueWalletWatch Extension
//
// Created by Marcos Rodriguez on 3/23/19.
// Copyright © 2019 Facebook. All rights reserved.
//
import WatchKit

View File

@ -1,10 +1,6 @@
//
// ReceiveInterfaceController.swift
// BlueWalletWatch Extension
//
// Created by Marcos Rodriguez on 3/12/19.
// Copyright © 2019 Facebook. All rights reserved.
//
// Created by Marcos Rodriguez on 3/11/19.
import WatchKit
import Foundation
@ -15,91 +11,85 @@ class ViewQRCodefaceController: WKInterfaceController {
static let identifier = "ViewQRCodefaceController"
@IBOutlet weak var imageInterface: WKInterfaceImage!
@IBOutlet weak var addressLabel: WKInterfaceLabel!
var address: String? {
didSet {
if let address = address, !address.isEmpty{
userActivity.userInfo = [HandOffUserInfoKey.Xpub.rawValue: address]
userActivity.becomeCurrent()
}
updateQRCode()
updateUserActivity()
}
}
private var interfaceMode = InterfaceMode.Address
private let userActivity: NSUserActivity = NSUserActivity(activityType: HandoffIdentifier.Xpub.rawValue)
override func awake(withContext context: Any?) {
super.awake(withContext: context)
userActivity.title = HandOffTitle.Xpub.rawValue
userActivity.requiredUserInfoKeys = [HandOffUserInfoKey.Xpub.rawValue]
userActivity.isEligibleForHandoff = true
configureUserActivity()
guard let passedContext = context as? String else {
pop()
return
}
address = passedContext
addressLabel.setText(passedContext)
toggleViewButtonPressed()
}
DispatchQueue.main.async {
guard let cgImage = EFQRCode.generate(
for: passedContext) else {
return
}
let image = UIImage(cgImage: cgImage)
self.imageInterface.setImage(nil)
self.imageInterface.setImage(image)
}
if #available(watchOSApplicationExtension 6.0, *) {
if let image = UIImage(systemName: "textformat.subscript") {
addMenuItem(with: image, title: "Address", action:#selector(toggleViewButtonPressed))
} else {
addMenuItem(with: .shuffle, title: "Address", action: #selector(toggleViewButtonPressed))
}
private func configureUserActivity() {
userActivity.title = HandOffTitle.Xpub.rawValue
userActivity.requiredUserInfoKeys = [HandOffUserInfoKey.Xpub.rawValue]
userActivity.isEligibleForHandoff = true
}
private func updateUserActivity() {
if let address = address, !address.isEmpty {
userActivity.userInfo = [HandOffUserInfoKey.Xpub.rawValue: address]
userActivity.becomeCurrent()
} else {
addMenuItem(with: .shuffle, title: "Address", action: #selector(toggleViewButtonPressed))
userActivity.invalidate()
}
}
@IBAction @objc func toggleViewButtonPressed() {
clearAllMenuItems()
switch interfaceMode {
case .Address:
addressLabel.setHidden(false)
imageInterface.setHidden(true)
if #available(watchOSApplicationExtension 6.0, *) {
if let image = UIImage(systemName: "qrcode") {
addMenuItem(with: image, title: "QR Code", action:#selector(toggleViewButtonPressed))
} else {
addMenuItem(with: .shuffle, title: "QR Code", action: #selector(toggleViewButtonPressed))
}
} else {
addMenuItem(with: .shuffle, title: "QR Code", action: #selector(toggleViewButtonPressed))
private func updateQRCode() {
guard let address = address, !address.isEmpty else {
imageInterface.setImage(nil)
return
}
DispatchQueue.global(qos: .userInteractive).async {
guard let cgImage = EFQRCode.generate(for: address) else {
return
}
case .QRCode:
addressLabel.setHidden(true)
imageInterface.setHidden(false)
if #available(watchOSApplicationExtension 6.0, *) {
if let image = UIImage(systemName: "textformat.subscript") {
addMenuItem(with: image, title: "Address", action:#selector(toggleViewButtonPressed))
} else {
addMenuItem(with: .shuffle, title: "Address", action: #selector(toggleViewButtonPressed))
}
} else {
addMenuItem(with: .shuffle, title: "Address", action: #selector(toggleViewButtonPressed))
DispatchQueue.main.async {
let image = UIImage(cgImage: cgImage)
self.imageInterface.setImage(image)
}
}
}
@IBAction @objc func toggleViewButtonPressed() {
clearAllMenuItems()
interfaceMode = interfaceMode == .QRCode ? .Address : .QRCode
let menuItemTitle = interfaceMode == .QRCode ? "QR Code" : "Address"
let systemImageName = interfaceMode == .QRCode ? "textformat.subscript" : "qrcode"
let defaultMenuItemIcon = interfaceMode == .QRCode ? WKMenuItemIcon.shuffle : WKMenuItemIcon.shuffle
addressLabel.setHidden(interfaceMode != .Address)
imageInterface.setHidden(interfaceMode != .QRCode)
if #available(watchOSApplicationExtension 6.0, *), let image = UIImage(systemName: systemImageName) {
addMenuItem(with: image, title: menuItemTitle, action: #selector(toggleViewButtonPressed))
} else {
addMenuItem(with: defaultMenuItemIcon, title: menuItemTitle, action: #selector(toggleViewButtonPressed))
}
}
override func willActivate() {
super.willActivate()
update(userActivity)
updateUserActivity()
}
override func didDeactivate() {
super.didDeactivate()
userActivity.invalidate()
invalidateUserActivity()
}
}

View File

@ -1,10 +1,6 @@
//
// WalletDetailsInterfaceController.swift
// BlueWalletWatch Extension
//
// Created by Marcos Rodriguez on 3/11/19.
// Copyright © 2019 Facebook. All rights reserved.
//
import WatchKit
import Foundation
@ -23,49 +19,69 @@ class WalletDetailsInterfaceController: WKInterfaceController {
@IBOutlet weak var noTransactionsLabel: WKInterfaceLabel!
@IBOutlet weak var transactionsTable: WKInterfaceTable!
override func awake(withContext context: Any?) {
super.awake(withContext: context)
guard let identifier = context as? Int else {
pop()
return
}
processInterface(identifier: identifier)
loadWalletDetails(identifier: identifier)
}
func processInterface(identifier: Int) {
let wallet = WatchDataSource.shared.wallets[identifier]
self.wallet = wallet
walletBalanceLabel.setHidden(wallet.hideBalance)
walletBalanceLabel.setText(wallet.hideBalance ? "" : wallet.balance)
walletNameLabel.setText(wallet.label)
walletBasicsGroup.setBackgroundImageNamed(WalletGradient(rawValue: wallet.type)?.imageString)
createInvoiceButton.setHidden(!(wallet.type == WalletGradient.LightningCustodial.rawValue || wallet.type == WalletGradient.LightningLDK.rawValue))
receiveButton.setHidden(wallet.receiveAddress.isEmpty)
viewXPubButton.setHidden(!((wallet.type != WalletGradient.LightningCustodial.rawValue || wallet.type != WalletGradient.LightningLDK.rawValue) && !(wallet.xpub ?? "").isEmpty))
processWalletsTable()
private func loadWalletDetails(identifier: Int) {
let wallet = WatchDataSource.shared.wallets[identifier]
self.wallet = wallet
updateWalletUI(wallet: wallet)
updateTransactionsTable(forWallet: wallet)
}
private func updateWalletUI(wallet: Wallet) {
walletBalanceLabel.setHidden(wallet.hideBalance)
walletBalanceLabel.setText(wallet.hideBalance ? "" : wallet.balance)
walletNameLabel.setText(wallet.label)
walletBasicsGroup.setBackgroundImageNamed(WalletGradient(rawValue: wallet.type)?.imageString)
let isLightningWallet = wallet.type == WalletGradient.LightningCustodial.rawValue || wallet.type == WalletGradient.LightningLDK.rawValue
createInvoiceButton.setHidden(!isLightningWallet)
receiveButton.setHidden(wallet.receiveAddress.isEmpty)
viewXPubButton.setHidden(!isXPubAvailable(wallet: wallet))
}
private func isXPubAvailable(wallet: Wallet) -> Bool {
return (wallet.type != WalletGradient.LightningCustodial.rawValue && wallet.type != WalletGradient.LightningLDK.rawValue) && !(wallet.xpub ?? "").isEmpty
}
private func updateTransactionsTable(forWallet wallet: Wallet) {
let transactions = wallet.transactions
transactionsTable.setNumberOfRows(transactions.count, withRowType: TransactionTableRow.identifier)
for index in 0..<transactions.count {
guard let controller = transactionsTable.rowController(at: index) as? TransactionTableRow else { continue }
let transaction = transactions[index]
controller.configure(with: transaction)
}
transactionsTable.setHidden(transactions.isEmpty)
noTransactionsLabel.setHidden(!transactions.isEmpty)
}
@IBAction func toggleBalanceVisibility(_ sender: Any) {
guard let wallet = wallet else {
return
return
}
if wallet.hideBalance {
showBalanceMenuItemTapped()
} else{
} else {
hideBalanceMenuItemTapped()
}
}
@objc func showBalanceMenuItemTapped() {
guard let identifier = wallet?.identifier else { return }
WatchDataSource.toggleWalletHideBalance(walletIdentifier: identifier, hideBalance: false) { [weak self] _ in
DispatchQueue.main.async {
WatchDataSource.postDataUpdatedNotification()
self?.processInterface(identifier: identifier)
self?.loadWalletDetails(identifier: identifier)
}
}
}
@ -75,7 +91,7 @@ class WalletDetailsInterfaceController: WKInterfaceController {
WatchDataSource.toggleWalletHideBalance(walletIdentifier: identifier, hideBalance: true) { [weak self] _ in
DispatchQueue.main.async {
WatchDataSource.postDataUpdatedNotification()
self?.processInterface(identifier: identifier)
self?.loadWalletDetails(identifier: identifier)
}
}
}
@ -89,42 +105,30 @@ class WalletDetailsInterfaceController: WKInterfaceController {
override func willActivate() {
super.willActivate()
transactionsTable.setHidden(wallet?.transactions.isEmpty ?? true)
noTransactionsLabel.setHidden(!(wallet?.transactions.isEmpty ?? false))
guard let wallet = wallet else { return }
updateTransactionsTable(forWallet: wallet)
}
@IBAction func receiveMenuItemTapped() {
guard let wallet = wallet else { return }
presentController(withName: ReceiveInterfaceController.identifier, context: (wallet, "receive"))
}
@objc private func processWalletsTable() {
transactionsTable.setNumberOfRows(wallet?.transactions.count ?? 0, withRowType: TransactionTableRow.identifier)
for index in 0..<transactionsTable.numberOfRows {
guard let controller = transactionsTable.rowController(at: index) as? TransactionTableRow, let transaction = wallet?.transactions[index] else { continue }
controller.amount = transaction.amount
controller.type = transaction.type
controller.memo = transaction.memo
controller.time = transaction.time
}
transactionsTable.setHidden(wallet?.transactions.isEmpty ?? true)
noTransactionsLabel.setHidden(!(wallet?.transactions.isEmpty ?? false))
}
@IBAction func createInvoiceTapped() {
if (WatchDataSource.shared.companionWalletsInitialized) {
pushController(withName: ReceiveInterfaceController.identifier, context: (wallet?.identifier, "createInvoice"))
if WatchDataSource.shared.companionWalletsInitialized {
guard let wallet = wallet else { return }
pushController(withName: ReceiveInterfaceController.identifier, context: (wallet.identifier, "createInvoice"))
} else {
WKInterfaceDevice.current().play(.failure)
presentAlert(withTitle: "Error", message: "Unable to create invoice. Please open BlueWallet on your iPhone and unlock your wallets.", preferredStyle: .alert, actions: [WKAlertAction(title: "OK", style: .default, handler: { [weak self] in
self?.dismiss()
})])
}
})])
}
}
override func contextForSegue(withIdentifier segueIdentifier: String) -> Any? {
return (wallet?.identifier, "receive")
guard let wallet = wallet else { return nil }
return (wallet.identifier, "receive")
}
}

View File

@ -3,7 +3,6 @@
// BlueWallet
//
// Created by Marcos Rodriguez on 9/19/19.
// Copyright © 2019 Facebook. All rights reserved.
//
import Foundation

View File

@ -3,7 +3,7 @@
// TodayExtension
//
// Created by Marcos Rodriguez on 11/2/19.
// Copyright © 2019 Facebook. All rights reserved.
//
import Foundation