Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apple watch support #99

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
307 changes: 303 additions & 4 deletions FreeOTP.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion FreeOTP/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ import UIKit

@UIApplicationMain
class AppDelegate : UIResponder, UIApplicationDelegate {

var window: UIWindow?


let watchSessionDelegate = WatchSessionDelegate()

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
return true
}
Expand Down
1 change: 1 addition & 0 deletions FreeOTP/Assets.xcassets/AppIcon.appiconset/Contents.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,4 @@
"author" : "xcode"
}
}

74 changes: 37 additions & 37 deletions FreeOTP/Base.lproj/Main.storyboard

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion FreeOTP/ImageDownloader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ class ImageDownloader : NSObject {
}

func fromURI(_ uri: String?, completion: @escaping (UIImage) -> Void) {
if let u = uri {
if var u = uri {
if u.hasPrefix("phasset:") {
let id = String(u[u.index(u.startIndex, offsetBy: "phasset:".characters.count)...])
let rslt = PHAsset.fetchAssets(withLocalIdentifiers: [id], options: nil)
Expand Down
2 changes: 1 addition & 1 deletion FreeOTP/TokenStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import Foundation
import Security

open class TokenStore : NSObject {
@objc fileprivate final class TokenOrder : NSObject, KeychainStorable {
@objc(TokenOrder) fileprivate final class TokenOrder : NSObject, KeychainStorable {
static let ACCOUNT = "09E969FC-53C3-4BE2-B653-4802949A26A7"
static let store = KeychainStore<TokenOrder>()
let account = ACCOUNT
Expand Down
43 changes: 43 additions & 0 deletions FreeOTP/WatchSessionDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// WatchSessionDelegate.swift
// FreeOTP
//
// Created by Jeff Bornemann on 1/16/18.
// Copyright © 2018 Fedora Project. All rights reserved.
//

import Foundation
import WatchConnectivity

class WatchSessionDelegate : NSObject, WCSessionDelegate {

override init() {
super.init()
if WCSession.isSupported() {
let session = WCSession.default
session.delegate = self
session.activate()
}
}

func session(_ session: WCSession,
didReceiveMessage message: [String : Any],
replyHandler: @escaping ([String : Any]) -> Void) {
let store: Int = message["store"] as! Int
let nextToken: Token? = TokenStore().load(store)
if nextToken != nil {
replyHandler(["token": nextToken?.codes[0].value as Any,
"account": nextToken?.account as Any,
"to": nextToken?.codes[0].to as Any])
}
else {
replyHandler(["token": "",
"account": "",
"to": Date(timeIntervalSinceNow: 5)])
}
}

func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {}
func sessionDidBecomeInactive(_ session: WCSession) {}
func sessionDidDeactivate(_ session: WCSession) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"images" : [
{
"idiom" : "watch",
"screenWidth" : "{130,145}",
"scale" : "2x"
},
{
"idiom" : "watch",
"screenWidth" : "{146,165}",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"assets" : [
{
"idiom" : "watch",
"filename" : "Circular.imageset",
"role" : "circular"
},
{
"idiom" : "watch",
"filename" : "Extra Large.imageset",
"role" : "extra-large"
},
{
"idiom" : "watch",
"filename" : "Modular.imageset",
"role" : "modular"
},
{
"idiom" : "watch",
"filename" : "Utilitarian.imageset",
"role" : "utilitarian"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"images" : [
{
"idiom" : "watch",
"screenWidth" : "{130,145}",
"scale" : "2x"
},
{
"idiom" : "watch",
"screenWidth" : "{146,165}",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"images" : [
{
"idiom" : "watch",
"screenWidth" : "{130,145}",
"scale" : "2x"
},
{
"idiom" : "watch",
"screenWidth" : "{146,165}",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"images" : [
{
"idiom" : "watch",
"screenWidth" : "{130,145}",
"scale" : "2x"
},
{
"idiom" : "watch",
"screenWidth" : "{146,165}",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

71 changes: 71 additions & 0 deletions freeotpwatch Extension/ExtensionDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//
// ExtensionDelegate.swift
// FreeOTPWatch Extension
//
// Created by Jeff Bornemann on 1/15/18.
// Copyright © 2018 Fedora Project. All rights reserved.
//

import WatchKit
import WatchConnectivity

class ExtensionDelegate: NSObject, WKExtensionDelegate, WCSessionDelegate {

var currentToken: String = ""
var account: String = ""

var to: Date = Date(timeIntervalSinceNow: 5)

func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {}

func applicationDidFinishLaunching() {
if WCSession.isSupported() {
let session = WCSession.default
session.delegate = self
session.activate()
}
}

func updateToken() {
if WCSession.isSupported() {
let session = WCSession.default
if session.isReachable {
session.sendMessage(["store": 0], replyHandler: { (replyMessage) -> Void in
self.currentToken = replyMessage["token"] as! String
self.account = replyMessage["account"] as! String
self.to = replyMessage["to"] as! Date
})
}
else {
self.currentToken = ""
self.account = ""
self.to = Date(timeIntervalSinceNow: 5)
}
}
}

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)
default:
// make sure to complete unhandled task types
task.setTaskCompletedWithSnapshot(false)
}
}
}

}
48 changes: 48 additions & 0 deletions freeotpwatch Extension/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?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>FreeOTPWatch 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>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>CLKComplicationPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).ComplicationController</string>
<key>CLKComplicationSupportedFamilies</key>
<array>
<string>CLKComplicationFamilyModularSmall</string>
<string>CLKComplicationFamilyModularLarge</string>
<string>CLKComplicationFamilyUtilitarianSmall</string>
<string>CLKComplicationFamilyUtilitarianSmallFlat</string>
<string>CLKComplicationFamilyUtilitarianLarge</string>
<string>CLKComplicationFamilyCircularSmall</string>
<string>CLKComplicationFamilyExtraLarge</string>
</array>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>WKAppBundleIdentifier</key>
<string>org.fedorahosted.freeotp.watchkitapp</string>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.watchkit</string>
</dict>
<key>WKExtensionDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).ExtensionDelegate</string>
</dict>
</plist>
68 changes: 68 additions & 0 deletions freeotpwatch Extension/InterfaceController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//
// InterfaceController.swift
// FreeOTPWatch Extension
//
// Created by Jeff Bornemann on 1/15/18.
// Copyright © 2018 Fedora Project. All rights reserved.
//

import WatchKit
import WatchConnectivity
import Foundation


class InterfaceController: WKInterfaceController {

@IBOutlet var token: WKInterfaceLabel!
@IBOutlet var account: WKInterfaceLabel!

var timer: Timer?

let delegate: ExtensionDelegate = WKExtension.shared().delegate as! ExtensionDelegate

@IBAction func update() {
delegate.updateToken()
updateText()
setTimer()
}

func updateText() {
if !delegate.currentToken.isEmpty {
account.setText(delegate.account)
token.setText(delegate.currentToken)
}
else {
account.setText("")
token.setText("Connecting..")
}
}

func setTimer() {
unsetTimer()
let timeToRun = delegate.to.timeIntervalSinceNow > 0 ? delegate.to.timeIntervalSinceNow : TimeInterval(1)
timer = Timer.scheduledTimer(timeInterval: timeToRun, target: self, selector: #selector(update), userInfo: nil, repeats: false)
}

func unsetTimer() {
timer?.invalidate()
timer = nil
}

override func willActivate() {
super.willActivate()
// This method is called when watch view controller is about to be visible to user
update()
}

override func awake(withContext context: Any?) {
super.awake(withContext: context)
}

override func didDeactivate() {
// This method is called when watch view controller is no longer visible
super.didDeactivate()
unsetTimer()
}

}

Loading