├── sample.gif
├── DesireKeyboard
├── Assets.xcassets
│ ├── Contents.json
│ ├── App Icon & Top Shelf Image.brandassets
│ │ ├── App Icon - Large.imagestack
│ │ │ ├── Back.imagestacklayer
│ │ │ │ ├── Contents.json
│ │ │ │ └── Content.imageset
│ │ │ │ │ └── Contents.json
│ │ │ ├── Front.imagestacklayer
│ │ │ │ ├── Contents.json
│ │ │ │ └── Content.imageset
│ │ │ │ │ └── Contents.json
│ │ │ ├── Middle.imagestacklayer
│ │ │ │ ├── Contents.json
│ │ │ │ └── Content.imageset
│ │ │ │ │ └── Contents.json
│ │ │ └── Contents.json
│ │ ├── App Icon - Small.imagestack
│ │ │ ├── Back.imagestacklayer
│ │ │ │ ├── Contents.json
│ │ │ │ └── Content.imageset
│ │ │ │ │ └── Contents.json
│ │ │ ├── Front.imagestacklayer
│ │ │ │ ├── Contents.json
│ │ │ │ └── Content.imageset
│ │ │ │ │ └── Contents.json
│ │ │ ├── Middle.imagestacklayer
│ │ │ │ ├── Contents.json
│ │ │ │ └── Content.imageset
│ │ │ │ │ └── Contents.json
│ │ │ └── Contents.json
│ │ ├── Top Shelf Image.imageset
│ │ │ └── Contents.json
│ │ └── Contents.json
│ └── LaunchImage.launchimage
│ │ └── Contents.json
├── Info.plist
├── ViewController.swift
├── AppDelegate.swift
├── CandidateCell.xib
├── DesireKeyboardView.xib
├── Base.lproj
│ └── Main.storyboard
├── DesireKeyboardView.swift
└── SwiftyJSON.swift
├── README.md
└── DesireKeyboard.xcodeproj
├── xcuserdata
└── tomoya.hirano.xcuserdatad
│ ├── xcdebugger
│ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes
│ ├── xcschememanagement.plist
│ └── DesireKeyboard.xcscheme
├── project.xcworkspace
├── contents.xcworkspacedata
└── xcuserdata
│ └── tomoya.hirano.xcuserdatad
│ └── UserInterfaceState.xcuserstate
└── project.pbxproj
/sample.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/noppefoxwolf/DesireKeyboard/HEAD/sample.gif
--------------------------------------------------------------------------------
/DesireKeyboard/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DesireKeyboard
2 |
3 | ## Awesome keyboard for tvOS.
4 |
5 | 
6 |
7 | inspired to PS4 motion keyboard.
8 |
--------------------------------------------------------------------------------
/DesireKeyboard.xcodeproj/xcuserdata/tomoya.hirano.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/DesireKeyboard/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/DesireKeyboard/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/DesireKeyboard/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/DesireKeyboard/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/DesireKeyboard/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/DesireKeyboard/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/DesireKeyboard.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/DesireKeyboard.xcodeproj/project.xcworkspace/xcuserdata/tomoya.hirano.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/noppefoxwolf/DesireKeyboard/HEAD/DesireKeyboard.xcodeproj/project.xcworkspace/xcuserdata/tomoya.hirano.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/DesireKeyboard/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "scale" : "1x"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/DesireKeyboard/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "scale" : "1x"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/DesireKeyboard/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "scale" : "1x"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/DesireKeyboard/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "scale" : "1x"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/DesireKeyboard/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "scale" : "1x"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/DesireKeyboard/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "scale" : "1x"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/DesireKeyboard/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "scale" : "1x"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/DesireKeyboard/Assets.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "orientation" : "landscape",
5 | "idiom" : "tv",
6 | "extent" : "full-screen",
7 | "minimum-system-version" : "9.0",
8 | "scale" : "1x"
9 | }
10 | ],
11 | "info" : {
12 | "version" : 1,
13 | "author" : "xcode"
14 | }
15 | }
--------------------------------------------------------------------------------
/DesireKeyboard/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "layers" : [
3 | {
4 | "filename" : "Front.imagestacklayer"
5 | },
6 | {
7 | "filename" : "Middle.imagestacklayer"
8 | },
9 | {
10 | "filename" : "Back.imagestacklayer"
11 | }
12 | ],
13 | "info" : {
14 | "version" : 1,
15 | "author" : "xcode"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/DesireKeyboard/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "layers" : [
3 | {
4 | "filename" : "Front.imagestacklayer"
5 | },
6 | {
7 | "filename" : "Middle.imagestacklayer"
8 | },
9 | {
10 | "filename" : "Back.imagestacklayer"
11 | }
12 | ],
13 | "info" : {
14 | "version" : 1,
15 | "author" : "xcode"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/DesireKeyboard.xcodeproj/xcuserdata/tomoya.hirano.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | DesireKeyboard.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | D795D73C1BF4AC8D00E4E68A
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/DesireKeyboard/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "assets" : [
3 | {
4 | "size" : "1280x768",
5 | "idiom" : "tv",
6 | "filename" : "App Icon - Large.imagestack",
7 | "role" : "primary-app-icon"
8 | },
9 | {
10 | "size" : "400x240",
11 | "idiom" : "tv",
12 | "filename" : "App Icon - Small.imagestack",
13 | "role" : "primary-app-icon"
14 | },
15 | {
16 | "size" : "1920x720",
17 | "idiom" : "tv",
18 | "filename" : "Top Shelf Image.imageset",
19 | "role" : "top-shelf-image"
20 | }
21 | ],
22 | "info" : {
23 | "version" : 1,
24 | "author" : "xcode"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/DesireKeyboard/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | arm64
30 |
31 | NSAppTransportSecurity
32 |
33 | NSAllowsArbitraryLoads
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/DesireKeyboard/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // DesireKeyboard
4 | //
5 | // Created by Tomoya Hirano on 2015/11/12.
6 | // Copyright © 2015年 Tomoya Hirano. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import GameKit
11 |
12 | class ViewController: GCEventViewController {
13 |
14 |
15 | @IBOutlet weak var keyboardView: DesireKeyboardView!
16 | @IBOutlet weak var textField: UITextField!
17 | // var controller:GCController?
18 |
19 | override func viewDidLoad() {
20 | super.viewDidLoad()
21 | keyboardView.targetInput = textField
22 |
23 | // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(setupController) name:GCControllerDidConnectNotification object:nil];
24 |
25 | NSNotificationCenter.defaultCenter().addObserver(self, selector: "setupController:", name: GCControllerDidConnectNotification, object: nil)
26 |
27 |
28 | }
29 |
30 | func setupController(notification:NSNotification){
31 | if let controller = GCController.controllers().first?.microGamepad?.controller {
32 | controller.motion?.valueChangedHandler = {(motion) in
33 | print(motion.attitude)
34 | }
35 | // controller.microGamepad?.dpad.xAxis.valueChangedHandler = { (_) in
36 | // print(controller.microGamepad?.dpad.xAxis.value)
37 | // }
38 | // controller.microGamepad?.dpad.yAxis.valueChangedHandler = { (_) in
39 | //
40 | // }
41 | // controller.motion?.valueChangedHandler = {(motion:GCMotion)in
42 | // print(motion.gravity.x)
43 | // }
44 | }
45 | }
46 |
47 |
48 | override func didReceiveMemoryWarning() {
49 | super.didReceiveMemoryWarning()
50 | }
51 |
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/DesireKeyboard/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // DesireKeyboard
4 | //
5 | // Created by Tomoya Hirano on 2015/11/12.
6 | // Copyright © 2015年 Tomoya Hirano. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(application: UIApplication) {
23 | // 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.
24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(application: UIApplication) {
33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(application: UIApplication) {
37 | // 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.
38 | }
39 |
40 | func applicationWillTerminate(application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/DesireKeyboard/CandidateCell.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/DesireKeyboard.xcodeproj/xcuserdata/tomoya.hirano.xcuserdatad/xcschemes/DesireKeyboard.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/DesireKeyboard/DesireKeyboardView.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/DesireKeyboard/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/DesireKeyboard.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | D76C2D241BF4CCEF00AC59EC /* DesireKeyboardView.xib in Resources */ = {isa = PBXBuildFile; fileRef = D76C2D231BF4CCEF00AC59EC /* DesireKeyboardView.xib */; };
11 | D79352051BF4DB4C002197FF /* CandidateCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D79352041BF4DB4C002197FF /* CandidateCell.xib */; };
12 | D79352071BF57C05002197FF /* SwiftyJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = D79352061BF57C05002197FF /* SwiftyJSON.swift */; };
13 | D795D7411BF4AC8D00E4E68A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D795D7401BF4AC8D00E4E68A /* AppDelegate.swift */; };
14 | D795D7431BF4AC8D00E4E68A /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D795D7421BF4AC8D00E4E68A /* ViewController.swift */; };
15 | D795D7461BF4AC8D00E4E68A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D795D7441BF4AC8D00E4E68A /* Main.storyboard */; };
16 | D795D7481BF4AC8D00E4E68A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D795D7471BF4AC8D00E4E68A /* Assets.xcassets */; };
17 | D7EC88691BF4AD21002ECD9D /* DesireKeyboardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EC88681BF4AD21002ECD9D /* DesireKeyboardView.swift */; };
18 | /* End PBXBuildFile section */
19 |
20 | /* Begin PBXFileReference section */
21 | D76C2D231BF4CCEF00AC59EC /* DesireKeyboardView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DesireKeyboardView.xib; sourceTree = ""; };
22 | D79352041BF4DB4C002197FF /* CandidateCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CandidateCell.xib; sourceTree = ""; };
23 | D79352061BF57C05002197FF /* SwiftyJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftyJSON.swift; sourceTree = ""; };
24 | D795D73D1BF4AC8D00E4E68A /* DesireKeyboard.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DesireKeyboard.app; sourceTree = BUILT_PRODUCTS_DIR; };
25 | D795D7401BF4AC8D00E4E68A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
26 | D795D7421BF4AC8D00E4E68A /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
27 | D795D7451BF4AC8D00E4E68A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
28 | D795D7471BF4AC8D00E4E68A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
29 | D795D7491BF4AC8D00E4E68A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
30 | D7EC88681BF4AD21002ECD9D /* DesireKeyboardView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DesireKeyboardView.swift; sourceTree = ""; };
31 | /* End PBXFileReference section */
32 |
33 | /* Begin PBXFrameworksBuildPhase section */
34 | D795D73A1BF4AC8D00E4E68A /* Frameworks */ = {
35 | isa = PBXFrameworksBuildPhase;
36 | buildActionMask = 2147483647;
37 | files = (
38 | );
39 | runOnlyForDeploymentPostprocessing = 0;
40 | };
41 | /* End PBXFrameworksBuildPhase section */
42 |
43 | /* Begin PBXGroup section */
44 | D795D7341BF4AC8D00E4E68A = {
45 | isa = PBXGroup;
46 | children = (
47 | D795D73F1BF4AC8D00E4E68A /* DesireKeyboard */,
48 | D795D73E1BF4AC8D00E4E68A /* Products */,
49 | );
50 | sourceTree = "";
51 | };
52 | D795D73E1BF4AC8D00E4E68A /* Products */ = {
53 | isa = PBXGroup;
54 | children = (
55 | D795D73D1BF4AC8D00E4E68A /* DesireKeyboard.app */,
56 | );
57 | name = Products;
58 | sourceTree = "";
59 | };
60 | D795D73F1BF4AC8D00E4E68A /* DesireKeyboard */ = {
61 | isa = PBXGroup;
62 | children = (
63 | D7EC88671BF4AD0E002ECD9D /* Lib */,
64 | D795D7401BF4AC8D00E4E68A /* AppDelegate.swift */,
65 | D795D7421BF4AC8D00E4E68A /* ViewController.swift */,
66 | D795D7441BF4AC8D00E4E68A /* Main.storyboard */,
67 | D795D7471BF4AC8D00E4E68A /* Assets.xcassets */,
68 | D795D7491BF4AC8D00E4E68A /* Info.plist */,
69 | );
70 | path = DesireKeyboard;
71 | sourceTree = "";
72 | };
73 | D7EC88671BF4AD0E002ECD9D /* Lib */ = {
74 | isa = PBXGroup;
75 | children = (
76 | D79352061BF57C05002197FF /* SwiftyJSON.swift */,
77 | D7EC88681BF4AD21002ECD9D /* DesireKeyboardView.swift */,
78 | D76C2D231BF4CCEF00AC59EC /* DesireKeyboardView.xib */,
79 | D79352041BF4DB4C002197FF /* CandidateCell.xib */,
80 | );
81 | name = Lib;
82 | sourceTree = "";
83 | };
84 | /* End PBXGroup section */
85 |
86 | /* Begin PBXNativeTarget section */
87 | D795D73C1BF4AC8D00E4E68A /* DesireKeyboard */ = {
88 | isa = PBXNativeTarget;
89 | buildConfigurationList = D795D74C1BF4AC8D00E4E68A /* Build configuration list for PBXNativeTarget "DesireKeyboard" */;
90 | buildPhases = (
91 | D795D7391BF4AC8D00E4E68A /* Sources */,
92 | D795D73A1BF4AC8D00E4E68A /* Frameworks */,
93 | D795D73B1BF4AC8D00E4E68A /* Resources */,
94 | );
95 | buildRules = (
96 | );
97 | dependencies = (
98 | );
99 | name = DesireKeyboard;
100 | productName = DesireKeyboard;
101 | productReference = D795D73D1BF4AC8D00E4E68A /* DesireKeyboard.app */;
102 | productType = "com.apple.product-type.application";
103 | };
104 | /* End PBXNativeTarget section */
105 |
106 | /* Begin PBXProject section */
107 | D795D7351BF4AC8D00E4E68A /* Project object */ = {
108 | isa = PBXProject;
109 | attributes = {
110 | LastSwiftUpdateCheck = 0710;
111 | LastUpgradeCheck = 0710;
112 | ORGANIZATIONNAME = "Tomoya Hirano";
113 | TargetAttributes = {
114 | D795D73C1BF4AC8D00E4E68A = {
115 | CreatedOnToolsVersion = 7.1;
116 | };
117 | };
118 | };
119 | buildConfigurationList = D795D7381BF4AC8D00E4E68A /* Build configuration list for PBXProject "DesireKeyboard" */;
120 | compatibilityVersion = "Xcode 3.2";
121 | developmentRegion = English;
122 | hasScannedForEncodings = 0;
123 | knownRegions = (
124 | en,
125 | Base,
126 | );
127 | mainGroup = D795D7341BF4AC8D00E4E68A;
128 | productRefGroup = D795D73E1BF4AC8D00E4E68A /* Products */;
129 | projectDirPath = "";
130 | projectRoot = "";
131 | targets = (
132 | D795D73C1BF4AC8D00E4E68A /* DesireKeyboard */,
133 | );
134 | };
135 | /* End PBXProject section */
136 |
137 | /* Begin PBXResourcesBuildPhase section */
138 | D795D73B1BF4AC8D00E4E68A /* Resources */ = {
139 | isa = PBXResourcesBuildPhase;
140 | buildActionMask = 2147483647;
141 | files = (
142 | D795D7481BF4AC8D00E4E68A /* Assets.xcassets in Resources */,
143 | D795D7461BF4AC8D00E4E68A /* Main.storyboard in Resources */,
144 | D76C2D241BF4CCEF00AC59EC /* DesireKeyboardView.xib in Resources */,
145 | D79352051BF4DB4C002197FF /* CandidateCell.xib in Resources */,
146 | );
147 | runOnlyForDeploymentPostprocessing = 0;
148 | };
149 | /* End PBXResourcesBuildPhase section */
150 |
151 | /* Begin PBXSourcesBuildPhase section */
152 | D795D7391BF4AC8D00E4E68A /* Sources */ = {
153 | isa = PBXSourcesBuildPhase;
154 | buildActionMask = 2147483647;
155 | files = (
156 | D795D7431BF4AC8D00E4E68A /* ViewController.swift in Sources */,
157 | D7EC88691BF4AD21002ECD9D /* DesireKeyboardView.swift in Sources */,
158 | D795D7411BF4AC8D00E4E68A /* AppDelegate.swift in Sources */,
159 | D79352071BF57C05002197FF /* SwiftyJSON.swift in Sources */,
160 | );
161 | runOnlyForDeploymentPostprocessing = 0;
162 | };
163 | /* End PBXSourcesBuildPhase section */
164 |
165 | /* Begin PBXVariantGroup section */
166 | D795D7441BF4AC8D00E4E68A /* Main.storyboard */ = {
167 | isa = PBXVariantGroup;
168 | children = (
169 | D795D7451BF4AC8D00E4E68A /* Base */,
170 | );
171 | name = Main.storyboard;
172 | sourceTree = "";
173 | };
174 | /* End PBXVariantGroup section */
175 |
176 | /* Begin XCBuildConfiguration section */
177 | D795D74A1BF4AC8D00E4E68A /* Debug */ = {
178 | isa = XCBuildConfiguration;
179 | buildSettings = {
180 | ALWAYS_SEARCH_USER_PATHS = NO;
181 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
182 | CLANG_CXX_LIBRARY = "libc++";
183 | CLANG_ENABLE_MODULES = YES;
184 | CLANG_ENABLE_OBJC_ARC = YES;
185 | CLANG_WARN_BOOL_CONVERSION = YES;
186 | CLANG_WARN_CONSTANT_CONVERSION = YES;
187 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
188 | CLANG_WARN_EMPTY_BODY = YES;
189 | CLANG_WARN_ENUM_CONVERSION = YES;
190 | CLANG_WARN_INT_CONVERSION = YES;
191 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
192 | CLANG_WARN_UNREACHABLE_CODE = YES;
193 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
194 | COPY_PHASE_STRIP = NO;
195 | DEBUG_INFORMATION_FORMAT = dwarf;
196 | ENABLE_STRICT_OBJC_MSGSEND = YES;
197 | ENABLE_TESTABILITY = YES;
198 | GCC_C_LANGUAGE_STANDARD = gnu99;
199 | GCC_DYNAMIC_NO_PIC = NO;
200 | GCC_NO_COMMON_BLOCKS = YES;
201 | GCC_OPTIMIZATION_LEVEL = 0;
202 | GCC_PREPROCESSOR_DEFINITIONS = (
203 | "DEBUG=1",
204 | "$(inherited)",
205 | );
206 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
207 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
208 | GCC_WARN_UNDECLARED_SELECTOR = YES;
209 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
210 | GCC_WARN_UNUSED_FUNCTION = YES;
211 | GCC_WARN_UNUSED_VARIABLE = YES;
212 | MTL_ENABLE_DEBUG_INFO = YES;
213 | ONLY_ACTIVE_ARCH = YES;
214 | SDKROOT = appletvos;
215 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
216 | TARGETED_DEVICE_FAMILY = 3;
217 | TVOS_DEPLOYMENT_TARGET = 9.0;
218 | };
219 | name = Debug;
220 | };
221 | D795D74B1BF4AC8D00E4E68A /* Release */ = {
222 | isa = XCBuildConfiguration;
223 | buildSettings = {
224 | ALWAYS_SEARCH_USER_PATHS = NO;
225 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
226 | CLANG_CXX_LIBRARY = "libc++";
227 | CLANG_ENABLE_MODULES = YES;
228 | CLANG_ENABLE_OBJC_ARC = YES;
229 | CLANG_WARN_BOOL_CONVERSION = YES;
230 | CLANG_WARN_CONSTANT_CONVERSION = YES;
231 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
232 | CLANG_WARN_EMPTY_BODY = YES;
233 | CLANG_WARN_ENUM_CONVERSION = YES;
234 | CLANG_WARN_INT_CONVERSION = YES;
235 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
236 | CLANG_WARN_UNREACHABLE_CODE = YES;
237 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
238 | COPY_PHASE_STRIP = NO;
239 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
240 | ENABLE_NS_ASSERTIONS = NO;
241 | ENABLE_STRICT_OBJC_MSGSEND = YES;
242 | GCC_C_LANGUAGE_STANDARD = gnu99;
243 | GCC_NO_COMMON_BLOCKS = YES;
244 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
245 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
246 | GCC_WARN_UNDECLARED_SELECTOR = YES;
247 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
248 | GCC_WARN_UNUSED_FUNCTION = YES;
249 | GCC_WARN_UNUSED_VARIABLE = YES;
250 | MTL_ENABLE_DEBUG_INFO = NO;
251 | SDKROOT = appletvos;
252 | TARGETED_DEVICE_FAMILY = 3;
253 | TVOS_DEPLOYMENT_TARGET = 9.0;
254 | VALIDATE_PRODUCT = YES;
255 | };
256 | name = Release;
257 | };
258 | D795D74D1BF4AC8D00E4E68A /* Debug */ = {
259 | isa = XCBuildConfiguration;
260 | buildSettings = {
261 | ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
262 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
263 | INFOPLIST_FILE = DesireKeyboard/Info.plist;
264 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
265 | PRODUCT_BUNDLE_IDENTIFIER = com.noppe.DesireKeyboard;
266 | PRODUCT_NAME = "$(TARGET_NAME)";
267 | };
268 | name = Debug;
269 | };
270 | D795D74E1BF4AC8D00E4E68A /* Release */ = {
271 | isa = XCBuildConfiguration;
272 | buildSettings = {
273 | ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
274 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
275 | INFOPLIST_FILE = DesireKeyboard/Info.plist;
276 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
277 | PRODUCT_BUNDLE_IDENTIFIER = com.noppe.DesireKeyboard;
278 | PRODUCT_NAME = "$(TARGET_NAME)";
279 | };
280 | name = Release;
281 | };
282 | /* End XCBuildConfiguration section */
283 |
284 | /* Begin XCConfigurationList section */
285 | D795D7381BF4AC8D00E4E68A /* Build configuration list for PBXProject "DesireKeyboard" */ = {
286 | isa = XCConfigurationList;
287 | buildConfigurations = (
288 | D795D74A1BF4AC8D00E4E68A /* Debug */,
289 | D795D74B1BF4AC8D00E4E68A /* Release */,
290 | );
291 | defaultConfigurationIsVisible = 0;
292 | defaultConfigurationName = Release;
293 | };
294 | D795D74C1BF4AC8D00E4E68A /* Build configuration list for PBXNativeTarget "DesireKeyboard" */ = {
295 | isa = XCConfigurationList;
296 | buildConfigurations = (
297 | D795D74D1BF4AC8D00E4E68A /* Debug */,
298 | D795D74E1BF4AC8D00E4E68A /* Release */,
299 | );
300 | defaultConfigurationIsVisible = 0;
301 | defaultConfigurationName = Release;
302 | };
303 | /* End XCConfigurationList section */
304 | };
305 | rootObject = D795D7351BF4AC8D00E4E68A /* Project object */;
306 | }
307 |
--------------------------------------------------------------------------------
/DesireKeyboard/DesireKeyboardView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DesireKeyboardView.swift
3 | // DesireKeyboard
4 | //
5 | // Created by Tomoya Hirano on 2015/11/12.
6 | // Copyright © 2015年 Tomoya Hirano. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | protocol DesireKeyboardKeysViewDelegate{
18 | func didSelectWord(word:String)
19 | func didPressDeleteKey()
20 | func didPressEnterKey()
21 | func didPressSpaceKey()
22 | }
23 |
24 | class PointerView:UIView {
25 | override init(frame: CGRect) {
26 | super.init(frame: frame)
27 | backgroundColor = UIColor(red:0.58, green:0.82, blue:0.86, alpha:0.5)
28 | layer.cornerRadius = frame.width/2
29 | layer.borderWidth = 2
30 | layer.borderColor = UIColor(red:0.58, green:0.82, blue:0.86, alpha:1).CGColor
31 | }
32 |
33 | required init?(coder aDecoder: NSCoder) {
34 | fatalError("init(coder:) has not been implemented")
35 | }
36 | }
37 |
38 | class DesireKeyboardView: UIView,UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout,DesireKeyboardKeysViewDelegate {
39 |
40 | @IBOutlet weak var collectionView: UICollectionView!
41 | @IBOutlet weak var keysView: DesireKeyboardKeysView!
42 |
43 | var targetInput:UITextField?
44 | var pointerView = PointerView()
45 |
46 | required init?(coder aDecoder: NSCoder) {
47 | super.init(coder: aDecoder)
48 | customViewCommonInit()
49 | }
50 |
51 | override init(frame: CGRect) {
52 | super.init(frame: frame)
53 | }
54 |
55 | var replace_words:[String:String] = [
56 | "あ":"ぁ","い":"ぃ","う":"ぅ","え":"ぇ","お":"ぉ",
57 | "や":"ゃ","ゆ":"ゅ","よ":"ょ","わ":"ゎ",
58 | "か":"が","き":"ぎ","く":"ぐ","け":"げ","こ":"ご",
59 | "さ":"ざ","し":"じ","す":"ず","せ":"ぜ","そ":"ぞ",
60 | "た":"だ","ち":"ぢ","つ":"づ","て":"で","と":"ど",
61 | "ば":"ぱ","び":"ぴ","ぶ":"ぷ","べ":"ぺ","ぼ":"ぽ",
62 | "は":"ば","ひ":"び","ふ":"ぶ","へ":"べ","ほ":"ぼ",
63 | ]
64 |
65 | var reverse_words:[String:String] = [
66 | "ぁ":"あ","ぃ":"い","ぅ":"う","ぇ":"え","ぉ":"お",
67 | "ゃ":"や","ゅ":"ゆ","ょ":"よ","ゎ":"わ",
68 | "が":"か","ぎ":"き","ぐ":"く","げ":"け","ご":"こ",
69 | "ざ":"さ","じ":"し","ず":"す","ぜ":"せ","ぞ":"そ",
70 | "だ":"た","ぢ":"ち","づ":"つ","で":"て","ど":"と",
71 | "ぱ":"は","ぴ":"ひ","ぷ":"ふ","ぺ":"へ","ぽ":"ほ",
72 | "ば":"は","び":"ひ","ぶ":"ふ","べ":"へ","ぼ":"ほ",
73 | ]
74 |
75 | func customViewCommonInit(){
76 | let view = NSBundle.mainBundle().loadNibNamed("DesireKeyboardView", owner: self, options: nil).first as! UIView
77 | view.frame = self.bounds
78 | view.translatesAutoresizingMaskIntoConstraints = true
79 | view.autoresizingMask = [.FlexibleWidth,.FlexibleHeight]
80 | view.backgroundColor = UIColor(red:0.08, green:0.08, blue:0.11, alpha:1)
81 | self.addSubview(view)
82 |
83 | let cellNib = UINib(nibName: "CandidateCell", bundle: nil)
84 | collectionView.registerNib(cellNib, forCellWithReuseIdentifier: "cell")
85 | collectionView.delegate = self
86 | collectionView.dataSource = self
87 |
88 |
89 | layer.cornerRadius = 6
90 | layer.masksToBounds = true
91 | layer.borderColor = UIColor.darkGrayColor().CGColor
92 | layer.borderWidth = 2
93 |
94 | keysView.delegate = self
95 |
96 | pointerView = PointerView(frame:CGRectMake(0,0,bounds.width/12,bounds.width/12))
97 | pointerView.hidden = true
98 | addSubview(pointerView)
99 | }
100 |
101 | var candidats:JSON?
102 |
103 | func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
104 | let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! CandidateCell
105 | cell.textLabel.text = candidats![0][1][indexPath.row].string
106 | return cell
107 | }
108 |
109 | func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
110 | return 1
111 | }
112 |
113 | func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
114 | return candidats?[0][1].count ?? 0
115 | }
116 |
117 | func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
118 | collectionView.deselectItemAtIndexPath(indexPath, animated: false)
119 | let targetString = candidats![0][0].string
120 | let replaceString = candidats![0][1][indexPath.row].string
121 | targetInput?.text = targetInput?.text!.stringByReplacingOccurrencesOfString(targetString!
122 | , withString: replaceString!)
123 | inputWord = ""
124 | candidats = nil
125 | collectionView.reloadData()
126 | }
127 |
128 | var inputWord:String = ""
129 | func didSelectWord(word: String) {
130 | if word == "、。" {
131 | if inputWord.characters.last == "、"{
132 | inputWord = inputWord.chopSuffix()
133 | targetInput?.text = targetInput?.text!.chopSuffix()
134 | inputWord += "。"
135 | targetInput?.text = (targetInput?.text)! + "。"
136 | }else if inputWord.characters.last == "。"{
137 | inputWord = inputWord.chopSuffix()
138 | targetInput?.text = targetInput?.text!.chopSuffix()
139 | inputWord += "、"
140 | targetInput?.text = (targetInput?.text)! + "、"
141 | }else{
142 | inputWord += "、"
143 | targetInput?.text = (targetInput?.text)! + "、"
144 | }
145 | }else if word == "小゛゜" {
146 | if let lastWord = inputWord.characters.last {
147 | if let c = replace_words["\(lastWord)"] {
148 | inputWord = inputWord.chopSuffix()
149 | inputWord += c
150 | targetInput?.text = targetInput?.text!.chopSuffix()
151 | targetInput?.text = (targetInput?.text)! + c
152 | }else if let c = reverse_words["\(lastWord)"]{
153 | inputWord = inputWord.chopSuffix()
154 | inputWord += c
155 | targetInput?.text = targetInput?.text!.chopSuffix()
156 | targetInput?.text = (targetInput?.text)! + c
157 | }
158 | }
159 | }else if word == "?!" {
160 | if inputWord.characters.last == "?"{
161 | inputWord = inputWord.chopSuffix()
162 | targetInput?.text = targetInput?.text!.chopSuffix()
163 | inputWord += "!"
164 | targetInput?.text = (targetInput?.text)! + "!"
165 | }else if inputWord.characters.last == "!"{
166 | inputWord = inputWord.chopSuffix()
167 | targetInput?.text = targetInput?.text!.chopSuffix()
168 | inputWord += "?"
169 | targetInput?.text = (targetInput?.text)! + "?"
170 | }else{
171 | inputWord += "?"
172 | targetInput?.text = (targetInput?.text)! + "?"
173 | }
174 | }else{
175 | inputWord += word
176 | targetInput?.text = (targetInput?.text)! + word
177 | getCandidate(inputWord)
178 | }
179 | }
180 | func didPressDeleteKey() {
181 | inputWord = inputWord.chopSuffix()
182 | targetInput?.text = targetInput?.text?.chopSuffix()
183 | getCandidate(inputWord)
184 | }
185 | func didPressEnterKey() {
186 | candidats = nil
187 | inputWord = ""
188 | self.collectionView.reloadData()
189 | }
190 | func didPressSpaceKey() {
191 | targetInput?.text = (targetInput?.text)! + " "
192 | }
193 |
194 | func getCandidate(words:String){
195 | let urlString = "http://www.google.com/transliterate?"
196 | let params:[String:String] = ["langpair":"ja-Hira|ja","text":words]
197 | let url = NSURL(string: urlString + params.urlEncodedQueryStringWithEncoding)
198 | let config = NSURLSessionConfiguration.defaultSessionConfiguration()
199 | let session = NSURLSession(configuration: config)
200 | let req = NSMutableURLRequest(URL: url!)
201 | let task = session.dataTaskWithRequest(req, completionHandler: {
202 | (data, resp, err) in
203 | self.candidats = JSON(data: data!)
204 | dispatch_async(dispatch_get_main_queue(), { () -> Void in
205 | self.collectionView.reloadData()
206 | })
207 | })
208 | task.resume()
209 | }
210 |
211 | override func touchesBegan(touches: Set, withEvent event: UIEvent?) {
212 | super.touchesBegan(touches, withEvent: event)
213 | pointerView.hidden = false
214 | pointerView.center = CGPointMake(bounds.width/2, bounds.height/2)
215 | }
216 |
217 | override func touchesEnded(touches: Set, withEvent event: UIEvent?) {
218 | super.touchesEnded(touches, withEvent: event)
219 | pointerView.hidden = true
220 | keysView.deselectAllButtons()
221 | }
222 |
223 | override func touchesMoved(touches: Set, withEvent event: UIEvent?) {
224 | super.touchesMoved(touches, withEvent: event)
225 | keysView.deselectAllButtons()
226 | let pos = touches.first?.locationInView(self)
227 | pointerView.center = pos!
228 | let v = keysView.hitTest(keysView.convertPoint(pos!, fromView: self), withEvent: nil)
229 | if let button = v as? KeyButton {
230 | button.hilight = true
231 | }
232 |
233 | (collectionView.visibleCells() as! [CandidateCell]).map({$0.hilight = false})
234 | if let index = collectionView.indexPathForItemAtPoint(collectionView.convertPoint(pos!, fromView: self)) {
235 | if let cell = collectionView.cellForItemAtIndexPath(index) as? CandidateCell {
236 | cell.hilight = true
237 | }
238 | }
239 | }
240 |
241 | override func pressesBegan(presses: Set, withEvent event: UIPressesEvent?) {
242 | super.pressesBegan(presses, withEvent: event)
243 | if presses.first?.type == UIPressType.Select {
244 | let v = keysView.hitTest(keysView.convertPoint(pointerView.center, fromView: self), withEvent: nil)
245 | if let button = v as? KeyButton {
246 | button.selectAction()
247 | }
248 | if let index = collectionView.indexPathForItemAtPoint(collectionView.convertPoint(pointerView.center, fromView: self)) {
249 | collectionView.delegate?.collectionView!(collectionView, didSelectItemAtIndexPath: index)
250 | }
251 | }
252 | }
253 |
254 | override func canBecomeFocused() -> Bool {
255 | return true
256 | }
257 |
258 | func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
259 | return CGSizeMake(collectionView.bounds.width/7, collectionView.bounds.height - 20)
260 | }
261 | }
262 |
263 | extension String {
264 | // URLエンコード
265 | var urlEncodedStringWithEncoding:String{
266 | let charactersToBeEscaped = ":/?&=;+!@#$()',*" as CFStringRef
267 | let charactersToLeaveUnescaped = "[]." as CFStringRef
268 |
269 | let raw = self
270 |
271 | let result = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, raw, charactersToLeaveUnescaped, charactersToBeEscaped, CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding)) as NSString
272 |
273 | return result as String
274 | }
275 |
276 | func chopSuffix(count: Int = 1) -> String {
277 | if self.characters.count == 0 {
278 | return self
279 | }
280 | return self.substringToIndex(self.endIndex.advancedBy(-count))
281 | }
282 | }
283 |
284 |
285 | extension Dictionary {
286 | // Dictionary内のデータをエンコード
287 | var urlEncodedQueryStringWithEncoding:String{
288 | var parts = [String]()
289 | for (key, value) in self {
290 | let keyString = (key as! String).urlEncodedStringWithEncoding
291 | let valueString = (value as! String).urlEncodedStringWithEncoding
292 | let query = "\(keyString)=\(valueString)" as String
293 | parts.append(query)
294 | }
295 | return parts.joinWithSeparator("&") as String
296 | }
297 | }
298 |
299 |
300 |
301 | class DesireKeyboardKeysView: UIView {
302 | required init?(coder aDecoder: NSCoder) {
303 | super.init(coder: aDecoder)
304 | userInteractionEnabled = true
305 | backgroundColor = UIColor.clearColor()
306 | setupKeys()
307 | }
308 |
309 | var delegate:DesireKeyboardKeysViewDelegate? = nil
310 |
311 | override init(frame: CGRect) {
312 | super.init(frame: frame)
313 | }
314 |
315 | override func layoutSubviews() {
316 | super.layoutSubviews()
317 | layoutKeyButtons()
318 | }
319 |
320 | var words = [
321 | ["あ","い","う","え","お"],
322 | ["か","き","く","け","こ"],
323 | ["さ","し","す","せ","そ"],
324 | ["た","ち","つ","て","と"],
325 | ["な","に","ぬ","ね","の"],
326 | ["は","ひ","ふ","へ","ほ"],
327 | ["ま","み","む","め","も"],
328 | ["や","ゆ","よ","、。","?!"],
329 | ["ら","り","る","れ","ろ"],
330 | ["わ","を","ん","ー","小゛゜"]
331 | ]
332 |
333 |
334 | var keyButtons:[[KeyButton]] = [[]]
335 | let space = KeyButton(frame: CGRectZero)
336 | let delete = KeyButton(frame: CGRectZero)
337 | let enter = KeyButton(frame: CGRectZero)
338 |
339 | func setupKeys(){
340 | for (_, column) in words.enumerate() {
341 | var keyColumn:[KeyButton] = []
342 | for (_, word) in column.enumerate() {
343 | let key = KeyButton(frame: CGRectZero)
344 | key.text = word
345 | addSubview(key)
346 | keyColumn.append(key)
347 | }
348 | keyButtons.append(keyColumn)
349 | }
350 | space.text = "スペース"
351 | space.selectedAction = {(_) in
352 | self.delegate?.didPressSpaceKey()
353 | }
354 | addSubview(space)
355 | delete.text = "⇐"
356 | delete.selectedAction = {(_) in
357 | self.delegate?.didPressDeleteKey()
358 | }
359 | addSubview(delete)
360 | enter.text = "確定"
361 | enter.selectedAction = {(_) in
362 | self.delegate?.didPressEnterKey()
363 | }
364 | addSubview(enter)
365 | }
366 |
367 | func deselectAllButtons(){
368 | for column in keyButtons {
369 | for key in column {
370 | key.hilight = false
371 | }
372 | }
373 | space.hilight = false
374 | delete.hilight = false
375 | enter.hilight = false
376 | }
377 |
378 | func layoutKeyButtons(){
379 | let keyWidth:CGFloat = bounds.width/10.0 - 2
380 | let keyHeight:CGFloat = bounds.height/7.0 - 2
381 | for (i,column) in keyButtons.enumerate() {
382 | for (j,button) in column.enumerate() {
383 | button.frame = CGRectMake(bounds.width - CGFloat(i)*(keyWidth+2), CGFloat(j)*(keyHeight+2), keyWidth, keyHeight)
384 | button.selectedAction = { (word) in
385 | self.delegate?.didSelectWord(word!)
386 | }
387 | }
388 | }
389 | space.frame = CGRectMake((keyWidth+2)*3, (keyHeight+2)*5, keyWidth*4, keyHeight)
390 | delete.frame = CGRectMake((keyWidth+2)*8, (keyHeight+2)*5, keyWidth*2, keyHeight)
391 | enter.frame = CGRectMake((keyWidth+2)*8, (keyHeight+2)*6, keyWidth*2, keyHeight)
392 | }
393 | }
394 |
395 | class CandidateCell: UICollectionViewCell {
396 | @IBOutlet weak var textLabel: UILabel!
397 |
398 | var hilight:Bool = false{
399 | didSet{
400 | if hilight {
401 | self.backgroundColor = UIColor.darkGrayColor()
402 | }else{
403 | self.backgroundColor = UIColor.clearColor()
404 | }
405 | }
406 | }
407 |
408 | override init(frame: CGRect){
409 | super.init(frame: frame)
410 | }
411 | required init?(coder aDecoder: NSCoder){
412 | super.init(coder: aDecoder)
413 | backgroundColor = UIColor.clearColor()
414 | }
415 |
416 | override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {
417 | super.didUpdateFocusInContext(context, withAnimationCoordinator: coordinator)
418 | if self.focused {
419 | self.backgroundColor = UIColor.darkGrayColor()
420 | }else{
421 | self.backgroundColor = UIColor.clearColor()
422 | }
423 | }
424 | }
425 |
426 | class KeyButton: UILabel {
427 |
428 | var unfocusBorderColor = UIColor(red:0.19, green:0.2, blue:0.22, alpha:1).CGColor
429 | var focusBorderColor = UIColor(red:0.58, green:0.82, blue:0.86, alpha:1).CGColor
430 | var hilight:Bool = false{
431 | didSet{
432 | if hilight {
433 | self.layer.borderColor = focusBorderColor
434 | }else{
435 | self.layer.borderColor = unfocusBorderColor
436 | }
437 | }
438 | }
439 |
440 | override init(frame: CGRect) {
441 | super.init(frame: frame)
442 | userInteractionEnabled = true
443 | backgroundColor = UIColor(red:0.14, green:0.14, blue:0.14, alpha:1)
444 | layer.cornerRadius = 6
445 | layer.borderColor = unfocusBorderColor
446 | layer.borderWidth = 4
447 | layer.masksToBounds = true
448 | textColor = UIColor.whiteColor()
449 | font = UIFont.boldSystemFontOfSize(24)
450 | textAlignment = .Center
451 | }
452 |
453 | var selectedAction:((word:String?) -> Void)?
454 |
455 | required init?(coder aDecoder: NSCoder) {
456 | fatalError("init(coder:) has not been implemented")
457 | }
458 |
459 | override func canBecomeFocused() -> Bool {
460 | return false
461 | }
462 |
463 | override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {
464 | super.didUpdateFocusInContext(context, withAnimationCoordinator: coordinator)
465 | if self.focused {
466 | self.layer.borderColor = focusBorderColor
467 | }else{
468 | self.layer.borderColor = unfocusBorderColor
469 | }
470 | }
471 |
472 | override func pressesBegan(presses: Set, withEvent event: UIPressesEvent?) {
473 | super.pressesBegan(presses, withEvent: event)
474 | if presses.first?.type == UIPressType.Select {
475 | selectedAction?(word: text)
476 | }
477 | }
478 |
479 | func selectAction(){
480 | selectedAction?(word: text)
481 | }
482 | }
483 |
484 |
--------------------------------------------------------------------------------
/DesireKeyboard/SwiftyJSON.swift:
--------------------------------------------------------------------------------
1 | // SwiftyJSON.swift
2 | //
3 | // Copyright (c) 2014 Ruoyu Fu, Pinglin Tang
4 | //
5 | // Permission is hereby granted, free of charge, to any person obtaining a copy
6 | // of this software and associated documentation files (the "Software"), to deal
7 | // in the Software without restriction, including without limitation the rights
8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | // copies of the Software, and to permit persons to whom the Software is
10 | // furnished to do so, subject to the following conditions:
11 | //
12 | // The above copyright notice and this permission notice shall be included in
13 | // all copies or substantial portions of the Software.
14 | //
15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | // THE SOFTWARE.
22 |
23 | import Foundation
24 |
25 | // MARK: - Error
26 |
27 | ///Error domain
28 | public let ErrorDomain: String! = "SwiftyJSONErrorDomain"
29 |
30 | ///Error code
31 | public let ErrorUnsupportedType: Int! = 999
32 | public let ErrorIndexOutOfBounds: Int! = 900
33 | public let ErrorWrongType: Int! = 901
34 | public let ErrorNotExist: Int! = 500
35 | public let ErrorInvalidJSON: Int! = 490
36 |
37 | // MARK: - JSON Type
38 |
39 | /**
40 | JSON's type definitions.
41 |
42 | See http://tools.ietf.org/html/rfc7231#section-4.3
43 | */
44 | public enum Type :Int{
45 |
46 | case Number
47 | case String
48 | case Bool
49 | case Array
50 | case Dictionary
51 | case Null
52 | case Unknown
53 | }
54 |
55 | // MARK: - JSON Base
56 |
57 | public struct JSON {
58 |
59 | /**
60 | Creates a JSON using the data.
61 |
62 | - parameter data: The NSData used to convert to json.Top level object in data is an NSArray or NSDictionary
63 | - parameter opt: The JSON serialization reading options. `.AllowFragments` by default.
64 | - parameter error: error The NSErrorPointer used to return the error. `nil` by default.
65 |
66 | - returns: The created JSON
67 | */
68 | public init(data:NSData, options opt: NSJSONReadingOptions = .AllowFragments, error: NSErrorPointer = nil) {
69 | do {
70 | let object: AnyObject = try NSJSONSerialization.JSONObjectWithData(data, options: opt)
71 | self.init(object)
72 | } catch let aError as NSError {
73 | if error != nil {
74 | error.memory = aError
75 | }
76 | self.init(NSNull())
77 | }
78 | }
79 |
80 | /**
81 | Creates a JSON using the object.
82 |
83 | - parameter object: The object must have the following properties: All objects are NSString/String, NSNumber/Int/Float/Double/Bool, NSArray/Array, NSDictionary/Dictionary, or NSNull; All dictionary keys are NSStrings/String; NSNumbers are not NaN or infinity.
84 |
85 | - returns: The created JSON
86 | */
87 | public init(_ object: AnyObject) {
88 | self.object = object
89 | }
90 |
91 | /**
92 | Creates a JSON from a [JSON]
93 |
94 | - parameter jsonArray: A Swift array of JSON objects
95 |
96 | - returns: The created JSON
97 | */
98 | public init(_ jsonArray:[JSON]) {
99 | self.init(jsonArray.map { $0.object })
100 | }
101 |
102 | /**
103 | Creates a JSON from a [String: JSON]
104 |
105 | - parameter jsonDictionary: A Swift dictionary of JSON objects
106 |
107 | - returns: The created JSON
108 | */
109 | public init(_ jsonDictionary:[String: JSON]) {
110 | var dictionary = [String: AnyObject]()
111 | for (key, json) in jsonDictionary {
112 | dictionary[key] = json.object
113 | }
114 | self.init(dictionary)
115 | }
116 |
117 | /// Private object
118 | private var rawArray: [AnyObject] = []
119 | private var rawDictionary: [String : AnyObject] = [:]
120 | private var rawString: String = ""
121 | private var rawNumber: NSNumber = 0
122 | private var rawNull: NSNull = NSNull()
123 | /// Private type
124 | private var _type: Type = .Null
125 | /// prviate error
126 | private var _error: NSError? = nil
127 |
128 | /// Object in JSON
129 | public var object: AnyObject {
130 | get {
131 | switch self.type {
132 | case .Array:
133 | return self.rawArray
134 | case .Dictionary:
135 | return self.rawDictionary
136 | case .String:
137 | return self.rawString
138 | case .Number:
139 | return self.rawNumber
140 | case .Bool:
141 | return self.rawNumber
142 | default:
143 | return self.rawNull
144 | }
145 | }
146 | set {
147 | _error = nil
148 | switch newValue {
149 | case let number as NSNumber:
150 | if number.isBool {
151 | _type = .Bool
152 | } else {
153 | _type = .Number
154 | }
155 | self.rawNumber = number
156 | case let string as String:
157 | _type = .String
158 | self.rawString = string
159 | case _ as NSNull:
160 | _type = .Null
161 | case let array as [AnyObject]:
162 | _type = .Array
163 | self.rawArray = array
164 | case let dictionary as [String : AnyObject]:
165 | _type = .Dictionary
166 | self.rawDictionary = dictionary
167 | default:
168 | _type = .Unknown
169 | _error = NSError(domain: ErrorDomain, code: ErrorUnsupportedType, userInfo: [NSLocalizedDescriptionKey: "It is a unsupported type"])
170 | }
171 | }
172 | }
173 |
174 | /// json type
175 | public var type: Type { get { return _type } }
176 |
177 | /// Error in JSON
178 | public var error: NSError? { get { return self._error } }
179 |
180 | /// The static null json
181 | @available(*, unavailable, renamed="null")
182 | public static var nullJSON: JSON { get { return null } }
183 | public static var null: JSON { get { return JSON(NSNull()) } }
184 | }
185 |
186 | // MARK: - CollectionType, SequenceType, Indexable
187 | extension JSON : Swift.CollectionType, Swift.SequenceType, Swift.Indexable {
188 |
189 | public typealias Generator = JSONGenerator
190 |
191 | public typealias Index = JSONIndex
192 |
193 | public var startIndex: JSON.Index {
194 | switch self.type {
195 | case .Array:
196 | return JSONIndex(arrayIndex: self.rawArray.startIndex)
197 | case .Dictionary:
198 | return JSONIndex(dictionaryIndex: self.rawDictionary.startIndex)
199 | default:
200 | return JSONIndex()
201 | }
202 | }
203 |
204 | public var endIndex: JSON.Index {
205 | switch self.type {
206 | case .Array:
207 | return JSONIndex(arrayIndex: self.rawArray.endIndex)
208 | case .Dictionary:
209 | return JSONIndex(dictionaryIndex: self.rawDictionary.endIndex)
210 | default:
211 | return JSONIndex()
212 | }
213 | }
214 |
215 | public subscript (position: JSON.Index) -> JSON.Generator.Element {
216 | switch self.type {
217 | case .Array:
218 | return (String(position.arrayIndex), JSON(self.rawArray[position.arrayIndex!]))
219 | case .Dictionary:
220 | let (key, value) = self.rawDictionary[position.dictionaryIndex!]
221 | return (key, JSON(value))
222 | default:
223 | return ("", JSON.null)
224 | }
225 | }
226 |
227 | /// If `type` is `.Array` or `.Dictionary`, return `array.empty` or `dictonary.empty` otherwise return `true`.
228 | public var isEmpty: Bool {
229 | get {
230 | switch self.type {
231 | case .Array:
232 | return self.rawArray.isEmpty
233 | case .Dictionary:
234 | return self.rawDictionary.isEmpty
235 | default:
236 | return true
237 | }
238 | }
239 | }
240 |
241 | /// If `type` is `.Array` or `.Dictionary`, return `array.count` or `dictonary.count` otherwise return `0`.
242 | public var count: Int {
243 | switch self.type {
244 | case .Array:
245 | return self.rawArray.count
246 | case .Dictionary:
247 | return self.rawDictionary.count
248 | default:
249 | return 0
250 | }
251 | }
252 |
253 | public func underestimateCount() -> Int {
254 | switch self.type {
255 | case .Array:
256 | return self.rawArray.underestimateCount()
257 | case .Dictionary:
258 | return self.rawDictionary.underestimateCount()
259 | default:
260 | return 0
261 | }
262 | }
263 |
264 | /**
265 | If `type` is `.Array` or `.Dictionary`, return a generator over the elements like `Array` or `Dictionary`, otherwise return a generator over empty.
266 |
267 | - returns: Return a *generator* over the elements of JSON.
268 | */
269 | public func generate() -> JSON.Generator {
270 | return JSON.Generator(self)
271 | }
272 | }
273 |
274 | public struct JSONIndex: ForwardIndexType, _Incrementable, Equatable, Comparable {
275 |
276 | let arrayIndex: Int?
277 | let dictionaryIndex: DictionaryIndex?
278 |
279 | let type: Type
280 |
281 | init(){
282 | self.arrayIndex = nil
283 | self.dictionaryIndex = nil
284 | self.type = .Unknown
285 | }
286 |
287 | init(arrayIndex: Int) {
288 | self.arrayIndex = arrayIndex
289 | self.dictionaryIndex = nil
290 | self.type = .Array
291 | }
292 |
293 | init(dictionaryIndex: DictionaryIndex) {
294 | self.arrayIndex = nil
295 | self.dictionaryIndex = dictionaryIndex
296 | self.type = .Dictionary
297 | }
298 |
299 | public func successor() -> JSONIndex {
300 | switch self.type {
301 | case .Array:
302 | return JSONIndex(arrayIndex: self.arrayIndex!.successor())
303 | case .Dictionary:
304 | return JSONIndex(dictionaryIndex: self.dictionaryIndex!.successor())
305 | default:
306 | return JSONIndex()
307 | }
308 | }
309 | }
310 |
311 | public func ==(lhs: JSONIndex, rhs: JSONIndex) -> Bool {
312 | switch (lhs.type, rhs.type) {
313 | case (.Array, .Array):
314 | return lhs.arrayIndex == rhs.arrayIndex
315 | case (.Dictionary, .Dictionary):
316 | return lhs.dictionaryIndex == rhs.dictionaryIndex
317 | default:
318 | return false
319 | }
320 | }
321 |
322 | public func <(lhs: JSONIndex, rhs: JSONIndex) -> Bool {
323 | switch (lhs.type, rhs.type) {
324 | case (.Array, .Array):
325 | return lhs.arrayIndex < rhs.arrayIndex
326 | case (.Dictionary, .Dictionary):
327 | return lhs.dictionaryIndex < rhs.dictionaryIndex
328 | default:
329 | return false
330 | }
331 | }
332 |
333 | public func <=(lhs: JSONIndex, rhs: JSONIndex) -> Bool {
334 | switch (lhs.type, rhs.type) {
335 | case (.Array, .Array):
336 | return lhs.arrayIndex <= rhs.arrayIndex
337 | case (.Dictionary, .Dictionary):
338 | return lhs.dictionaryIndex <= rhs.dictionaryIndex
339 | default:
340 | return false
341 | }
342 | }
343 |
344 | public func >=(lhs: JSONIndex, rhs: JSONIndex) -> Bool {
345 | switch (lhs.type, rhs.type) {
346 | case (.Array, .Array):
347 | return lhs.arrayIndex >= rhs.arrayIndex
348 | case (.Dictionary, .Dictionary):
349 | return lhs.dictionaryIndex >= rhs.dictionaryIndex
350 | default:
351 | return false
352 | }
353 | }
354 |
355 | public func >(lhs: JSONIndex, rhs: JSONIndex) -> Bool {
356 | switch (lhs.type, rhs.type) {
357 | case (.Array, .Array):
358 | return lhs.arrayIndex > rhs.arrayIndex
359 | case (.Dictionary, .Dictionary):
360 | return lhs.dictionaryIndex > rhs.dictionaryIndex
361 | default:
362 | return false
363 | }
364 | }
365 |
366 | public struct JSONGenerator : GeneratorType {
367 |
368 | public typealias Element = (String, JSON)
369 |
370 | private let type: Type
371 | private var dictionayGenerate: DictionaryGenerator?
372 | private var arrayGenerate: IndexingGenerator<[AnyObject]>?
373 | private var arrayIndex: Int = 0
374 |
375 | init(_ json: JSON) {
376 | self.type = json.type
377 | if type == .Array {
378 | self.arrayGenerate = json.rawArray.generate()
379 | }else {
380 | self.dictionayGenerate = json.rawDictionary.generate()
381 | }
382 | }
383 |
384 | public mutating func next() -> JSONGenerator.Element? {
385 | switch self.type {
386 | case .Array:
387 | if let o = self.arrayGenerate!.next() {
388 | return (String(self.arrayIndex++), JSON(o))
389 | } else {
390 | return nil
391 | }
392 | case .Dictionary:
393 | if let (k, v): (String, AnyObject) = self.dictionayGenerate!.next() {
394 | return (k, JSON(v))
395 | } else {
396 | return nil
397 | }
398 | default:
399 | return nil
400 | }
401 | }
402 | }
403 |
404 | // MARK: - Subscript
405 |
406 | /**
407 | * To mark both String and Int can be used in subscript.
408 | */
409 | public enum JSONKey {
410 | case Index(Int)
411 | case Key(String)
412 | }
413 |
414 | public protocol JSONSubscriptType {
415 | var jsonKey:JSONKey { get }
416 | }
417 |
418 | extension Int: JSONSubscriptType {
419 | public var jsonKey:JSONKey {
420 | return JSONKey.Index(self)
421 | }
422 | }
423 |
424 | extension String: JSONSubscriptType {
425 | public var jsonKey:JSONKey {
426 | return JSONKey.Key(self)
427 | }
428 | }
429 |
430 | extension JSON {
431 |
432 | /// If `type` is `.Array`, return json which's object is `array[index]`, otherwise return null json with error.
433 | private subscript(index index: Int) -> JSON {
434 | get {
435 | if self.type != .Array {
436 | var r = JSON.null
437 | r._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] failure, It is not an array"])
438 | return r
439 | } else if index >= 0 && index < self.rawArray.count {
440 | return JSON(self.rawArray[index])
441 | } else {
442 | var r = JSON.null
443 | r._error = NSError(domain: ErrorDomain, code:ErrorIndexOutOfBounds , userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] is out of bounds"])
444 | return r
445 | }
446 | }
447 | set {
448 | if self.type == .Array {
449 | if self.rawArray.count > index && newValue.error == nil {
450 | self.rawArray[index] = newValue.object
451 | }
452 | }
453 | }
454 | }
455 |
456 | /// If `type` is `.Dictionary`, return json which's object is `dictionary[key]` , otherwise return null json with error.
457 | private subscript(key key: String) -> JSON {
458 | get {
459 | var r = JSON.null
460 | if self.type == .Dictionary {
461 | if let o = self.rawDictionary[key] {
462 | r = JSON(o)
463 | } else {
464 | r._error = NSError(domain: ErrorDomain, code: ErrorNotExist, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] does not exist"])
465 | }
466 | } else {
467 | r._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] failure, It is not an dictionary"])
468 | }
469 | return r
470 | }
471 | set {
472 | if self.type == .Dictionary && newValue.error == nil {
473 | self.rawDictionary[key] = newValue.object
474 | }
475 | }
476 | }
477 |
478 | /// If `sub` is `Int`, return `subscript(index:)`; If `sub` is `String`, return `subscript(key:)`.
479 | private subscript(sub sub: JSONSubscriptType) -> JSON {
480 | get {
481 | switch sub.jsonKey {
482 | case .Index(let index): return self[index: index]
483 | case .Key(let key): return self[key: key]
484 | }
485 | }
486 | set {
487 | switch sub.jsonKey {
488 | case .Index(let index): self[index: index] = newValue
489 | case .Key(let key): self[key: key] = newValue
490 | }
491 | }
492 | }
493 |
494 | /**
495 | Find a json in the complex data structuresby using the Int/String's array.
496 |
497 | - parameter path: The target json's path. Example:
498 |
499 | let json = JSON[data]
500 | let path = [9,"list","person","name"]
501 | let name = json[path]
502 |
503 | The same as: let name = json[9]["list"]["person"]["name"]
504 |
505 | - returns: Return a json found by the path or a null json with error
506 | */
507 | public subscript(path: [JSONSubscriptType]) -> JSON {
508 | get {
509 | return path.reduce(self) { $0[sub: $1] }
510 | }
511 | set {
512 | switch path.count {
513 | case 0:
514 | return
515 | case 1:
516 | self[sub:path[0]].object = newValue.object
517 | default:
518 | var aPath = path; aPath.removeAtIndex(0)
519 | var nextJSON = self[sub: path[0]]
520 | nextJSON[aPath] = newValue
521 | self[sub: path[0]] = nextJSON
522 | }
523 | }
524 | }
525 |
526 | /**
527 | Find a json in the complex data structuresby using the Int/String's array.
528 |
529 | - parameter path: The target json's path. Example:
530 |
531 | let name = json[9,"list","person","name"]
532 |
533 | The same as: let name = json[9]["list"]["person"]["name"]
534 |
535 | - returns: Return a json found by the path or a null json with error
536 | */
537 | public subscript(path: JSONSubscriptType...) -> JSON {
538 | get {
539 | return self[path]
540 | }
541 | set {
542 | self[path] = newValue
543 | }
544 | }
545 | }
546 |
547 | // MARK: - LiteralConvertible
548 |
549 | extension JSON: Swift.StringLiteralConvertible {
550 |
551 | public init(stringLiteral value: StringLiteralType) {
552 | self.init(value)
553 | }
554 |
555 | public init(extendedGraphemeClusterLiteral value: StringLiteralType) {
556 | self.init(value)
557 | }
558 |
559 | public init(unicodeScalarLiteral value: StringLiteralType) {
560 | self.init(value)
561 | }
562 | }
563 |
564 | extension JSON: Swift.IntegerLiteralConvertible {
565 |
566 | public init(integerLiteral value: IntegerLiteralType) {
567 | self.init(value)
568 | }
569 | }
570 |
571 | extension JSON: Swift.BooleanLiteralConvertible {
572 |
573 | public init(booleanLiteral value: BooleanLiteralType) {
574 | self.init(value)
575 | }
576 | }
577 |
578 | extension JSON: Swift.FloatLiteralConvertible {
579 |
580 | public init(floatLiteral value: FloatLiteralType) {
581 | self.init(value)
582 | }
583 | }
584 |
585 | extension JSON: Swift.DictionaryLiteralConvertible {
586 |
587 | public init(dictionaryLiteral elements: (String, AnyObject)...) {
588 | self.init(elements.reduce([String : AnyObject]()){(dictionary: [String : AnyObject], element:(String, AnyObject)) -> [String : AnyObject] in
589 | var d = dictionary
590 | d[element.0] = element.1
591 | return d
592 | })
593 | }
594 | }
595 |
596 | extension JSON: Swift.ArrayLiteralConvertible {
597 |
598 | public init(arrayLiteral elements: AnyObject...) {
599 | self.init(elements)
600 | }
601 | }
602 |
603 | extension JSON: Swift.NilLiteralConvertible {
604 |
605 | public init(nilLiteral: ()) {
606 | self.init(NSNull())
607 | }
608 | }
609 |
610 | // MARK: - Raw
611 |
612 | extension JSON: Swift.RawRepresentable {
613 |
614 | public init?(rawValue: AnyObject) {
615 | if JSON(rawValue).type == .Unknown {
616 | return nil
617 | } else {
618 | self.init(rawValue)
619 | }
620 | }
621 |
622 | public var rawValue: AnyObject {
623 | return self.object
624 | }
625 |
626 | public func rawData(options opt: NSJSONWritingOptions = NSJSONWritingOptions(rawValue: 0)) throws -> NSData {
627 | guard NSJSONSerialization.isValidJSONObject(self.object) else {
628 | throw NSError(domain: ErrorDomain, code: ErrorInvalidJSON, userInfo: [NSLocalizedDescriptionKey: "JSON is invalid"])
629 | }
630 |
631 | return try NSJSONSerialization.dataWithJSONObject(self.object, options: opt)
632 | }
633 |
634 | public func rawString(encoding: UInt = NSUTF8StringEncoding, options opt: NSJSONWritingOptions = .PrettyPrinted) -> String? {
635 | switch self.type {
636 | case .Array, .Dictionary:
637 | do {
638 | let data = try self.rawData(options: opt)
639 | return NSString(data: data, encoding: encoding) as? String
640 | } catch _ {
641 | return nil
642 | }
643 | case .String:
644 | return self.rawString
645 | case .Number:
646 | return self.rawNumber.stringValue
647 | case .Bool:
648 | return self.rawNumber.boolValue.description
649 | case .Null:
650 | return "null"
651 | default:
652 | return nil
653 | }
654 | }
655 | }
656 |
657 | // MARK: - Printable, DebugPrintable
658 |
659 | extension JSON: Swift.Printable, Swift.DebugPrintable {
660 |
661 | public var description: String {
662 | if let string = self.rawString(options:.PrettyPrinted) {
663 | return string
664 | } else {
665 | return "unknown"
666 | }
667 | }
668 |
669 | public var debugDescription: String {
670 | return description
671 | }
672 | }
673 |
674 | // MARK: - Array
675 |
676 | extension JSON {
677 |
678 | //Optional [JSON]
679 | public var array: [JSON]? {
680 | get {
681 | if self.type == .Array {
682 | return self.rawArray.map{ JSON($0) }
683 | } else {
684 | return nil
685 | }
686 | }
687 | }
688 |
689 | //Non-optional [JSON]
690 | public var arrayValue: [JSON] {
691 | get {
692 | return self.array ?? []
693 | }
694 | }
695 |
696 | //Optional [AnyObject]
697 | public var arrayObject: [AnyObject]? {
698 | get {
699 | switch self.type {
700 | case .Array:
701 | return self.rawArray
702 | default:
703 | return nil
704 | }
705 | }
706 | set {
707 | if let array = newValue {
708 | self.object = array
709 | } else {
710 | self.object = NSNull()
711 | }
712 | }
713 | }
714 | }
715 |
716 | // MARK: - Dictionary
717 |
718 | extension JSON {
719 |
720 | //Optional [String : JSON]
721 | public var dictionary: [String : JSON]? {
722 | if self.type == .Dictionary {
723 | return self.rawDictionary.reduce([String : JSON]()) { (dictionary: [String : JSON], element: (String, AnyObject)) -> [String : JSON] in
724 | var d = dictionary
725 | d[element.0] = JSON(element.1)
726 | return d
727 | }
728 | } else {
729 | return nil
730 | }
731 | }
732 |
733 | //Non-optional [String : JSON]
734 | public var dictionaryValue: [String : JSON] {
735 | return self.dictionary ?? [:]
736 | }
737 |
738 | //Optional [String : AnyObject]
739 | public var dictionaryObject: [String : AnyObject]? {
740 | get {
741 | switch self.type {
742 | case .Dictionary:
743 | return self.rawDictionary
744 | default:
745 | return nil
746 | }
747 | }
748 | set {
749 | if let v = newValue {
750 | self.object = v
751 | } else {
752 | self.object = NSNull()
753 | }
754 | }
755 | }
756 | }
757 |
758 | // MARK: - Bool
759 |
760 | extension JSON: Swift.BooleanType {
761 |
762 | //Optional bool
763 | public var bool: Bool? {
764 | get {
765 | switch self.type {
766 | case .Bool:
767 | return self.rawNumber.boolValue
768 | default:
769 | return nil
770 | }
771 | }
772 | set {
773 | if newValue != nil {
774 | self.object = NSNumber(bool: newValue!)
775 | } else {
776 | self.object = NSNull()
777 | }
778 | }
779 | }
780 |
781 | //Non-optional bool
782 | public var boolValue: Bool {
783 | get {
784 | switch self.type {
785 | case .Bool, .Number, .String:
786 | return self.object.boolValue
787 | default:
788 | return false
789 | }
790 | }
791 | set {
792 | self.object = NSNumber(bool: newValue)
793 | }
794 | }
795 | }
796 |
797 | // MARK: - String
798 |
799 | extension JSON {
800 |
801 | //Optional string
802 | public var string: String? {
803 | get {
804 | switch self.type {
805 | case .String:
806 | return self.object as? String
807 | default:
808 | return nil
809 | }
810 | }
811 | set {
812 | if newValue != nil {
813 | self.object = NSString(string:newValue!)
814 | } else {
815 | self.object = NSNull()
816 | }
817 | }
818 | }
819 |
820 | //Non-optional string
821 | public var stringValue: String {
822 | get {
823 | switch self.type {
824 | case .String:
825 | return self.object as! String
826 | case .Number:
827 | return self.object.stringValue
828 | case .Bool:
829 | return (self.object as! Bool).description
830 | default:
831 | return ""
832 | }
833 | }
834 | set {
835 | self.object = NSString(string:newValue)
836 | }
837 | }
838 | }
839 |
840 | // MARK: - Number
841 | extension JSON {
842 |
843 | //Optional number
844 | public var number: NSNumber? {
845 | get {
846 | switch self.type {
847 | case .Number, .Bool:
848 | return self.rawNumber
849 | default:
850 | return nil
851 | }
852 | }
853 | set {
854 | self.object = newValue ?? NSNull()
855 | }
856 | }
857 |
858 | //Non-optional number
859 | public var numberValue: NSNumber {
860 | get {
861 | switch self.type {
862 | case .String:
863 | let decimal = NSDecimalNumber(string: self.object as? String)
864 | if decimal == NSDecimalNumber.notANumber() { // indicates parse error
865 | return NSDecimalNumber.zero()
866 | }
867 | return decimal
868 | case .Number, .Bool:
869 | return self.object as! NSNumber
870 | default:
871 | return NSNumber(double: 0.0)
872 | }
873 | }
874 | set {
875 | self.object = newValue
876 | }
877 | }
878 | }
879 |
880 | //MARK: - Null
881 | extension JSON {
882 |
883 | public var null: NSNull? {
884 | get {
885 | switch self.type {
886 | case .Null:
887 | return self.rawNull
888 | default:
889 | return nil
890 | }
891 | }
892 | set {
893 | self.object = NSNull()
894 | }
895 | }
896 | public func isExists() -> Bool{
897 | if let errorValue = error where errorValue.code == ErrorNotExist{
898 | return false
899 | }
900 | return true
901 | }
902 | }
903 |
904 | //MARK: - URL
905 | extension JSON {
906 |
907 | //Optional URL
908 | public var URL: NSURL? {
909 | get {
910 | switch self.type {
911 | case .String:
912 | if let encodedString_ = self.rawString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet()) {
913 | return NSURL(string: encodedString_)
914 | } else {
915 | return nil
916 | }
917 | default:
918 | return nil
919 | }
920 | }
921 | set {
922 | self.object = newValue?.absoluteString ?? NSNull()
923 | }
924 | }
925 | }
926 |
927 | // MARK: - Int, Double, Float, Int8, Int16, Int32, Int64
928 |
929 | extension JSON {
930 |
931 | public var double: Double? {
932 | get {
933 | return self.number?.doubleValue
934 | }
935 | set {
936 | if newValue != nil {
937 | self.object = NSNumber(double: newValue!)
938 | } else {
939 | self.object = NSNull()
940 | }
941 | }
942 | }
943 |
944 | public var doubleValue: Double {
945 | get {
946 | return self.numberValue.doubleValue
947 | }
948 | set {
949 | self.object = NSNumber(double: newValue)
950 | }
951 | }
952 |
953 | public var float: Float? {
954 | get {
955 | return self.number?.floatValue
956 | }
957 | set {
958 | if newValue != nil {
959 | self.object = NSNumber(float: newValue!)
960 | } else {
961 | self.object = NSNull()
962 | }
963 | }
964 | }
965 |
966 | public var floatValue: Float {
967 | get {
968 | return self.numberValue.floatValue
969 | }
970 | set {
971 | self.object = NSNumber(float: newValue)
972 | }
973 | }
974 |
975 | public var int: Int? {
976 | get {
977 | return self.number?.longValue
978 | }
979 | set {
980 | if newValue != nil {
981 | self.object = NSNumber(integer: newValue!)
982 | } else {
983 | self.object = NSNull()
984 | }
985 | }
986 | }
987 |
988 | public var intValue: Int {
989 | get {
990 | return self.numberValue.integerValue
991 | }
992 | set {
993 | self.object = NSNumber(integer: newValue)
994 | }
995 | }
996 |
997 | public var uInt: UInt? {
998 | get {
999 | return self.number?.unsignedLongValue
1000 | }
1001 | set {
1002 | if newValue != nil {
1003 | self.object = NSNumber(unsignedLong: newValue!)
1004 | } else {
1005 | self.object = NSNull()
1006 | }
1007 | }
1008 | }
1009 |
1010 | public var uIntValue: UInt {
1011 | get {
1012 | return self.numberValue.unsignedLongValue
1013 | }
1014 | set {
1015 | self.object = NSNumber(unsignedLong: newValue)
1016 | }
1017 | }
1018 |
1019 | public var int8: Int8? {
1020 | get {
1021 | return self.number?.charValue
1022 | }
1023 | set {
1024 | if newValue != nil {
1025 | self.object = NSNumber(char: newValue!)
1026 | } else {
1027 | self.object = NSNull()
1028 | }
1029 | }
1030 | }
1031 |
1032 | public var int8Value: Int8 {
1033 | get {
1034 | return self.numberValue.charValue
1035 | }
1036 | set {
1037 | self.object = NSNumber(char: newValue)
1038 | }
1039 | }
1040 |
1041 | public var uInt8: UInt8? {
1042 | get {
1043 | return self.number?.unsignedCharValue
1044 | }
1045 | set {
1046 | if newValue != nil {
1047 | self.object = NSNumber(unsignedChar: newValue!)
1048 | } else {
1049 | self.object = NSNull()
1050 | }
1051 | }
1052 | }
1053 |
1054 | public var uInt8Value: UInt8 {
1055 | get {
1056 | return self.numberValue.unsignedCharValue
1057 | }
1058 | set {
1059 | self.object = NSNumber(unsignedChar: newValue)
1060 | }
1061 | }
1062 |
1063 | public var int16: Int16? {
1064 | get {
1065 | return self.number?.shortValue
1066 | }
1067 | set {
1068 | if newValue != nil {
1069 | self.object = NSNumber(short: newValue!)
1070 | } else {
1071 | self.object = NSNull()
1072 | }
1073 | }
1074 | }
1075 |
1076 | public var int16Value: Int16 {
1077 | get {
1078 | return self.numberValue.shortValue
1079 | }
1080 | set {
1081 | self.object = NSNumber(short: newValue)
1082 | }
1083 | }
1084 |
1085 | public var uInt16: UInt16? {
1086 | get {
1087 | return self.number?.unsignedShortValue
1088 | }
1089 | set {
1090 | if newValue != nil {
1091 | self.object = NSNumber(unsignedShort: newValue!)
1092 | } else {
1093 | self.object = NSNull()
1094 | }
1095 | }
1096 | }
1097 |
1098 | public var uInt16Value: UInt16 {
1099 | get {
1100 | return self.numberValue.unsignedShortValue
1101 | }
1102 | set {
1103 | self.object = NSNumber(unsignedShort: newValue)
1104 | }
1105 | }
1106 |
1107 | public var int32: Int32? {
1108 | get {
1109 | return self.number?.intValue
1110 | }
1111 | set {
1112 | if newValue != nil {
1113 | self.object = NSNumber(int: newValue!)
1114 | } else {
1115 | self.object = NSNull()
1116 | }
1117 | }
1118 | }
1119 |
1120 | public var int32Value: Int32 {
1121 | get {
1122 | return self.numberValue.intValue
1123 | }
1124 | set {
1125 | self.object = NSNumber(int: newValue)
1126 | }
1127 | }
1128 |
1129 | public var uInt32: UInt32? {
1130 | get {
1131 | return self.number?.unsignedIntValue
1132 | }
1133 | set {
1134 | if newValue != nil {
1135 | self.object = NSNumber(unsignedInt: newValue!)
1136 | } else {
1137 | self.object = NSNull()
1138 | }
1139 | }
1140 | }
1141 |
1142 | public var uInt32Value: UInt32 {
1143 | get {
1144 | return self.numberValue.unsignedIntValue
1145 | }
1146 | set {
1147 | self.object = NSNumber(unsignedInt: newValue)
1148 | }
1149 | }
1150 |
1151 | public var int64: Int64? {
1152 | get {
1153 | return self.number?.longLongValue
1154 | }
1155 | set {
1156 | if newValue != nil {
1157 | self.object = NSNumber(longLong: newValue!)
1158 | } else {
1159 | self.object = NSNull()
1160 | }
1161 | }
1162 | }
1163 |
1164 | public var int64Value: Int64 {
1165 | get {
1166 | return self.numberValue.longLongValue
1167 | }
1168 | set {
1169 | self.object = NSNumber(longLong: newValue)
1170 | }
1171 | }
1172 |
1173 | public var uInt64: UInt64? {
1174 | get {
1175 | return self.number?.unsignedLongLongValue
1176 | }
1177 | set {
1178 | if newValue != nil {
1179 | self.object = NSNumber(unsignedLongLong: newValue!)
1180 | } else {
1181 | self.object = NSNull()
1182 | }
1183 | }
1184 | }
1185 |
1186 | public var uInt64Value: UInt64 {
1187 | get {
1188 | return self.numberValue.unsignedLongLongValue
1189 | }
1190 | set {
1191 | self.object = NSNumber(unsignedLongLong: newValue)
1192 | }
1193 | }
1194 | }
1195 |
1196 | //MARK: - Comparable
1197 | extension JSON : Swift.Comparable {}
1198 |
1199 | public func ==(lhs: JSON, rhs: JSON) -> Bool {
1200 |
1201 | switch (lhs.type, rhs.type) {
1202 | case (.Number, .Number):
1203 | return lhs.rawNumber == rhs.rawNumber
1204 | case (.String, .String):
1205 | return lhs.rawString == rhs.rawString
1206 | case (.Bool, .Bool):
1207 | return lhs.rawNumber.boolValue == rhs.rawNumber.boolValue
1208 | case (.Array, .Array):
1209 | return lhs.rawArray as NSArray == rhs.rawArray as NSArray
1210 | case (.Dictionary, .Dictionary):
1211 | return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary
1212 | case (.Null, .Null):
1213 | return true
1214 | default:
1215 | return false
1216 | }
1217 | }
1218 |
1219 | public func <=(lhs: JSON, rhs: JSON) -> Bool {
1220 |
1221 | switch (lhs.type, rhs.type) {
1222 | case (.Number, .Number):
1223 | return lhs.rawNumber <= rhs.rawNumber
1224 | case (.String, .String):
1225 | return lhs.rawString <= rhs.rawString
1226 | case (.Bool, .Bool):
1227 | return lhs.rawNumber.boolValue == rhs.rawNumber.boolValue
1228 | case (.Array, .Array):
1229 | return lhs.rawArray as NSArray == rhs.rawArray as NSArray
1230 | case (.Dictionary, .Dictionary):
1231 | return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary
1232 | case (.Null, .Null):
1233 | return true
1234 | default:
1235 | return false
1236 | }
1237 | }
1238 |
1239 | public func >=(lhs: JSON, rhs: JSON) -> Bool {
1240 |
1241 | switch (lhs.type, rhs.type) {
1242 | case (.Number, .Number):
1243 | return lhs.rawNumber >= rhs.rawNumber
1244 | case (.String, .String):
1245 | return lhs.rawString >= rhs.rawString
1246 | case (.Bool, .Bool):
1247 | return lhs.rawNumber.boolValue == rhs.rawNumber.boolValue
1248 | case (.Array, .Array):
1249 | return lhs.rawArray as NSArray == rhs.rawArray as NSArray
1250 | case (.Dictionary, .Dictionary):
1251 | return lhs.rawDictionary as NSDictionary == rhs.rawDictionary as NSDictionary
1252 | case (.Null, .Null):
1253 | return true
1254 | default:
1255 | return false
1256 | }
1257 | }
1258 |
1259 | public func >(lhs: JSON, rhs: JSON) -> Bool {
1260 |
1261 | switch (lhs.type, rhs.type) {
1262 | case (.Number, .Number):
1263 | return lhs.rawNumber > rhs.rawNumber
1264 | case (.String, .String):
1265 | return lhs.rawString > rhs.rawString
1266 | default:
1267 | return false
1268 | }
1269 | }
1270 |
1271 | public func <(lhs: JSON, rhs: JSON) -> Bool {
1272 |
1273 | switch (lhs.type, rhs.type) {
1274 | case (.Number, .Number):
1275 | return lhs.rawNumber < rhs.rawNumber
1276 | case (.String, .String):
1277 | return lhs.rawString < rhs.rawString
1278 | default:
1279 | return false
1280 | }
1281 | }
1282 |
1283 | private let trueNumber = NSNumber(bool: true)
1284 | private let falseNumber = NSNumber(bool: false)
1285 | private let trueObjCType = String.fromCString(trueNumber.objCType)
1286 | private let falseObjCType = String.fromCString(falseNumber.objCType)
1287 |
1288 | // MARK: - NSNumber: Comparable
1289 |
1290 | extension NSNumber {
1291 | var isBool:Bool {
1292 | get {
1293 | let objCType = String.fromCString(self.objCType)
1294 | if (self.compare(trueNumber) == NSComparisonResult.OrderedSame && objCType == trueObjCType)
1295 | || (self.compare(falseNumber) == NSComparisonResult.OrderedSame && objCType == falseObjCType){
1296 | return true
1297 | } else {
1298 | return false
1299 | }
1300 | }
1301 | }
1302 | }
1303 |
1304 | public func ==(lhs: NSNumber, rhs: NSNumber) -> Bool {
1305 | switch (lhs.isBool, rhs.isBool) {
1306 | case (false, true):
1307 | return false
1308 | case (true, false):
1309 | return false
1310 | default:
1311 | return lhs.compare(rhs) == NSComparisonResult.OrderedSame
1312 | }
1313 | }
1314 |
1315 | public func !=(lhs: NSNumber, rhs: NSNumber) -> Bool {
1316 | return !(lhs == rhs)
1317 | }
1318 |
1319 | public func <(lhs: NSNumber, rhs: NSNumber) -> Bool {
1320 |
1321 | switch (lhs.isBool, rhs.isBool) {
1322 | case (false, true):
1323 | return false
1324 | case (true, false):
1325 | return false
1326 | default:
1327 | return lhs.compare(rhs) == NSComparisonResult.OrderedAscending
1328 | }
1329 | }
1330 |
1331 | public func >(lhs: NSNumber, rhs: NSNumber) -> Bool {
1332 |
1333 | switch (lhs.isBool, rhs.isBool) {
1334 | case (false, true):
1335 | return false
1336 | case (true, false):
1337 | return false
1338 | default:
1339 | return lhs.compare(rhs) == NSComparisonResult.OrderedDescending
1340 | }
1341 | }
1342 |
1343 | public func <=(lhs: NSNumber, rhs: NSNumber) -> Bool {
1344 |
1345 | switch (lhs.isBool, rhs.isBool) {
1346 | case (false, true):
1347 | return false
1348 | case (true, false):
1349 | return false
1350 | default:
1351 | return lhs.compare(rhs) != NSComparisonResult.OrderedDescending
1352 | }
1353 | }
1354 |
1355 | public func >=(lhs: NSNumber, rhs: NSNumber) -> Bool {
1356 |
1357 | switch (lhs.isBool, rhs.isBool) {
1358 | case (false, true):
1359 | return false
1360 | case (true, false):
1361 | return false
1362 | default:
1363 | return lhs.compare(rhs) != NSComparisonResult.OrderedAscending
1364 | }
1365 | }
1366 |
--------------------------------------------------------------------------------