@ -0,0 +1,138 @@ |
|||
import * as watch from 'react-native-watch-connectivity'; |
|||
import { InteractionManager } from 'react-native'; |
|||
const loc = require('./loc'); |
|||
export default class WatchConnectivity { |
|||
isAppInstalled = false; |
|||
BlueApp = require('./BlueApp'); |
|||
|
|||
constructor() { |
|||
this.getIsWatchAppInstalled(); |
|||
} |
|||
|
|||
getIsWatchAppInstalled() { |
|||
watch.getIsWatchAppInstalled((err, isAppInstalled) => { |
|||
if (!err) { |
|||
this.isAppInstalled = isAppInstalled; |
|||
this.sendWalletsToWatch(); |
|||
} |
|||
}); |
|||
watch.subscribeToMessages(async (err, message, reply) => { |
|||
if (!err) { |
|||
if (message.request === 'createInvoice') { |
|||
const createInvoiceRequest = await this.handleLightningInvoiceCreateRequest( |
|||
message.walletIndex, |
|||
message.amount, |
|||
message.description, |
|||
); |
|||
reply({ invoicePaymentRequest: createInvoiceRequest }); |
|||
} |
|||
} else { |
|||
reply(err); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
async handleLightningInvoiceCreateRequest(walletIndex, amount, description) { |
|||
const wallet = this.BlueApp.getWallets()[walletIndex]; |
|||
if (wallet.allowReceive() && amount > 0 && description.trim().length > 0) { |
|||
try { |
|||
const invoiceRequest = await wallet.addInvoice(amount, description); |
|||
return invoiceRequest; |
|||
} catch (error) { |
|||
return error; |
|||
} |
|||
} |
|||
} |
|||
|
|||
async sendWalletsToWatch() { |
|||
InteractionManager.runAfterInteractions(async () => { |
|||
if (this.isAppInstalled) { |
|||
const allWallets = this.BlueApp.getWallets(); |
|||
let wallets = []; |
|||
for (const wallet of allWallets) { |
|||
let receiveAddress = ''; |
|||
if (wallet.allowReceive()) { |
|||
if (wallet.getAddressAsync) { |
|||
receiveAddress = await wallet.getAddressAsync(); |
|||
} else { |
|||
receiveAddress = wallet.getAddress(); |
|||
} |
|||
} |
|||
let transactions = wallet.getTransactions(10); |
|||
let watchTransactions = []; |
|||
for (const transaction of transactions) { |
|||
let type = 'pendingConfirmation'; |
|||
let memo = ''; |
|||
let amount = 0; |
|||
|
|||
if (transaction.hasOwnProperty('confirmations') && !transaction.confirmations > 0) { |
|||
type = 'pendingConfirmation'; |
|||
} else if (transaction.type === 'user_invoice' || transaction.type === 'payment_request') { |
|||
const currentDate = new Date(); |
|||
const now = (currentDate.getTime() / 1000) | 0; |
|||
const invoiceExpiration = transaction.timestamp + transaction.expire_time; |
|||
|
|||
if (invoiceExpiration > now) { |
|||
type = 'pendingConfirmation'; |
|||
} else if (invoiceExpiration < now) { |
|||
if (transaction.ispaid) { |
|||
type = 'received'; |
|||
} else { |
|||
type = 'sent'; |
|||
} |
|||
} |
|||
} else if (transaction.value / 100000000 < 0) { |
|||
type = 'sent'; |
|||
} else { |
|||
type = 'received'; |
|||
} |
|||
if (transaction.type === 'user_invoice' || transaction.type === 'payment_request') { |
|||
if (isNaN(transaction.value)) { |
|||
amount = '0'; |
|||
} |
|||
const currentDate = new Date(); |
|||
const now = (currentDate.getTime() / 1000) | 0; |
|||
const invoiceExpiration = transaction.timestamp + transaction.expire_time; |
|||
|
|||
if (invoiceExpiration > now) { |
|||
amount = loc.formatBalance(transaction.value, wallet.getPreferredBalanceUnit(), true).toString(); |
|||
} else if (invoiceExpiration < now) { |
|||
if (transaction.ispaid) { |
|||
amount = loc.formatBalance(transaction.value, wallet.getPreferredBalanceUnit(), true).toString(); |
|||
} else { |
|||
amount = loc.lnd.expired; |
|||
} |
|||
} else { |
|||
amount = loc.formatBalance(transaction.value, wallet.getPreferredBalanceUnit(), true).toString(); |
|||
} |
|||
} else { |
|||
amount = loc.formatBalance(transaction.value, wallet.getPreferredBalanceUnit(), true).toString(); |
|||
} |
|||
if (this.BlueApp.tx_metadata[transaction.hash] && this.BlueApp.tx_metadata[transaction.hash]['memo']) { |
|||
memo = this.BlueApp.tx_metadata[transaction.hash]['memo']; |
|||
} else if (transaction.memo) { |
|||
memo = transaction.memo; |
|||
} |
|||
const watchTX = { type, amount, memo, time: loc.transactionTimeToReadable(transaction.received) }; |
|||
watchTransactions.push(watchTX); |
|||
} |
|||
wallets.push({ |
|||
label: wallet.getLabel(), |
|||
balance: loc.formatBalance(Number(wallet.getBalance()), wallet.getPreferredBalanceUnit(), true), |
|||
type: wallet.type, |
|||
preferredBalanceUnit: wallet.getPreferredBalanceUnit(), |
|||
receiveAddress: receiveAddress, |
|||
transactions: watchTransactions, |
|||
}); |
|||
} |
|||
|
|||
watch.updateApplicationContext({ wallets }); |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
|
|||
WatchConnectivity.init = function() { |
|||
if (WatchConnectivity.shared) return; |
|||
WatchConnectivity.shared = new WatchConnectivity(); |
|||
}; |
@ -0,0 +1 @@ |
|||
export default from '@react-native-community/async-storage/jest/async-storage-mock' |
@ -0,0 +1,131 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<Scheme |
|||
LastUpgradeVersion = "1020" |
|||
version = "2.0"> |
|||
<BuildAction |
|||
parallelizeBuildables = "YES" |
|||
buildImplicitDependencies = "YES"> |
|||
<BuildActionEntries> |
|||
<BuildActionEntry |
|||
buildForTesting = "YES" |
|||
buildForRunning = "YES" |
|||
buildForProfiling = "YES" |
|||
buildForArchiving = "YES" |
|||
buildForAnalyzing = "YES"> |
|||
<BuildableReference |
|||
BuildableIdentifier = "primary" |
|||
BlueprintIdentifier = "B40D4E2F225841EC00428FCC" |
|||
BuildableName = "BlueWalletWatch.app" |
|||
BlueprintName = "BlueWalletWatch" |
|||
ReferencedContainer = "container:BlueWallet.xcodeproj"> |
|||
</BuildableReference> |
|||
</BuildActionEntry> |
|||
<BuildActionEntry |
|||
buildForTesting = "YES" |
|||
buildForRunning = "YES" |
|||
buildForProfiling = "YES" |
|||
buildForArchiving = "YES" |
|||
buildForAnalyzing = "YES"> |
|||
<BuildableReference |
|||
BuildableIdentifier = "primary" |
|||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A" |
|||
BuildableName = "BlueWallet.app" |
|||
BlueprintName = "BlueWallet" |
|||
ReferencedContainer = "container:BlueWallet.xcodeproj"> |
|||
</BuildableReference> |
|||
</BuildActionEntry> |
|||
</BuildActionEntries> |
|||
</BuildAction> |
|||
<TestAction |
|||
buildConfiguration = "Debug" |
|||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" |
|||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" |
|||
shouldUseLaunchSchemeArgsEnv = "YES"> |
|||
<Testables> |
|||
</Testables> |
|||
<MacroExpansion> |
|||
<BuildableReference |
|||
BuildableIdentifier = "primary" |
|||
BlueprintIdentifier = "B40D4E2F225841EC00428FCC" |
|||
BuildableName = "BlueWalletWatch.app" |
|||
BlueprintName = "BlueWalletWatch" |
|||
ReferencedContainer = "container:BlueWallet.xcodeproj"> |
|||
</BuildableReference> |
|||
</MacroExpansion> |
|||
<AdditionalOptions> |
|||
</AdditionalOptions> |
|||
</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" |
|||
launchAutomaticallySubstyle = "8" |
|||
notificationPayloadFile = "BlueWalletWatch Extension/PushNotificationPayload.apns"> |
|||
<RemoteRunnable |
|||
runnableDebuggingMode = "2" |
|||
BundleIdentifier = "com.apple.Carousel" |
|||
RemotePath = "/BlueWallet"> |
|||
<BuildableReference |
|||
BuildableIdentifier = "primary" |
|||
BlueprintIdentifier = "B40D4E2F225841EC00428FCC" |
|||
BuildableName = "BlueWalletWatch.app" |
|||
BlueprintName = "BlueWalletWatch" |
|||
ReferencedContainer = "container:BlueWallet.xcodeproj"> |
|||
</BuildableReference> |
|||
</RemoteRunnable> |
|||
<MacroExpansion> |
|||
<BuildableReference |
|||
BuildableIdentifier = "primary" |
|||
BlueprintIdentifier = "B40D4E2F225841EC00428FCC" |
|||
BuildableName = "BlueWalletWatch.app" |
|||
BlueprintName = "BlueWalletWatch" |
|||
ReferencedContainer = "container:BlueWallet.xcodeproj"> |
|||
</BuildableReference> |
|||
</MacroExpansion> |
|||
<AdditionalOptions> |
|||
</AdditionalOptions> |
|||
</LaunchAction> |
|||
<ProfileAction |
|||
buildConfiguration = "Release" |
|||
shouldUseLaunchSchemeArgsEnv = "YES" |
|||
savedToolIdentifier = "" |
|||
useCustomWorkingDirectory = "NO" |
|||
debugDocumentVersioning = "YES" |
|||
launchAutomaticallySubstyle = "8" |
|||
notificationPayloadFile = "BlueWalletWatch Extension/PushNotificationPayload.apns"> |
|||
<RemoteRunnable |
|||
runnableDebuggingMode = "2" |
|||
BundleIdentifier = "com.apple.Carousel" |
|||
RemotePath = "/BlueWallet"> |
|||
<BuildableReference |
|||
BuildableIdentifier = "primary" |
|||
BlueprintIdentifier = "B40D4E2F225841EC00428FCC" |
|||
BuildableName = "BlueWalletWatch.app" |
|||
BlueprintName = "BlueWalletWatch" |
|||
ReferencedContainer = "container:BlueWallet.xcodeproj"> |
|||
</BuildableReference> |
|||
</RemoteRunnable> |
|||
<MacroExpansion> |
|||
<BuildableReference |
|||
BuildableIdentifier = "primary" |
|||
BlueprintIdentifier = "B40D4E2F225841EC00428FCC" |
|||
BuildableName = "BlueWalletWatch.app" |
|||
BlueprintName = "BlueWalletWatch" |
|||
ReferencedContainer = "container:BlueWallet.xcodeproj"> |
|||
</BuildableReference> |
|||
</MacroExpansion> |
|||
</ProfileAction> |
|||
<AnalyzeAction |
|||
buildConfiguration = "Debug"> |
|||
</AnalyzeAction> |
|||
<ArchiveAction |
|||
buildConfiguration = "Release" |
|||
revealArchiveInOrganizer = "YES"> |
|||
</ArchiveAction> |
|||
</Scheme> |
@ -0,0 +1,128 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<Scheme |
|||
LastUpgradeVersion = "1020" |
|||
version = "1.3"> |
|||
<BuildAction |
|||
parallelizeBuildables = "YES" |
|||
buildImplicitDependencies = "YES"> |
|||
<BuildActionEntries> |
|||
<BuildActionEntry |
|||
buildForTesting = "YES" |
|||
buildForRunning = "YES" |
|||
buildForProfiling = "YES" |
|||
buildForArchiving = "YES" |
|||
buildForAnalyzing = "YES"> |
|||
<BuildableReference |
|||
BuildableIdentifier = "primary" |
|||
BlueprintIdentifier = "B40D4E2F225841EC00428FCC" |
|||
BuildableName = "BlueWalletWatch.app" |
|||
BlueprintName = "BlueWalletWatch" |
|||
ReferencedContainer = "container:BlueWallet.xcodeproj"> |
|||
</BuildableReference> |
|||
</BuildActionEntry> |
|||
<BuildActionEntry |
|||
buildForTesting = "YES" |
|||
buildForRunning = "YES" |
|||
buildForProfiling = "YES" |
|||
buildForArchiving = "YES" |
|||
buildForAnalyzing = "YES"> |
|||
<BuildableReference |
|||
BuildableIdentifier = "primary" |
|||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A" |
|||
BuildableName = "BlueWallet.app" |
|||
BlueprintName = "BlueWallet" |
|||
ReferencedContainer = "container:BlueWallet.xcodeproj"> |
|||
</BuildableReference> |
|||
</BuildActionEntry> |
|||
</BuildActionEntries> |
|||
</BuildAction> |
|||
<TestAction |
|||
buildConfiguration = "Debug" |
|||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" |
|||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" |
|||
shouldUseLaunchSchemeArgsEnv = "YES"> |
|||
<Testables> |
|||
</Testables> |
|||
<MacroExpansion> |
|||
<BuildableReference |
|||
BuildableIdentifier = "primary" |
|||
BlueprintIdentifier = "B40D4E2F225841EC00428FCC" |
|||
BuildableName = "BlueWalletWatch.app" |
|||
BlueprintName = "BlueWalletWatch" |
|||
ReferencedContainer = "container:BlueWallet.xcodeproj"> |
|||
</BuildableReference> |
|||
</MacroExpansion> |
|||
<AdditionalOptions> |
|||
</AdditionalOptions> |
|||
</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" |
|||
notificationPayloadFile = "BlueWalletWatch Extension/PushNotificationPayload.apns"> |
|||
<RemoteRunnable |
|||
runnableDebuggingMode = "2" |
|||
BundleIdentifier = "com.apple.Carousel" |
|||
RemotePath = "/BlueWallet"> |
|||
<BuildableReference |
|||
BuildableIdentifier = "primary" |
|||
BlueprintIdentifier = "B40D4E2F225841EC00428FCC" |
|||
BuildableName = "BlueWalletWatch.app" |
|||
BlueprintName = "BlueWalletWatch" |
|||
ReferencedContainer = "container:BlueWallet.xcodeproj"> |
|||
</BuildableReference> |
|||
</RemoteRunnable> |
|||
<MacroExpansion> |
|||
<BuildableReference |
|||
BuildableIdentifier = "primary" |
|||
BlueprintIdentifier = "B40D4E2F225841EC00428FCC" |
|||
BuildableName = "BlueWalletWatch.app" |
|||
BlueprintName = "BlueWalletWatch" |
|||
ReferencedContainer = "container:BlueWallet.xcodeproj"> |
|||
</BuildableReference> |
|||
</MacroExpansion> |
|||
<AdditionalOptions> |
|||
</AdditionalOptions> |
|||
</LaunchAction> |
|||
<ProfileAction |
|||
buildConfiguration = "Release" |
|||
shouldUseLaunchSchemeArgsEnv = "YES" |
|||
savedToolIdentifier = "" |
|||
useCustomWorkingDirectory = "NO" |
|||
debugDocumentVersioning = "YES"> |
|||
<RemoteRunnable |
|||
runnableDebuggingMode = "2" |
|||
BundleIdentifier = "com.apple.Carousel" |
|||
RemotePath = "/BlueWallet"> |
|||
<BuildableReference |
|||
BuildableIdentifier = "primary" |
|||
BlueprintIdentifier = "B40D4E2F225841EC00428FCC" |
|||
BuildableName = "BlueWalletWatch.app" |
|||
BlueprintName = "BlueWalletWatch" |
|||
ReferencedContainer = "container:BlueWallet.xcodeproj"> |
|||
</BuildableReference> |
|||
</RemoteRunnable> |
|||
<MacroExpansion> |
|||
<BuildableReference |
|||
BuildableIdentifier = "primary" |
|||
BlueprintIdentifier = "B40D4E2F225841EC00428FCC" |
|||
BuildableName = "BlueWalletWatch.app" |
|||
BlueprintName = "BlueWalletWatch" |
|||
ReferencedContainer = "container:BlueWallet.xcodeproj"> |
|||
</BuildableReference> |
|||
</MacroExpansion> |
|||
</ProfileAction> |
|||
<AnalyzeAction |
|||
buildConfiguration = "Debug"> |
|||
</AnalyzeAction> |
|||
<ArchiveAction |
|||
buildConfiguration = "Release" |
|||
revealArchiveInOrganizer = "YES"> |
|||
</ArchiveAction> |
|||
</Scheme> |
@ -0,0 +1,19 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<Workspace |
|||
version = "1.0"> |
|||
<FileRef |
|||
location = "group:BlueWallet.xcodeproj"> |
|||
</FileRef> |
|||
<FileRef |
|||
location = "group:Pods/Pods.xcodeproj"> |
|||
</FileRef> |
|||
<FileRef |
|||
location = "group:../node_modules/react-native-tcp/ios/TcpSockets.xcodeproj"> |
|||
</FileRef> |
|||
<FileRef |
|||
location = "group:../node_modules/@remobile/react-native-qrcode-local-image/ios/RCTQRCodeLocalImage.xcodeproj"> |
|||
</FileRef> |
|||
<FileRef |
|||
location = "group:../node_modules/react-native-privacy-snapshot/RCTPrivacySnapshot.xcodeproj"> |
|||
</FileRef> |
|||
</Workspace> |
@ -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> |
@ -0,0 +1,56 @@ |
|||
// |
|||
// ExtensionDelegate.swift |
|||
// BlueWalletWatch Extension |
|||
// |
|||
// Created by Marcos Rodriguez on 3/6/19. |
|||
// Copyright © 2019 Facebook. All rights reserved. |
|||
// |
|||
|
|||
import WatchKit |
|||
|
|||
class ExtensionDelegate: NSObject, WKExtensionDelegate { |
|||
|
|||
func applicationDidFinishLaunching() { |
|||
// Perform any final initialization of your application. |
|||
} |
|||
|
|||
func applicationDidBecomeActive() { |
|||
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. |
|||
} |
|||
|
|||
func applicationWillResignActive() { |
|||
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. |
|||
// Use this method to pause ongoing tasks, disable timers, etc. |
|||
} |
|||
|
|||
func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) { |
|||
// Sent when the system needs to launch the application in the background to process tasks. Tasks arrive in a set, so loop through and process each one. |
|||
for task in backgroundTasks { |
|||
// Use a switch statement to check the task type |
|||
switch task { |
|||
case let backgroundTask as WKApplicationRefreshBackgroundTask: |
|||
// Be sure to complete the background task once you’re done. |
|||
backgroundTask.setTaskCompletedWithSnapshot(false) |
|||
case let snapshotTask as WKSnapshotRefreshBackgroundTask: |
|||
// Snapshot tasks have a unique completion call, make sure to set your expiration date |
|||
snapshotTask.setTaskCompleted(restoredDefaultState: true, estimatedSnapshotExpiration: Date.distantFuture, userInfo: nil) |
|||
case let connectivityTask as WKWatchConnectivityRefreshBackgroundTask: |
|||
// Be sure to complete the connectivity task once you’re done. |
|||
connectivityTask.setTaskCompletedWithSnapshot(false) |
|||
case let urlSessionTask as WKURLSessionRefreshBackgroundTask: |
|||
// Be sure to complete the URL session task once you’re done. |
|||
urlSessionTask.setTaskCompletedWithSnapshot(false) |
|||
case let relevantShortcutTask as WKRelevantShortcutRefreshBackgroundTask: |
|||
// Be sure to complete the relevant-shortcut task once you're done. |
|||
relevantShortcutTask.setTaskCompletedWithSnapshot(false) |
|||
case let intentDidRunTask as WKIntentDidRunRefreshBackgroundTask: |
|||
// Be sure to complete the intent-did-run task once you're done. |
|||
intentDidRunTask.setTaskCompletedWithSnapshot(false) |
|||
default: |
|||
// make sure to complete unhandled task types |
|||
task.setTaskCompletedWithSnapshot(false) |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
@ -0,0 +1,38 @@ |
|||
<?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>BlueWalletWatch Extension</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>$(PRODUCT_NAME)</string> |
|||
<key>CFBundlePackageType</key> |
|||
<string>XPC!</string> |
|||
<key>CFBundleShortVersionString</key> |
|||
<string>3.9.8</string> |
|||
<key>CFBundleVersion</key> |
|||
<string>239</string> |
|||
<key>LSApplicationCategoryType</key> |
|||
<string></string> |
|||
<key>NSExtension</key> |
|||
<dict> |
|||
<key>NSExtensionAttributes</key> |
|||
<dict> |
|||
<key>WKAppBundleIdentifier</key> |
|||
<string>io.bluewallet.bluewallet.watch</string> |
|||
</dict> |
|||
<key>NSExtensionPointIdentifier</key> |
|||
<string>com.apple.watchkit</string> |
|||
</dict> |
|||
<key>WKExtensionDelegateClassName</key> |
|||
<string>$(PRODUCT_MODULE_NAME).ExtensionDelegate</string> |
|||
</dict> |
|||
</plist> |
@ -0,0 +1,57 @@ |
|||
// |
|||
// InterfaceController.swift |
|||
// 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 { |
|||
|
|||
@IBOutlet weak var walletsTable: WKInterfaceTable! |
|||
@IBOutlet weak var loadingIndicatorGroup: WKInterfaceGroup! |
|||
@IBOutlet weak var noWalletsAvailableLabel: WKInterfaceLabel! |
|||
|
|||
override func willActivate() { |
|||
// This method is called when watch view controller is about to be visible to user |
|||
super.willActivate() |
|||
WCSession.default.sendMessage(["message" : "sendApplicationContext"], replyHandler: nil, errorHandler: nil) |
|||
|
|||
if (WatchDataSource.shared.wallets.isEmpty) { |
|||
loadingIndicatorGroup.setHidden(true) |
|||
noWalletsAvailableLabel.setHidden(false) |
|||
} else { |
|||
processWalletsTable() |
|||
} |
|||
NotificationCenter.default.addObserver(self, selector: #selector(processWalletsTable), name: WatchDataSource.NotificationName.dataUpdated, object: nil) |
|||
} |
|||
|
|||
@objc private func processWalletsTable() { |
|||
loadingIndicatorGroup.setHidden(false) |
|||
walletsTable.setHidden(true) |
|||
walletsTable.setNumberOfRows(WatchDataSource.shared.wallets.count, withRowType: WalletInformation.identifier) |
|||
|
|||
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.name = wallet.label |
|||
controller.balance = wallet.balance |
|||
controller.type = WalletGradient(rawValue: wallet.type) ?? .SegwitHD |
|||
} |
|||
loadingIndicatorGroup.setHidden(true) |
|||
noWalletsAvailableLabel.setHidden(!WatchDataSource.shared.wallets.isEmpty) |
|||
walletsTable.setHidden(WatchDataSource.shared.wallets.isEmpty) |
|||
} |
|||
|
|||
override func contextForSegue(withIdentifier segueIdentifier: String, in table: WKInterfaceTable, rowIndex: Int) -> Any? { |
|||
return rowIndex; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,38 @@ |
|||
// |
|||
// NotificationController.swift |
|||
// BlueWalletWatch Extension |
|||
// |
|||
// Created by Marcos Rodriguez on 3/6/19. |
|||
// Copyright © 2019 Facebook. All rights reserved. |
|||
// |
|||
|
|||
import WatchKit |
|||
import Foundation |
|||
import UserNotifications |
|||
|
|||
|
|||
class NotificationController: WKUserNotificationInterfaceController { |
|||
|
|||
override init() { |
|||
// Initialize variables here. |
|||
super.init() |
|||
|
|||
// Configure interface objects here. |
|||
} |
|||
|
|||
override func willActivate() { |
|||
// This method is called when watch view controller is about to be visible to user |
|||
super.willActivate() |
|||
} |
|||
|
|||
override func didDeactivate() { |
|||
// This method is called when watch view controller is no longer visible |
|||
super.didDeactivate() |
|||
} |
|||
|
|||
override func didReceive(_ notification: UNNotification) { |
|||
// This method is called when a notification needs to be presented. |
|||
// Implement it if you use a dynamic notification interface. |
|||
// Populate your dynamic notification interface as quickly as possible. |
|||
} |
|||
} |
@ -0,0 +1,155 @@ |
|||
// |
|||
// NumericKeypadInterfaceController.swift |
|||
// BlueWalletWatch Extension |
|||
// |
|||
// Created by Marcos Rodriguez on 3/23/19. |
|||
// Copyright © 2019 Facebook. All rights reserved. |
|||
// |
|||
|
|||
import WatchKit |
|||
import Foundation |
|||
|
|||
|
|||
class NumericKeypadInterfaceController: WKInterfaceController { |
|||
|
|||
static let identifier = "NumericKeypadInterfaceController" |
|||
private var amount: [String] = ["0"] |
|||
var keyPadType: NumericKeypadType = .BTC |
|||
struct NotificationName { |
|||
static let keypadDataChanged = Notification.Name(rawValue: "Notification.NumericKeypadInterfaceController.keypadDataChanged") |
|||
} |
|||
struct Notifications { |
|||
static let keypadDataChanged = Notification(name: NotificationName.keypadDataChanged) |
|||
} |
|||
enum NumericKeypadType: String { |
|||
case BTC = "BTC" |
|||
case SATS = "sats" |
|||
} |
|||
|
|||
@IBOutlet weak var periodButton: WKInterfaceButton! |
|||
|
|||
override func awake(withContext context: Any?) { |
|||
super.awake(withContext: context) |
|||
if let context = context as? SpecifyInterfaceController.SpecificQRCodeContent { |
|||
amount = context.amountStringArray |
|||
keyPadType = context.bitcoinUnit |
|||
} |
|||
periodButton.setEnabled(keyPadType == .SATS) |
|||
} |
|||
|
|||
override func willActivate() { |
|||
// This method is called when watch view controller is about to be visible to user |
|||
super.willActivate() |
|||
updateTitle() |
|||
} |
|||
|
|||
private func updateTitle() { |
|||
var title = "" |
|||
for amount in self.amount { |
|||
let isValid = Double(amount) |
|||
if amount == "." || isValid != nil { |
|||
title.append(String(amount)) |
|||
} |
|||
} |
|||
if title.isEmpty { |
|||
title = "0" |
|||
} |
|||
setTitle("< \(title) \(keyPadType)") |
|||
NotificationCenter.default.post(name: NotificationName.keypadDataChanged, object: amount) |
|||
} |
|||
|
|||
private func append(value: String) { |
|||
guard amount.filter({$0 != "."}).count <= 9 && !(amount.contains(".") && value == ".") else { |
|||
return |
|||
} |
|||
switch keyPadType { |
|||
case .SATS: |
|||
if amount.first == "0" { |
|||
if value == "0" { |
|||
return |
|||
} |
|||
amount[0] = value |
|||
} else { |
|||
amount.append(value) |
|||
} |
|||
case .BTC: |
|||
if amount.isEmpty { |
|||
if (value == "0") { |
|||
amount.append("0") |
|||
} else if value == "." && !amount.contains(".") { |
|||
amount.append("0") |
|||
amount.append(".") |
|||
} else { |
|||
amount.append(value) |
|||
} |
|||
} else if let first = amount.first, first == "0" { |
|||
if amount.count > 1, amount[1] != "." { |
|||
amount.insert(".", at: 1) |
|||
} else if amount.count == 1, amount.first == "0" && value != "." { |
|||
amount.append(".") |
|||
amount.append(value) |
|||
} else { |
|||
amount.append(value) |
|||
} |
|||
} else { |
|||
amount.append(value) |
|||
} |
|||
} |
|||
updateTitle() |
|||
} |
|||
|
|||
@IBAction func keypadNumberOneTapped() { |
|||
append(value: "1") |
|||
} |
|||
|
|||
@IBAction func keypadNumberTwoTapped() { |
|||
append(value: "2") |
|||
} |
|||
|
|||
@IBAction func keypadNumberThreeTapped() { |
|||
append(value: "3") |
|||
} |
|||
|
|||
@IBAction func keypadNumberFourTapped() { |
|||
append(value: "4") |
|||
} |
|||
|
|||
@IBAction func keypadNumberFiveTapped() { |
|||
append(value: "5") |
|||
} |
|||
|
|||
@IBAction func keypadNumberSixTapped() { |
|||
append(value: "6") |
|||
} |
|||
|
|||
@IBAction func keypadNumberSevenTapped() { |
|||
append(value: "7") |
|||
} |
|||
|
|||
@IBAction func keypadNumberEightTapped() { |
|||
append(value: "8") |
|||
} |
|||
|
|||
@IBAction func keypadNumberNineTapped() { |
|||
append(value: "9") |
|||
} |
|||
|
|||
@IBAction func keypadNumberZeroTapped() { |
|||
append(value: "0") |
|||
} |
|||
|
|||
@IBAction func keypadNumberDotTapped() { |
|||
guard !amount.contains("."), keyPadType == .BTC else { return } |
|||
append(value: ".") |
|||
} |
|||
|
|||
@IBAction func keypadNumberRemoveTapped() { |
|||
guard !amount.isEmpty else { |
|||
setTitle("< 0 \(keyPadType)") |
|||
return |
|||
} |
|||
amount.removeLast() |
|||
updateTitle() |
|||
} |
|||
|
|||
} |
@ -0,0 +1,39 @@ |
|||
// |
|||
// Wallet.swift |
|||
// BlueWalletWatch Extension |
|||
// |
|||
// Created by Marcos Rodriguez on 3/13/19. |
|||
// Copyright © 2019 Facebook. All rights reserved. |
|||
// |
|||
|
|||
import Foundation |
|||
|
|||
class Transaction: NSObject, NSCoding { |
|||
static let identifier: String = "Transaction" |
|||
|
|||
let time: String |
|||
let memo: String |
|||
let amount: String |
|||
let type: String |
|||
|
|||
init(time: String, memo: String, type: String, amount: String) { |
|||
self.time = time |
|||
self.memo = memo |
|||
self.type = type |
|||
self.amount = amount |
|||
} |
|||
|
|||
func encode(with aCoder: NSCoder) { |
|||
aCoder.encode(time, forKey: "time") |
|||
aCoder.encode(memo, forKey: "memo") |
|||
aCoder.encode(type, forKey: "type") |
|||
aCoder.encode(amount, forKey: "amount") |
|||
} |
|||
|
|||
required init?(coder aDecoder: NSCoder) { |
|||
time = aDecoder.decodeObject(forKey: "time") as! String |
|||
memo = aDecoder.decodeObject(forKey: "memo") as! String |
|||
amount = aDecoder.decodeObject(forKey: "amount") as! String |
|||
type = aDecoder.decodeObject(forKey: "type") as! String |
|||
} |
|||
} |
@ -0,0 +1,52 @@ |
|||
// |
|||
// TransactionTableRow.swift |
|||
// BlueWalletWatch Extension |
|||
// |
|||
// Created by Marcos Rodriguez on 3/10/19. |
|||
// Copyright © 2019 Facebook. All rights reserved. |
|||
// |
|||
|
|||
import WatchKit |
|||
|
|||
class TransactionTableRow: NSObject { |
|||
|
|||
@IBOutlet private weak var transactionAmountLabel: WKInterfaceLabel! |
|||
@IBOutlet private weak var transactionMemoLabel: WKInterfaceLabel! |
|||
@IBOutlet private weak var transactionTimeLabel: WKInterfaceLabel! |
|||
@IBOutlet private weak var transactionTypeImage: WKInterfaceImage! |
|||
|
|||
static let identifier: String = "TransactionTableRow" |
|||
|
|||
var amount: String = "" { |
|||
willSet { |
|||
transactionAmountLabel.setText(newValue) |
|||
} |
|||
} |
|||
|
|||
var memo: String = "" { |
|||
willSet { |
|||
transactionMemoLabel.setText(newValue) |
|||
} |
|||
} |
|||
|
|||
var time: String = "" { |
|||
willSet { |
|||
transactionTimeLabel.setText(newValue) |
|||
} |
|||
} |
|||
|
|||
var type: String = "" { |
|||
willSet { |
|||
if (newValue == "pendingConfirmation") { |
|||
transactionTypeImage.setImage(UIImage(named: "pendingConfirmation")) |
|||
} else if (newValue == "received") { |
|||
transactionTypeImage.setImage(UIImage(named: "receivedArrow")) |
|||
} else if (newValue == "sent") { |
|||
transactionTypeImage.setImage(UIImage(named: "sentArrow")) |
|||
} else { |
|||
transactionTypeImage.setImage(nil) |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
@ -0,0 +1,51 @@ |
|||
// |
|||
// Wallet.swift |
|||
// BlueWalletWatch Extension |
|||
// |
|||
// Created by Marcos Rodriguez on 3/13/19. |
|||
// Copyright © 2019 Facebook. All rights reserved. |
|||
// |
|||
|
|||
import Foundation |
|||
|
|||
class Wallet: NSObject, NSCoding { |
|||
static let identifier: String = "Wallet" |
|||
|
|||
var identifier: Int? |
|||
let label: String |
|||
let balance: String |
|||
let type: String |
|||
let preferredBalanceUnit: String |
|||
let receiveAddress: String |
|||
let transactions: [Transaction] |
|||
|
|||
init(label: String, balance: String, type: String, preferredBalanceUnit: String, receiveAddress: String, transactions: [Transaction], identifier: Int) { |
|||
self.label = label |
|||
self.balance = balance |
|||
self.type = type |
|||
self.preferredBalanceUnit = preferredBalanceUnit |
|||
self.receiveAddress = receiveAddress |
|||
self.transactions = transactions |
|||
self.identifier = identifier |
|||
} |
|||
|
|||
func encode(with aCoder: NSCoder) { |
|||
aCoder.encode(label, forKey: "label") |
|||
aCoder.encode(balance, forKey: "balance") |
|||
aCoder.encode(type, forKey: "type") |
|||
aCoder.encode(receiveAddress, forKey: "receiveAddress") |
|||
aCoder.encode(preferredBalanceUnit, forKey: "preferredBalanceUnit") |
|||
aCoder.encode(transactions, forKey: "transactions") |
|||
aCoder.encode(identifier, forKey: "identifier") |
|||
} |
|||
|
|||
required init?(coder aDecoder: NSCoder) { |
|||
label = aDecoder.decodeObject(forKey: "label") as! String |
|||
balance = aDecoder.decodeObject(forKey: "balance") as! String |
|||
type = aDecoder.decodeObject(forKey: "type") as! String |
|||
preferredBalanceUnit = aDecoder.decodeObject(forKey: "preferredBalanceUnit") as! String |
|||
receiveAddress = aDecoder.decodeObject(forKey: "receiveAddress") as! String |
|||
transactions = aDecoder.decodeObject(forKey: "transactions") as? [Transaction] ?? [Transaction]() |
|||
} |
|||
|
|||
} |
@ -0,0 +1,32 @@ |
|||
// |
|||
// WalletGradient.swift |
|||
// BlueWalletWatch Extension |
|||
// |
|||
// Created by Marcos Rodriguez on 3/23/19. |
|||
// Copyright © 2019 Facebook. All rights reserved. |
|||
// |
|||
|
|||
import Foundation |
|||
|
|||
enum WalletGradient: String { |
|||
case SegwitHD = "HDsegwitP2SH" |
|||
case Segwit = "segwitP2SH" |
|||
case LightningCustodial = "lightningCustodianWallet" |
|||
case ACINQStrike = "LightningACINQ" |
|||
case WatchOnly = "watchOnly" |
|||
|
|||
var imageString: String{ |
|||
switch self { |
|||
case .Segwit: |
|||
return "wallet" |
|||
case .ACINQStrike: |
|||
return "walletACINQ" |
|||
case .SegwitHD: |
|||
return "walletHD" |
|||
case .WatchOnly: |
|||
return "walletWatchOnly" |
|||
case .LightningCustodial: |
|||
return "walletLightningCustodial" |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,36 @@ |
|||
// |
|||
// WalletInformation.swift |
|||
// BlueWalletWatch Extension |
|||
// |
|||
// Created by Marcos Rodriguez on 3/10/19. |
|||
// Copyright © 2019 Facebook. All rights reserved. |
|||
// |
|||
|
|||
import WatchKit |
|||
|
|||
class WalletInformation: NSObject { |
|||
|
|||
@IBOutlet private weak var walletBalanceLabel: WKInterfaceLabel! |
|||
@IBOutlet private weak var walletNameLabel: WKInterfaceLabel! |
|||
@IBOutlet private weak var walletGroup: WKInterfaceGroup! |
|||
static let identifier: String = "WalletInformation" |
|||
|
|||
var name: String = "" { |
|||
willSet { |
|||
walletNameLabel.setText(newValue) |
|||
} |
|||
} |
|||
|
|||
var balance: String = "" { |
|||
willSet { |
|||
walletBalanceLabel.setText(newValue) |
|||
} |
|||
} |
|||
|
|||
var type: WalletGradient = .SegwitHD { |
|||
willSet { |
|||
walletGroup.setBackgroundImageNamed(newValue.imageString) |
|||
} |
|||
} |
|||
|
|||
} |
@ -0,0 +1,103 @@ |
|||
// |
|||
// WatchDataSource.swift |
|||
// BlueWalletWatch Extension |
|||
// |
|||
// Created by Marcos Rodriguez on 3/20/19. |
|||
// Copyright © 2019 Facebook. All rights reserved. |
|||
// |
|||
|
|||
|
|||
import Foundation |
|||
import WatchConnectivity |
|||
|
|||
class WatchDataSource: NSObject, WCSessionDelegate { |
|||
struct NotificationName { |
|||
static let dataUpdated = Notification.Name(rawValue: "Notification.WalletDataSource.Updated") |
|||
} |
|||
struct Notifications { |
|||
static let dataUpdated = Notification(name: NotificationName.dataUpdated) |
|||
} |
|||
|
|||
static let shared = WatchDataSource() |
|||
var wallets: [Wallet] = [Wallet]() |
|||
private let keychain = KeychainSwift() |
|||
|
|||
override init() { |
|||
super.init() |
|||
if WCSession.isSupported() { |
|||
print("Activating watch session") |
|||
WCSession.default.delegate = self |
|||
WCSession.default.activate() |
|||
} |
|||
} |
|||
|
|||
func processWalletsData(walletsInfo: [String: Any]) { |
|||
if let walletsToProcess = walletsInfo["wallets"] as? [[String: Any]] { |
|||
wallets.removeAll(); |
|||
for (index, entry) in walletsToProcess.enumerated() { |
|||
guard let label = entry["label"] as? String, let balance = entry["balance"] as? String, let type = entry["type"] as? String, let preferredBalanceUnit = entry["preferredBalanceUnit"] as? String, let receiveAddress = entry["receiveAddress"] as? String, let transactions = entry["transactions"] as? [[String: Any]] else { |
|||
continue |
|||
} |
|||
var transactionsProcessed = [Transaction]() |
|||
for transactionEntry in transactions { |
|||
guard let time = transactionEntry["time"] as? String, let memo = transactionEntry["memo"] as? String, let amount = transactionEntry["amount"] as? String, let type = transactionEntry["type"] as? String else { continue } |
|||
let transaction = Transaction(time: time, memo: memo, type: type, amount: amount) |
|||
transactionsProcessed.append(transaction) |
|||
} |
|||
let wallet = Wallet(label: label, balance: balance, type: type, preferredBalanceUnit: preferredBalanceUnit, receiveAddress: receiveAddress, transactions: transactionsProcessed, identifier: index) |
|||
wallets.append(wallet) |
|||
} |
|||
|
|||
if let walletsArchived = try? NSKeyedArchiver.archivedData(withRootObject: wallets, requiringSecureCoding: false) { |
|||
keychain.set(walletsArchived, forKey: Wallet.identifier) |
|||
} |
|||
WatchDataSource.postDataUpdatedNotification() |
|||
} |
|||
} |
|||
|
|||
static func postDataUpdatedNotification() { |
|||
NotificationCenter.default.post(Notifications.dataUpdated) |
|||
} |
|||
|
|||
static func requestLightningInvoice(walletIdentifier: Int, amount: Double, description: String?, responseHandler: @escaping (_ invoice: String) -> Void) { |
|||
guard WatchDataSource.shared.wallets.count > walletIdentifier else { |
|||
responseHandler("") |
|||
return |
|||
} |
|||
WCSession.default.sendMessage(["request": "createInvoice", "walletIndex": walletIdentifier, "amount": amount, "description": description ?? ""], replyHandler: { (reply: [String : Any]) in |
|||
if let invoicePaymentRequest = reply["invoicePaymentRequest"] as? String, !invoicePaymentRequest.isEmpty { |
|||
responseHandler(invoicePaymentRequest) |
|||
} else { |
|||
responseHandler("") |
|||
} |
|||
}) { (error) in |
|||
print(error) |
|||
responseHandler("") |
|||
|
|||
} |
|||
} |
|||
|
|||
func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any], replyHandler: @escaping ([String : Any]) -> Void) { |
|||
WatchDataSource.shared.processWalletsData(walletsInfo: applicationContext) |
|||
} |
|||
|
|||
func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) { |
|||
WatchDataSource.shared.processWalletsData(walletsInfo: applicationContext) |
|||
} |
|||
|
|||
func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) { |
|||
// WatchDataSource.shared.processWalletsData(walletsInfo: userInfo) |
|||
} |
|||
|
|||
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) { |
|||
if activationState == .activated { |
|||
WCSession.default.sendMessage([:], replyHandler: nil, errorHandler: nil) |
|||
if let existingData = keychain.getData(Wallet.identifier), let walletData = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(existingData) as? [Wallet] { |
|||
guard let walletData = walletData, walletData != self.wallets else { return } |
|||
wallets = walletData |
|||
WatchDataSource.postDataUpdatedNotification() |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
@ -0,0 +1,20 @@ |
|||
{ |
|||
"aps": { |
|||
"alert": { |
|||
"body": "Test message", |
|||
"title": "Optional title", |
|||
"subtitle": "Optional subtitle" |
|||
}, |
|||
"category": "myCategory", |
|||
"thread-id":"5280" |
|||
}, |
|||
|
|||
"WatchKit Simulator Actions": [ |
|||
{ |
|||
"title": "First Button", |
|||
"identifier": "firstButtonAction" |
|||
} |
|||
], |
|||
|
|||
"customKey": "Use this file to define a testing payload for your notifications. The aps dictionary specifies the category, alert text and title. The WatchKit Simulator Actions array can provide info for one or more action buttons in addition to the standard Dismiss button. Any other top level keys are custom payload. If you have multiple such JSON files in your project, you'll be able to select them when choosing to debug the notification interface of your Watch App." |
|||
} |
@ -0,0 +1,115 @@ |
|||
// |
|||
// ReceiveInterfaceController.swift |
|||
// BlueWalletWatch Extension |
|||
// |
|||
// Created by Marcos Rodriguez on 3/12/19. |
|||
// Copyright © 2019 Facebook. All rights reserved. |
|||
// |
|||
|
|||
import WatchKit |
|||
import Foundation |
|||
import EFQRCode |
|||
|
|||
class ReceiveInterfaceController: WKInterfaceController { |
|||
|
|||
static let identifier = "ReceiveInterfaceController" |
|||
@IBOutlet weak var imageInterface: WKInterfaceImage! |
|||
private var wallet: Wallet? |
|||
private var isRenderingQRCode: Bool? |
|||
@IBOutlet weak var loadingIndicator: WKInterfaceGroup! |
|||
|
|||
override func awake(withContext context: Any?) { |
|||
super.awake(withContext: context) |
|||
guard let identifier = context as? Int, WatchDataSource.shared.wallets.count > identifier else { |
|||
pop() |
|||
return |
|||
} |
|||
let wallet = WatchDataSource.shared.wallets[identifier] |
|||
self.wallet = wallet |
|||
NotificationCenter.default.addObserver(forName: SpecifyInterfaceController.NotificationName.createQRCode, object: nil, queue: nil) { [weak self] (notification) in |
|||
self?.isRenderingQRCode = true |
|||
if let wallet = self?.wallet, wallet.type == "lightningCustodianWallet", let object = notification.object as? SpecifyInterfaceController.SpecificQRCodeContent, let amount = object.amount { |
|||
self?.imageInterface.setHidden(true) |
|||
self?.loadingIndicator.setHidden(false) |
|||
WatchDataSource.requestLightningInvoice(walletIdentifier: identifier, amount: amount, description: object.description, responseHandler: { (invoice) in |
|||
DispatchQueue.main.async { |
|||
if (!invoice.isEmpty) { |
|||
guard let cgImage = EFQRCode.generate( |
|||
content: "lightning:\(invoice)") else { |
|||
return |
|||
} |
|||
let image = UIImage(cgImage: cgImage) |
|||
self?.loadingIndicator.setHidden(true) |
|||
self?.imageInterface.setHidden(false) |
|||
self?.imageInterface.setImage(nil) |
|||
self?.imageInterface.setImage(image) |
|||
} else { |
|||
self?.pop() |
|||
self?.presentAlert(withTitle: "Error", message: "Unable to create invoice. Please, make sure your iPhone is paired and nearby.", preferredStyle: .alert, actions: [WKAlertAction(title: "OK", style: .default, handler: { [weak self] in |
|||
self?.dismiss() |
|||
})]) |
|||
} |
|||
} |
|||
}) |
|||
} else { |
|||
guard let notificationObject = notification.object as? SpecifyInterfaceController.SpecificQRCodeContent, let walletContext = self?.wallet, !walletContext.receiveAddress.isEmpty, let receiveAddress = self?.wallet?.receiveAddress else { return } |
|||
var address = "bitcoin:\(receiveAddress)" |
|||
|
|||
var hasAmount = false |
|||
if let amount = notificationObject.amount { |
|||
address.append("?amount=\(amount)&") |
|||
hasAmount = true |
|||
} |
|||
if let description = notificationObject.description { |
|||
if (!hasAmount) { |
|||
address.append("?") |
|||
} |
|||
address.append("label=\(description)") |
|||
} |
|||
|
|||
DispatchQueue.main.async { |
|||
guard let cgImage = EFQRCode.generate( |
|||
content: address) else { |
|||
return |
|||
} |
|||
let image = UIImage(cgImage: cgImage) |
|||
self?.imageInterface.setImage(nil) |
|||
self?.imageInterface.setImage(image) |
|||
self?.imageInterface.setHidden(false) |
|||
self?.loadingIndicator.setHidden(true) |
|||
self?.isRenderingQRCode = false |
|||
} |
|||
} |
|||
} |
|||
|
|||
guard !wallet.receiveAddress.isEmpty, let cgImage = EFQRCode.generate( |
|||
content: wallet.receiveAddress) else { |
|||
return |
|||
} |
|||
|
|||
let image = UIImage(cgImage: cgImage) |
|||
imageInterface.setImage(image) |
|||
} |
|||
|
|||
override func didAppear() { |
|||
super.didAppear() |
|||
if wallet?.type == "lightningCustodianWallet" { |
|||
if isRenderingQRCode == nil { |
|||
presentController(withName: SpecifyInterfaceController.identifier, context: wallet?.identifier) |
|||
isRenderingQRCode = false |
|||
} else if isRenderingQRCode == false { |
|||
pop() |
|||
} |
|||
} |
|||
} |
|||
|
|||
override func didDeactivate() { |
|||
super.didDeactivate() |
|||
NotificationCenter.default.removeObserver(self, name: SpecifyInterfaceController.NotificationName.createQRCode, object: nil) |
|||
} |
|||
|
|||
@IBAction func specifyMenuItemTapped() { |
|||
presentController(withName: SpecifyInterfaceController.identifier, context: wallet?.identifier) |
|||
} |
|||
|
|||
} |
@ -0,0 +1,90 @@ |
|||
// |
|||
// SpecifyInterfaceController.swift |
|||
// BlueWalletWatch Extension |
|||
// |
|||
// Created by Marcos Rodriguez on 3/23/19. |
|||
// Copyright © 2019 Facebook. All rights reserved. |
|||
// |
|||
|
|||
import WatchKit |
|||
import Foundation |
|||
|
|||
class SpecifyInterfaceController: WKInterfaceController { |
|||
|
|||
static let identifier = "SpecifyInterfaceController" |
|||
@IBOutlet weak var descriptionButton: WKInterfaceButton! |
|||
@IBOutlet weak var amountButton: WKInterfaceButton! |
|||
struct SpecificQRCodeContent { |
|||
var amount: Double? |
|||
var description: String? |
|||
var amountStringArray: [String] = ["0"] |
|||
var bitcoinUnit: NumericKeypadInterfaceController.NumericKeypadType = .BTC |
|||
} |
|||
var specifiedQRContent: SpecificQRCodeContent = SpecificQRCodeContent(amount: nil, description: nil, amountStringArray: ["0"], bitcoinUnit: .BTC) |
|||
var wallet: Wallet? |
|||
struct NotificationName { |
|||
static let createQRCode = Notification.Name(rawValue: "Notification.SpecifyInterfaceController.createQRCode") |
|||
} |
|||
struct Notifications { |
|||
static let createQRCode = Notification(name: NotificationName.createQRCode) |
|||
} |
|||
|
|||
override func awake(withContext context: Any?) { |
|||
super.awake(withContext: context) |
|||
guard let identifier = context as? Int, WatchDataSource.shared.wallets.count > identifier else { |
|||
return |
|||
} |
|||
let wallet = WatchDataSource.shared.wallets[identifier] |
|||
self.wallet = wallet |
|||
self.specifiedQRContent.bitcoinUnit = wallet.type == "lightningCustodianWallet" ? .SATS : .BTC |
|||
NotificationCenter.default.addObserver(forName: NumericKeypadInterfaceController.NotificationName.keypadDataChanged, object: nil, queue: nil) { [weak self] (notification) in |
|||
guard let amountObject = notification.object as? [String], !amountObject.isEmpty else { return } |
|||
if amountObject.count == 1 && (amountObject.first == "." || amountObject.first == "0") { |
|||
return |
|||
} |
|||
var title = "" |
|||
for amount in amountObject { |
|||
let isValid = Double(amount) |
|||
if amount == "." || isValid != nil { |
|||
title.append(String(amount)) |
|||
} |
|||
} |
|||
self?.specifiedQRContent.amountStringArray = amountObject |
|||
if let amountDouble = Double(title), let keyPadType = self?.specifiedQRContent.bitcoinUnit { |
|||
self?.specifiedQRContent.amount = amountDouble |
|||
self?.amountButton.setTitle("\(title) \(keyPadType)") |
|||
} |
|||
} |
|||
} |
|||
|
|||
override func didDeactivate() { |
|||
// This method is called when watch view controller is no longer visible |
|||
super.didDeactivate() |
|||
NotificationCenter.default.removeObserver(self, name: NumericKeypadInterfaceController.NotificationName.keypadDataChanged, object: nil) |
|||
} |
|||
|
|||
@IBAction func descriptionButtonTapped() { |
|||
presentTextInputController(withSuggestions: nil, allowedInputMode: .allowEmoji) { [weak self] (result: [Any]?) in |
|||
DispatchQueue.main.async { |
|||
if let result = result, let text = result.first as? String { |
|||
self?.specifiedQRContent.description = text |
|||
self?.descriptionButton.setTitle(nil) |
|||
self?.descriptionButton.setTitle(text) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
@IBAction func createButtonTapped() { |
|||
NotificationCenter.default.post(name: NotificationName.createQRCode, object: specifiedQRContent) |
|||
dismiss() |
|||
} |
|||
|
|||
override func contextForSegue(withIdentifier segueIdentifier: String) -> Any? { |
|||
if segueIdentifier == NumericKeypadInterfaceController.identifier { |
|||
return specifiedQRContent |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
} |
@ -0,0 +1,68 @@ |
|||
// |
|||
// WalletDetailsInterfaceController.swift |
|||
// BlueWalletWatch Extension |
|||
// |
|||
// Created by Marcos Rodriguez on 3/11/19. |
|||
// Copyright © 2019 Facebook. All rights reserved. |
|||
// |
|||
|
|||
import WatchKit |
|||
import Foundation |
|||
|
|||
|
|||
class WalletDetailsInterfaceController: WKInterfaceController { |
|||
|
|||
var wallet: Wallet? |
|||
static let identifier = "WalletDetailsInterfaceController" |
|||
@IBOutlet weak var walletBasicsGroup: WKInterfaceGroup! |
|||
@IBOutlet weak var walletBalanceLabel: WKInterfaceLabel! |
|||
@IBOutlet weak var walletNameLabel: WKInterfaceLabel! |
|||
@IBOutlet weak var receiveButton: WKInterfaceButton! |
|||
@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 |
|||
} |
|||
let wallet = WatchDataSource.shared.wallets[identifier] |
|||
self.wallet = wallet |
|||
walletBalanceLabel.setText(wallet.balance) |
|||
walletNameLabel.setText(wallet.label) |
|||
walletBasicsGroup.setBackgroundImageNamed(WalletGradient(rawValue: wallet.type)?.imageString) |
|||
|
|||
processWalletsTable() |
|||
} |
|||
|
|||
override func willActivate() { |
|||
super.willActivate() |
|||
transactionsTable.setHidden(wallet?.transactions.isEmpty ?? true) |
|||
noTransactionsLabel.setHidden(!(wallet?.transactions.isEmpty ?? false)) |
|||
} |
|||
|
|||
@IBAction func receiveMenuItemTapped() { |
|||
presentController(withName: ReceiveInterfaceController.identifier, context: wallet) |
|||
} |
|||
|
|||
@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)) |
|||
} |
|||
|
|||
override func contextForSegue(withIdentifier segueIdentifier: String) -> Any? { |
|||
return wallet?.identifier |
|||
} |
|||
|
|||
} |
After Width: | Height: | Size: 193 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 2.2 KiB |
@ -0,0 +1,92 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"size" : "24x24", |
|||
"idiom" : "watch", |
|||
"filename" : "Icon-48.png", |
|||
"scale" : "2x", |
|||
"role" : "notificationCenter", |
|||
"subtype" : "38mm" |
|||
}, |
|||
{ |
|||
"size" : "27.5x27.5", |
|||
"idiom" : "watch", |
|||
"filename" : "Icon-55.png", |
|||
"scale" : "2x", |
|||
"role" : "notificationCenter", |
|||
"subtype" : "42mm" |
|||
}, |
|||
{ |
|||
"size" : "29x29", |
|||
"idiom" : "watch", |
|||
"filename" : "58.png", |
|||
"role" : "companionSettings", |
|||
"scale" : "2x" |
|||
}, |
|||
{ |
|||
"size" : "29x29", |
|||
"idiom" : "watch", |
|||
"filename" : "87.png", |
|||
"role" : "companionSettings", |
|||
"scale" : "3x" |
|||
}, |
|||
{ |
|||
"size" : "40x40", |
|||
"idiom" : "watch", |
|||
"filename" : "watch.png", |
|||
"scale" : "2x", |
|||
"role" : "appLauncher", |
|||
"subtype" : "38mm" |
|||
}, |
|||
{ |
|||
"size" : "44x44", |
|||
"idiom" : "watch", |
|||
"filename" : "Icon-88.png", |
|||
"scale" : "2x", |
|||
"role" : "appLauncher", |
|||
"subtype" : "40mm" |
|||
}, |
|||
{ |
|||
"size" : "50x50", |
|||
"idiom" : "watch", |
|||
"filename" : "Icon-173.png", |
|||
"scale" : "2x", |
|||
"role" : "appLauncher", |
|||
"subtype" : "44mm" |
|||
}, |
|||
{ |
|||
"size" : "86x86", |
|||
"idiom" : "watch", |
|||
"filename" : "Icon-172.png", |
|||
"scale" : "2x", |
|||
"role" : "quickLook", |
|||
"subtype" : "38mm" |
|||
}, |
|||
{ |
|||
"size" : "98x98", |
|||
"idiom" : "watch", |
|||
"filename" : "Icon-196.png", |
|||
"scale" : "2x", |
|||
"role" : "quickLook", |
|||
"subtype" : "42mm" |
|||
}, |
|||
{ |
|||
"size" : "108x108", |
|||
"idiom" : "watch", |
|||
"filename" : "group-copy-2@3x.png", |
|||
"scale" : "2x", |
|||
"role" : "quickLook", |
|||
"subtype" : "44mm" |
|||
}, |
|||
{ |
|||
"size" : "1024x1024", |
|||
"idiom" : "watch-marketing", |
|||
"filename" : "1024.png", |
|||
"scale" : "1x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"version" : 1, |
|||
"author" : "xcode" |
|||
} |
|||
} |
After Width: | Height: | Size: 7.5 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 9.0 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 9.4 KiB |
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,6 @@ |
|||
{ |
|||
"info" : { |
|||
"version" : 1, |
|||
"author" : "xcode" |
|||
} |
|||
} |
@ -0,0 +1,13 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"idiom" : "watch", |
|||
"filename" : "group-copy-2@3x.png", |
|||
"scale" : "2x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"version" : 1, |
|||
"author" : "xcode" |
|||
} |
|||
} |
After Width: | Height: | Size: 14 KiB |
@ -0,0 +1,13 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"idiom" : "watch", |
|||
"filename" : "shape@3x.png", |
|||
"scale" : "2x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"version" : 1, |
|||
"author" : "xcode" |
|||
} |
|||
} |
After Width: | Height: | Size: 692 B |
@ -0,0 +1,13 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"idiom" : "watch", |
|||
"filename" : "qr-code@3x.png", |
|||
"scale" : "2x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"version" : 1, |
|||
"author" : "xcode" |
|||
} |
|||
} |
After Width: | Height: | Size: 112 KiB |
@ -0,0 +1,13 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"idiom" : "watch", |
|||
"filename" : "path-copy-3@2x.png", |
|||
"scale" : "2x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"version" : 1, |
|||
"author" : "xcode" |
|||
} |
|||
} |
After Width: | Height: | Size: 447 B |
@ -0,0 +1,13 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"idiom" : "watch", |
|||
"filename" : "path-copy@2x.png", |
|||
"scale" : "2x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"version" : 1, |
|||
"author" : "xcode" |
|||
} |
|||
} |
After Width: | Height: | Size: 471 B |
@ -0,0 +1,23 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"idiom" : "universal", |
|||
"filename" : "mask.png", |
|||
"scale" : "1x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"filename" : "mask@2x.png", |
|||
"scale" : "2x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"filename" : "mask@3x.png", |
|||
"scale" : "3x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"version" : 1, |
|||
"author" : "xcode" |
|||
} |
|||
} |
After Width: | Height: | Size: 5.4 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 25 KiB |
@ -0,0 +1,23 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"idiom" : "universal", |
|||
"filename" : "mask.png", |
|||
"scale" : "1x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"filename" : "mask@2x.png", |
|||
"scale" : "2x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"filename" : "mask@3x.png", |
|||
"scale" : "3x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"version" : 1, |
|||
"author" : "xcode" |
|||
} |
|||
} |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 25 KiB |
@ -0,0 +1,13 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"idiom" : "watch", |
|||
"filename" : "mask@3x.png", |
|||
"scale" : "2x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"version" : 1, |
|||
"author" : "xcode" |
|||
} |
|||
} |
After Width: | Height: | Size: 25 KiB |
@ -0,0 +1,13 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"idiom" : "watch", |
|||
"filename" : "mask@3x.png", |
|||
"scale" : "2x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"version" : 1, |
|||
"author" : "xcode" |
|||
} |
|||
} |
After Width: | Height: | Size: 26 KiB |
@ -0,0 +1,23 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"idiom" : "universal", |
|||
"filename" : "mask.png", |
|||
"scale" : "1x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"filename" : "mask@2x.png", |
|||
"scale" : "2x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"filename" : "mask@3x.png", |
|||
"scale" : "3x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"version" : 1, |
|||
"author" : "xcode" |
|||
} |
|||
} |
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 24 KiB |
@ -0,0 +1,339 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<document type="com.apple.InterfaceBuilder.WatchKit.Storyboard" version="3.0" toolsVersion="14490.70" targetRuntime="watchKit" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="AgC-eL-Hgc"> |
|||
<device id="watch44" orientation="portrait"> |
|||
<adaptation id="fullscreen"/> |
|||
</device> |
|||
<dependencies> |
|||
<deployment identifier="watchOS"/> |
|||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/> |
|||
<plugIn identifier="com.apple.InterfaceBuilder.IBWatchKitPlugin" version="14490.21"/> |
|||
</dependencies> |
|||
<scenes> |
|||
<!--BlueWallet--> |
|||
<scene sceneID="aou-V4-d1y"> |
|||
<objects> |
|||
<controller title="BlueWallet" fullBounds="YES" id="AgC-eL-Hgc" customClass="InterfaceController" customModule="BlueWalletWatch" customModuleProvider="target"> |
|||
<items> |
|||
<table alignment="left" id="jUH-JS-ccp"> |
|||
<items> |
|||
<tableRow identifier="WalletInformation" id="Rdv-UZ-gaS" customClass="WalletInformation" customModule="BlueWalletWatch_Extension"> |
|||
<group key="rootItem" width="1" height="66.5" alignment="left" backgroundImage="walletHD" radius="8" id="H28-wi-Sks" customClass="WalletInformation" customModule="BlueWalletWatch_Extension"> |
|||
<items> |
|||
<label width="6" alignment="left" id="RJV-QC-scb"/> |
|||
<group width="1" alignment="center" verticalAlignment="center" layout="vertical" id="UrU-xX-jYW"> |
|||
<items> |
|||
<label width="1" alignment="left" text="Balance" minimumScaleFactor="0.5" id="QYx-3e-6zf"> |
|||
<fontDescription key="font" style="UICTFontTextStyleHeadline"/> |
|||
</label> |
|||
<label alignment="left" text="Wallet" id="qpj-I1-cWt"/> |
|||
</items> |
|||
</group> |
|||
</items> |
|||
</group> |
|||
<connections> |
|||
<outlet property="walletBalanceLabel" destination="QYx-3e-6zf" id="cfa-2U-FBQ"/> |
|||
<outlet property="walletGroup" destination="H28-wi-Sks" id="ydq-d4-4eb"/> |
|||
<outlet property="walletNameLabel" destination="qpj-I1-cWt" id="dd9-XB-XMc"/> |
|||
<segue destination="XWa-4i-Abg" kind="push" identifier="WalletDetailsInterfaceController" id="Qts-pn-15q"/> |
|||
</connections> |
|||
</tableRow> |
|||
</items> |
|||
</table> |
|||
<group width="1" alignment="left" verticalAlignment="center" layout="vertical" id="1Db-mZ-yxl"> |
|||
<items> |
|||
<imageView width="60" height="60" alignment="center" image="loadingIndicator" contentMode="scaleAspectFit" id="dLA-pP-GUU"/> |
|||
<label alignment="center" text="Loading wallets..." id="hCG-Eg-bck"/> |
|||
</items> |
|||
</group> |
|||
<label alignment="center" verticalAlignment="center" hidden="YES" text="No wallets available. Please, add one by opening BlueWallet on your iPhone." textAlignment="center" numberOfLines="0" id="I2I-8t-hp3"/> |
|||
</items> |
|||
<connections> |
|||
<outlet property="loadingIndicatorGroup" destination="1Db-mZ-yxl" id="XPX-Y8-dv0"/> |
|||
<outlet property="noWalletsAvailableLabel" destination="I2I-8t-hp3" id="c4O-Mg-3ps"/> |
|||
<outlet property="walletsTable" destination="jUH-JS-ccp" id="ONe-Gg-EJn"/> |
|||
</connections> |
|||
</controller> |
|||
</objects> |
|||
<point key="canvasLocation" x="220" y="345"/> |
|||
</scene> |
|||
<!--WalletDetailsInterfaceController--> |
|||
<scene sceneID="KqX-Cy-IJm"> |
|||
<objects> |
|||
<controller identifier="WalletDetailsInterfaceController" id="XWa-4i-Abg" customClass="WalletDetailsInterfaceController" customModule="BlueWalletWatch_Extension"> |
|||
<items> |
|||
<group width="1" height="66.5" alignment="left" backgroundImage="walletHD" radius="8" id="275-K7-Qhe" customClass="WalletInformation" customModule="BlueWalletWatch_Extension"> |
|||
<items> |
|||
<label width="6" alignment="left" id="QMf-Fm-1cw"/> |
|||
<group width="1" widthAdjustment="-10" alignment="center" verticalAlignment="center" layout="vertical" id="jx2-si-OEm"> |
|||
<items> |
|||
<label alignment="left" text="Balance" minimumScaleFactor="0.5" id="WTr-jJ-w7L"> |
|||
<fontDescription key="font" style="UICTFontTextStyleHeadline"/> |
|||
</label> |
|||
<label width="1" alignment="left" text="Wallet" id="PQi-JV-aYW"/> |
|||
</items> |
|||
</group> |
|||
</items> |
|||
</group> |
|||
<button width="1" alignment="left" title="Receive" id="bPO-h8-ccD"> |
|||
<color key="titleColor" red="0.18431372549019609" green="0.37254901960784315" blue="0.70196078431372544" alpha="1" colorSpace="calibratedRGB"/> |
|||
<color key="backgroundColor" red="0.80000000000000004" green="0.8666666666666667" blue="0.97647058823529409" alpha="1" colorSpace="calibratedRGB"/> |
|||
<fontDescription key="font" type="system" weight="medium" pointSize="16"/> |
|||
<connections> |
|||
<segue destination="egq-Yw-qK5" kind="push" identifier="ReceiveInterfaceController" id="zEG-Xi-Smb"/> |
|||
</connections> |
|||
</button> |
|||
<label alignment="center" verticalAlignment="bottom" text="No Transactions" textAlignment="left" id="pi4-Bk-Jiq"/> |
|||
<table alignment="left" id="nyQ-lX-DX0"> |
|||
<items> |
|||
<tableRow identifier="TransactionTableRow" id="HuQ-ep-L9j" customClass="TransactionTableRow" customModule="BlueWalletWatch_Extension"> |
|||
<group key="rootItem" width="1" height="0.0" alignment="left" id="3X8-cc-rOv"> |
|||
<items> |
|||
<button alignment="left" id="NEN-rG-rmr"> |
|||
<group key="contentGroup" width="1" alignment="left" id="NY7-0s-nLc"> |
|||
<items> |
|||
<imageView width="23" height="16" alignment="left" verticalAlignment="center" image="pendingConfirmation" contentMode="scaleAspectFit" id="hWs-WA-db1"/> |
|||
<group width="1" alignment="left" layout="vertical" spacing="8" id="Tes-g9-rp0"> |
|||
<items> |
|||
<label width="1" alignment="left" text="Time" minimumScaleFactor="0.10000000000000001" id="GqE-KB-TRD"> |
|||
<fontDescription key="font" style="UICTFontTextStyleSubhead"/> |
|||
</label> |
|||
<label width="1" alignment="left" verticalAlignment="bottom" text="memo" numberOfLines="0" id="AJ8-p9-ID7"> |
|||
<color key="textColor" red="0.63137254901960782" green="0.63137254901960782" blue="0.63137254901960782" alpha="0.84999999999999998" colorSpace="calibratedRGB"/> |
|||
<fontDescription key="font" style="UICTFontTextStyleSubhead"/> |
|||
</label> |
|||
<label width="1" alignment="left" text="Amount" textAlignment="left" minimumScaleFactor="0.10000000000000001" id="sAS-LI-RY7"> |
|||
<fontDescription key="font" style="UICTFontTextStyleSubhead"/> |
|||
</label> |
|||
</items> |
|||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> |
|||
<edgeInsets key="margins" left="4" right="27" top="8" bottom="8"/> |
|||
</group> |
|||
</items> |
|||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> |
|||
</group> |
|||
</button> |
|||
</items> |
|||
</group> |
|||
<connections> |
|||
<outlet property="transactionAmountLabel" destination="sAS-LI-RY7" id="TkE-JU-sRF"/> |
|||
<outlet property="transactionMemoLabel" destination="AJ8-p9-ID7" id="9I4-VO-d0H"/> |
|||
<outlet property="transactionTimeLabel" destination="GqE-KB-TRD" id="idk-sO-obD"/> |
|||
<outlet property="transactionTypeImage" destination="hWs-WA-db1" id="BF8-T8-T5U"/> |
|||
</connections> |
|||
</tableRow> |
|||
</items> |
|||
</table> |
|||
</items> |
|||
<connections> |
|||
<outlet property="noTransactionsLabel" destination="pi4-Bk-Jiq" id="zft-Hw-KuZ"/> |
|||
<outlet property="receiveButton" destination="bPO-h8-ccD" id="xBq-42-9qP"/> |
|||
<outlet property="transactionsTable" destination="nyQ-lX-DX0" id="N1x-px-s08"/> |
|||
<outlet property="walletBalanceLabel" destination="WTr-jJ-w7L" id="kiU-ZS-2dh"/> |
|||
<outlet property="walletBasicsGroup" destination="275-K7-Qhe" id="nvB-rn-8Xn"/> |
|||
<outlet property="walletNameLabel" destination="PQi-JV-aYW" id="dfi-Ai-rOe"/> |
|||
</connections> |
|||
</controller> |
|||
</objects> |
|||
<point key="canvasLocation" x="467.86956521739125" y="344.55357142857144"/> |
|||
</scene> |
|||
<!--Static Notification Interface Controller--> |
|||
<scene sceneID="AEw-b0-oYE"> |
|||
<objects> |
|||
<notificationController id="YCC-NB-fut"> |
|||
<items> |
|||
<label alignment="left" text="Alert Label" numberOfLines="0" id="IdU-wH-bcW"/> |
|||
</items> |
|||
<notificationCategory key="notificationCategory" identifier="myCategory" id="JfB-70-Muf"/> |
|||
<connections> |
|||
<outlet property="notificationAlertLabel" destination="IdU-wH-bcW" id="JKC-fr-R95"/> |
|||
<segue destination="4sK-HA-Art" kind="relationship" relationship="dynamicNotificationInterface" id="kXh-Jw-8B1"/> |
|||
<segue destination="eXb-UN-Cd0" kind="relationship" relationship="dynamicInteractiveNotificationInterface" id="mpB-YA-K8N"/> |
|||
</connections> |
|||
</notificationController> |
|||
</objects> |
|||
<point key="canvasLocation" x="220" y="643"/> |
|||
</scene> |
|||
<!--Notification Controller--> |
|||
<scene sceneID="ZPc-GJ-vnh"> |
|||
<objects> |
|||
<controller id="4sK-HA-Art" customClass="NotificationController" customModule="BlueWalletWatch" customModuleProvider="target"/> |
|||
</objects> |
|||
<point key="canvasLocation" x="468" y="643"/> |
|||
</scene> |
|||
<!--ReceiveInterfaceController--> |
|||
<scene sceneID="tQ7-Qr-5i4"> |
|||
<objects> |
|||
<controller identifier="ReceiveInterfaceController" fullBounds="YES" fullScreen="YES" id="egq-Yw-qK5" customClass="ReceiveInterfaceController" customModule="BlueWalletWatch_Extension"> |
|||
<items> |
|||
<imageView height="1" alignment="left" id="Dnb-sM-wdN"/> |
|||
<group width="1" alignment="center" verticalAlignment="center" hidden="YES" layout="vertical" id="0If-FP-smM"> |
|||
<items> |
|||
<imageView width="60" height="60" alignment="center" image="loadingIndicator" contentMode="scaleAspectFit" id="nQb-s6-ySB"/> |
|||
<label alignment="center" text="Creating Invoice..." id="n5f-iL-ib7"/> |
|||
</items> |
|||
</group> |
|||
</items> |
|||
<menu key="menu" id="GDw-hN-TVp"> |
|||
<items> |
|||
<menuItem title="Customize" icon="more" id="RHB-IJ-Utd"> |
|||
<connections> |
|||
<action selector="specifyMenuItemTapped" destination="egq-Yw-qK5" id="KMQ-wI-vdE"/> |
|||
</connections> |
|||
</menuItem> |
|||
</items> |
|||
</menu> |
|||
<edgeInsets key="margins" left="4" right="4" top="4" bottom="4"/> |
|||
<connections> |
|||
<outlet property="imageInterface" destination="Dnb-sM-wdN" id="z1e-zC-anB"/> |
|||
<outlet property="loadingIndicator" destination="0If-FP-smM" id="Wtf-mm-8Ke"/> |
|||
</connections> |
|||
</controller> |
|||
</objects> |
|||
<point key="canvasLocation" x="716" y="345"/> |
|||
</scene> |
|||
<!--SpecifyInterfaceController--> |
|||
<scene sceneID="erR-Ld-VGW"> |
|||
<objects> |
|||
<controller identifier="SpecifyInterfaceController" id="aUg-UP-Vh5" customClass="SpecifyInterfaceController" customModule="BlueWalletWatch_Extension"> |
|||
<items> |
|||
<button width="1" alignment="left" title="Description" id="fcI-6Z-moQ"> |
|||
<connections> |
|||
<action selector="descriptionButtonTapped" destination="aUg-UP-Vh5" id="ZT5-rL-QZq"/> |
|||
</connections> |
|||
</button> |
|||
<button width="1" alignment="left" title="Amount" id="0Hm-hv-Yi3"> |
|||
<connections> |
|||
<segue destination="2PN-Fb-8j5" kind="modal" identifier="NumericKeypadInterfaceController" id="LlG-6l-ghO"/> |
|||
</connections> |
|||
</button> |
|||
<separator alignment="left" alpha="0.0" id="i7u-PI-g7Q"> |
|||
<color key="color" red="0.63137254899999995" green="0.63137254899999995" blue="0.63137254899999995" alpha="0.84999999999999998" colorSpace="calibratedRGB"/> |
|||
</separator> |
|||
<button width="1" alignment="left" verticalAlignment="bottom" title="Create" id="6eh-lx-UEe"> |
|||
<color key="titleColor" red="0.1843137255" green="0.37254901959999998" blue="0.70196078429999997" alpha="1" colorSpace="calibratedRGB"/> |
|||
<color key="backgroundColor" red="0.80000000000000004" green="0.86666666670000003" blue="0.97647058819999999" alpha="1" colorSpace="calibratedRGB"/> |
|||
<fontDescription key="font" type="system" weight="medium" pointSize="16"/> |
|||
<connections> |
|||
<action selector="createButtonTapped" destination="aUg-UP-Vh5" id="dnh-3i-jIE"/> |
|||
</connections> |
|||
</button> |
|||
</items> |
|||
<connections> |
|||
<outlet property="amountButton" destination="0Hm-hv-Yi3" id="9DN-zh-BGB"/> |
|||
<outlet property="descriptionButton" destination="fcI-6Z-moQ" id="a7M-ZD-Zsi"/> |
|||
</connections> |
|||
</controller> |
|||
</objects> |
|||
<point key="canvasLocation" x="967" y="357"/> |
|||
</scene> |
|||
<!--NumericKeypadInterfaceController--> |
|||
<scene sceneID="4Mp-O7-Llm"> |
|||
<objects> |
|||
<controller identifier="NumericKeypadInterfaceController" fullBounds="YES" id="2PN-Fb-8j5" customClass="NumericKeypadInterfaceController" customModule="BlueWalletWatch_Extension"> |
|||
<items> |
|||
<group height="0.25" alignment="left" id="kaq-2v-f7r"> |
|||
<items> |
|||
<button width="0.33300000000000002" alignment="left" verticalAlignment="center" title="1" id="ghD-Jq-ubw"> |
|||
<fontDescription key="font" type="system" weight="heavy" pointSize="15"/> |
|||
<connections> |
|||
<action selector="keypadNumberOneTapped" destination="2PN-Fb-8j5" id="n6o-GR-D7i"/> |
|||
</connections> |
|||
</button> |
|||
<button width="0.33300000000000002" alignment="left" verticalAlignment="center" title="2" id="aUI-EE-NVw"> |
|||
<fontDescription key="font" type="system" weight="heavy" pointSize="15"/> |
|||
<connections> |
|||
<action selector="keypadNumberTwoTapped" destination="2PN-Fb-8j5" id="pfD-Db-6od"/> |
|||
</connections> |
|||
</button> |
|||
<button width="0.33300000000000002" alignment="left" verticalAlignment="center" title="3" id="TKO-lc-aYf"> |
|||
<fontDescription key="font" type="system" weight="heavy" pointSize="15"/> |
|||
<connections> |
|||
<action selector="keypadNumberThreeTapped" destination="2PN-Fb-8j5" id="fqm-0L-U6Z"/> |
|||
</connections> |
|||
</button> |
|||
</items> |
|||
</group> |
|||
<group height="0.25" alignment="left" verticalAlignment="center" id="JB4-ZC-T8y"> |
|||
<items> |
|||
<button width="0.33300000000000002" alignment="left" verticalAlignment="center" title="4" id="kH2-N1-Hbe"> |
|||
<fontDescription key="font" type="system" weight="heavy" pointSize="15"/> |
|||
<connections> |
|||
<action selector="keypadNumberFourTapped" destination="2PN-Fb-8j5" id="r24-dK-OUA"/> |
|||
</connections> |
|||
</button> |
|||
<button width="0.33300000000000002" alignment="left" verticalAlignment="center" title="5" id="AA6-Gq-qRe"> |
|||
<fontDescription key="font" type="system" weight="heavy" pointSize="15"/> |
|||
<connections> |
|||
<action selector="keypadNumberFiveTapped" destination="2PN-Fb-8j5" id="yTW-cf-ZCP"/> |
|||
</connections> |
|||
</button> |
|||
<button width="0.33300000000000002" alignment="left" verticalAlignment="center" title="6" id="Nt9-we-M9f"> |
|||
<fontDescription key="font" type="system" weight="heavy" pointSize="15"/> |
|||
<connections> |
|||
<action selector="keypadNumberSixTapped" destination="2PN-Fb-8j5" id="xOh-ab-nWm"/> |
|||
</connections> |
|||
</button> |
|||
</items> |
|||
</group> |
|||
<group height="0.25" alignment="left" verticalAlignment="center" id="CT1-xK-izT"> |
|||
<items> |
|||
<button width="0.33300000000000002" alignment="left" verticalAlignment="center" title="7" id="ohU-B0-mvg"> |
|||
<fontDescription key="font" type="system" weight="heavy" pointSize="15"/> |
|||
<connections> |
|||
<action selector="keypadNumberSevenTapped" destination="2PN-Fb-8j5" id="8CA-Q5-XZt"/> |
|||
</connections> |
|||
</button> |
|||
<button width="0.33300000000000002" alignment="left" verticalAlignment="center" title="8" id="3FQ-tZ-9kd"> |
|||
<fontDescription key="font" type="system" weight="heavy" pointSize="15"/> |
|||
<connections> |
|||
<action selector="keypadNumberEightTapped" destination="2PN-Fb-8j5" id="4h8-vi-GjT"/> |
|||
</connections> |
|||
</button> |
|||
<button width="0.33300000000000002" alignment="left" verticalAlignment="center" title="9" id="NJM-uR-nyO"> |
|||
<fontDescription key="font" type="system" weight="heavy" pointSize="15"/> |
|||
<connections> |
|||
<action selector="keypadNumberNineTapped" destination="2PN-Fb-8j5" id="qpZ-nf-E5y"/> |
|||
</connections> |
|||
</button> |
|||
</items> |
|||
</group> |
|||
<group height="0.25" alignment="left" verticalAlignment="center" id="hqA-Nb-d5C"> |
|||
<items> |
|||
<button width="0.33300000000000002" height="1" alignment="left" verticalAlignment="center" title="." id="g6Z-9t-ahQ"> |
|||
<fontDescription key="font" type="system" weight="heavy" pointSize="15"/> |
|||
<connections> |
|||
<action selector="keypadNumberDotTapped" destination="2PN-Fb-8j5" id="K7P-bQ-h24"/> |
|||
</connections> |
|||
</button> |
|||
<button width="0.33300000000000002" height="1" alignment="left" verticalAlignment="center" title="0" id="S1H-Id-l6g"> |
|||
<fontDescription key="font" type="system" weight="heavy" pointSize="15"/> |
|||
<connections> |
|||
<action selector="keypadNumberZeroTapped" destination="2PN-Fb-8j5" id="YH1-KR-oIu"/> |
|||
</connections> |
|||
</button> |
|||
<button width="0.33300000000000002" height="1" alignment="left" verticalAlignment="center" title="<" id="q8Q-tK-nzd"> |
|||
<fontDescription key="font" type="system" weight="heavy" pointSize="15"/> |
|||
<connections> |
|||
<action selector="keypadNumberRemoveTapped" destination="2PN-Fb-8j5" id="l7u-ZB-AyF"/> |
|||
</connections> |
|||
</button> |
|||
</items> |
|||
</group> |
|||
</items> |
|||
<connections> |
|||
<outlet property="periodButton" destination="g6Z-9t-ahQ" id="ynz-0C-Fxe"/> |
|||
</connections> |
|||
</controller> |
|||
</objects> |
|||
<point key="canvasLocation" x="1197" y="357"/> |
|||
</scene> |
|||
<!--Notification Controller--> |
|||
<scene sceneID="Niz-AI-uX2"> |
|||
<objects> |
|||
<controller id="eXb-UN-Cd0" customClass="NotificationController" customModule="BlueWalletWatch" customModuleProvider="target"/> |
|||
</objects> |
|||
<point key="canvasLocation" x="220" y="1029"/> |
|||
</scene> |
|||
</scenes> |
|||
<color key="tintColor" red="0.40784313725490196" green="0.73333333333333328" blue="0.88235294117647056" alpha="1" colorSpace="calibratedRGB"/> |
|||
</document> |
@ -0,0 +1,33 @@ |
|||
<?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>BlueWallet</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>$(PRODUCT_NAME)</string> |
|||
<key>CFBundlePackageType</key> |
|||
<string>APPL</string> |
|||
<key>CFBundleShortVersionString</key> |
|||
<string>3.9.8</string> |
|||
<key>CFBundleVersion</key> |
|||
<string>239</string> |
|||
<key>UISupportedInterfaceOrientations</key> |
|||
<array> |
|||
<string>UIInterfaceOrientationPortrait</string> |
|||
<string>UIInterfaceOrientationPortraitUpsideDown</string> |
|||
</array> |
|||
<key>WKCompanionAppBundleIdentifier</key> |
|||
<string>io.bluewallet.bluewallet</string> |
|||
<key>WKWatchKitApp</key> |
|||
<true/> |
|||
</dict> |
|||
</plist> |
@ -0,0 +1,454 @@ |
|||
// |
|||
// Keychain helper for iOS/Swift. |
|||
// |
|||
// https://github.com/evgenyneu/keychain-swift |
|||
// |
|||
// This file was automatically generated by combining multiple Swift source files. |
|||
// |
|||
|
|||
|
|||
// ---------------------------- |
|||
// |
|||
// KeychainSwift.swift |
|||
// |
|||
// ---------------------------- |
|||
|
|||
import Security |
|||
import Foundation |
|||
|
|||
/** |
|||
|
|||
A collection of helper functions for saving text and data in the keychain. |
|||
|
|||
*/ |
|||
open class KeychainSwift { |
|||
|
|||
var lastQueryParameters: [String: Any]? // Used by the unit tests |
|||
|
|||
/// Contains result code from the last operation. Value is noErr (0) for a successful result. |
|||
open var lastResultCode: OSStatus = noErr |
|||
|
|||
var keyPrefix = "" // Can be useful in test. |
|||
|
|||
/** |
|||
|
|||
Specify an access group that will be used to access keychain items. Access groups can be used to share keychain items between applications. When access group value is nil all application access groups are being accessed. Access group name is used by all functions: set, get, delete and clear. |
|||
|
|||
*/ |
|||
open var accessGroup: String? |
|||
|
|||
|
|||
/** |
|||
|
|||
Specifies whether the items can be synchronized with other devices through iCloud. Setting this property to true will |
|||
add the item to other devices with the `set` method and obtain synchronizable items with the `get` command. Deleting synchronizable items will remove them from all devices. In order for keychain synchronization to work the user must enable "Keychain" in iCloud settings. |
|||
|
|||
Does not work on macOS. |
|||
|
|||
*/ |
|||
open var synchronizable: Bool = false |
|||
|
|||
private let readLock = NSLock() |
|||
|
|||
/// Instantiate a KeychainSwift object |
|||
public init() { } |
|||
|
|||
/** |
|||
|
|||
- parameter keyPrefix: a prefix that is added before the key in get/set methods. Note that `clear` method still clears everything from the Keychain. |
|||
|
|||
*/ |
|||
public init(keyPrefix: String) { |
|||
self.keyPrefix = keyPrefix |
|||
} |
|||
|
|||
/** |
|||
|
|||
Stores the text value in the keychain item under the given key. |
|||
|
|||
- parameter key: Key under which the text value is stored in the keychain. |
|||
- parameter value: Text string to be written to the keychain. |
|||
- parameter withAccess: Value that indicates when your app needs access to the text in the keychain item. By default the .AccessibleWhenUnlocked option is used that permits the data to be accessed only while the device is unlocked by the user. |
|||
|
|||
- returns: True if the text was successfully written to the keychain. |
|||
|
|||
*/ |
|||
@discardableResult |
|||
open func set(_ value: String, forKey key: String, |
|||
withAccess access: KeychainSwiftAccessOptions? = nil) -> Bool { |
|||
|
|||
if let value = value.data(using: String.Encoding.utf8) { |
|||
return set(value, forKey: key, withAccess: access) |
|||
} |
|||
|
|||
return false |
|||
} |
|||
|
|||
/** |
|||
|
|||
Stores the data in the keychain item under the given key. |
|||
|
|||
- parameter key: Key under which the data is stored in the keychain. |
|||
- parameter value: Data to be written to the keychain. |
|||
- parameter withAccess: Value that indicates when your app needs access to the text in the keychain item. By default the .AccessibleWhenUnlocked option is used that permits the data to be accessed only while the device is unlocked by the user. |
|||
|
|||
- returns: True if the text was successfully written to the keychain. |
|||
|
|||
*/ |
|||
@discardableResult |
|||
open func set(_ value: Data, forKey key: String, |
|||
withAccess access: KeychainSwiftAccessOptions? = nil) -> Bool { |
|||
|
|||
delete(key) // Delete any existing key before saving it |
|||
|
|||
let accessible = access?.value ?? KeychainSwiftAccessOptions.defaultOption.value |
|||
|
|||
let prefixedKey = keyWithPrefix(key) |
|||
|
|||
var query: [String : Any] = [ |
|||
KeychainSwiftConstants.klass : kSecClassGenericPassword, |
|||
KeychainSwiftConstants.attrAccount : prefixedKey, |
|||
KeychainSwiftConstants.valueData : value, |
|||
KeychainSwiftConstants.accessible : accessible |
|||
] |
|||
|
|||
query = addAccessGroupWhenPresent(query) |
|||
query = addSynchronizableIfRequired(query, addingItems: true) |
|||
lastQueryParameters = query |
|||
|
|||
lastResultCode = SecItemAdd(query as CFDictionary, nil) |
|||
|
|||
return lastResultCode == noErr |
|||
} |
|||
|
|||
/** |
|||
|
|||
Stores the boolean value in the keychain item under the given key. |
|||
|
|||
- parameter key: Key under which the value is stored in the keychain. |
|||
- parameter value: Boolean to be written to the keychain. |
|||
- parameter withAccess: Value that indicates when your app needs access to the value in the keychain item. By default the .AccessibleWhenUnlocked option is used that permits the data to be accessed only while the device is unlocked by the user. |
|||
|
|||
- returns: True if the value was successfully written to the keychain. |
|||
|
|||
*/ |
|||
@discardableResult |
|||
open func set(_ value: Bool, forKey key: String, |
|||
withAccess access: KeychainSwiftAccessOptions? = nil) -> Bool { |
|||
|
|||
let bytes: [UInt8] = value ? [1] : [0] |
|||
let data = Data(bytes) |
|||
|
|||
return set(data, forKey: key, withAccess: access) |
|||
} |
|||
|
|||
/** |
|||
|
|||
Retrieves the text value from the keychain that corresponds to the given key. |
|||
|
|||
- parameter key: The key that is used to read the keychain item. |
|||
- returns: The text value from the keychain. Returns nil if unable to read the item. |
|||
|
|||
*/ |
|||
open func get(_ key: String) -> String? { |
|||
if let data = getData(key) { |
|||
|
|||
if let currentString = String(data: data, encoding: .utf8) { |
|||
return currentString |
|||
} |
|||
|
|||
lastResultCode = -67853 // errSecInvalidEncoding |
|||
} |
|||
|
|||
return nil |
|||
} |
|||
|
|||
/** |
|||
|
|||
Retrieves the data from the keychain that corresponds to the given key. |
|||
|
|||
- parameter key: The key that is used to read the keychain item. |
|||
- returns: The text value from the keychain. Returns nil if unable to read the item. |
|||
|
|||
*/ |
|||
open func getData(_ key: String) -> Data? { |
|||
// The lock prevents the code to be run simlultaneously |
|||
// from multiple threads which may result in crashing |
|||
readLock.lock() |
|||
defer { readLock.unlock() } |
|||
|
|||
let prefixedKey = keyWithPrefix(key) |
|||
|
|||
var query: [String: Any] = [ |
|||
KeychainSwiftConstants.klass : kSecClassGenericPassword, |
|||
KeychainSwiftConstants.attrAccount : prefixedKey, |
|||
KeychainSwiftConstants.returnData : kCFBooleanTrue!, |
|||
KeychainSwiftConstants.matchLimit : kSecMatchLimitOne |
|||
] |
|||
|
|||
query = addAccessGroupWhenPresent(query) |
|||
query = addSynchronizableIfRequired(query, addingItems: false) |
|||
lastQueryParameters = query |
|||
|
|||
var result: AnyObject? |
|||
|
|||
lastResultCode = withUnsafeMutablePointer(to: &result) { |
|||
SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0)) |
|||
} |
|||
|
|||
if lastResultCode == noErr { return result as? Data } |
|||
|
|||
return nil |
|||
} |
|||
|
|||
/** |
|||
|
|||
Retrieves the boolean value from the keychain that corresponds to the given key. |
|||
|
|||
- parameter key: The key that is used to read the keychain item. |
|||
- returns: The boolean value from the keychain. Returns nil if unable to read the item. |
|||
|
|||
*/ |
|||
open func getBool(_ key: String) -> Bool? { |
|||
guard let data = getData(key) else { return nil } |
|||
guard let firstBit = data.first else { return nil } |
|||
return firstBit == 1 |
|||
} |
|||
|
|||
/** |
|||
|
|||
Deletes the single keychain item specified by the key. |
|||
|
|||
- parameter key: The key that is used to delete the keychain item. |
|||
- returns: True if the item was successfully deleted. |
|||
|
|||
*/ |
|||
@discardableResult |
|||
open func delete(_ key: String) -> Bool { |
|||
let prefixedKey = keyWithPrefix(key) |
|||
|
|||
var query: [String: Any] = [ |
|||
KeychainSwiftConstants.klass : kSecClassGenericPassword, |
|||
KeychainSwiftConstants.attrAccount : prefixedKey |
|||
] |
|||
|
|||
query = addAccessGroupWhenPresent(query) |
|||
query = addSynchronizableIfRequired(query, addingItems: false) |
|||
lastQueryParameters = query |
|||
|
|||
lastResultCode = SecItemDelete(query as CFDictionary) |
|||
|
|||
return lastResultCode == noErr |
|||
} |
|||
|
|||
/** |
|||
|
|||
Deletes all Keychain items used by the app. Note that this method deletes all items regardless of the prefix settings used for initializing the class. |
|||
|
|||
- returns: True if the keychain items were successfully deleted. |
|||
|
|||
*/ |
|||
@discardableResult |
|||
open func clear() -> Bool { |
|||
var query: [String: Any] = [ kSecClass as String : kSecClassGenericPassword ] |
|||
query = addAccessGroupWhenPresent(query) |
|||
query = addSynchronizableIfRequired(query, addingItems: false) |
|||
lastQueryParameters = query |
|||
|
|||
lastResultCode = SecItemDelete(query as CFDictionary) |
|||
|
|||
return lastResultCode == noErr |
|||
} |
|||
|
|||
/// Returns the key with currently set prefix. |
|||
func keyWithPrefix(_ key: String) -> String { |
|||
return "\(keyPrefix)\(key)" |
|||
} |
|||
|
|||
func addAccessGroupWhenPresent(_ items: [String: Any]) -> [String: Any] { |
|||
guard let accessGroup = accessGroup else { return items } |
|||
|
|||
var result: [String: Any] = items |
|||
result[KeychainSwiftConstants.accessGroup] = accessGroup |
|||
return result |
|||
} |
|||
|
|||
/** |
|||
|
|||
Adds kSecAttrSynchronizable: kSecAttrSynchronizableAny` item to the dictionary when the `synchronizable` property is true. |
|||
|
|||
- parameter items: The dictionary where the kSecAttrSynchronizable items will be added when requested. |
|||
- parameter addingItems: Use `true` when the dictionary will be used with `SecItemAdd` method (adding a keychain item). For getting and deleting items, use `false`. |
|||
|
|||
- returns: the dictionary with kSecAttrSynchronizable item added if it was requested. Otherwise, it returns the original dictionary. |
|||
|
|||
*/ |
|||
func addSynchronizableIfRequired(_ items: [String: Any], addingItems: Bool) -> [String: Any] { |
|||
if !synchronizable { return items } |
|||
var result: [String: Any] = items |
|||
result[KeychainSwiftConstants.attrSynchronizable] = addingItems == true ? true : kSecAttrSynchronizableAny |
|||
return result |
|||
} |
|||
} |
|||
|
|||
|
|||
// ---------------------------- |
|||
// |
|||
// TegKeychainConstants.swift |
|||
// |
|||
// ---------------------------- |
|||
|
|||
import Foundation |
|||
import Security |
|||
|
|||
/// Constants used by the library |
|||
public struct KeychainSwiftConstants { |
|||
/// Specifies a Keychain access group. Used for sharing Keychain items between apps. |
|||
public static var accessGroup: String { return toString(kSecAttrAccessGroup) } |
|||
|
|||
/** |
|||
|
|||
A value that indicates when your app needs access to the data in a keychain item. The default value is AccessibleWhenUnlocked. For a list of possible values, see KeychainSwiftAccessOptions. |
|||
|
|||
*/ |
|||
public static var accessible: String { return toString(kSecAttrAccessible) } |
|||
|
|||
/// Used for specifying a String key when setting/getting a Keychain value. |
|||
public static var attrAccount: String { return toString(kSecAttrAccount) } |
|||
|
|||
/// Used for specifying synchronization of keychain items between devices. |
|||
public static var attrSynchronizable: String { return toString(kSecAttrSynchronizable) } |
|||
|
|||
/// An item class key used to construct a Keychain search dictionary. |
|||
public static var klass: String { return toString(kSecClass) } |
|||
|
|||
/// Specifies the number of values returned from the keychain. The library only supports single values. |
|||
public static var matchLimit: String { return toString(kSecMatchLimit) } |
|||
|
|||
/// A return data type used to get the data from the Keychain. |
|||
public static var returnData: String { return toString(kSecReturnData) } |
|||
|
|||
/// Used for specifying a value when setting a Keychain value. |
|||
public static var valueData: String { return toString(kSecValueData) } |
|||
|
|||
static func toString(_ value: CFString) -> String { |
|||
return value as String |
|||
} |
|||
} |
|||
|
|||
|
|||
// ---------------------------- |
|||
// |
|||
// KeychainSwiftAccessOptions.swift |
|||
// |
|||
// ---------------------------- |
|||
|
|||
import Security |
|||
|
|||
/** |
|||
|
|||
These options are used to determine when a keychain item should be readable. The default value is AccessibleWhenUnlocked. |
|||
|
|||
*/ |
|||
public enum KeychainSwiftAccessOptions { |
|||
|
|||
/** |
|||
|
|||
The data in the keychain item can be accessed only while the device is unlocked by the user. |
|||
|
|||
This is recommended for items that need to be accessible only while the application is in the foreground. Items with this attribute migrate to a new device when using encrypted backups. |
|||
|
|||
This is the default value for keychain items added without explicitly setting an accessibility constant. |
|||
|
|||
*/ |
|||
case accessibleWhenUnlocked |
|||
|
|||
/** |
|||
|
|||
The data in the keychain item can be accessed only while the device is unlocked by the user. |
|||
|
|||
This is recommended for items that need to be accessible only while the application is in the foreground. Items with this attribute do not migrate to a new device. Thus, after restoring from a backup of a different device, these items will not be present. |
|||
|
|||
*/ |
|||
case accessibleWhenUnlockedThisDeviceOnly |
|||
|
|||
/** |
|||
|
|||
The data in the keychain item cannot be accessed after a restart until the device has been unlocked once by the user. |
|||
|
|||
After the first unlock, the data remains accessible until the next restart. This is recommended for items that need to be accessed by background applications. Items with this attribute migrate to a new device when using encrypted backups. |
|||
|
|||
*/ |
|||
case accessibleAfterFirstUnlock |
|||
|
|||
/** |
|||
|
|||
The data in the keychain item cannot be accessed after a restart until the device has been unlocked once by the user. |
|||
|
|||
After the first unlock, the data remains accessible until the next restart. This is recommended for items that need to be accessed by background applications. Items with this attribute do not migrate to a new device. Thus, after restoring from a backup of a different device, these items will not be present. |
|||
|
|||
*/ |
|||
case accessibleAfterFirstUnlockThisDeviceOnly |
|||
|
|||
/** |
|||
|
|||
The data in the keychain item can always be accessed regardless of whether the device is locked. |
|||
|
|||
This is not recommended for application use. Items with this attribute migrate to a new device when using encrypted backups. |
|||
|
|||
*/ |
|||
case accessibleAlways |
|||
|
|||
/** |
|||
|
|||
The data in the keychain can only be accessed when the device is unlocked. Only available if a passcode is set on the device. |
|||
|
|||
This is recommended for items that only need to be accessible while the application is in the foreground. Items with this attribute never migrate to a new device. After a backup is restored to a new device, these items are missing. No items can be stored in this class on devices without a passcode. Disabling the device passcode causes all items in this class to be deleted. |
|||
|
|||
*/ |
|||
case accessibleWhenPasscodeSetThisDeviceOnly |
|||
|
|||
/** |
|||
|
|||
The data in the keychain item can always be accessed regardless of whether the device is locked. |
|||
|
|||
This is not recommended for application use. Items with this attribute do not migrate to a new device. Thus, after restoring from a backup of a different device, these items will not be present. |
|||
|
|||
*/ |
|||
case accessibleAlwaysThisDeviceOnly |
|||
|
|||
static var defaultOption: KeychainSwiftAccessOptions { |
|||
return .accessibleWhenUnlocked |
|||
} |
|||
|
|||
var value: String { |
|||
switch self { |
|||
case .accessibleWhenUnlocked: |
|||
return toString(kSecAttrAccessibleWhenUnlocked) |
|||
|
|||
case .accessibleWhenUnlockedThisDeviceOnly: |
|||
return toString(kSecAttrAccessibleWhenUnlockedThisDeviceOnly) |
|||
|
|||
case .accessibleAfterFirstUnlock: |
|||
return toString(kSecAttrAccessibleAfterFirstUnlock) |
|||
|
|||
case .accessibleAfterFirstUnlockThisDeviceOnly: |
|||
return toString(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly) |
|||
|
|||
case .accessibleAlways: |
|||
return toString(kSecAttrAccessibleAlways) |
|||
|
|||
case .accessibleWhenPasscodeSetThisDeviceOnly: |
|||
return toString(kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly) |
|||
|
|||
case .accessibleAlwaysThisDeviceOnly: |
|||
return toString(kSecAttrAccessibleAlwaysThisDeviceOnly) |
|||
} |
|||
} |
|||
|
|||
func toString(_ value: CFString) -> String { |
|||
return KeychainSwiftConstants.toString(value) |
|||
} |
|||
} |
|||
|
|||
|
@ -0,0 +1,127 @@ |
|||
|
|||
# Uncomment the next line to define a global platform for your project |
|||
# platform :ios, '9.0' |
|||
platform :ios, '10.0' |
|||
workspace 'BlueWallet' |
|||
post_install do |installer| |
|||
installer.pods_project.targets.each do |target| |
|||
target.build_configurations.each do |config| |
|||
puts "Setting Swift Version setting for #{target.name}..." |
|||
config.build_settings['SWIFT_VERSION'] = '4.2' |
|||
end |
|||
end |
|||
end |
|||
|
|||
|
|||
def sharedPods |
|||
# Explicitly include Yoga if you are using RN >= 0.42.0 |
|||
pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga' |
|||
|
|||
# Third party deps podspec link |
|||
pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec' |
|||
pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec' |
|||
pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec' |
|||
pod 'React', :path => '../node_modules/react-native', :subspecs => [ |
|||
'Core', |
|||
'CxxBridge', # Include this for RN >= 0.47 |
|||
'DevSupport', # Include this to enable In-App Devmenu if RN >= 0.43 |
|||
'RCTText', |
|||
'RCTImage', # <-- Add RCTImage |
|||
'RCTNetwork', |
|||
'RCTActionSheet', |
|||
'RCTLinkingIOS', |
|||
'RCTWebSocket', # Needed for debugging |
|||
'RCTAnimation', # Needed for FlatList and animations running on native UI thread |
|||
# Add any other subspecs you want to use in your project |
|||
] |
|||
end |
|||
|
|||
target 'BlueWallet' do |
|||
# Uncomment the next line if you're using Swift or would like to use dynamic frameworks |
|||
# use_frameworks! |
|||
project 'BlueWallet.xcodeproj' |
|||
platform :ios, '10.0' |
|||
# Pods for BlueWallet |
|||
# React Native requirements |
|||
|
|||
sharedPods |
|||
pod 'RNWatch', :path => '../node_modules/react-native-watch-connectivity' |
|||
|
|||
pod 'react-native-webview', :path => '../node_modules/react-native-webview' |
|||
|
|||
pod 'react-native-camera', :path => '../node_modules/react-native-camera' |
|||
|
|||
pod 'RNDeviceInfo', :path => '../node_modules/react-native-device-info' |
|||
|
|||
pod 'RNGestureHandler', :path => '../node_modules/react-native-gesture-handler' |
|||
|
|||
pod 'RNFS', :path => '../node_modules/react-native-fs' |
|||
|
|||
pod 'react-native-google-analytics-bridge', :path => '../node_modules/react-native-google-analytics-bridge' |
|||
|
|||
pod 'react-native-haptic-feedback', :path => '../node_modules/react-native-haptic-feedback' |
|||
|
|||
pod 'BVLinearGradient', :path => '../node_modules/react-native-linear-gradient' |
|||
|
|||
pod 'RNRate', :path => '../node_modules/react-native-rate/ios' |
|||
|
|||
pod 'react-native-image-picker', :path => '../node_modules/react-native-image-picker' |
|||
|
|||
pod 'RNSVG', :path => '../node_modules/react-native-svg' |
|||
|
|||
pod 'RNVectorIcons', :path => '../node_modules/react-native-vector-icons' |
|||
|
|||
pod 'react-native-randombytes', :path => '../node_modules/react-native-randombytes' |
|||
|
|||
pod 'react-native-slider', :path => '../node_modules/@react-native-community/slider' |
|||
|
|||
pod 'SentryReactNative', :path => '../node_modules/react-native-sentry' |
|||
|
|||
pod 'ToolTipMenu', :path => '../node_modules/react-native-tooltip' |
|||
|
|||
pod 'RNCAsyncStorage', :path => '../node_modules/@react-native-community/async-storage' |
|||
|
|||
end |
|||
|
|||
target 'BlueWalletTests' do |
|||
inherit! :search_paths |
|||
# Pods for testing |
|||
|
|||
end |
|||
|
|||
target 'BlueWalletWatch' do |
|||
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks |
|||
# use_frameworks! |
|||
# Pods for BlueWalletWatch |
|||
platform :watchos, '5.1' |
|||
end |
|||
|
|||
target 'BlueWalletWatch Extension' do |
|||
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks |
|||
# use_frameworks! |
|||
platform :watchos, '5.1' |
|||
pod 'EFQRCode', '~> 5.0.0' |
|||
# Pods for BlueWalletWatch Extension |
|||
end |
|||
|
|||
|
|||
target 'TcpSockets' do |
|||
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks |
|||
# use_frameworks! |
|||
project '../node_modules/react-native-tcp/ios/TcpSockets.xcodeproj' |
|||
sharedPods |
|||
end |
|||
|
|||
target 'RCTQRCodeLocalImage' do |
|||
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks |
|||
# use_frameworks! |
|||
project '../node_modules/@remobile/react-native-qrcode-local-image/ios/RCTQRCodeLocalImage.xcodeproj' |
|||
sharedPods |
|||
end |
|||
|
|||
target 'RCTPrivacySnapshot' do |
|||
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks |
|||
# use_frameworks! |
|||
project '../node_modules/react-native-privacy-snapshot/RCTPrivacySnapshot.xcodeproj' |
|||
sharedPods |
|||
end |
@ -0,0 +1,232 @@ |
|||
PODS: |
|||
- boost-for-react-native (1.63.0) |
|||
- BVLinearGradient (2.5.4): |
|||
- React |
|||
- DoubleConversion (1.1.6) |
|||
- EFQRCode (5.0.0): |
|||
- swift_qrcodejs (~> 1.1.1) |
|||
- Folly (2018.10.22.00): |
|||
- boost-for-react-native |
|||
- DoubleConversion |
|||
- glog |
|||
- glog (0.3.5) |
|||
- React (0.59.6): |
|||
- React/Core (= 0.59.6) |
|||
- react-native-camera (2.6.0): |
|||
- React |
|||
- react-native-camera/RCT (= 2.6.0) |
|||
- react-native-camera/RN (= 2.6.0) |
|||
- react-native-camera/RCT (2.6.0): |
|||
- React |
|||
- react-native-camera/RN (2.6.0): |
|||
- React |
|||
- react-native-google-analytics-bridge (7.1.0): |
|||
- react-native-google-analytics-bridge/Core (= 7.1.0) |
|||
- react-native-google-analytics-bridge/Core (7.1.0): |
|||
- React |
|||
- react-native-haptic-feedback (1.7.1): |
|||
- React |
|||
- react-native-image-picker (0.28.1): |
|||
- React |
|||
- react-native-randombytes (3.5.2): |
|||
- React |
|||
- react-native-slider (1.1.0): |
|||
- React |
|||
- react-native-webview (5.8.1): |
|||
- React |
|||
- React/Core (0.59.6): |
|||
- yoga (= 0.59.6.React) |
|||
- React/CxxBridge (0.59.6): |
|||
- Folly (= 2018.10.22.00) |
|||
- React/Core |
|||
- React/cxxreact |
|||
- React/jsiexecutor |
|||
- React/cxxreact (0.59.6): |
|||
- boost-for-react-native (= 1.63.0) |
|||
- DoubleConversion |
|||
- Folly (= 2018.10.22.00) |
|||
- glog |
|||
- React/jsinspector |
|||
- React/DevSupport (0.59.6): |
|||
- React/Core |
|||
- React/RCTWebSocket |
|||
- React/fishhook (0.59.6) |
|||
- React/jsi (0.59.6): |
|||
- DoubleConversion |
|||
- Folly (= 2018.10.22.00) |
|||
- glog |
|||
- React/jsiexecutor (0.59.6): |
|||
- DoubleConversion |
|||
- Folly (= 2018.10.22.00) |
|||
- glog |
|||
- React/cxxreact |
|||
- React/jsi |
|||
- React/jsinspector (0.59.6) |
|||
- React/RCTActionSheet (0.59.6): |
|||
- React/Core |
|||
- React/RCTAnimation (0.59.6): |
|||
- React/Core |
|||
- React/RCTBlob (0.59.6): |
|||
- React/Core |
|||
- React/RCTImage (0.59.6): |
|||
- React/Core |
|||
- React/RCTNetwork |
|||
- React/RCTLinkingIOS (0.59.6): |
|||
- React/Core |
|||
- React/RCTNetwork (0.59.6): |
|||
- React/Core |
|||
- React/RCTText (0.59.6): |
|||
- React/Core |
|||
- React/RCTWebSocket (0.59.6): |
|||
- React/Core |
|||
- React/fishhook |
|||
- React/RCTBlob |
|||
- RNCAsyncStorage (1.3.3): |
|||
- React |
|||
- RNDeviceInfo (1.6.0): |
|||
- React |
|||
- RNFS (2.13.3): |
|||
- React |
|||
- RNGestureHandler (1.2.0): |
|||
- React |
|||
- RNRate (1.0.1): |
|||
- React |
|||
- RNSVG (9.4.0): |
|||
- React |
|||
- RNVectorIcons (6.4.2): |
|||
- React |
|||
- RNWatch (0.2.0): |
|||
- React |
|||
- Sentry (4.1.3): |
|||
- Sentry/Core (= 4.1.3) |
|||
- Sentry/Core (4.1.3) |
|||
- SentryReactNative (0.42.0): |
|||
- React |
|||
- Sentry (~> 4.1.3) |
|||
- swift_qrcodejs (1.1.1) |
|||
- ToolTipMenu (5.2.1): |
|||
- React |
|||
- yoga (0.59.6.React) |
|||
|
|||
DEPENDENCIES: |
|||
- BVLinearGradient (from `../node_modules/react-native-linear-gradient`) |
|||
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) |
|||
- EFQRCode (~> 5.0.0) |
|||
- Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`) |
|||
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) |
|||
- react-native-camera (from `../node_modules/react-native-camera`) |
|||
- react-native-google-analytics-bridge (from `../node_modules/react-native-google-analytics-bridge`) |
|||
- react-native-haptic-feedback (from `../node_modules/react-native-haptic-feedback`) |
|||
- react-native-image-picker (from `../node_modules/react-native-image-picker`) |
|||
- react-native-randombytes (from `../node_modules/react-native-randombytes`) |
|||
- "react-native-slider (from `../node_modules/@react-native-community/slider`)" |
|||
- react-native-webview (from `../node_modules/react-native-webview`) |
|||
- React/Core (from `../node_modules/react-native`) |
|||
- React/CxxBridge (from `../node_modules/react-native`) |
|||
- React/DevSupport (from `../node_modules/react-native`) |
|||
- React/RCTActionSheet (from `../node_modules/react-native`) |
|||
- React/RCTAnimation (from `../node_modules/react-native`) |
|||
- React/RCTImage (from `../node_modules/react-native`) |
|||
- React/RCTLinkingIOS (from `../node_modules/react-native`) |
|||
- React/RCTNetwork (from `../node_modules/react-native`) |
|||
- React/RCTText (from `../node_modules/react-native`) |
|||
- React/RCTWebSocket (from `../node_modules/react-native`) |
|||
- "RNCAsyncStorage (from `../node_modules/@react-native-community/async-storage`)" |
|||
- RNDeviceInfo (from `../node_modules/react-native-device-info`) |
|||
- RNFS (from `../node_modules/react-native-fs`) |
|||
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`) |
|||
- RNRate (from `../node_modules/react-native-rate/ios`) |
|||
- RNSVG (from `../node_modules/react-native-svg`) |
|||
- RNVectorIcons (from `../node_modules/react-native-vector-icons`) |
|||
- RNWatch (from `../node_modules/react-native-watch-connectivity`) |
|||
- SentryReactNative (from `../node_modules/react-native-sentry`) |
|||
- ToolTipMenu (from `../node_modules/react-native-tooltip`) |
|||
- yoga (from `../node_modules/react-native/ReactCommon/yoga`) |
|||
|
|||
SPEC REPOS: |
|||
https://github.com/cocoapods/specs.git: |
|||
- boost-for-react-native |
|||
- EFQRCode |
|||
- Sentry |
|||
- swift_qrcodejs |
|||
|
|||
EXTERNAL SOURCES: |
|||
BVLinearGradient: |
|||
:path: "../node_modules/react-native-linear-gradient" |
|||
DoubleConversion: |
|||
:podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" |
|||
Folly: |
|||
:podspec: "../node_modules/react-native/third-party-podspecs/Folly.podspec" |
|||
glog: |
|||
:podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" |
|||
React: |
|||
:path: "../node_modules/react-native" |
|||
react-native-camera: |
|||
:path: "../node_modules/react-native-camera" |
|||
react-native-google-analytics-bridge: |
|||
:path: "../node_modules/react-native-google-analytics-bridge" |
|||
react-native-haptic-feedback: |
|||
:path: "../node_modules/react-native-haptic-feedback" |
|||
react-native-image-picker: |
|||
:path: "../node_modules/react-native-image-picker" |
|||
react-native-randombytes: |
|||
:path: "../node_modules/react-native-randombytes" |
|||
react-native-slider: |
|||
:path: "../node_modules/@react-native-community/slider" |
|||
react-native-webview: |
|||
:path: "../node_modules/react-native-webview" |
|||
RNCAsyncStorage: |
|||
:path: "../node_modules/@react-native-community/async-storage" |
|||
RNDeviceInfo: |
|||
:path: "../node_modules/react-native-device-info" |
|||
RNFS: |
|||
:path: "../node_modules/react-native-fs" |
|||
RNGestureHandler: |
|||
:path: "../node_modules/react-native-gesture-handler" |
|||
RNRate: |
|||
:path: "../node_modules/react-native-rate/ios" |
|||
RNSVG: |
|||
:path: "../node_modules/react-native-svg" |
|||
RNVectorIcons: |
|||
:path: "../node_modules/react-native-vector-icons" |
|||
RNWatch: |
|||
:path: "../node_modules/react-native-watch-connectivity" |
|||
SentryReactNative: |
|||
:path: "../node_modules/react-native-sentry" |
|||
ToolTipMenu: |
|||
:path: "../node_modules/react-native-tooltip" |
|||
yoga: |
|||
:path: "../node_modules/react-native/ReactCommon/yoga" |
|||
|
|||
SPEC CHECKSUMS: |
|||
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c |
|||
BVLinearGradient: b0b70acf63ee888829b7c2ebbf6b50e227396e55 |
|||
DoubleConversion: bb338842f62ab1d708ceb63ec3d999f0f3d98ecd |
|||
EFQRCode: 07437cfbce3a1e497397a4f3d766c980d8972608 |
|||
Folly: de497beb10f102453a1afa9edbf8cf8a251890de |
|||
glog: aefd1eb5dda2ab95ba0938556f34b98e2da3a60d |
|||
React: 1d605e098d69bdf08960787f3446f0a9dc2e2ccf |
|||
react-native-camera: 9c50d7def800895e7991ccda6203929553ceec9c |
|||
react-native-google-analytics-bridge: 0a86be2860b81a3562fe60ac40c0ad732340046f |
|||
react-native-haptic-feedback: f675486e3889e3229272158943c1e9e075247e5a |
|||
react-native-image-picker: f42de90075c5b1af53417af927631d909a1a746e |
|||
react-native-randombytes: d3184d351604f78e019535178766590188bbc133 |
|||
react-native-slider: 743940825f1fa1b37e8396ffd8cebe41f4967e1f |
|||
react-native-webview: a42108b827082f8f0333529b0772102031d5960d |
|||
RNCAsyncStorage: 289488409d0c42f30e12535e3f45c5bd3cfc73d2 |
|||
RNDeviceInfo: 08dd79c5adef48b6dc103bf3ddf208039aa78664 |
|||
RNFS: bbb1a64eb245763daf34aea86f97c97c4e85f74c |
|||
RNGestureHandler: 7ccf2f3f60458e084f9ada01fbaf610f6fef073c |
|||
RNRate: 72b5c9c2e62de9a01710918eb83d75fb99b44c7b |
|||
RNSVG: 4834be1d644eb77f0e3f6de851881b83758a3124 |
|||
RNVectorIcons: 8c52e1e8da1153613fdef44748e865c25556cb9c |
|||
RNWatch: 394c44f35352309ab414daaadfa3c55a4a5224ee |
|||
Sentry: 4e8a17b61ddd116f89536cc81d567fdee1ebca96 |
|||
SentryReactNative: fc630be25b30c1a494b478ba1fa38f761cc6da20 |
|||
swift_qrcodejs: 0bacbfe321a99954c7b8e04c75562007ea4e4f7c |
|||
ToolTipMenu: a01f5df49eb1a1ffbc5e1e81d2ec42b832436421 |
|||
yoga: 128daf064cacaede0c3bb27424b6b4c71052e6cd |
|||
|
|||
PODFILE CHECKSUM: 40fe32f25e14511848fc633565a8030139a972fa |
|||
|
|||
COCOAPODS: 1.5.3 |
@ -0,0 +1,26 @@ |
|||
{ |
|||
"name": "RNDeviceInfo", |
|||
"version": "1.6.0", |
|||
"summary": "Get device information using react-native", |
|||
"license": "MIT", |
|||
"authors": { |
|||
"name": "Rebecca Hughes", |
|||
"email": "rebecca@learnium.net", |
|||
"url": "https://github.com/rebeccahughes" |
|||
}, |
|||
"homepage": "git+https://github.com/react-native-community/react-native-device-info.git", |
|||
"platforms": { |
|||
"ios": "9.0", |
|||
"tvos": "10.0" |
|||
}, |
|||
"source": { |
|||
"git": "https://github.com/react-native-community/react-native-device-info.git", |
|||
"tag": "1.6.0" |
|||
}, |
|||
"source_files": "ios/**/*.{h,m}", |
|||
"dependencies": { |
|||
"React": [ |
|||
|
|||
] |
|||
} |
|||
} |
@ -0,0 +1,23 @@ |
|||
{ |
|||
"name": "RNSVG", |
|||
"version": "9.4.0", |
|||
"summary": "SVG library for react-native", |
|||
"license": "MIT", |
|||
"homepage": "https://github.com/react-native-community/react-native-svg", |
|||
"authors": "Horcrux Chen", |
|||
"source": { |
|||
"git": "https://github.com/react-native-community/react-native-svg.git", |
|||
"tag": "9.4.0" |
|||
}, |
|||
"source_files": "ios/**/*.{h,m}", |
|||
"requires_arc": true, |
|||
"platforms": { |
|||
"ios": "8.0", |
|||
"tvos": "9.2" |
|||
}, |
|||
"dependencies": { |
|||
"React": [ |
|||
|
|||
] |
|||
} |
|||
} |
@ -0,0 +1,565 @@ |
|||
{ |
|||
"name": "React", |
|||
"version": "0.59.6", |
|||
"summary": "A framework for building native apps using React", |
|||
"description": "React Native apps are built using the React JS\nframework, and render directly to native UIKit\nelements using a fully asynchronous architecture.\nThere is no browser and no HTML. We have picked what\nwe think is the best set of features from these and\nother technologies to build what we hope to become\nthe best product development framework available,\nwith an emphasis on iteration speed, developer\ndelight, continuity of technology, and absolutely\nbeautiful and fast products with no compromises in\nquality or capability.", |
|||
"homepage": "http://facebook.github.io/react-native/", |
|||
"license": "MIT", |
|||
"authors": "Facebook", |
|||
"source": { |
|||
"git": "https://github.com/facebook/react-native.git", |
|||
"tag": "v0.59.6" |
|||
}, |
|||
"default_subspecs": "Core", |
|||
"requires_arc": true, |
|||
"platforms": { |
|||
"ios": "9.0", |
|||
"tvos": "9.2" |
|||
}, |
|||
"pod_target_xcconfig": { |
|||
"CLANG_CXX_LANGUAGE_STANDARD": "c++14" |
|||
}, |
|||
"preserve_paths": [ |
|||
"package.json", |
|||
"LICENSE", |
|||
"LICENSE-docs" |
|||
], |
|||
"cocoapods_version": ">= 1.2.0", |
|||
"subspecs": [ |
|||
{ |
|||
"name": "Core", |
|||
"dependencies": { |
|||
"yoga": [ |
|||
"0.59.6.React" |
|||
] |
|||
}, |
|||
"source_files": "React/**/*.{c,h,m,mm,S,cpp}", |
|||
"exclude_files": [ |
|||
"**/__tests__/*", |
|||
"IntegrationTests/*", |
|||
"React/DevSupport/*", |
|||
"React/Inspector/*", |
|||
"ReactCommon/yoga/*", |
|||
"React/Cxx*/*", |
|||
"React/Fabric/**/*" |
|||
], |
|||
"ios": { |
|||
"exclude_files": "React/**/RCTTV*.*" |
|||
}, |
|||
"tvos": { |
|||
"exclude_files": [ |
|||
"React/Modules/RCTClipboard*", |
|||
"React/Views/RCTDatePicker*", |
|||
"React/Views/RCTPicker*", |
|||
"React/Views/RCTRefreshControl*", |
|||
"React/Views/RCTSlider*", |
|||
"React/Views/RCTSwitch*", |
|||
"React/Views/RCTWebView*" |
|||
] |
|||
}, |
|||
"compiler_flags": "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", |
|||
"header_dir": "React", |
|||
"frameworks": "JavaScriptCore", |
|||
"libraries": "stdc++", |
|||
"pod_target_xcconfig": { |
|||
"HEADER_SEARCH_PATHS": "\"$(PODS_TARGET_SRCROOT)/ReactCommon\"" |
|||
} |
|||
}, |
|||
{ |
|||
"name": "CxxBridge", |
|||
"dependencies": { |
|||
"Folly": [ |
|||
"2018.10.22.00" |
|||
], |
|||
"React/Core": [ |
|||
|
|||
], |
|||
"React/cxxreact": [ |
|||
|
|||
], |
|||
"React/jsiexecutor": [ |
|||
|
|||
] |
|||
}, |
|||
"compiler_flags": "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", |
|||
"private_header_files": "React/Cxx*/*.h", |
|||
"source_files": "React/Cxx*/*.{h,m,mm}" |
|||
}, |
|||
{ |
|||
"name": "DevSupport", |
|||
"dependencies": { |
|||
"React/Core": [ |
|||
|
|||
], |
|||
"React/RCTWebSocket": [ |
|||
|
|||
] |
|||
}, |
|||
"source_files": [ |
|||
"React/DevSupport/*", |
|||
"React/Inspector/*" |
|||
] |
|||
}, |
|||
{ |
|||
"name": "RCTFabric", |
|||
"dependencies": { |
|||
"Folly": [ |
|||
"2018.10.22.00" |
|||
], |
|||
"React/Core": [ |
|||
|
|||
], |
|||
"React/fabric": [ |
|||
|
|||
] |
|||
}, |
|||
"compiler_flags": "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", |
|||
"source_files": "React/Fabric/**/*.{c,h,m,mm,S,cpp}", |
|||
"exclude_files": "**/tests/*", |
|||
"header_dir": "React", |
|||
"frameworks": "JavaScriptCore", |
|||
"pod_target_xcconfig": { |
|||
"HEADER_SEARCH_PATHS": "\"$(PODS_TARGET_SRCROOT)/ReactCommon\"" |
|||
} |
|||
}, |
|||
{ |
|||
"name": "tvOS", |
|||
"dependencies": { |
|||
"React/Core": [ |
|||
|
|||
] |
|||
}, |
|||
"source_files": "React/**/RCTTV*.{h,m}" |
|||
}, |
|||
{ |
|||
"name": "jsinspector", |
|||
"source_files": "ReactCommon/jsinspector/*.{cpp,h}", |
|||
"private_header_files": "ReactCommon/jsinspector/*.h", |
|||
"pod_target_xcconfig": { |
|||
"HEADER_SEARCH_PATHS": "\"$(PODS_TARGET_SRCROOT)/ReactCommon\"" |
|||
} |
|||
}, |
|||
{ |
|||
"name": "jsiexecutor", |
|||
"dependencies": { |
|||
"React/cxxreact": [ |
|||
|
|||
], |
|||
"React/jsi": [ |
|||
|
|||
], |
|||
"Folly": [ |
|||
"2018.10.22.00" |
|||
], |
|||
"DoubleConversion": [ |
|||
|
|||
], |
|||
"glog": [ |
|||
|
|||
] |
|||
}, |
|||
"compiler_flags": "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", |
|||
"source_files": "ReactCommon/jsiexecutor/jsireact/*.{cpp,h}", |
|||
"private_header_files": "ReactCommon/jsiexecutor/jsireact/*.h", |
|||
"header_dir": "jsireact", |
|||
"pod_target_xcconfig": { |
|||
"HEADER_SEARCH_PATHS": "\"$(PODS_TARGET_SRCROOT)/ReactCommon\", \"$(PODS_TARGET_SRCROOT)/ReactCommon/jsiexecutor\"" |
|||
} |
|||
}, |
|||
{ |
|||
"name": "jsi", |
|||
"dependencies": { |
|||
"Folly": [ |
|||
"2018.10.22.00" |
|||
], |
|||
"DoubleConversion": [ |
|||
|
|||
], |
|||
"glog": [ |
|||
|
|||
] |
|||
}, |
|||
"compiler_flags": "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", |
|||
"source_files": "ReactCommon/jsi/*.{cpp,h}", |
|||
"private_header_files": "ReactCommon/jsi/*.h", |
|||
"frameworks": "JavaScriptCore", |
|||
"pod_target_xcconfig": { |
|||
"HEADER_SEARCH_PATHS": "\"$(PODS_TARGET_SRCROOT)/ReactCommon\"" |
|||
} |
|||
}, |
|||
{ |
|||
"name": "PrivateDatabase", |
|||
"source_files": "ReactCommon/privatedata/*.{cpp,h}", |
|||
"private_header_files": "ReactCommon/privatedata/*.h", |
|||
"pod_target_xcconfig": { |
|||
"HEADER_SEARCH_PATHS": "\"$(PODS_TARGET_SRCROOT)/ReactCommon\"" |
|||
} |
|||
}, |
|||
{ |
|||
"name": "cxxreact", |
|||
"dependencies": { |
|||
"React/jsinspector": [ |
|||
|
|||
], |
|||
"boost-for-react-native": [ |
|||
"1.63.0" |
|||
], |
|||
"Folly": [ |
|||
"2018.10.22.00" |
|||
], |
|||
"DoubleConversion": [ |
|||
|
|||
], |
|||
"glog": [ |
|||
|
|||
] |
|||
}, |
|||
"compiler_flags": "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", |
|||
"source_files": "ReactCommon/cxxreact/*.{cpp,h}", |
|||
"exclude_files": "ReactCommon/cxxreact/SampleCxxModule.*", |
|||
"private_header_files": "ReactCommon/cxxreact/*.h", |
|||
"pod_target_xcconfig": { |
|||
"HEADER_SEARCH_PATHS": "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/boost-for-react-native\" \"$(PODS_ROOT)/DoubleConversion\" \"$(PODS_ROOT)/Folly\"" |
|||
} |
|||
}, |
|||
{ |
|||
"name": "fabric", |
|||
"subspecs": [ |
|||
{ |
|||
"name": "activityindicator", |
|||
"dependencies": { |
|||
"Folly": [ |
|||
"2018.10.22.00" |
|||
] |
|||
}, |
|||
"compiler_flags": "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", |
|||
"source_files": "ReactCommon/fabric/activityindicator/**/*.{cpp,h}", |
|||
"exclude_files": "**/tests/*", |
|||
"header_dir": "fabric/activityindicator", |
|||
"pod_target_xcconfig": { |
|||
"HEADER_SEARCH_PATHS": "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Folly\"" |
|||
} |
|||
}, |
|||
{ |
|||
"name": "attributedstring", |
|||
"dependencies": { |
|||
"Folly": [ |
|||
"2018.10.22.00" |
|||
] |
|||
}, |
|||
"compiler_flags": "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", |
|||
"source_files": "ReactCommon/fabric/attributedstring/**/*.{cpp,h}", |
|||
"exclude_files": "**/tests/*", |
|||
"header_dir": "fabric/attributedstring", |
|||
"pod_target_xcconfig": { |
|||
"HEADER_SEARCH_PATHS": "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Folly\"" |
|||
} |
|||
}, |
|||
{ |
|||
"name": "core", |
|||
"dependencies": { |
|||
"Folly": [ |
|||
"2018.10.22.00" |
|||
] |
|||
}, |
|||
"compiler_flags": "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", |
|||
"source_files": "ReactCommon/fabric/core/**/*.{cpp,h}", |
|||
"exclude_files": "**/tests/*", |
|||
"header_dir": "fabric/core", |
|||
"pod_target_xcconfig": { |
|||
"HEADER_SEARCH_PATHS": "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Folly\"" |
|||
} |
|||
}, |
|||
{ |
|||
"name": "debug", |
|||
"dependencies": { |
|||
"Folly": [ |
|||
"2018.10.22.00" |
|||
] |
|||
}, |
|||
"compiler_flags": "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", |
|||
"source_files": "ReactCommon/fabric/debug/**/*.{cpp,h}", |
|||
"exclude_files": "**/tests/*", |
|||
"header_dir": "fabric/debug", |
|||
"pod_target_xcconfig": { |
|||
"HEADER_SEARCH_PATHS": "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Folly\"" |
|||
} |
|||
}, |
|||
{ |
|||
"name": "graphics", |
|||
"dependencies": { |
|||
"Folly": [ |
|||
"2018.10.22.00" |
|||
] |
|||
}, |
|||
"compiler_flags": "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", |
|||
"source_files": "ReactCommon/fabric/graphics/**/*.{cpp,h}", |
|||
"exclude_files": "**/tests/*", |
|||
"header_dir": "fabric/graphics", |
|||
"pod_target_xcconfig": { |
|||
"HEADER_SEARCH_PATHS": "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Folly\"" |
|||
} |
|||
}, |
|||
{ |
|||
"name": "scrollview", |
|||
"dependencies": { |
|||
"Folly": [ |
|||
"2018.10.22.00" |
|||
] |
|||
}, |
|||
"compiler_flags": "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", |
|||
"source_files": "ReactCommon/fabric/scrollview/**/*.{cpp,h}", |
|||
"exclude_files": "**/tests/*", |
|||
"header_dir": "fabric/scrollview", |
|||
"pod_target_xcconfig": { |
|||
"HEADER_SEARCH_PATHS": "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Folly\"" |
|||
} |
|||
}, |
|||
{ |
|||
"name": "text", |
|||
"dependencies": { |
|||
"Folly": [ |
|||
"2018.10.22.00" |
|||
] |
|||
}, |
|||
"compiler_flags": "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", |
|||
"source_files": "ReactCommon/fabric/text/**/*.{cpp,h}", |
|||
"exclude_files": "**/tests/*", |
|||
"header_dir": "fabric/text", |
|||
"pod_target_xcconfig": { |
|||
"HEADER_SEARCH_PATHS": "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Folly\"" |
|||
} |
|||
}, |
|||
{ |
|||
"name": "textlayoutmanager", |
|||
"dependencies": { |
|||
"Folly": [ |
|||
"2018.10.22.00" |
|||
] |
|||
}, |
|||
"compiler_flags": "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", |
|||
"source_files": "ReactCommon/fabric/textlayoutmanager/**/*.{cpp,h,mm}", |
|||
"exclude_files": "**/tests/*", |
|||
"header_dir": "fabric/textlayoutmanager", |
|||
"pod_target_xcconfig": { |
|||
"HEADER_SEARCH_PATHS": "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Folly\"" |
|||
} |
|||
}, |
|||
{ |
|||
"name": "uimanager", |
|||
"dependencies": { |
|||
"Folly": [ |
|||
"2018.10.22.00" |
|||
] |
|||
}, |
|||
"compiler_flags": "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", |
|||
"source_files": "ReactCommon/fabric/uimanager/**/*.{cpp,h}", |
|||
"exclude_files": "**/tests/*", |
|||
"header_dir": "fabric/uimanager", |
|||
"pod_target_xcconfig": { |
|||
"HEADER_SEARCH_PATHS": "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Folly\"" |
|||
} |
|||
}, |
|||
{ |
|||
"name": "view", |
|||
"dependencies": { |
|||
"Folly": [ |
|||
"2018.10.22.00" |
|||
], |
|||
"yoga": [ |
|||
|
|||
] |
|||
}, |
|||
"compiler_flags": "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", |
|||
"source_files": "ReactCommon/fabric/view/**/*.{cpp,h}", |
|||
"exclude_files": "**/tests/*", |
|||
"header_dir": "fabric/view", |
|||
"pod_target_xcconfig": { |
|||
"HEADER_SEARCH_PATHS": "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Folly\"" |
|||
} |
|||
} |
|||
] |
|||
}, |
|||
{ |
|||
"name": "RCTFabricSample", |
|||
"dependencies": { |
|||
"Folly": [ |
|||
"2018.10.22.00" |
|||
] |
|||
}, |
|||
"compiler_flags": "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", |
|||
"source_files": "ReactCommon/fabric/sample/**/*.{cpp,h}", |
|||
"exclude_files": "**/tests/*", |
|||
"header_dir": "fabric/sample", |
|||
"pod_target_xcconfig": { |
|||
"HEADER_SEARCH_PATHS": "\"$(PODS_TARGET_SRCROOT)/ReactCommon\" \"$(PODS_ROOT)/Folly\"" |
|||
} |
|||
}, |
|||
{ |
|||
"name": "ART", |
|||
"dependencies": { |
|||
"React/Core": [ |
|||
|
|||
] |
|||
}, |
|||
"source_files": "Libraries/ART/**/*.{h,m}" |
|||
}, |
|||
{ |
|||
"name": "RCTActionSheet", |
|||
"dependencies": { |
|||
"React/Core": [ |
|||
|
|||
] |
|||
}, |
|||
"source_files": "Libraries/ActionSheetIOS/*.{h,m}" |
|||
}, |
|||
{ |
|||
"name": "RCTAnimation", |
|||
"dependencies": { |
|||
"React/Core": [ |
|||
|
|||
] |
|||
}, |
|||
"source_files": "Libraries/NativeAnimation/{Drivers/*,Nodes/*,*}.{h,m}", |
|||
"header_dir": "RCTAnimation" |
|||
}, |
|||
{ |
|||
"name": "RCTBlob", |
|||
"dependencies": { |
|||
"React/Core": [ |
|||
|
|||
] |
|||
}, |
|||
"source_files": "Libraries/Blob/*.{h,m,mm}", |
|||
"preserve_paths": "Libraries/Blob/*.js" |
|||
}, |
|||
{ |
|||
"name": "RCTCameraRoll", |
|||
"dependencies": { |
|||
"React/Core": [ |
|||
|
|||
], |
|||
"React/RCTImage": [ |
|||
|
|||
] |
|||
}, |
|||
"source_files": "Libraries/CameraRoll/*.{h,m}" |
|||
}, |
|||
{ |
|||
"name": "RCTGeolocation", |
|||
"dependencies": { |
|||
"React/Core": [ |
|||
|
|||
] |
|||
}, |
|||
"source_files": "Libraries/Geolocation/*.{h,m}" |
|||
}, |
|||
{ |
|||
"name": "RCTImage", |
|||
"dependencies": { |
|||
"React/Core": [ |
|||
|
|||
], |
|||
"React/RCTNetwork": [ |
|||
|
|||
] |
|||
}, |
|||
"source_files": "Libraries/Image/*.{h,m}" |
|||
}, |
|||
{ |
|||
"name": "RCTNetwork", |
|||
"dependencies": { |
|||
"React/Core": [ |
|||
|
|||
] |
|||
}, |
|||
"source_files": "Libraries/Network/*.{h,m,mm}" |
|||
}, |
|||
{ |
|||
"name": "RCTPushNotification", |
|||
"dependencies": { |
|||
"React/Core": [ |
|||
|
|||
] |
|||
}, |
|||
"source_files": "Libraries/PushNotificationIOS/*.{h,m}" |
|||
}, |
|||
{ |
|||
"name": "RCTSettings", |
|||
"dependencies": { |
|||
"React/Core": [ |
|||
|
|||
] |
|||
}, |
|||
"source_files": "Libraries/Settings/*.{h,m}" |
|||
}, |
|||
{ |
|||
"name": "RCTText", |
|||
"dependencies": { |
|||
"React/Core": [ |
|||
|
|||
] |
|||
}, |
|||
"source_files": "Libraries/Text/**/*.{h,m}" |
|||
}, |
|||
{ |
|||
"name": "RCTVibration", |
|||
"dependencies": { |
|||
"React/Core": [ |
|||
|
|||
] |
|||
}, |
|||
"source_files": "Libraries/Vibration/*.{h,m}" |
|||
}, |
|||
{ |
|||
"name": "RCTWebSocket", |
|||
"dependencies": { |
|||
"React/Core": [ |
|||
|
|||
], |
|||
"React/RCTBlob": [ |
|||
|
|||
], |
|||
"React/fishhook": [ |
|||
|
|||
] |
|||
}, |
|||
"source_files": "Libraries/WebSocket/*.{h,m}" |
|||
}, |
|||
{ |
|||
"name": "fishhook", |
|||
"header_dir": "fishhook", |
|||
"source_files": "Libraries/fishhook/*.{h,c}" |
|||
}, |
|||
{ |
|||
"name": "RCTLinkingIOS", |
|||
"dependencies": { |
|||
"React/Core": [ |
|||
|
|||
] |
|||
}, |
|||
"source_files": "Libraries/LinkingIOS/*.{h,m}" |
|||
}, |
|||
{ |
|||
"name": "RCTTest", |
|||
"dependencies": { |
|||
"React/Core": [ |
|||
|
|||
] |
|||
}, |
|||
"source_files": "Libraries/RCTTest/**/*.{h,m}", |
|||
"frameworks": "XCTest" |
|||
}, |
|||
{ |
|||
"name": "_ignore_me_subspec_for_linting_", |
|||
"dependencies": { |
|||
"React/Core": [ |
|||
|
|||
], |
|||
"React/CxxBridge": [ |
|||
|
|||
] |
|||
} |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,97 @@ |
|||
{ |
|||
"name": "react-native-camera", |
|||
"version": "2.6.0", |
|||
"summary": "A Camera component for React Native. Also reads barcodes.", |
|||
"description": "A Camera component for React Native. Also reads barcodes.", |
|||
"license": "MIT AND Apache-2.0 AND BSD-3-Clause", |
|||
"authors": { |
|||
"name": "Lochlan Wansbrough", |
|||
"email": "lochie@live.com", |
|||
"url": "http://lwansbrough.com" |
|||
}, |
|||
"homepage": "https://github.com/react-native-community/react-native-camera", |
|||
"source": { |
|||
"git": "https://github.com/react-native-community/react-native-camera", |
|||
"tag": "v2.6.0" |
|||
}, |
|||
"requires_arc": true, |
|||
"platforms": { |
|||
"ios": "9.0" |
|||
}, |
|||
"default_subspecs": [ |
|||
"RN", |
|||
"RCT" |
|||
], |
|||
"preserve_paths": [ |
|||
"LICENSE", |
|||
"README.md", |
|||
"package.json", |
|||
"index.js" |
|||
], |
|||
"dependencies": { |
|||
"React": [ |
|||
|
|||
] |
|||
}, |
|||
"subspecs": [ |
|||
{ |
|||
"name": "RCT", |
|||
"source_files": "ios/RCT/**/*.{h,m}" |
|||
}, |
|||
{ |
|||
"name": "RN", |
|||
"source_files": "ios/RN/**/*.{h,m}" |
|||
}, |
|||
{ |
|||
"name": "TextDetector", |
|||
"dependencies": { |
|||
"react-native-camera/RN": [ |
|||
|
|||
], |
|||
"react-native-camera/RCT": [ |
|||
|
|||
], |
|||
"Firebase/MLVision": [ |
|||
|
|||
], |
|||
"Firebase/MLVisionTextModel": [ |
|||
|
|||
] |
|||
} |
|||
}, |
|||
{ |
|||
"name": "FaceDetectorMLKit", |
|||
"dependencies": { |
|||
"react-native-camera/RN": [ |
|||
|
|||
], |
|||
"react-native-camera/RCT": [ |
|||
|
|||
], |
|||
"Firebase/MLVision": [ |
|||
|
|||
], |
|||
"Firebase/MLVisionFaceModel": [ |
|||
|
|||
] |
|||
} |
|||
}, |
|||
{ |
|||
"name": "BarcodeDetectorMLKit", |
|||
"dependencies": { |
|||
"react-native-camera/RN": [ |
|||
|
|||
], |
|||
"react-native-camera/RCT": [ |
|||
|
|||
], |
|||
"Firebase/MLVision": [ |
|||
|
|||
], |
|||
"Firebase/MLVisionBarcodeModel": [ |
|||
|
|||
] |
|||
} |
|||
} |
|||
] |
|||
} |