From 90644e08952dcd43ea1d502f0c99fae0e6ddbda5 Mon Sep 17 00:00:00 2001 From: Michael Dorner Date: Sun, 1 Jan 2017 17:51:26 +0100 Subject: [PATCH] major changes - added demo application GUI - changed Bluetooth toggle from power to enable --- BeeTee Demo/AppDelegate.swift | 4 +- BeeTee Demo/Assets.xcassets/Contents.json | 6 + .../DeviceListing.imageset/Contents.json | 23 ++ .../DeviceListing.imageset/noun_18353-1.png | Bin 0 -> 1437 bytes .../DeviceListing.imageset/noun_18353-2.png | Bin 0 -> 900 bytes .../DeviceListing.imageset/noun_18353.png | Bin 0 -> 1953 bytes .../MissionControl.imageset/Contents.json | 23 ++ .../noun_655374_cc-1.png | Bin 0 -> 2248 bytes .../noun_655374_cc-2.png | Bin 0 -> 1196 bytes .../noun_655374_cc.png | Bin 0 -> 3422 bytes BeeTee Demo/Base.lproj/Main.storyboard | 258 +++++++++++++++--- BeeTee Demo/Info.plist | 2 +- .../MissionControlViewController.swift | 43 +++ BeeTee Demo/ViewController.swift | 43 --- BeeTee.xcodeproj/project.pbxproj | 50 +++- BeeTee/BeeTee.swift | 56 ++-- BeeTee/BeeTeeModel.swift | 70 +++++ BeeTee/BluetoothManagerHandler.h | 2 + BeeTee/BluetoothManagerHandler.m | 8 + BeeTee/DeviceDetailViewController.swift | 65 +++++ BeeTee/DeviceListingViewController.swift | 44 +++ 21 files changed, 580 insertions(+), 117 deletions(-) create mode 100644 BeeTee Demo/Assets.xcassets/Contents.json create mode 100644 BeeTee Demo/Assets.xcassets/DeviceListing.imageset/Contents.json create mode 100644 BeeTee Demo/Assets.xcassets/DeviceListing.imageset/noun_18353-1.png create mode 100644 BeeTee Demo/Assets.xcassets/DeviceListing.imageset/noun_18353-2.png create mode 100644 BeeTee Demo/Assets.xcassets/DeviceListing.imageset/noun_18353.png create mode 100644 BeeTee Demo/Assets.xcassets/MissionControl.imageset/Contents.json create mode 100644 BeeTee Demo/Assets.xcassets/MissionControl.imageset/noun_655374_cc-1.png create mode 100644 BeeTee Demo/Assets.xcassets/MissionControl.imageset/noun_655374_cc-2.png create mode 100644 BeeTee Demo/Assets.xcassets/MissionControl.imageset/noun_655374_cc.png create mode 100644 BeeTee Demo/MissionControlViewController.swift delete mode 100644 BeeTee Demo/ViewController.swift create mode 100644 BeeTee/BeeTeeModel.swift create mode 100644 BeeTee/DeviceDetailViewController.swift create mode 100644 BeeTee/DeviceListingViewController.swift diff --git a/BeeTee Demo/AppDelegate.swift b/BeeTee Demo/AppDelegate.swift index c82842c..b2f88e3 100644 --- a/BeeTee Demo/AppDelegate.swift +++ b/BeeTee Demo/AppDelegate.swift @@ -3,13 +3,13 @@ */ import UIKit +import CoreLocation @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true @@ -36,7 +36,5 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func applicationWillTerminate(_ application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } - - } diff --git a/BeeTee Demo/Assets.xcassets/Contents.json b/BeeTee Demo/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/BeeTee Demo/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/BeeTee Demo/Assets.xcassets/DeviceListing.imageset/Contents.json b/BeeTee Demo/Assets.xcassets/DeviceListing.imageset/Contents.json new file mode 100644 index 0000000..3eaecb5 --- /dev/null +++ b/BeeTee Demo/Assets.xcassets/DeviceListing.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "noun_18353-2.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "noun_18353-1.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "noun_18353.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/BeeTee Demo/Assets.xcassets/DeviceListing.imageset/noun_18353-1.png b/BeeTee Demo/Assets.xcassets/DeviceListing.imageset/noun_18353-1.png new file mode 100644 index 0000000000000000000000000000000000000000..d279a6e3d5c668a33c1153982ab8ebb327322899 GIT binary patch literal 1437 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nC-mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5l;AAzh%9Dc;1&j9Muu5) zBp4VNBQrxHN+NuHtdjF{^%7I^lT!66atnZ}85nFTtboki)RIJnirk#MVyg;UC9n!B zAR8pCucQE0Qj%?}6yY17;GAESs$i;TqGzCF$EBd4U{jQmW)z9|8>y;bpKhp88yV>WRp=I1=9MH?=;jqGLkxkLMfuL^+7WFhI$72aI=A0Z9t+{{zaLoK$}74 z+Zoz`RicPN?Xl4ZS&rlwh)=KcOG#lU&8Z;xksh&xf7d@%EW`ZUW%@YimFc}J@2i* zfBt6tcZ>A(wdZ%v_06jPYMuRd>%OmR-~YaLEBo!`tD&A#8?~52*;es{NUksnNL_Hs zAyQJ}Qq#kQFIIdv*51F};Mw}sJR%*Ae=NQ$`8C`w4tHtw!7C{Ifi6S;0EdV%6Ht zMvdbKed?ReNB-4(>J#wnaBRSF&bv%W0fG73*T}E-&7I%Qx!{SKz0A6mSL#AbJ{cOU zzINrQm<*$zk>IkXOPudW zotPK!?2v56)sqKb%}whoT<~O_N1pO2wnwXW{P#b=6mVwG`xA);Q)3psd>|IQe{#}= zU(4^F{$N(UZLeog;|hs`K8yCT-dQaEK&i#T?s|bn$p)P{t2G2_J0`EZH~*MfxZ9~I z79Nv|MOcNjA9<}|^$ve*=2Et3$;uMVIohHgEQY+_`wnb6b9VZa+Yd#KoT}*3ZSc!C zeEYJU{cPzEj@E-0?yE=zR5>E`mkwpyKb96`WQlMQ~&w3;7o7Hw#tRdEGXZZR?8Vnrt6@^I~(pFE7;Bv+S!@#)gk_k@I?QO#He!*lgasuIPQ9Mba0I zBZ^yJIG~NCg2Yzd5PWl~7*Yqo0M~+M^o&S1sV0`)48v9ez z4plFida~3c?D#K-gWHon&wusjJL8|rZ$c-B!*UHM8|9`v5cgUhaVPxJ*=SH9=;`X` Jvd$@?2>|urU{e49 literal 0 HcmV?d00001 diff --git a/BeeTee Demo/Assets.xcassets/DeviceListing.imageset/noun_18353-2.png b/BeeTee Demo/Assets.xcassets/DeviceListing.imageset/noun_18353-2.png new file mode 100644 index 0000000000000000000000000000000000000000..54070c7b72c2a7cb949fdbb474100585941faede GIT binary patch literal 900 zcmeAS@N?(olHy`uVBq!ia0vp^k|4~%1|*NXY)uAIEa{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8X6a5n0T@z%2~Ij105p zNH8!kMrMXYltlRYSS9D@>LsS+C#C9DVstT4fPE4;bsH1+JHo@{EISEfi{E8 zw==W>t3(ll+GC>+vK+}V5TAlYfnK%aveAbJn;nv_ z^f~B#ef_$HyLVZ)Iz|6WWw**Ii~YOyA7`wo-C4W+lXm#*f5r50LTdNUX~#Vtz2IU? zkUo~kdoF>m?V;=;`K^9E@7uf$^okZuTdFP@E?GKFcLw9+_O(+#vi8Y0RIS~S_4#ho^PuhB8rvrMyxPDR{2?Os^1Ytonw<5MtR}ChI@Q9Sdr^2tbL@<^ za088+z~ChHUk?OgW&}N#Ui-mD%u8?o@6MX3x0fDV^)5ls?V-e-PV=?$kJuJH>$0wG zSgzA=F%RcSq_{((kfNe+lrBgG1_}T1l z+jQiOQApLT3)c0Up8mL0_W5(lxfwR03STF-{J6gE?(y{g%{2z*B9Cu#!s1 UfV04wTu@r~boFyt=akR{07aHhegFUf literal 0 HcmV?d00001 diff --git a/BeeTee Demo/Assets.xcassets/DeviceListing.imageset/noun_18353.png b/BeeTee Demo/Assets.xcassets/DeviceListing.imageset/noun_18353.png new file mode 100644 index 0000000000000000000000000000000000000000..3bad4585b6240d894443e4ce2c454fa680c47046 GIT binary patch literal 1953 zcmaJ?cUaR&8vao?1Q0}e4WS8=1khbcNJ0xH%mdPgaqa)_`ftU*LT1Zjda$tLP~w}0%-^L+Eoyz|cc&Nt6I&s=bJ{F^jb6$}7? zGy#tz@$+#(fW-N|xnt}+KZyog6RiQ@UWVi@S&To2Q1B!o0L1D8Kmr>8w)s%P8~~g) z0f6}c06<*@0HyHUCKoh+K_VRQ9SH!E2LvGmT+dYo03q)XH!qeK(E&wa(Bb4DMj#a) zO%La@0RSD1;t%Om78w#v4-Jb%MPs0!87Tf(03)D~&lDC71N9<0Lu?sLD&%|k5x5By z3x+@-XlBqU6bX0i>vsMO1O1W33P&LjQBhIwsKamuGZ z3O7M~)8=nQ3s963Gla@_7U*M5(Vv-r!oK>T5d!o7In0+zKcoCov0yaf+qGfA4qXP` z03cRFz*)OR3oTyv?JIUw?mhZ&%WI#?0GXMXRbXfbzkMgdy1_Mtq+2-=PR>5wpQEOf zt=2z+Crmr1K?$iQ9ESY(bunYU|E;+1r?TUgdCY-g-GNcJ#%& z-{YM0wL7g$WTiw!{(mwRIj=y|EXTKZyN+1e^RNv_`%{yk;2QZUhZ7!Wex%ZLByCa) zILU|D95$xwJK?E~%4Zmr!i-73;KH?qly*gAsZMZ-_?CTumCSa_>J71;*xIcSimi;| zJtHssoC{JOQ~Iw|g!%^!L9r(r>^Hrub>?!7CX93S0}5FVchcd;@V2uD7aT`d&TqT) za4Z~0Jw&Cn@P;wVzV=J5Y3k4QIES;RuCDvoYZ0+C7TWHgcs&nORiR@4a@-zt`&dBg z3Bvq>ZfXb1P6+R1YUOoP2Xyi%o~qGds-=Tv8r}w_%!5G{k>xC9<)qBR%|S0RDjZr* zyAG%5Z~Xj#YK>IQ9Ez{GwMNZeOBHH0n-(gw+ipluAJOB`?JI_Twy(uom~OpA-VQuR zDk`ePNs3~$C*W4;RU*&g#_8^R{+(pvIIOExINb%V;d-}FQZj`R$Btt=kyP48vq`-} z6o~$Ad9{CEa_4*5Jo(*zLi5h6$syq%F2go^RMN~rO;1$^Nj0aWxwq3aglETQg>@rL z7uC=PPDVt~nz-G5Y6h*ZKxW%^$TTDSMZ^NP;OQ;oMXYAg=EW}aAzb74Hp_IkJ2wL~ zF)c6E5%I9ytQOTYG^j%3&^152O^`di(+2?oH{znLH(e%Y+Mo+^4k@ng#CNM^rz=2` zUV6m`Ryxl#mbb&hs|N>$?~WM;aB?E=E==3MVv(OOrEGTjVHG#PjTuJihZv94al3HY zhk$UrVX|=#L%gUZdbmVya_M(rk_Oqoey`-8E1F`avPUc;PH2^m!ys*)++y^4-Eh6w zm}hz>Oqf*H?ST8Om=|K(GAsSo_k0xW$qyhq_+pkJVXh9C3AdWeiocW~^|*{i9F)_8 zifoYr+_!tCm;3P_#@?$DuHk8k2N6b|H$Qd7^;_=br@cFl?mJ{A62q>p*A+$8Rk>scZFM5Cmbzv7$~Cc~-=o>RdO9dG%Cf#b%VQ_UsXRz76megR zd9mXq??O_~eRZNg{bSMN#h6butD9r9vvYe^%K5sA18qhP?=u}}o)+BK(-(~Q5p@~w ze)7ow^>z7%pI_LmOK&hwWXfg04Djym1G^8ZWc&o9^o;lV$l09AhQb-+#|wIiSKfLz zo>Y*L7=1kM+n{-jQa= zP;<9Tz6R1a*G*@`NG1}sO*lnndS=zL^pM5*dbtYOhl&%%p~StM zv4VkVm*9I(&bt3XS>5o_9tnO>OkK&*5w&cWmEGayjIJC(-U#aE`7Yn5Samc*MVR{_ zbI^D~pUN>`+L&H`WSLiBZ(^qAqD*oMdw0N`I4=eXl zPEr4*k0*^CC0g)vEAJm2mZZ%(+f}i?HGi7L;8beOqhC1@>>*xY;<>#F5LW`UuNoFf zmYS#a4$v>&?Ctfo?A4_FG`Rn=T1lmz8IybLQB`o#K8n^vAyOeFDKP+|3=;qAH0CV6 ZCuS>3=s!?XeOT}j66_ptl{NuMe*ndXOAr76 literal 0 HcmV?d00001 diff --git a/BeeTee Demo/Assets.xcassets/MissionControl.imageset/Contents.json b/BeeTee Demo/Assets.xcassets/MissionControl.imageset/Contents.json new file mode 100644 index 0000000..95279c6 --- /dev/null +++ b/BeeTee Demo/Assets.xcassets/MissionControl.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "noun_655374_cc-2.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "noun_655374_cc-1.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "noun_655374_cc.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/BeeTee Demo/Assets.xcassets/MissionControl.imageset/noun_655374_cc-1.png b/BeeTee Demo/Assets.xcassets/MissionControl.imageset/noun_655374_cc-1.png new file mode 100644 index 0000000000000000000000000000000000000000..b559db96ebc7cae8892d53f5da45ed8e726d3d75 GIT binary patch literal 2248 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 - + @@ -9,48 +9,232 @@ - - + + - - - - - - + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BeeTee Demo/Info.plist b/BeeTee Demo/Info.plist index 2b02ec4..8850fde 100644 --- a/BeeTee Demo/Info.plist +++ b/BeeTee Demo/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.0 + 3.0 CFBundleVersion 1 LSRequiresIPhoneOS diff --git a/BeeTee Demo/MissionControlViewController.swift b/BeeTee Demo/MissionControlViewController.swift new file mode 100644 index 0000000..af51eba --- /dev/null +++ b/BeeTee Demo/MissionControlViewController.swift @@ -0,0 +1,43 @@ +/* + This file is part of BeeTee Project. It is subject to the license terms in the LICENSE file found in the top-level directory of this distribution and at https://github.com/michaeldorner/BeeTee/blob/master/LICENSE. No part of BeeTee Project, including this file, may be copied, modified, propagated, or distributed except according to the terms contained in the LICENSE file. + */ + +import UIKit + + +class MissionControlViewController: UITableViewController, BeeTeeDelegate { + + private let beeTeeModel = BeeTeeModel.sharedInstance + + @IBOutlet weak var bluetoothPowerSwitch: UISwitch! + @IBOutlet weak var bluetoothScanSwitch: UISwitch! + + override func viewDidLoad() { + super.viewDidLoad() + beeTeeModel.subscribe(subscriber: self) + bluetoothPowerSwitch.setOn(beeTeeModel.bluetoothIsOn(), animated: false) + bluetoothScanSwitch.setOn(beeTeeModel.isScanning(), animated: false) + } + + @IBAction func switchBluetoothPower() { + if beeTeeModel.bluetoothIsOn() { + beeTeeModel.turnBluetoothOff() + } else { + beeTeeModel.turnBluetoothOn() + } + } + + @IBAction func switchBluetoothScanStatus() { + if beeTeeModel.isScanning() { + beeTeeModel.stopScan() + } else { + beeTeeModel.startScanForDevices() + } + } + + func receivedBeeTeeNotification(notification: BeeTeeNotification) { + tableView.reloadData() + bluetoothPowerSwitch.setOn(beeTeeModel.bluetoothIsOn(), animated: true) + bluetoothScanSwitch.setOn(beeTeeModel.isScanning(), animated: true) + } +} diff --git a/BeeTee Demo/ViewController.swift b/BeeTee Demo/ViewController.swift deleted file mode 100644 index 8fd136e..0000000 --- a/BeeTee Demo/ViewController.swift +++ /dev/null @@ -1,43 +0,0 @@ -/* - This file is part of BeeTee Project. It is subject to the license terms in the LICENSE file found in the top-level directory of this distribution and at https://github.com/michaeldorner/BeeTee/blob/master/LICENSE. No part of BeeTee Project, including this file, may be copied, modified, propagated, or distributed except according to the terms contained in the LICENSE file. - */ - -import UIKit - - - -class ViewController: UIViewController, BeeTeeDelegate { - let beeTee = BeeTee() - - override func viewDidLoad() { - super.viewDidLoad() - // Do any additional setup after loading the view, typically from a nib. - - beeTee.delegate = self - } - - override func didReceiveMemoryWarning() { - super.didReceiveMemoryWarning() - // Dispose of any resources that can be recreated. - } - - @IBAction func pressOn(_ sender: UIButton) { - beeTee.turnBluetoothOn() - } - - @IBAction func pressOff(_ sender: UIButton) { - beeTee.turnBluetoothOff() - } - @IBAction func pressStatus(_ sender: UIButton) { - if beeTee.isScanning() { - beeTee.stopScan() - } else { - beeTee.startScanForDevices() - } - } - - func receivedBeeTeeNotification(notification: BeeTeeNotification) { - //print(notification) - } -} - diff --git a/BeeTee.xcodeproj/project.pbxproj b/BeeTee.xcodeproj/project.pbxproj index 48fc5f7..b2d65ce 100644 --- a/BeeTee.xcodeproj/project.pbxproj +++ b/BeeTee.xcodeproj/project.pbxproj @@ -7,11 +7,14 @@ objects = { /* Begin PBXBuildFile section */ + 5F0893721E17F82500197FAD /* MissionControlViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F0893711E17F82500197FAD /* MissionControlViewController.swift */; }; + 5F0893761E181C7B00197FAD /* BeeTeeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F0893751E181C7B00197FAD /* BeeTeeModel.swift */; }; + 5F08937D1E19021500197FAD /* DeviceListingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F08937C1E19021500197FAD /* DeviceListingViewController.swift */; }; + 5F08937F1E19071800197FAD /* DeviceDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F08937E1E19071800197FAD /* DeviceDetailViewController.swift */; }; 5F1764F71E0EBFB0003F888A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F1764F61E0EBFB0003F888A /* AppDelegate.swift */; }; 5F1764F91E0EBFBA003F888A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5F1764F81E0EBFBA003F888A /* Assets.xcassets */; }; 5F1764FE1E0EBFC2003F888A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5F1764FA1E0EBFC2003F888A /* LaunchScreen.storyboard */; }; 5F1764FF1E0EBFC2003F888A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5F1764FC1E0EBFC2003F888A /* Main.storyboard */; }; - 5F1765031E0EBFD2003F888A /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F1765011E0EBFD2003F888A /* ViewController.swift */; }; 5F2409071E0C0134004AF90F /* BeeTeeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F2409061E0C0134004AF90F /* BeeTeeTests.swift */; }; 5F9F63371E0EB9300014A043 /* BeeTee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9F632F1E0EB9300014A043 /* BeeTee.swift */; }; 5F9F63381E0EB9300014A043 /* BeeTeeDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9F63301E0EB9300014A043 /* BeeTeeDevice.swift */; }; @@ -30,12 +33,15 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 5F0893711E17F82500197FAD /* MissionControlViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MissionControlViewController.swift; path = "BeeTee Demo/MissionControlViewController.swift"; sourceTree = SOURCE_ROOT; }; + 5F0893751E181C7B00197FAD /* BeeTeeModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeeTeeModel.swift; sourceTree = ""; }; + 5F08937C1E19021500197FAD /* DeviceListingViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceListingViewController.swift; sourceTree = ""; }; + 5F08937E1E19071800197FAD /* DeviceDetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceDetailViewController.swift; sourceTree = ""; }; 5F1764F61E0EBFB0003F888A /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = "BeeTee Demo/AppDelegate.swift"; sourceTree = SOURCE_ROOT; }; 5F1764F81E0EBFBA003F888A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = "BeeTee Demo/Assets.xcassets"; sourceTree = SOURCE_ROOT; }; 5F1764FB1E0EBFC2003F888A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = "BeeTee Demo/Base.lproj/LaunchScreen.storyboard"; sourceTree = SOURCE_ROOT; }; 5F1764FD1E0EBFC2003F888A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = "BeeTee Demo/Base.lproj/Main.storyboard"; sourceTree = SOURCE_ROOT; }; 5F1765001E0EBFD2003F888A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = "BeeTee Demo/Info.plist"; sourceTree = SOURCE_ROOT; }; - 5F1765011E0EBFD2003F888A /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ViewController.swift; path = "BeeTee Demo/ViewController.swift"; sourceTree = SOURCE_ROOT; }; 5F2408EE1E0C0134004AF90F /* BeeTee.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BeeTee.app; sourceTree = BUILT_PRODUCTS_DIR; }; 5F2409021E0C0134004AF90F /* BeeTeeTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BeeTeeTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 5F2409061E0C0134004AF90F /* BeeTeeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BeeTeeTests.swift; sourceTree = ""; }; @@ -69,6 +75,34 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 5F0893791E18F95B00197FAD /* View */ = { + isa = PBXGroup; + children = ( + 5F1764F81E0EBFBA003F888A /* Assets.xcassets */, + 5F1764FA1E0EBFC2003F888A /* LaunchScreen.storyboard */, + 5F1764FC1E0EBFC2003F888A /* Main.storyboard */, + ); + name = View; + sourceTree = ""; + }; + 5F08937A1E18F96900197FAD /* Controller */ = { + isa = PBXGroup; + children = ( + 5F0893711E17F82500197FAD /* MissionControlViewController.swift */, + 5F08937C1E19021500197FAD /* DeviceListingViewController.swift */, + 5F08937E1E19071800197FAD /* DeviceDetailViewController.swift */, + ); + name = Controller; + sourceTree = ""; + }; + 5F08937B1E18F97000197FAD /* Model */ = { + isa = PBXGroup; + children = ( + 5F0893751E181C7B00197FAD /* BeeTeeModel.swift */, + ); + name = Model; + sourceTree = ""; + }; 5F2408E51E0C0134004AF90F = { isa = PBXGroup; children = ( @@ -92,11 +126,10 @@ isa = PBXGroup; children = ( 5F1765001E0EBFD2003F888A /* Info.plist */, - 5F1765011E0EBFD2003F888A /* ViewController.swift */, 5F1764F61E0EBFB0003F888A /* AppDelegate.swift */, - 5F1764F81E0EBFBA003F888A /* Assets.xcassets */, - 5F1764FA1E0EBFC2003F888A /* LaunchScreen.storyboard */, - 5F1764FC1E0EBFC2003F888A /* Main.storyboard */, + 5F0893791E18F95B00197FAD /* View */, + 5F08937A1E18F96900197FAD /* Controller */, + 5F08937B1E18F97000197FAD /* Model */, ); name = "BeeTee Demo"; path = BeeTee; @@ -251,9 +284,12 @@ 5F9F633A1E0EB9300014A043 /* BluetoothManagerHandler.m in Sources */, 5F9F63371E0EB9300014A043 /* BeeTee.swift in Sources */, 5F1764F71E0EBFB0003F888A /* AppDelegate.swift in Sources */, - 5F1765031E0EBFD2003F888A /* ViewController.swift in Sources */, + 5F08937D1E19021500197FAD /* DeviceListingViewController.swift in Sources */, 5F9F63381E0EB9300014A043 /* BeeTeeDevice.swift in Sources */, + 5F08937F1E19071800197FAD /* DeviceDetailViewController.swift in Sources */, + 5F0893761E181C7B00197FAD /* BeeTeeModel.swift in Sources */, 5F9F63391E0EB9300014A043 /* BluetoothDeviceHandler.m in Sources */, + 5F0893721E17F82500197FAD /* MissionControlViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/BeeTee/BeeTee.swift b/BeeTee/BeeTee.swift index c6826a0..c035297 100644 --- a/BeeTee/BeeTee.swift +++ b/BeeTee/BeeTee.swift @@ -33,57 +33,55 @@ public class BeeTee { public var delegate: BeeTeeDelegate? = nil public var availableDevices: [BeeTeeDevice] { get { - return Array(devices) + return Array(_availableDevices) } } private let bluetoothManagerHandler = BluetoothManagerHandler.sharedInstance()! - private var devices = Set() - private var observers = [NSObjectProtocol]() + private var _availableDevices = Set() + private var tokenCache = [BeeTeeNotification: NSObjectProtocol]() - convenience init(delegate: BeeTeeDelegate) { - self.init() - self.delegate = delegate - } - - init() { + public init() { + for beeTeeNotification in BeeTeeNotification.allNotifications { - print("registered \(beeTeeNotification)") + print("Registered \(beeTeeNotification)") - let observer = NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: beeTeeNotification.rawValue), object: nil, queue: OperationQueue.main) { (notification) in + let notification = NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: beeTeeNotification.rawValue), object: nil, queue: OperationQueue.main) { [unowned self] (notification) in + let beeTeeNotification = BeeTeeNotification.init(rawValue: notification.name.rawValue)! switch beeTeeNotification { case .DeviceDiscovered: let beeTeeDevice = self.extractBeeTeeDevice(from: notification) - self.devices.insert(beeTeeDevice) + self._availableDevices.insert(beeTeeDevice) case .DeviceRemoved: let beeTeeDevice = self.extractBeeTeeDevice(from: notification) - self.devices.remove(beeTeeDevice) + self._availableDevices.remove(beeTeeDevice) default: break } - print(beeTeeNotification) - self.delegate?.receivedBeeTeeNotification(notification: beeTeeNotification) + if (self.delegate != nil) { + self.delegate?.receivedBeeTeeNotification(notification: beeTeeNotification) + } } - observers.append(observer) + self.tokenCache[beeTeeNotification] = notification } } deinit { - for observer in observers { - NotificationCenter.default.removeObserver(observer) + for key in tokenCache.keys { + NotificationCenter.default.removeObserver(tokenCache[key]!) } } - public func turnBluetoothOn() { - bluetoothManagerHandler.setPower(true) + public func enableBluetooth() { + bluetoothManagerHandler.enable() } - public func turnBluetoothOff() { - bluetoothManagerHandler.setPower(false) + public func disableBluetooth() { + bluetoothManagerHandler.disable() } - public func bluetoothIsOn() -> Bool { - return bluetoothManagerHandler.powered() + public func bluetoothIsEnabled() -> Bool { + return bluetoothManagerHandler.enabled() } public func startScanForDevices() { @@ -92,14 +90,15 @@ public class BeeTee { public func stopScan() { bluetoothManagerHandler.stopScan() + resetAvailableDevices() } public func isScanning() -> Bool { return bluetoothManagerHandler.isScanning() } - public func debugLowLevel() { - NSLog("This is a dirty C hack and only for demonstration and deep debugging, but not for production.") // credits to http://stackoverflow.com/a/3738387/1864294 + public static func debugLowLevel() { + print("This is a dirty C hack and only for demonstration and deep debugging, but not for production.") // credits to http://stackoverflow.com/a/3738387/1864294 CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), nil, { (_, observer, name, _, _) in @@ -113,9 +112,14 @@ public class BeeTee { .deliverImmediately) } + private func resetAvailableDevices() { + _availableDevices.removeAll() + } + private func extractBeeTeeDevice(from notification: Notification) -> BeeTeeDevice { let bluetoothDevice = BluetoothDeviceHandler(notification: notification)! let beeTeeDevice = BeeTeeDevice(name: bluetoothDevice.name, address: bluetoothDevice.address, majorClass: bluetoothDevice.majorClass, minorClass: bluetoothDevice.minorClass, type: bluetoothDevice.type, supportsBatteryLevel: bluetoothDevice.supportsBatteryLevel, detectingDate: Date()) return beeTeeDevice } } + diff --git a/BeeTee/BeeTeeModel.swift b/BeeTee/BeeTeeModel.swift new file mode 100644 index 0000000..16b93b6 --- /dev/null +++ b/BeeTee/BeeTeeModel.swift @@ -0,0 +1,70 @@ +/* + This file is part of BeeTee Project. It is subject to the license terms in the LICENSE file found in the top-level directory of this distribution and at https://github.com/michaeldorner/BeeTee/blob/master/LICENSE. No part of BeeTee Project, including this file, may be copied, modified, propagated, or distributed except according to the terms contained in the LICENSE file. + */ + +import Foundation + +class BeeTeeModel: BeeTeeDelegate { + + static let sharedInstance = BeeTeeModel() + + private let beeTee = BeeTee() + private var subscribers = [BeeTeeDelegate]() + + public var availableDevices: [BeeTeeDevice] { + get { + return beeTee.availableDevices + } + } + + private init() { + beeTee.delegate = self + } + + func receivedBeeTeeNotification(notification: BeeTeeNotification) { + for subscriber in subscribers { + subscriber.receivedBeeTeeNotification(notification: notification) + } + print("BeeTeeNotification: " + String(describing: notification)) + } + + public func turnBluetoothOn() { + beeTee.enableBluetooth() + print("Bluetooth turned on") + + } + + public func turnBluetoothOff() { + beeTee.disableBluetooth() + print("Bluetooth turned off") + + } + + public func bluetoothIsOn() -> Bool { + return beeTee.bluetoothIsEnabled() + } + + public func startScanForDevices() { + beeTee.startScanForDevices() + print("Bluetooth started scanning for new devices") + + } + + public func stopScan() { + beeTee.stopScan() + print("Bluetooth stopped scanning") + } + + public func isScanning() -> Bool { + return beeTee.isScanning() + } + + public func subscribe(subscriber: BeeTeeDelegate) { + subscribers.append(subscriber) + } + + public func unsubscribe(subscriber: BeeTeeDelegate) { + //todo: add remove + } + +} diff --git a/BeeTee/BluetoothManagerHandler.h b/BeeTee/BluetoothManagerHandler.h index 60bf2f8..0946255 100644 --- a/BeeTee/BluetoothManagerHandler.h +++ b/BeeTee/BluetoothManagerHandler.h @@ -15,5 +15,7 @@ - (void) stopScan; - (bool) isScanning; - (bool) enabled; +- (void) disable; +- (void) enable; @end diff --git a/BeeTee/BluetoothManagerHandler.m b/BeeTee/BluetoothManagerHandler.m index 7e60460..0053656 100644 --- a/BeeTee/BluetoothManagerHandler.m +++ b/BeeTee/BluetoothManagerHandler.m @@ -57,4 +57,12 @@ - (bool)enabled { return [_bluetoothManager enabled]; } +- (void)disable { + [_bluetoothManager setEnabled:false]; +} + +- (void)enable { + [_bluetoothManager setEnabled:true]; +} + @end diff --git a/BeeTee/DeviceDetailViewController.swift b/BeeTee/DeviceDetailViewController.swift new file mode 100644 index 0000000..4552099 --- /dev/null +++ b/BeeTee/DeviceDetailViewController.swift @@ -0,0 +1,65 @@ +/* + This file is part of BeeTee Project. It is subject to the license terms in the LICENSE file found in the top-level directory of this distribution and at https://github.com/michaeldorner/BeeTee/blob/master/LICENSE. No part of BeeTee Project, including this file, may be copied, modified, propagated, or distributed except according to the terms contained in the LICENSE file. + */ + +import UIKit + + +class DeviceDetailViewController: UITableViewController { + + var device: BeeTeeDevice? = nil + let attributes = ["Name", "Address", "Major Class", "Minor Class", "Type", "Battery"] + + override func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return attributes.count + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + var value: String = "" + if (device != nil) { + switch indexPath.row { + case 0: + value = device!.name + case 1: + value = device!.address + case 2: + value = String(device!.majorClass) + case 3: + value = String(device!.minorCass) + case 4: + value = String(device!.type) + case 5: + value = device!.supportsBatteryLevel ? "Yes" : "No" + default: break + } + } + let cell = tableView.dequeueReusableCell(withIdentifier: "DeviceDetailCellIdentifier")! + cell.textLabel?.text = attributes[indexPath.row] + cell.detailTextLabel?.text = value + + return cell + } + + override func tableView(_ tableView: UITableView, shouldShowMenuForRowAt indexPath: IndexPath) -> Bool { + return (tableView.cellForRow(at: indexPath)?.detailTextLabel?.text) != nil + } + + override func tableView(_ tableView: UITableView, canPerformAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: Any?) -> Bool { + return action == #selector(copy(_:)) + } + + override func tableView(_ tableView: UITableView, performAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: Any?) { + if action == #selector(copy(_:)) { + let cell = tableView.cellForRow(at: indexPath) + let pasteboard = UIPasteboard.general + pasteboard.string = cell?.detailTextLabel?.text + } + } + + + +} diff --git a/BeeTee/DeviceListingViewController.swift b/BeeTee/DeviceListingViewController.swift new file mode 100644 index 0000000..4f06364 --- /dev/null +++ b/BeeTee/DeviceListingViewController.swift @@ -0,0 +1,44 @@ +/* + This file is part of BeeTee Project. It is subject to the license terms in the LICENSE file found in the top-level directory of this distribution and at https://github.com/michaeldorner/BeeTee/blob/master/LICENSE. No part of BeeTee Project, including this file, may be copied, modified, propagated, or distributed except according to the terms contained in the LICENSE file. + */ + +import UIKit + +class DeviceListingViewController: UITableViewController, BeeTeeDelegate { + let beeTeeModel = BeeTeeModel.sharedInstance + + override func viewDidLoad() { + super.viewDidLoad() + beeTeeModel.subscribe(subscriber: self) + } + + func receivedBeeTeeNotification(notification: BeeTeeNotification) { + tableView.reloadData() + } + + override func numberOfSections(in tableView: UITableView) -> Int { + return 1 + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return beeTeeModel.availableDevices.count + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let beeTeeDevice = beeTeeModel.availableDevices[indexPath.row] + + let cell = tableView.dequeueReusableCell(withIdentifier: "DeviceCellIdentifier")! + cell.textLabel?.text = beeTeeDevice.name + cell.detailTextLabel?.text = beeTeeDevice.address + + return cell + } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + let indexPath = tableView.indexPath(for: sender as! UITableViewCell)! + let selectedDevice = beeTeeModel.availableDevices[indexPath.row] + + let deviceDetailViewController: DeviceDetailViewController = segue.destination as! DeviceDetailViewController + deviceDetailViewController.device = selectedDevice + } +}