Skip to content

Commit

Permalink
Initial add ⚡️
Browse files Browse the repository at this point in the history
  • Loading branch information
andybons committed Nov 6, 2016
1 parent e603a09 commit d8cb3dd
Show file tree
Hide file tree
Showing 22 changed files with 1,233 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,5 @@ fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots
fastlane/test_output

.DS_Store
566 changes: 566 additions & 0 deletions GRGE/GRGE.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions GRGE/GRGE/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
return true
}
}

98 changes: 98 additions & 0 deletions GRGE/GRGE/Assets.xcassets/AppIcon.appiconset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "[email protected]",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "[email protected]",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-76.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "[email protected]",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "[email protected]",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions GRGE/GRGE/Base.lproj/LaunchScreen.storyboard
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11535.1" systemVersion="15G1004" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11523"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" cocoaTouchSystemColor="viewFlipsideBackgroundColor"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>
176 changes: 176 additions & 0 deletions GRGE/GRGE/Base.lproj/Main.storyboard

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions GRGE/GRGE/GRGE-Bridging-Header.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef GRGE_Bridging_Header_h
#define GRGE_Bridging_Header_h

#import <CommonCrypto/CommonCrypto.h>

#endif /* GRGE_Bridging_Header_h */
45 changes: 45 additions & 0 deletions GRGE/GRGE/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(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>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
153 changes: 153 additions & 0 deletions GRGE/GRGE/MainViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import UIKit

class MainViewController: UIViewController {
static private let instructionsText = "Press and hold in the area above"
static private let keepHoldingText = "Keep holding…"
static private let requestMadeText = "Sending request…"
static private let successText = "Hooray! Door triggered."
static private let errorText = "Uh oh. Something went wrong."

@IBOutlet var settingsButton: UIButton?
@IBOutlet var mainButton: UIButton?
@IBOutlet var mainLabel: UILabel?

private var touchTimer: Timer?
private var textTimer: Timer?
private var requestPending = false
private let isolationQueue = DispatchQueue(label: "com.andybons.GRGE.requestPendingQueue",
attributes: .concurrent)

override func viewDidLoad() {
super.viewDidLoad()

mainLabel!.text = MainViewController.instructionsText

let settingsIconImage = UIImage(named: "gears")!.withRenderingMode(UIImageRenderingMode.alwaysTemplate)
settingsButton!.setImage(settingsIconImage, for: UIControlState.normal)
settingsButton!.tintColor = UIColor.white
}

override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}

@IBAction func onTouchDown(button: UIButton) {
var reqPending: Bool!
isolationQueue.sync {
reqPending = requestPending
}
if textTimer != nil || reqPending { return }

touchTimer = Timer(timeInterval: 3.0,
repeats: false,
block: {_ in
self.clearTouchTimer()
self.triggerDoor()
})
RunLoop.current.add(touchTimer!, forMode: RunLoopMode.commonModes)
setMainLabelText(MainViewController.keepHoldingText)
}

@IBAction func onTouchUp(button: UIButton) {
var reqPending: Bool!
isolationQueue.sync {
reqPending = requestPending
}
if textTimer != nil || reqPending { return }

clearTouchTimer()
setMainLabelText(MainViewController.instructionsText)
}

func setMainLabelText(_ text: String) {
UIView.transition(with: mainLabel!,
duration: 0.25,
options: UIViewAnimationOptions.transitionCrossDissolve,
animations: { self.mainLabel!.text = text },
completion: nil)
}

func setMainLabelText(_ text: String, forDuration: TimeInterval) {
clearTextTimer()
setMainLabelText(text)
textTimer = Timer(timeInterval: 3.0,
repeats: false,
block: {_ in
self.clearTextTimer()
self.setMainLabelText(MainViewController.instructionsText)
}
)
RunLoop.main.add(textTimer!, forMode: RunLoopMode.commonModes)
}

func clearTextTimer() {
if textTimer != nil {
textTimer!.invalidate()
textTimer = nil
}
}

func clearTouchTimer() {
if touchTimer != nil {
touchTimer!.invalidate()
touchTimer = nil
}
}

func triggerDoor() {
let defaults = UserDefaults.standard
let baseURL = defaults.string(forKey: UserSettingsKey.baseURL)
let sharedSecret = defaults.string(forKey: UserSettingsKey.sharedSecret)
if baseURL == nil || sharedSecret == nil {
print("Must set base URL and shared secret")
return
}
let timeSinceEpoch = String(Int(NSDate().timeIntervalSince1970))
let key = hmacsha1(str: timeSinceEpoch, key: sharedSecret!)
let url = URL(string: "\(baseURL!)?t=\(timeSinceEpoch)&key=\(key)")
isolationQueue.async(flags: .barrier) {
self.requestPending = true
}
setMainLabelText(MainViewController.requestMadeText)
print("Making request to \(url!)")
let task = URLSession.shared.dataTask(with: url!, completionHandler: {
data, response, error in

self.isolationQueue.async(flags: .barrier) {
self.requestPending = false
}

if let errorStr = error?.localizedDescription {
print("error:", errorStr)
DispatchQueue.main.async {
self.setMainLabelText(MainViewController.errorText, forDuration: 5.0)
}
} else if let httpResponse = response as? HTTPURLResponse {
print("Status: \(httpResponse.statusCode)")
if httpResponse.statusCode == 200 {
DispatchQueue.main.async {
self.setMainLabelText(MainViewController.successText, forDuration: 5.0)
}
} else {
DispatchQueue.main.async {
self.setMainLabelText(MainViewController.errorText, forDuration: 5.0)
}
}
if data != nil {
let body = String(data:data!, encoding:String.Encoding.utf8)
print("Response body: \(body!)")
}
}
})
task.resume()
}

func hmacsha1(str: String, key: String) -> String {
let cData = str.cString(using: String.Encoding.utf8)!
let cKey = key.cString(using: String.Encoding.utf8)!
var result = [CUnsignedChar](repeating: 0, count:Int(CC_SHA1_DIGEST_LENGTH))
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA1), cKey, Int(strlen(cKey)), cData, Int(strlen(cData)), &result)
let hexBytes = result.map { String(format: "%02hhx", $0) }
return hexBytes.joined()
}
}
Loading

0 comments on commit d8cb3dd

Please sign in to comment.