├── Crashlytics.framework
├── Versions
│ ├── Current
│ └── A
│ │ ├── Crashlytics
│ │ ├── Resources
│ │ └── Info.plist
│ │ └── Headers
│ │ └── Crashlytics.h
├── Headers
├── Resources
├── Crashlytics
├── run
├── submit
└── Modules
│ └── module.modulemap
├── Hydro
├── Images.xcassets
│ ├── 1.imageset
│ │ ├── 1.pdf
│ │ └── Contents.json
│ ├── 2.imageset
│ │ ├── 2.pdf
│ │ └── Contents.json
│ ├── 3.imageset
│ │ ├── 3.pdf
│ │ └── Contents.json
│ ├── EM.imageset
│ │ ├── EM.pdf
│ │ └── Contents.json
│ ├── HK.imageset
│ │ ├── HK.pdf
│ │ └── Contents.json
│ ├── JP.imageset
│ │ ├── JP.pdf
│ │ └── Contents.json
│ ├── PW.imageset
│ │ ├── PW.pdf
│ │ └── Contents.json
│ ├── logo.imageset
│ │ ├── logo.pdf
│ │ └── Contents.json
│ ├── Check.imageset
│ │ ├── Check.pdf
│ │ └── Contents.json
│ ├── Button.imageset
│ │ ├── Button.pdf
│ │ └── Contents.json
│ ├── flag_sg.imageset
│ │ ├── flag_sg.pdf
│ │ └── Contents.json
│ ├── flag_us.imageset
│ │ ├── flag_us.pdf
│ │ └── Contents.json
│ ├── Map.imageset
│ │ ├── World Map color.pdf
│ │ └── Contents.json
│ ├── World Map.imageset
│ │ ├── World Map.pdf
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ ├── icon-ipad_76.png
│ │ ├── icon-iphone_29.png
│ │ ├── icon-ipad_76@2x.png
│ │ ├── icon-iphone_29@2x.png
│ │ ├── icon-iphone_29@3x.png
│ │ ├── icon-iphone_40@2x.png
│ │ ├── icon-iphone_40@3x.png
│ │ ├── icon-iphone_60@2x.png
│ │ ├── icon-iphone_60@3x.png
│ │ ├── icon-iphone_29@2x-1.png
│ │ ├── icon-iphone_40@2x-1.png
│ │ ├── icon-iphone_40@3x-1.png
│ │ └── Contents.json
│ ├── Background.imageset
│ │ ├── Background.pdf
│ │ └── Contents.json
│ ├── Button_wire.imageset
│ │ ├── Button_wire.pdf
│ │ └── Contents.json
│ └── Button + Connect.imageset
│ │ ├── Button + Connect.pdf
│ │ └── Contents.json
├── Views
│ ├── scaleView.h
│ ├── locationView.h
│ ├── InviteView.h
│ ├── stationView.h
│ ├── scaleView.m
│ ├── stationView.m
│ ├── locationView.m
│ └── InviteView.m
├── Button
│ ├── HydroButton.h
│ └── HydroButton.m
├── AppDelegate.h
├── main.m
├── stationDelegate
│ ├── VPNStations.h
│ └── VPNStations.m
├── Hydro.entitlements
├── ViewController.h
├── GVUserDefaults+Hydro.h
├── VCKetChain.h
├── HydroHelper
│ ├── HydroHelper.h
│ └── HydroHelper.m
├── GVUserDefaults+Hydro.m
├── LoginViewController
│ ├── LoginViewController.h
│ └── LoginViewController.m
├── config.json.example
├── VCIPsecVPNManager.h
├── Cell
│ ├── StationTableViewCell.h
│ └── StationTableViewCell.m
├── Info.plist
├── Base.lproj
│ ├── LaunchScreen.xib
│ └── Main.storyboard
├── AppDelegate.m
├── VCKetChain.m
├── VCIPsecVPNManager.m
└── ViewController.m
├── README.md
├── Hydro.xcodeproj
└── project.xcworkspace
│ └── contents.xcworkspacedata
├── Hydro.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ └── Hydro.xcscmblueprint
├── Podfile
├── Today
├── Today.entitlements
├── VPNButton.h
├── TodayViewController.h
├── Info.plist
├── VPNButton.m
├── TodayViewController.m
└── MainInterface.storyboard
├── .gitignore
├── HydroTests
├── Info.plist
└── HydroTests.m
└── Podfile.lock
/Crashlytics.framework/Versions/Current:
--------------------------------------------------------------------------------
1 | A
--------------------------------------------------------------------------------
/Crashlytics.framework/Headers:
--------------------------------------------------------------------------------
1 | Versions/Current/Headers
--------------------------------------------------------------------------------
/Crashlytics.framework/Resources:
--------------------------------------------------------------------------------
1 | Versions/Current/Resources
--------------------------------------------------------------------------------
/Crashlytics.framework/Crashlytics:
--------------------------------------------------------------------------------
1 | Versions/Current/Crashlytics
--------------------------------------------------------------------------------
/Crashlytics.framework/run:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Crashlytics.framework/run
--------------------------------------------------------------------------------
/Crashlytics.framework/submit:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Crashlytics.framework/submit
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/1.imageset/1.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/1.imageset/1.pdf
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/2.imageset/2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/2.imageset/2.pdf
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/3.imageset/3.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/3.imageset/3.pdf
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/EM.imageset/EM.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/EM.imageset/EM.pdf
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/HK.imageset/HK.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/HK.imageset/HK.pdf
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/JP.imageset/JP.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/JP.imageset/JP.pdf
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/PW.imageset/PW.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/PW.imageset/PW.pdf
--------------------------------------------------------------------------------
/Crashlytics.framework/Versions/A/Crashlytics:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Crashlytics.framework/Versions/A/Crashlytics
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/logo.imageset/logo.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/logo.imageset/logo.pdf
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Hydro
2 | =====
3 |
4 | [Hydro.network 的开发旅程](http://zhowkev.in/2015/03/09/hydro-network-de-kai-fa-lu-cheng/)
5 |
6 | Hydro Network
7 |
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/Check.imageset/Check.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/Check.imageset/Check.pdf
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/Button.imageset/Button.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/Button.imageset/Button.pdf
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/flag_sg.imageset/flag_sg.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/flag_sg.imageset/flag_sg.pdf
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/flag_us.imageset/flag_us.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/flag_us.imageset/flag_us.pdf
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/Map.imageset/World Map color.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/Map.imageset/World Map color.pdf
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/World Map.imageset/World Map.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/World Map.imageset/World Map.pdf
--------------------------------------------------------------------------------
/Crashlytics.framework/Modules/module.modulemap:
--------------------------------------------------------------------------------
1 | framework module Crashlytics {
2 | umbrella header "Crashlytics.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/AppIcon.appiconset/icon-ipad_76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/AppIcon.appiconset/icon-ipad_76.png
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/Background.imageset/Background.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/Background.imageset/Background.pdf
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/AppIcon.appiconset/icon-iphone_29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/AppIcon.appiconset/icon-iphone_29.png
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/Button_wire.imageset/Button_wire.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/Button_wire.imageset/Button_wire.pdf
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/AppIcon.appiconset/icon-ipad_76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/AppIcon.appiconset/icon-ipad_76@2x.png
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/AppIcon.appiconset/icon-iphone_29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/AppIcon.appiconset/icon-iphone_29@2x.png
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/AppIcon.appiconset/icon-iphone_29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/AppIcon.appiconset/icon-iphone_29@3x.png
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/AppIcon.appiconset/icon-iphone_40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/AppIcon.appiconset/icon-iphone_40@2x.png
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/AppIcon.appiconset/icon-iphone_40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/AppIcon.appiconset/icon-iphone_40@3x.png
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/AppIcon.appiconset/icon-iphone_60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/AppIcon.appiconset/icon-iphone_60@2x.png
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/AppIcon.appiconset/icon-iphone_60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/AppIcon.appiconset/icon-iphone_60@3x.png
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/AppIcon.appiconset/icon-iphone_29@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/AppIcon.appiconset/icon-iphone_29@2x-1.png
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/AppIcon.appiconset/icon-iphone_40@2x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/AppIcon.appiconset/icon-iphone_40@2x-1.png
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/AppIcon.appiconset/icon-iphone_40@3x-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/AppIcon.appiconset/icon-iphone_40@3x-1.png
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/Button + Connect.imageset/Button + Connect.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CatchChat/Hydro.network/HEAD/Hydro/Images.xcassets/Button + Connect.imageset/Button + Connect.pdf
--------------------------------------------------------------------------------
/Hydro.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "1.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "2.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/3.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "3.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/EM.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "EM.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/HK.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "HK.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/JP.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "JP.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/PW.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "PW.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/logo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "logo.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/Button.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Button.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/Check.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Check.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/Map.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "World Map color.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/World Map.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "World Map.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/flag_us.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "flag_us.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/Background.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Background.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/Button_wire.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Button_wire.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/Button + Connect.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Button + Connect.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/Hydro/Views/scaleView.h:
--------------------------------------------------------------------------------
1 | //
2 | // scaleView.h
3 | // Hydro
4 | //
5 | // Created by kevinzhow on 14/12/25.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface scaleView : UIView
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Hydro.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Hydro/Button/HydroButton.h:
--------------------------------------------------------------------------------
1 | //
2 | // HydroButton.h
3 | // Hydro
4 | //
5 | // Created by kevinzhow on 14/12/25.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface HydroButton : UIButton
12 |
13 | -(void)touchDown;
14 |
15 | -(void)touchUpInside;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/Hydro/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // Hydro
4 | //
5 | // Created by kevinzhow on 14/12/25.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 |
16 | @end
17 |
18 |
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '6.0'
3 |
4 | target 'Hydro' do
5 | pod 'AFNetworking'
6 | pod 'pop'
7 | pod 'GBPing'
8 | pod 'TPKeyboardAvoiding'
9 | pod 'SAMTextField'
10 | pod 'GVUserDefaults'
11 | pod 'Shimmer'
12 | pod 'SVProgressHUD'
13 | end
14 |
15 | target 'HydroTests' do
16 |
17 | end
18 |
19 |
--------------------------------------------------------------------------------
/Hydro/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // Hydro
4 | //
5 | // Created by kevinzhow on 14/12/25.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Hydro/Views/locationView.h:
--------------------------------------------------------------------------------
1 | //
2 | // locationView.h
3 | // Hydro
4 | //
5 | // Created by kevinzhow on 14/12/26.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface locationView : UIView
12 |
13 | @property (nonatomic) CAShapeLayer * circleShape;
14 |
15 | @property (nonatomic) CAShapeLayer * ringShape;
16 |
17 | -(void)show;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/Hydro/Views/InviteView.h:
--------------------------------------------------------------------------------
1 | //
2 | // InviteView.h
3 | // Hydro
4 | //
5 | // Created by NIX on 14/12/27.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface InviteView : UIView
13 |
14 | @property (nonatomic, strong) SAMTextField *emailTextField;
15 | @property (nonatomic, strong) UIButton *inviteButton;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/flag_sg.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x",
6 | "filename" : "flag_sg.pdf"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/Hydro/stationDelegate/VPNStations.h:
--------------------------------------------------------------------------------
1 | //
2 | // VPNStations.h
3 | // Hydro
4 | //
5 | // Created by NIX on 14/12/26.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface VPNStations : NSObject
12 |
13 | @property (nonatomic, strong) NSArray *stations;
14 |
15 | @property (nonatomic, strong) NSDictionary *config;
16 |
17 | + (VPNStations *)sharedInstance;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/Hydro/Hydro.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.developer.networking.vpn.api
6 |
7 | allow-vpn
8 |
9 | com.apple.security.application-groups
10 |
11 | group.catchlab.TodayExtensionSharingDefaults
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Today/Today.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.developer.networking.vpn.api
6 |
7 | allow-vpn
8 |
9 | com.apple.security.application-groups
10 |
11 | group.catchlab.TodayExtensionSharingDefaults
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Today/VPNButton.h:
--------------------------------------------------------------------------------
1 | //
2 | // VPNButton.h
3 | // Hydro
4 | //
5 | // Created by NIX on 14/12/26.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | typedef NS_ENUM(NSUInteger, VPNButtonState) {
12 | VPNButtonStateNormal,
13 | VPNButtonStateConnecting,
14 | VPNButtonStateConnected,
15 | VPNButtonStateConnectFailed,
16 | };
17 |
18 | @interface VPNButton : UIButton
19 |
20 | @property (nonatomic) VPNButtonState buttonState;
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/Hydro/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // Hydro
4 | //
5 | // Created by kevinzhow on 14/12/25.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "HydroHelper.h"
11 | #import "VCIPsecVPNManager.h"
12 | #import "HydroButton.h"
13 | #import "stationView.h"
14 | #import "locationView.h"
15 |
16 |
17 | @interface ViewController : UIViewController
18 |
19 | @property (weak, nonatomic) IBOutlet UITableView *stationsTableVIew;
20 |
21 | @end
22 |
23 |
--------------------------------------------------------------------------------
/Hydro/GVUserDefaults+Hydro.h:
--------------------------------------------------------------------------------
1 | //
2 | // GVUserDefaults+Hydro.h
3 | // Hydro
4 | //
5 | // Created by kevinzhow on 14/12/25.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import "GVUserDefaults.h"
10 |
11 | @interface GVUserDefaults (Hydro)
12 |
13 | @property (nonatomic, strong) NSString *email;
14 | @property (nonatomic, strong) NSString *server;
15 | @property (nonatomic, strong) NSString *token;
16 |
17 | @property (nonatomic) BOOL ikev2;
18 |
19 | @property (nonatomic, strong) NSDictionary *currentStationDict;
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/Hydro/VCKetChain.h:
--------------------------------------------------------------------------------
1 | //
2 | // VCKetChain.h
3 | // VPNCloud
4 | //
5 | // Created by kevinzhow on 14/11/12.
6 | // Copyright (c) 2014年 Kingaxis Inc. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface VCKetChain : NSObject
12 | {
13 | NSString * service;
14 | NSString * group;
15 | }
16 | -(id) initWithService:(NSString *) service_ withGroup:(NSString*)group_;
17 |
18 | -(BOOL) insert:(NSString *)key : (NSData *)data;
19 | -(BOOL) update:(NSString*)key :(NSData*) data;
20 | -(BOOL) remove: (NSString*)key;
21 | -(NSData*) find:(NSString*)key;
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/Hydro/HydroHelper/HydroHelper.h:
--------------------------------------------------------------------------------
1 | //
2 | // HydroHelper.h
3 | // Hydro
4 | //
5 | // Created by kevinzhow on 14/12/25.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #define SCREEN_HEIGHT ([UIScreen mainScreen].bounds.size.height)
12 | #define SCREEN_WIDTH ([UIScreen mainScreen].bounds.size.width)
13 |
14 | extern NSString * const CCNFillUserInfo;
15 |
16 | extern NSString * const CCNFilterStationStatus;
17 |
18 |
19 | @interface HydroHelper : NSObject
20 |
21 | + (UIImage *)imageFromColor:(UIColor*)color;
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/Hydro/GVUserDefaults+Hydro.m:
--------------------------------------------------------------------------------
1 | //
2 | // GVUserDefaults+Hydro.m
3 | // Hydro
4 | //
5 | // Created by kevinzhow on 14/12/25.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import "GVUserDefaults+Hydro.h"
10 | #import "VPNStations.h"
11 |
12 | @implementation GVUserDefaults (Hydro)
13 |
14 | @dynamic email;
15 | @dynamic token;
16 | @dynamic server;
17 | @dynamic ikev2;
18 | @dynamic currentStationDict;
19 |
20 | - (NSDictionary *)setupDefaults {
21 | return @{
22 | @"server": [[VPNStations sharedInstance].stations.firstObject valueForKey:@"host"]
23 | };
24 | }
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/Hydro/LoginViewController/LoginViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // LoginViewController.h
3 | // Hydro
4 | //
5 | // Created by kevinzhow on 14/12/25.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "HydroHelper.h"
11 | #import
12 |
13 | @interface LoginViewController : UIViewController
14 | @property (weak, nonatomic) IBOutlet UIScrollView *scrollview;
15 | @property (weak, nonatomic) IBOutlet SAMTextField *emailtextfield;
16 | @property (weak, nonatomic) IBOutlet SAMTextField *passwordField;
17 |
18 | - (IBAction)doClickLoginButton:(id)sender;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | .DS_Store
4 | build/
5 | *.pbxuser
6 | !default.pbxuser
7 | *.mode1v3
8 | !default.mode1v3
9 | *.mode2v3
10 | !default.mode2v3
11 | *.perspectivev3
12 | !default.perspectivev3
13 | xcuserdata
14 | *.xccheckout
15 | *.moved-aside
16 | DerivedData
17 | *.hmap
18 | *.ipa
19 | *.xcuserstate
20 | *.json
21 | # CocoaPods
22 | #
23 | # We recommend against adding the Pods directory to your .gitignore. However
24 | # you should judge for yourself, the pros and cons are mentioned at:
25 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
26 | #
27 | HockeySDK-iOS/
28 | Pods/
29 | # Pods/
30 |
--------------------------------------------------------------------------------
/Hydro/Views/stationView.h:
--------------------------------------------------------------------------------
1 | //
2 | // stationView.h
3 | // Hydro
4 | //
5 | // Created by kevinzhow on 14/12/25.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "FBShimmeringView.h"
11 |
12 | @interface stationView : UIView
13 |
14 | @property (nonatomic) UIImageView * stationFlag;
15 |
16 | @property (nonatomic) UIImageView * stationStatusIcon;
17 |
18 | @property (nonatomic) UILabel * statusLabel;
19 |
20 | @property (nonatomic) UILabel * nameLabel;
21 |
22 | @property (nonatomic) NSString * name;
23 |
24 | @property (nonatomic) NSString * status;
25 |
26 | @property (nonatomic) FBShimmeringView * shimmeringView;
27 |
28 | @property (nonatomic) BOOL displayed;
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/HydroTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | catchlab.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Today/TodayViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // TodayViewController.h
3 | // Today
4 | //
5 | // Created by NIX on 14/12/26.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "VPNButton.h"
11 |
12 | @interface TodayViewController : UIViewController
13 |
14 | @property (weak, nonatomic) IBOutlet VPNButton *country1;
15 |
16 | @property (weak, nonatomic) IBOutlet VPNButton *country2;
17 | @property (weak, nonatomic) IBOutlet VPNButton *country3;
18 | @property (weak, nonatomic) IBOutlet UILabel *signInLabel;
19 | @property (weak, nonatomic) IBOutlet VPNButton *country4;
20 | @property (weak, nonatomic) IBOutlet NSLayoutConstraint *countrySpaceConstraint;
21 | @property (weak, nonatomic) IBOutlet NSLayoutConstraint *country2SpaceConstraint;
22 | @property (weak, nonatomic) IBOutlet NSLayoutConstraint *country3SpaceConstraint;
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/Hydro/config.json.example:
--------------------------------------------------------------------------------
1 | {
2 | "stations": [
3 | {
4 | "name":"Singapore",
5 | "host":"domain.com",
6 | "short_name":"flag_sg",
7 | "x":0.55,
8 | "y":0.40
9 | },
10 | {
11 | "name":"HongKong",
12 | "host":"domain.com",
13 | "short_name":"HK",
14 | "x":0.65,
15 | "y":0.20
16 | },
17 | {
18 | "name":"Japan",
19 | "host":"domain.com",
20 | "short_name":"JP",
21 | "x":0.73,
22 | "y":0.15
23 | },
24 | {
25 | "name":"United States",
26 | "host":"domain.com",
27 | "short_name":"flag_us",
28 | "x":-0.5,
29 | "y":0.15
30 | }
31 | ],
32 | "server": "http://domain.com",
33 | "server_auth": "/path",
34 | "can_do_invite": "/path",
35 | "do_invite": "/path",
36 | "validate_user": "/path"
37 | }
38 |
--------------------------------------------------------------------------------
/Hydro/HydroHelper/HydroHelper.m:
--------------------------------------------------------------------------------
1 | //
2 | // HydroHelper.m
3 | // Hydro
4 | //
5 | // Created by kevinzhow on 14/12/25.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import "HydroHelper.h"
10 |
11 | NSString *const CCNFillUserInfo = @"CCFillUserInfo";
12 | NSString *const CCNFilterStationStatus = @"CCNFilterStationStatus";
13 |
14 | @implementation HydroHelper
15 |
16 | + (UIImage *)imageFromColor:(UIColor*)color
17 | {
18 | CGRect rect = CGRectMake(0, 0, 1, 1);
19 | UIGraphicsBeginImageContext(rect.size);
20 | CGContextRef context = UIGraphicsGetCurrentContext();
21 | CGContextSetFillColorWithColor(context,
22 | [color CGColor]);
23 | // [[UIColor colorWithRed:222./255 green:227./255 blue: 229./255 alpha:1] CGColor]) ;
24 | CGContextFillRect(context, rect);
25 | UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
26 | UIGraphicsEndImageContext();
27 | return img;
28 | }
29 |
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/Crashlytics.framework/Versions/A/Resources/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | English
7 | CFBundleExecutable
8 | Crashlytics
9 | CFBundleIdentifier
10 | com.crashlytics.ios
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | Crashlytics
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 2.2.10
19 | CFBundleSupportedPlatforms
20 |
21 | iPhoneOS
22 |
23 | CFBundleVersion
24 | 45
25 | DTPlatformName
26 | iphoneos
27 | MinimumOSVersion
28 | 4.0
29 |
30 |
31 |
--------------------------------------------------------------------------------
/HydroTests/HydroTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // HydroTests.m
3 | // HydroTests
4 | //
5 | // Created by kevinzhow on 14/12/25.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface HydroTests : XCTestCase
13 |
14 | @end
15 |
16 | @implementation HydroTests
17 |
18 | - (void)setUp {
19 | [super setUp];
20 | // Put setup code here. This method is called before the invocation of each test method in the class.
21 | }
22 |
23 | - (void)tearDown {
24 | // Put teardown code here. This method is called after the invocation of each test method in the class.
25 | [super tearDown];
26 | }
27 |
28 | - (void)testExample {
29 | // This is an example of a functional test case.
30 | XCTAssert(YES, @"Pass");
31 | }
32 |
33 | - (void)testPerformanceExample {
34 | // This is an example of a performance test case.
35 | [self measureBlock:^{
36 | // Put the code you want to measure the time of here.
37 | }];
38 | }
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/Today/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | Hydro
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | catchlab.Hydro.$(PRODUCT_NAME:rfc1034identifier)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | XPC!
19 | CFBundleShortVersionString
20 | 1.1.5
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 12
25 | NSExtension
26 |
27 | NSExtensionMainStoryboard
28 | MainInterface
29 | NSExtensionPointIdentifier
30 | com.apple.widget-extension
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/Hydro/VCIPsecVPNManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // VCIPsecVPNManager.h
3 | // VPNCloud
4 | //
5 | // Created by kevinzhow on 14/11/12.
6 | // Copyright (c) 2014年 Kingaxis Inc. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 |
13 | @interface VCIPsecVPNManager : NSObject
14 |
15 | @property (nonatomic) NEVPNManager * vpnManager;
16 |
17 | -(void)prepareWithCompletion:(void (^)(NSError *error))done;
18 |
19 | -(void)connectIPSecIKEv2WithHost:(NSString *)host andUsername:(NSString *)username andPassword:(NSString *)password andP12Name:(NSString *)p12Name andidentityDataPassword:(NSString *)identityDataPassword andGroupName:(NSString *)groupName;
20 |
21 | -(void)connectIPSecWithHost:(NSString *)host andUsername:(NSString *)username andPassword:(NSString *)password andPSK:(NSString *)psk andGroupName:(NSString *)groupName;
22 |
23 | -(void)connectIPSecIKEv2WithHost:(NSString *)host andUsername:(NSString *)username andPassword:(NSString *)password andPSK:(NSString *)psk andGroupName:(NSString *)groupName;
24 |
25 | @property (nonatomic) BOOL IKEv1Enabled;
26 |
27 | @property (nonatomic) BOOL IKEv2Enabled;
28 |
29 | @end
30 |
--------------------------------------------------------------------------------
/Hydro/Cell/StationTableViewCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // StationTableViewCell.h
3 | // Hydro
4 | //
5 | // Created by kevinzhow on 14/12/25.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 |
13 | @interface StationTableViewCell : UITableViewCell
14 |
15 | @property (weak, nonatomic) IBOutlet UIImageView *statusIcon;
16 |
17 | @property (nonatomic) NSString * domain;
18 |
19 | @property (weak, nonatomic) IBOutlet UIImageView *flagImageView;
20 |
21 | @property (weak, nonatomic) IBOutlet UILabel *stationNameLabel;
22 |
23 | @property (nonatomic) BOOL isPing;
24 |
25 | @property (nonatomic) int stopPingCount;
26 |
27 | @property (nonatomic) NSMutableArray * allPingResult;
28 |
29 | @property (nonatomic) GBPing * ping;
30 |
31 | @property (nonatomic) float rtt;
32 |
33 | @property (weak, nonatomic) IBOutlet UIImageView *checkStatusIcon;
34 |
35 | @property (nonatomic) NSDictionary * stationDic;
36 |
37 | -(void)makeCheck;
38 |
39 | @property (nonatomic) BOOL checked;
40 |
41 | -(void)setDomain:(NSString *)domain withIndex:(NSInteger)index;
42 | @property (nonatomic) NSInteger failCount;
43 |
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/Hydro/stationDelegate/VPNStations.m:
--------------------------------------------------------------------------------
1 | //
2 | // VPNStations.m
3 | // Hydro
4 | //
5 | // Created by NIX on 14/12/26.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import "VPNStations.h"
10 |
11 | @interface VPNStations()
12 |
13 | @end
14 |
15 | @implementation VPNStations
16 |
17 | + (VPNStations *)sharedInstance
18 | {
19 | static VPNStations *_sharedInstance = nil;
20 |
21 | static dispatch_once_t onceToken;
22 | dispatch_once(&onceToken, ^{
23 | _sharedInstance = [[VPNStations alloc] init];
24 | });
25 |
26 | return _sharedInstance;
27 | }
28 |
29 | - (id)init{
30 | self = [super init];
31 | if (self) {
32 |
33 | NSString *filePath = [[NSBundle mainBundle] pathForResource:@"config" ofType:@"json"];
34 | NSData *JSONData = [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:nil];
35 | NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:JSONData options:NSJSONReadingMutableContainers error:nil];
36 | self.stations = [jsonObject valueForKey:@"stations"];
37 | self.config = jsonObject;
38 |
39 | }
40 | return self;
41 | }
42 |
43 |
44 | @end
45 |
--------------------------------------------------------------------------------
/Hydro/Button/HydroButton.m:
--------------------------------------------------------------------------------
1 | //
2 | // HydroButton.m
3 | // Hydro
4 | //
5 | // Created by kevinzhow on 14/12/25.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import "HydroButton.h"
10 | #import
11 |
12 | @implementation HydroButton
13 |
14 | /*
15 | // Only override drawRect: if you perform custom drawing.
16 | // An empty implementation adversely affects performance during animation.
17 | - (void)drawRect:(CGRect)rect {
18 | // Drawing code
19 | }
20 | */
21 |
22 |
23 | - (void)touchDown {
24 | [self.layer pop_removeAnimationForKey:@"AnimationScaleBack"];
25 | POPSpringAnimation *anim =
26 | [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
27 | anim.springBounciness = 10;
28 | anim.springSpeed = 20;
29 | anim.toValue = [NSValue valueWithCGPoint:CGPointMake(0.8, 0.8)];
30 | [self.layer pop_addAnimation:anim forKey:@"AnimationScale"];
31 | }
32 |
33 |
34 |
35 | - (void)touchUpInside{
36 |
37 | [self.layer pop_removeAnimationForKey:@"AnimationScale"];
38 | POPSpringAnimation *anim =
39 | [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
40 | anim.springBounciness = 10;
41 | anim.springSpeed = 20;
42 | anim.toValue = [NSValue valueWithCGPoint:CGPointMake(1.0, 1.0)];
43 | [self.layer pop_addAnimation:anim forKey:@"AnimationScaleBack"];
44 |
45 |
46 | }
47 |
48 |
49 | @end
50 |
--------------------------------------------------------------------------------
/Hydro/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | catchlab.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.1.5
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 12
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UIStatusBarHidden
34 |
35 | UIStatusBarStyle
36 | UIStatusBarStyleLightContent
37 | UISupportedInterfaceOrientations
38 |
39 | UIInterfaceOrientationPortrait
40 |
41 | UIViewControllerBasedStatusBarAppearance
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - AFNetworking (2.5.4):
3 | - AFNetworking/NSURLConnection (= 2.5.4)
4 | - AFNetworking/NSURLSession (= 2.5.4)
5 | - AFNetworking/Reachability (= 2.5.4)
6 | - AFNetworking/Security (= 2.5.4)
7 | - AFNetworking/Serialization (= 2.5.4)
8 | - AFNetworking/UIKit (= 2.5.4)
9 | - AFNetworking/NSURLConnection (2.5.4):
10 | - AFNetworking/Reachability
11 | - AFNetworking/Security
12 | - AFNetworking/Serialization
13 | - AFNetworking/NSURLSession (2.5.4):
14 | - AFNetworking/Reachability
15 | - AFNetworking/Security
16 | - AFNetworking/Serialization
17 | - AFNetworking/Reachability (2.5.4)
18 | - AFNetworking/Security (2.5.4)
19 | - AFNetworking/Serialization (2.5.4)
20 | - AFNetworking/UIKit (2.5.4):
21 | - AFNetworking/NSURLConnection
22 | - AFNetworking/NSURLSession
23 | - GBPing (1.1.1)
24 | - GVUserDefaults (1.0.1)
25 | - pop (1.0.7)
26 | - SAMTextField (0.1.2)
27 | - Shimmer (1.0.2)
28 | - SVProgressHUD (1.1.3)
29 | - TPKeyboardAvoiding (1.2.6)
30 |
31 | DEPENDENCIES:
32 | - AFNetworking
33 | - GBPing
34 | - GVUserDefaults
35 | - pop
36 | - SAMTextField
37 | - Shimmer
38 | - SVProgressHUD
39 | - TPKeyboardAvoiding
40 |
41 | SPEC CHECKSUMS:
42 | AFNetworking: 05edc0ac4c4c8cf57bcf4b84be5b0744b6d8e71e
43 | GBPing: 96434766235731ff5b4573584fac8add16b31f71
44 | GVUserDefaults: acb40729f70984008d0650e49d7e422f1bbfa597
45 | pop: 628ffc631644601567ee8bfaaaea493ebd7d0923
46 | SAMTextField: a0f4eb5b48b45aef56453c265262b45154bc3e2a
47 | Shimmer: c5374be1c2b0c9e292fb05b339a513cf291cac86
48 | SVProgressHUD: 748080e4f36e603f6c02aec292664239df5279c1
49 | TPKeyboardAvoiding: ee4dd35e3bb7bb64bfbda47e7cc9ba872ff10f77
50 |
51 | COCOAPODS: 0.38.2
52 |
--------------------------------------------------------------------------------
/Hydro.xcworkspace/xcshareddata/Hydro.xcscmblueprint:
--------------------------------------------------------------------------------
1 | {
2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "AD9AE3CADFCF220BDF608F8FE2C3794930E9FBE8",
3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
4 |
5 | },
6 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
7 | "66ECCB7E69137BF099D26851106CA4CBC27A9471" : 0,
8 | "AD9AE3CADFCF220BDF608F8FE2C3794930E9FBE8" : 0
9 | },
10 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "CFBCE743-3F8E-41D8-8437-8AABAB64B189",
11 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
12 | "66ECCB7E69137BF099D26851106CA4CBC27A9471" : "Hydro",
13 | "AD9AE3CADFCF220BDF608F8FE2C3794930E9FBE8" : "Hydro_Opensource"
14 | },
15 | "DVTSourceControlWorkspaceBlueprintNameKey" : "Hydro",
16 | "DVTSourceControlWorkspaceBlueprintVersion" : 203,
17 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "Hydro.xcworkspace",
18 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
19 | {
20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/CatchChat\/Hydro.git",
21 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "66ECCB7E69137BF099D26851106CA4CBC27A9471"
23 | },
24 | {
25 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:CatchChat\/Hydro.network.git",
26 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
27 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "AD9AE3CADFCF220BDF608F8FE2C3794930E9FBE8"
28 | }
29 | ]
30 | }
--------------------------------------------------------------------------------
/Hydro/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "29x29",
5 | "idiom" : "iphone",
6 | "filename" : "icon-iphone_29@2x.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "29x29",
11 | "idiom" : "iphone",
12 | "filename" : "icon-iphone_29@3x.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "40x40",
17 | "idiom" : "iphone",
18 | "filename" : "icon-iphone_40@2x.png",
19 | "scale" : "2x"
20 | },
21 | {
22 | "size" : "40x40",
23 | "idiom" : "iphone",
24 | "filename" : "icon-iphone_40@3x.png",
25 | "scale" : "3x"
26 | },
27 | {
28 | "size" : "60x60",
29 | "idiom" : "iphone",
30 | "filename" : "icon-iphone_60@2x.png",
31 | "scale" : "2x"
32 | },
33 | {
34 | "size" : "60x60",
35 | "idiom" : "iphone",
36 | "filename" : "icon-iphone_60@3x.png",
37 | "scale" : "3x"
38 | },
39 | {
40 | "size" : "29x29",
41 | "idiom" : "ipad",
42 | "filename" : "icon-iphone_29.png",
43 | "scale" : "1x"
44 | },
45 | {
46 | "size" : "29x29",
47 | "idiom" : "ipad",
48 | "filename" : "icon-iphone_29@2x-1.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "40x40",
53 | "idiom" : "ipad",
54 | "filename" : "icon-iphone_40@2x-1.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "size" : "40x40",
59 | "idiom" : "ipad",
60 | "filename" : "icon-iphone_40@3x-1.png",
61 | "scale" : "2x"
62 | },
63 | {
64 | "size" : "76x76",
65 | "idiom" : "ipad",
66 | "filename" : "icon-ipad_76.png",
67 | "scale" : "1x"
68 | },
69 | {
70 | "size" : "76x76",
71 | "idiom" : "ipad",
72 | "filename" : "icon-ipad_76@2x.png",
73 | "scale" : "2x"
74 | }
75 | ],
76 | "info" : {
77 | "version" : 1,
78 | "author" : "xcode"
79 | }
80 | }
--------------------------------------------------------------------------------
/Hydro/Views/scaleView.m:
--------------------------------------------------------------------------------
1 | //
2 | // scaleView.m
3 | // Hydro
4 | //
5 | // Created by kevinzhow on 14/12/25.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import "scaleView.h"
10 | #import
11 |
12 | @implementation scaleView
13 |
14 | /*
15 | // Only override drawRect: if you perform custom drawing.
16 | // An empty implementation adversely affects performance during animation.
17 | - (void)drawRect:(CGRect)rect {
18 | // Drawing code
19 | }
20 | */
21 |
22 |
23 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
24 | [self.layer pop_removeAnimationForKey:@"AnimationScaleBack"];
25 | POPSpringAnimation *anim =
26 | [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
27 | anim.springBounciness = 10;
28 | anim.springSpeed = 20;
29 | anim.fromValue = [NSValue valueWithCGPoint:CGPointMake(1.0, 1.0)];
30 | anim.toValue = [NSValue valueWithCGPoint:CGPointMake(0.8, 0.8)];
31 | [self.layer pop_addAnimation:anim forKey:@"AnimationScale"];
32 | }
33 |
34 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
35 | [self.layer pop_removeAnimationForKey:@"AnimationScale"];
36 | POPSpringAnimation *anim =
37 | [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
38 | anim.springBounciness = 10;
39 | anim.springSpeed = 20;
40 | anim.fromValue = [NSValue valueWithCGPoint:CGPointMake(0.8, 0.8)];
41 | anim.toValue = [NSValue valueWithCGPoint:CGPointMake(1.0, 1.0)];
42 | [self.layer pop_addAnimation:anim forKey:@"AnimationScaleBack"];
43 | }
44 |
45 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
46 |
47 | [self.layer pop_removeAnimationForKey:@"AnimationScale"];
48 | POPSpringAnimation *anim =
49 | [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
50 | anim.springBounciness = 10;
51 | anim.springSpeed = 20;
52 | anim.fromValue = [NSValue valueWithCGPoint:CGPointMake(0.8, 0.8)];
53 | anim.toValue = [NSValue valueWithCGPoint:CGPointMake(1.0, 1.0)];
54 | [self.layer pop_addAnimation:anim forKey:@"AnimationScaleBack"];
55 |
56 |
57 |
58 | }
59 |
60 | @end
61 |
--------------------------------------------------------------------------------
/Hydro/Base.lproj/LaunchScreen.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 |
--------------------------------------------------------------------------------
/Hydro/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // Hydro
4 | //
5 | // Created by kevinzhow on 14/12/25.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 | #import
11 |
12 | @interface AppDelegate ()
13 |
14 | @end
15 |
16 | @implementation AppDelegate
17 |
18 |
19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
20 | // Override point for customization after application launch.
21 | [Crashlytics startWithAPIKey:@"de004490005a062fa95a4d5676a7edbfbe42c582"];
22 | application.applicationSupportsShakeToEdit = YES;
23 |
24 | return YES;
25 | }
26 |
27 | - (void)applicationWillResignActive:(UIApplication *)application {
28 | // 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.
29 | // 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.
30 | }
31 |
32 | - (void)applicationDidEnterBackground:(UIApplication *)application {
33 | // 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.
34 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
35 | }
36 |
37 | - (void)applicationWillEnterForeground:(UIApplication *)application {
38 | // 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.
39 | }
40 |
41 | - (void)applicationDidBecomeActive:(UIApplication *)application {
42 | // 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.
43 | }
44 |
45 | - (void)applicationWillTerminate:(UIApplication *)application {
46 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
47 | }
48 |
49 | @end
50 |
--------------------------------------------------------------------------------
/Today/VPNButton.m:
--------------------------------------------------------------------------------
1 | //
2 | // VPNButton.m
3 | // Hydro
4 | //
5 | // Created by NIX on 14/12/26.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import "VPNButton.h"
10 | #import "HydroHelper.h"
11 |
12 | @interface VPNButton()
13 |
14 | @property (nonatomic, strong) CAShapeLayer *maskShapeLayer;
15 | @property (nonatomic, strong) CAShapeLayer *stateShapeLayer;
16 |
17 | @end
18 |
19 | @implementation VPNButton
20 |
21 | - (void)awakeFromNib
22 | {
23 | [super awakeFromNib];
24 |
25 | self.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.12];
26 |
27 | [self setBackgroundImage:[HydroHelper imageFromColor:[UIColor colorWithWhite:0.0 alpha:0.32]] forState:UIControlStateHighlighted];
28 | }
29 |
30 | - (CAShapeLayer *)maskShapeLayer
31 | {
32 | if (!_maskShapeLayer) {
33 | _maskShapeLayer = [CAShapeLayer layer];
34 |
35 | self.layer.mask = _maskShapeLayer;
36 | }
37 |
38 | return _maskShapeLayer;
39 | }
40 |
41 | - (CAShapeLayer *)stateShapeLayer
42 | {
43 | if (!_stateShapeLayer) {
44 | _stateShapeLayer = [CAShapeLayer layer];
45 | _stateShapeLayer.lineWidth = 3.0;
46 | _stateShapeLayer.strokeColor = [UIColor clearColor].CGColor;
47 | _stateShapeLayer.fillColor = [UIColor clearColor].CGColor;
48 | _stateShapeLayer.lineJoin = @"round";
49 | _stateShapeLayer.lineCap = @"round";
50 |
51 | [self.layer addSublayer:_stateShapeLayer];
52 | }
53 |
54 | return _stateShapeLayer;
55 | }
56 |
57 | - (UIBezierPath *)polygonPathWithRect:(CGRect)rect slides:(NSInteger)slides rotationAngle:(CGFloat)rotationAngle scale:(CGFloat)scale;
58 | {
59 | CGFloat radius = MIN(rect.size.width, rect.size.height) * 0.5 * scale;
60 | CGFloat stepAngle = M_PI * 2.0 / slides;
61 | CGPoint center = CGPointMake(rect.size.width * 0.5, rect.size.height * 0.5);
62 |
63 | UIBezierPath *path = [UIBezierPath bezierPath];
64 | [path moveToPoint:CGPointMake(center.x + radius * cosf(0 + stepAngle * 0.5), center.y + radius * sinf(0 + stepAngle * 0.5))];
65 |
66 | for (NSInteger i = 1; i < 6; i++) {
67 | CGFloat angle = stepAngle * (i);
68 | [path addLineToPoint:CGPointMake(center.x + radius * cosf(angle + stepAngle * 0.5), center.y + radius * sinf(angle + stepAngle * 0.5))];
69 | }
70 |
71 | [path closePath];
72 |
73 | return path;
74 | }
75 |
76 | - (void)layoutSubviews
77 | {
78 | [super layoutSubviews];
79 |
80 | UIBezierPath *maskPath = [self polygonPathWithRect:self.bounds slides:6 rotationAngle:M_PI / 6.0 scale:1.0];
81 | self.maskShapeLayer.path = maskPath.CGPath;
82 |
83 | UIBezierPath *statePath = [self polygonPathWithRect:self.bounds slides:6 rotationAngle:M_PI / 6.0 scale:0.9];
84 | self.stateShapeLayer.path = statePath.CGPath;
85 | }
86 |
87 | - (void)setButtonState:(VPNButtonState)buttonState
88 | {
89 | _buttonState = buttonState;
90 |
91 | NSArray *colors = @[
92 | [UIColor clearColor],
93 | [UIColor yellowColor],
94 | [UIColor colorWithRed:60/255.0 green:171/255.0 blue:218/255.0 alpha:1.0],
95 | [UIColor lightGrayColor],
96 | ];
97 |
98 | UIColor *color = colors[_buttonState % colors.count];
99 | self.stateShapeLayer.strokeColor = color.CGColor;
100 | }
101 |
102 | @end
103 |
--------------------------------------------------------------------------------
/Hydro/Views/stationView.m:
--------------------------------------------------------------------------------
1 | //
2 | // stationView.m
3 | // Hydro
4 | //
5 | // Created by kevinzhow on 14/12/25.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import "stationView.h"
10 | #import "HydroHelper.h"
11 |
12 |
13 | @implementation stationView
14 |
15 |
16 | -(id)initWithFrame:(CGRect)frame
17 | {
18 | self = [super initWithFrame:frame];
19 |
20 | if (self) {
21 |
22 | float flagWidth = self.frame.size.width /5;
23 | self.stationFlag = [[UIImageView alloc] initWithFrame:CGRectMake(self.frame.size.width/2.0 - flagWidth/2.0, 30, flagWidth, self.frame.size.height / 2)];
24 | [self addSubview:self.stationFlag];
25 | self.stationFlag.contentMode = UIViewContentModeScaleAspectFit;
26 |
27 | self.nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, self.stationFlag.frame.size.height + 15.0, frame.size.width, 35.0)];
28 | self.nameLabel.textColor = [UIColor whiteColor];
29 | self.nameLabel.font = [UIFont fontWithName:@"Avenir-Medium" size:28.0];
30 | self.nameLabel.textAlignment = NSTextAlignmentCenter;
31 | [self addSubview:self.nameLabel];
32 |
33 | self.statusLabel = [[UILabel alloc] initWithFrame:CGRectZero];
34 | self.statusLabel.textColor = [UIColor whiteColor];
35 | self.statusLabel.font = [UIFont fontWithName:@"Avenir" size:16.0];
36 | self.statusLabel.textAlignment = NSTextAlignmentCenter;
37 | [self addSubview:self.statusLabel];
38 |
39 | self.stationStatusIcon = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
40 |
41 | [self addSubview:self.stationStatusIcon];
42 |
43 |
44 | self.shimmeringView = [[FBShimmeringView alloc] initWithFrame:self.statusLabel.bounds];
45 | [self addSubview:self.shimmeringView];
46 |
47 | self.shimmeringView.shimmeringSpeed = 80.0;
48 |
49 | self.shimmeringView.contentView = self.statusLabel;
50 |
51 | _status = @"Disconnected";
52 |
53 |
54 | }
55 |
56 | return self;
57 | }
58 |
59 |
60 | -(void)setName:(NSString *)name
61 | {
62 | _name = name;
63 | self.nameLabel.text = name;
64 | }
65 |
66 |
67 | -(void)setStatus:(NSString *)status
68 | {
69 | _status = status;
70 | self.statusLabel.text = status;
71 | [self.statusLabel sizeToFit];
72 |
73 | self.shimmeringView.frame = self.statusLabel.frame;
74 |
75 | if ([status isEqualToString:@"Connected"]) {
76 | // Start shimmering.
77 | self.shimmeringView.shimmering = NO;
78 | self.shimmeringView.center = CGPointMake(SCREEN_WIDTH/2.0 + 5.0, self.nameLabel.center.y + self.nameLabel.frame.size.height / 2 + 15.0);
79 | self.stationStatusIcon.image = [UIImage imageNamed:@"1"];
80 | }else{
81 | // Start shimmering.
82 | self.shimmeringView.shimmering = YES;
83 | self.stationStatusIcon.image = nil;
84 | self.shimmeringView.center = CGPointMake(SCREEN_WIDTH/2.0, self.nameLabel.center.y + self.nameLabel.frame.size.height / 2 + 15.0);
85 | }
86 |
87 | self.stationStatusIcon.center = CGPointMake(self.shimmeringView.center.x - self.shimmeringView.frame.size.width /2.0 - 10.0, self.nameLabel.center.y + self.nameLabel.frame.size.height / 2 + 15.0);
88 |
89 |
90 | }
91 | /*
92 | // Only override drawRect: if you perform custom drawing.
93 | // An empty implementation adversely affects performance during animation.
94 | - (void)drawRect:(CGRect)rect {
95 | // Drawing code
96 | }
97 | */
98 |
99 | @end
100 |
--------------------------------------------------------------------------------
/Hydro/VCKetChain.m:
--------------------------------------------------------------------------------
1 | //
2 | // VCKetChain.m
3 | // VPNCloud
4 | //
5 | // Created by kevinzhow on 14/11/12.
6 | // Copyright (c) 2014年 Kingaxis Inc. All rights reserved.
7 | //
8 |
9 | #import "VCKetChain.h"
10 | #import
11 |
12 | @implementation VCKetChain
13 | -(id) initWithService:(NSString *) service_ withGroup:(NSString*)group_
14 | {
15 | self =[super init];
16 | if(self)
17 | {
18 | service = [NSString stringWithString:service_];
19 |
20 | if(group_)
21 | group = [NSString stringWithString:group_];
22 | }
23 |
24 | return self;
25 | }
26 | -(NSMutableDictionary*) prepareDict:(NSString *) key
27 | {
28 |
29 | NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
30 | [dict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
31 |
32 | NSData *encodedKey = [key dataUsingEncoding:NSUTF8StringEncoding];
33 | [dict setObject:encodedKey forKey:(__bridge id)kSecAttrGeneric];
34 | [dict setObject:encodedKey forKey:(__bridge id)kSecAttrAccount];
35 | [dict setObject:service forKey:(__bridge id)kSecAttrService];
36 | [dict setObject:@YES forKey:(__bridge id)kSecReturnPersistentRef];
37 | [dict setObject:(__bridge id)kSecAttrAccessibleAlwaysThisDeviceOnly forKey:(__bridge id)kSecAttrAccessible];
38 |
39 | //This is for sharing data across apps
40 | if(group != nil)
41 | [dict setObject:group forKey:(__bridge id)kSecAttrAccessGroup];
42 |
43 | return dict;
44 |
45 | }
46 | -(BOOL) insert:(NSString *)key : (NSData *)data
47 | {
48 | NSMutableDictionary * dict =[self prepareDict:key];
49 | [dict setObject:data forKey:(__bridge id)kSecValueData];
50 |
51 | OSStatus status = SecItemAdd((__bridge CFDictionaryRef)dict, NULL);
52 | if(errSecSuccess != status) {
53 | NSLog(@"Unable add item with key =%@ error:%ld",key,status);
54 | }
55 | return (errSecSuccess == status);
56 | }
57 |
58 |
59 | static NSString * const serviceName = @"im.zorro.ipsec_demo.vpn_config";
60 | -(NSData*) find:(NSString*)key
61 | {
62 |
63 | // NSMutableDictionary *searchDictionary = [[NSMutableDictionary alloc] init];
64 | //
65 | // NSData *encodedIdentifier = [key dataUsingEncoding:NSUTF8StringEncoding];
66 | //
67 | // searchDictionary[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword;
68 | // searchDictionary[(__bridge id)kSecAttrGeneric] = encodedIdentifier;
69 | // searchDictionary[(__bridge id)kSecAttrAccount] = encodedIdentifier;
70 | // searchDictionary[(__bridge id)kSecAttrService] = serviceName;
71 | //
72 | // searchDictionary[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne;
73 | // searchDictionary[(__bridge id)kSecReturnPersistentRef] = @YES;
74 | //
75 | // CFTypeRef result = NULL;
76 | // SecItemCopyMatching((__bridge CFDictionaryRef)searchDictionary, &result);
77 | //
78 | // return (__bridge_transfer NSData *)result;
79 |
80 |
81 | NSMutableDictionary *dict = [self prepareDict:key];
82 | [dict setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
83 | // [dict setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
84 | CFTypeRef result = NULL;
85 | OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)dict,&result);
86 |
87 | if( status != errSecSuccess) {
88 | NSLog(@"Unable to fetch item for key %@ with error:%ld",key,status);
89 | return nil;
90 | }
91 |
92 | return (__bridge NSData *)result;
93 | }
94 |
95 |
96 |
97 | -(BOOL) update:(NSString*)key :(NSData*) data
98 | {
99 | NSMutableDictionary * dictKey =[self prepareDict:key];
100 |
101 | NSMutableDictionary * dictUpdate =[[NSMutableDictionary alloc] init];
102 | [dictUpdate setObject:data forKey:(__bridge id)kSecValueData];
103 |
104 | OSStatus status = SecItemUpdate((__bridge CFDictionaryRef)dictKey, (__bridge CFDictionaryRef)dictUpdate);
105 | if(errSecSuccess != status) {
106 | NSLog(@"Unable add update with key =%@ error:%ld",key,status);
107 | }
108 | return (errSecSuccess == status);
109 |
110 | return YES;
111 |
112 | }
113 | -(BOOL) remove: (NSString*)key
114 | {
115 | NSMutableDictionary *dict = [self prepareDict:key];
116 | OSStatus status = SecItemDelete((__bridge CFDictionaryRef)dict);
117 | if( status != errSecSuccess) {
118 | NSLog(@"Unable to remove item for key %@ with error:%ld",key,status);
119 | return NO;
120 | }
121 | return YES;
122 | }
123 | @end
124 |
--------------------------------------------------------------------------------
/Hydro/Views/locationView.m:
--------------------------------------------------------------------------------
1 | //
2 | // locationView.m
3 | // Hydro
4 | //
5 | // Created by kevinzhow on 14/12/26.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import "locationView.h"
10 | #import
11 |
12 | @implementation locationView
13 |
14 | /*
15 | // Only override drawRect: if you perform custom drawing.
16 | // An empty implementation adversely affects performance during animation.
17 | - (void)drawRect:(CGRect)rect {
18 | // Drawing code
19 | }
20 | */
21 |
22 | -(id)initWithFrame:(CGRect)frame{
23 | self = [super initWithFrame:frame];
24 | if (self) {
25 | self.backgroundColor = [UIColor clearColor];
26 | int radius = frame.size.width/6;
27 | int radius_2 = frame.size.width/6.0;
28 |
29 | self.circleShape = [CAShapeLayer layer];
30 | self.circleShape.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 2.0*radius, 2.0*radius)
31 | cornerRadius:radius].CGPath;;
32 | self.circleShape.strokeColor = [[UIColor whiteColor] CGColor];
33 | self.circleShape.fillColor = [UIColor whiteColor].CGColor;
34 | self.circleShape.lineWidth = 1.0;
35 |
36 | self.circleShape.position = CGPointMake(self.frame.size.width/2.0-radius,
37 | self.frame.size.height/2.0-radius);
38 |
39 | self.ringShape = [CAShapeLayer layer];
40 | self.ringShape.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 2.0*radius_2, 2.0*radius_2)
41 | cornerRadius:radius_2].CGPath;;
42 | self.ringShape.strokeColor = [[UIColor whiteColor] CGColor];
43 | self.ringShape.fillColor = nil;
44 | self.ringShape.lineWidth = 1.0;
45 |
46 |
47 | self.ringShape.position = CGPointMake(self.frame.size.width/2.0-radius_2,
48 | self.frame.size.height/2.0-radius_2);
49 |
50 | // Add CAShapeLayer to our view
51 |
52 | [self.layer addSublayer:self.circleShape];
53 | [self.layer addSublayer:self.ringShape];
54 |
55 | [self waveAnimation];
56 | }
57 |
58 | return self;
59 | }
60 |
61 |
62 | -(void)waveAnimation
63 | {
64 | int radius = self.frame.size.width/6;
65 | int radius_2 = self.frame.size.width/6.0;
66 |
67 | POPBasicAnimation *animAlpha = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerOpacity];
68 | animAlpha.fromValue = @1.0;
69 | animAlpha.toValue = @0.0;
70 | animAlpha.duration = 3.0;
71 | animAlpha.completionBlock = ^(POPAnimation *anim, BOOL finished) {
72 |
73 | if (finished) {
74 | [self waveAnimation];
75 | }};
76 | [self.ringShape pop_addAnimation:animAlpha forKey:@"AlphaMap"];
77 |
78 |
79 |
80 | CABasicAnimation * pathAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
81 | pathAnimation.fromValue = (id)[UIBezierPath bezierPathWithRoundedRect:CGRectMake(self.frame.size.width/2.0-radius_2, self.frame.size.height/2.0-radius_2, 2.0*radius_2, 2.0*radius_2)
82 | cornerRadius:radius_2].CGPath;;
83 | pathAnimation.toValue = (id)[UIBezierPath bezierPathWithRoundedRect:CGRectMake(self.frame.size.width/2.0-radius_2*8, self.frame.size.height/2.0-radius_2*8, 8.0*2*radius_2, 8.0*2*radius_2)
84 | cornerRadius:radius_2*8].CGPath;;
85 | pathAnimation.duration = 3.0f;
86 | pathAnimation.autoreverses = NO;
87 | pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
88 | [self.ringShape addAnimation:pathAnimation forKey:@"animationKey"];
89 |
90 | self.ringShape.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(self.frame.size.width/2.0-radius_2*8, self.frame.size.height/2.0-radius_2*8, 8.0*2*radius_2, 8.0*2*radius_2)
91 | cornerRadius:radius_2*8].CGPath;;
92 |
93 |
94 |
95 | CABasicAnimation * path2Animation = [CABasicAnimation animationWithKeyPath:@"path"];
96 | path2Animation.fromValue = (id)[UIBezierPath bezierPathWithRoundedRect:CGRectMake(self.frame.size.width/2.0-radius, self.frame.size.height/2.0-radius, 2.0*radius, 2.0*radius)
97 | cornerRadius:radius].CGPath;;
98 | path2Animation.toValue = (id)[UIBezierPath bezierPathWithRoundedRect:CGRectMake(self.frame.size.width/2.0-radius, self.frame.size.height/2.0-radius, 2.0*radius, 2.0*radius)
99 | cornerRadius:radius].CGPath;;
100 | path2Animation.duration = 3.0f;
101 | path2Animation.autoreverses = NO;
102 | path2Animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
103 | [self.circleShape addAnimation:path2Animation forKey:@"animationKey"];
104 |
105 | self.circleShape.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(self.frame.size.width/2.0-radius, self.frame.size.height/2.0-radius, 2.0*radius, 2.0*radius)
106 | cornerRadius:radius].CGPath;;
107 | }
108 |
109 |
110 | -(void)show
111 | {
112 | POPSpringAnimation *animAlpha = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerOpacity];
113 | animAlpha.toValue = @1.0;
114 | animAlpha.springBounciness = 0.5;
115 | animAlpha.springSpeed = 12.0;
116 | animAlpha.completionBlock = ^(POPAnimation *anim, BOOL finished) {
117 | if (finished) {}};
118 | [self.layer pop_addAnimation:animAlpha forKey:@"AlphaLocation"];
119 | }
120 |
121 | @end
122 |
--------------------------------------------------------------------------------
/Hydro/LoginViewController/LoginViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // LoginViewController.m
3 | // Hydro
4 | //
5 | // Created by kevinzhow on 14/12/25.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import "LoginViewController.h"
10 | #import
11 | #import "GVUserDefaults+Hydro.h"
12 | #import
13 | #import "VPNStations.h"
14 |
15 | @interface LoginViewController ()
16 |
17 | @end
18 |
19 | @implementation LoginViewController
20 |
21 | - (void)viewDidLoad {
22 | [super viewDidLoad];
23 | UITapGestureRecognizer *letterTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(highlightLetter:)];
24 | [self.view addGestureRecognizer:letterTapRecognizer];
25 | self.view.backgroundColor = [UIColor clearColor];
26 |
27 |
28 | self.emailtextfield.delegate = self;
29 | self.passwordField.delegate = self;
30 | self.passwordField.adjustsFontSizeToFitWidth = YES;
31 | self.passwordField.minimumFontSize = 12;
32 |
33 | self.emailtextfield.adjustsFontSizeToFitWidth = YES;
34 | self.emailtextfield.minimumFontSize = 12;
35 |
36 | self.passwordField.textEdgeInsets = UIEdgeInsetsMake(0.0f, 40.0f, 10.0f, 10.0f);
37 |
38 | UIFont *font = [UIFont fontWithName:@"Avenir-Medium" size:17.0];
39 | NSDictionary *attrsDictionary =
40 | [NSDictionary dictionaryWithObjectsAndKeys:font,NSFontAttributeName,
41 | [UIColor colorWithWhite:1.0 alpha:0.5], NSForegroundColorAttributeName,
42 | nil];
43 |
44 | NSAttributedString *attrString =
45 | [[NSAttributedString alloc] initWithString:@"Password"
46 | attributes:attrsDictionary];
47 |
48 | NSAttributedString *attrEmailString =
49 | [[NSAttributedString alloc] initWithString:@"Email"
50 | attributes:attrsDictionary];
51 |
52 | self.passwordField.attributedPlaceholder = attrString;
53 |
54 | self.emailtextfield.attributedPlaceholder = attrEmailString;
55 |
56 | self.emailtextfield.textEdgeInsets = UIEdgeInsetsMake(0.0f, 40.0f, 10.0f, 10.0f);
57 |
58 | // Do any additional setup after loading the view.
59 | }
60 |
61 |
62 | - (BOOL) textFieldShouldReturn:(UITextField *)textField
63 | {
64 | if (textField == self.emailtextfield)
65 | {
66 | [self.emailtextfield resignFirstResponder];
67 | [self.passwordField becomeFirstResponder];
68 | }
69 | else if (textField == self.passwordField)
70 | {
71 | [self.passwordField resignFirstResponder];
72 |
73 | [self doClickLoginButton:self];
74 | }
75 |
76 | return true;
77 | }
78 |
79 |
80 | -(IBAction) highlightLetter:(UITapGestureRecognizer*)recognizer
81 | {
82 | // UIView *view = [recognizer view];
83 | [self.view endEditing:YES];
84 | }
85 |
86 |
87 | - (void)didReceiveMemoryWarning {
88 | [super didReceiveMemoryWarning];
89 | // Dispose of any resources that can be recreated.
90 | }
91 |
92 | /*
93 | #pragma mark - Navigation
94 |
95 | // In a storyboard-based application, you will often want to do a little preparation before navigation
96 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
97 | // Get the new view controller using [segue destinationViewController].
98 | // Pass the selected object to the new view controller.
99 | }
100 | */
101 |
102 | - (IBAction)doClickLoginButton:(id)sender {
103 |
104 | if (self.emailtextfield.text.length < 1 || self.passwordField.text.length < 1) {
105 |
106 |
107 | return;
108 |
109 | }
110 |
111 | [SVProgressHUD show];
112 |
113 | AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
114 | NSDictionary *parameters = @{
115 | @"email": self.emailtextfield.text,
116 | @"password":self.passwordField.text
117 | };
118 | [manager POST:[NSString stringWithFormat:@"%@%@",[[VPNStations sharedInstance].config valueForKey:@"server"], [[VPNStations sharedInstance].config valueForKey:@"server_auth"]] parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
119 | NSLog(@"JSON: %@", responseObject);
120 |
121 |
122 | NSString * token = [responseObject valueForKey:@"message"];
123 | NSString * status = [responseObject valueForKey:@"status"];
124 | if([status isEqualToString:@"error"]){
125 |
126 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
127 | // time-consuming task
128 | dispatch_async(dispatch_get_main_queue(), ^{
129 | [SVProgressHUD showErrorWithStatus:@"Auth Error"];
130 | });
131 | });
132 | }else{
133 |
134 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
135 | // time-consuming task
136 | dispatch_async(dispatch_get_main_queue(), ^{
137 | [SVProgressHUD dismiss];
138 | });
139 | });
140 | [GVUserDefaults standardUserDefaults].token = token;
141 |
142 |
143 |
144 | [[NSNotificationCenter defaultCenter] postNotificationName:CCNFillUserInfo object:nil];
145 | [self dismissViewControllerAnimated:YES completion:^{
146 |
147 | }];
148 |
149 | NSUserDefaults *sharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.catchlab.TodayExtensionSharingDefaults"];
150 |
151 | [sharedDefaults setBool:YES forKey:@"ActiveToday"];
152 | [sharedDefaults synchronize]; // (!!) This is crucial.
153 | }
154 |
155 | } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
156 | NSLog(@"Error: %@", error);
157 |
158 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
159 | // time-consuming task
160 | dispatch_async(dispatch_get_main_queue(), ^{
161 | [SVProgressHUD dismiss];
162 | });
163 | });
164 | }];
165 |
166 |
167 | }
168 | @end
169 |
--------------------------------------------------------------------------------
/Hydro/Cell/StationTableViewCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // StationTableViewCell.m
3 | // Hydro
4 | //
5 | // Created by kevinzhow on 14/12/25.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import "StationTableViewCell.h"
10 | #import
11 | #import "HydroHelper.h"
12 |
13 | @implementation StationTableViewCell
14 |
15 | - (void)awakeFromNib {
16 | // Initialization code
17 | [[NSNotificationCenter defaultCenter] addObserver:self
18 | selector:@selector(filterStationStatus:)
19 | name:CCNFilterStationStatus
20 | object:nil];
21 | self.backgroundColor = [UIColor clearColor];
22 | }
23 |
24 |
25 | -(void)filterStationStatus:(NSNotification *)notification
26 | {
27 | NSDictionary * dict = notification.object;
28 | if (![[dict valueForKey:@"host"] isEqualToString:self.domain]) {
29 | [self uncheck];
30 | }else{
31 | if (!self.checked) {
32 | [self doCheck];
33 | }
34 | }
35 | }
36 |
37 | -(void)ping:(GBPing *)pinger didReceiveReplyWithSummary:(GBPingSummary *)summary {
38 |
39 | // NSLog(@"REPLY %@ > %@", pinger.host, summary);
40 | [self checkFinalStatusWith:pinger andSummert:summary];
41 |
42 | }
43 |
44 | -(void)checkFinalStatusWith:(GBPing *)pinger andSummert:(GBPingSummary *)summary
45 | {
46 | self.rtt += summary.rtt;
47 | if(self.stopPingCount < 5){
48 | self.stopPingCount += 1;
49 | [self.allPingResult addObject:summary];
50 |
51 | }else{
52 | self.isPing = NO;
53 | [self.ping stop];
54 | float status = self.rtt/self.stopPingCount * 1000;
55 | // NSLog(@"Result is %.3f", status);
56 |
57 | if (status < 150) {
58 | self.statusIcon.image = [UIImage imageNamed:@"1"];
59 | }else if (status >= 150 && status < 250){
60 | self.statusIcon.image = [UIImage imageNamed:@"2"];
61 | }else{
62 | self.statusIcon.image = [UIImage imageNamed:@"3"];
63 | }
64 |
65 | [self updateFailedCount];
66 |
67 | }
68 | }
69 |
70 | -(void)updateFailedCount
71 | {
72 | if (self.failCount / 5.0 > 0.2) {
73 | self.statusIcon.image = [UIImage imageNamed:@"3"];
74 | }
75 | }
76 |
77 | -(void)setDomain:(NSString *)domain withIndex:(NSInteger)index
78 | {
79 | _domain = domain;
80 |
81 |
82 | self.ping = [[GBPing alloc] init];
83 | self.ping.host = domain;
84 | self.ping.delegate = self;
85 | self.ping.timeout = 4;
86 | self.ping.pingPeriod = 0.3 + (0.1 * index);
87 | self.stopPingCount = 0;
88 | self.isPing = YES;
89 | self.allPingResult = [NSMutableArray new];
90 | self.failCount = 0;
91 |
92 | [self.ping setupWithBlock:^(BOOL success, NSError *error) { //necessary to resolve hostname
93 | if (success) {
94 | //start pinging
95 | [self.ping startPinging];
96 | }
97 | else {
98 | NSLog(@"failed to start");
99 | }
100 | }];
101 |
102 | }
103 |
104 | //-(void)ping:(GBPing *)pinger didReceiveUnexpectedReplyWithSummary:(GBPingSummary *)summary {
105 | // NSLog(@"BREPLY> %@", summary);
106 | // self.failCount += 1;
107 | // self.stopPingCount += 1;
108 | // [self checkFinalStatusWith:pinger andSummert:summary];
109 | //}
110 |
111 | //-(void)ping:(GBPing *)pinger didSendPingWithSummary:(GBPingSummary *)summary {
112 | // NSLog(@"SENT %@ > %@", pinger.host ,summary);
113 | //}
114 |
115 | -(void)ping:(GBPing *)pinger didTimeoutWithSummary:(GBPingSummary *)summary {
116 | NSLog(@"TIMOUT> %@", summary);
117 | self.failCount += 1;
118 | self.stopPingCount += 1;
119 | [self checkFinalStatusWith:pinger andSummert:summary];
120 | }
121 |
122 | -(void)ping:(GBPing *)pinger didFailWithError:(NSError *)error {
123 | NSLog(@"FAIL> %@", error);
124 | self.failCount += 1;
125 | self.stopPingCount += 1;
126 | [self updateFailedCount];
127 | }
128 | //
129 | -(void)ping:(GBPing *)pinger didFailToSendPingWithSummary:(GBPingSummary *)summary error:(NSError *)error {
130 | NSLog(@"FSENT> %@, %@", summary, error);
131 | self.failCount += 1;
132 | self.stopPingCount += 1;
133 | [self checkFinalStatusWith:pinger andSummert:summary];
134 | }
135 |
136 |
137 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
138 | [super setSelected:selected animated:animated];
139 |
140 | NSLog(@"Selected");
141 | // Configure the view for the selected state
142 | }
143 |
144 |
145 |
146 | -(void)makeCheck
147 | {
148 | if (self.checked) {
149 |
150 | }else{
151 | [self doCheck];
152 | }
153 | }
154 |
155 | -(void)uncheck
156 | {
157 | self.checked = NO;
158 | self.checkStatusIcon.image = nil;
159 | }
160 |
161 | -(void)doCheck{
162 |
163 | self.checked = YES;
164 | self.checkStatusIcon.image = [UIImage imageNamed:@"Check"];
165 | [[NSNotificationCenter defaultCenter] postNotificationName:CCNFilterStationStatus object:self.stationDic];
166 | }
167 |
168 | -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
169 | {
170 |
171 | POPSpringAnimation *anim =
172 | [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
173 | anim.springBounciness = 10;
174 | anim.springSpeed = 10;
175 | anim.fromValue = [NSValue valueWithCGPoint:CGPointMake(1.0, 1.0)];
176 | anim.toValue = [NSValue valueWithCGPoint:CGPointMake(0.9, 0.9)];
177 | [self.layer pop_addAnimation:anim forKey:@"AnimationScaleTo"];
178 | anim.completionBlock = ^(POPAnimation *anim, BOOL finished) {
179 | if (finished) {
180 |
181 | }
182 | };
183 |
184 | [super touchesBegan:touches withEvent:event];
185 | }
186 |
187 | -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
188 |
189 | POPSpringAnimation *anim =
190 | [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
191 | anim.springBounciness = 10;
192 | anim.springSpeed = 10;
193 | anim.fromValue = [NSValue valueWithCGPoint:CGPointMake(0.9, 0.9)];
194 | anim.toValue = [NSValue valueWithCGPoint:CGPointMake(1.0, 1.0)];
195 | [self.layer pop_addAnimation:anim forKey:@"AnimationScaleBack"];
196 | anim.completionBlock = ^(POPAnimation *anim, BOOL finished) {
197 | if (finished) {
198 |
199 | }
200 | };
201 |
202 | [super touchesEnded:touches withEvent:event];
203 | }
204 |
205 | -(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
206 | {
207 | POPSpringAnimation *anim =
208 | [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
209 | anim.springBounciness = 10;
210 | anim.springSpeed = 10;
211 | anim.fromValue = [NSValue valueWithCGPoint:CGPointMake(0.9, 0.9)];
212 | anim.toValue = [NSValue valueWithCGPoint:CGPointMake(1.0, 1.0)];
213 | [self.layer pop_addAnimation:anim forKey:@"AnimationScaleBack"];
214 | anim.completionBlock = ^(POPAnimation *anim, BOOL finished) {
215 | if (finished) {
216 |
217 | }
218 | };
219 |
220 | [super touchesCancelled:touches withEvent:event];
221 | }
222 |
223 | @end
224 |
--------------------------------------------------------------------------------
/Crashlytics.framework/Versions/A/Headers/Crashlytics.h:
--------------------------------------------------------------------------------
1 | //
2 | // Crashlytics.h
3 | // Crashlytics
4 | //
5 | // Copyright 2013 Crashlytics, Inc. All rights reserved.
6 | //
7 |
8 | #import
9 |
10 | /**
11 | *
12 | * The CLS_LOG macro provides as easy way to gather more information in your log messages that are
13 | * sent with your crash data. CLS_LOG prepends your custom log message with the function name and
14 | * line number where the macro was used. If your app was built with the DEBUG preprocessor macro
15 | * defined CLS_LOG uses the CLSNSLog function which forwards your log message to NSLog and CLSLog.
16 | * If the DEBUG preprocessor macro is not defined CLS_LOG uses CLSLog only.
17 | *
18 | * Example output:
19 | * -[AppDelegate login:] line 134 $ login start
20 | *
21 | * If you would like to change this macro, create a new header file, unset our define and then define
22 | * your own version. Make sure this new header file is imported after the Crashlytics header file.
23 | *
24 | * #undef CLS_LOG
25 | * #define CLS_LOG(__FORMAT__, ...) CLSNSLog...
26 | *
27 | **/
28 | #ifdef DEBUG
29 | #define CLS_LOG(__FORMAT__, ...) CLSNSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
30 | #else
31 | #define CLS_LOG(__FORMAT__, ...) CLSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
32 | #endif
33 |
34 | /**
35 | *
36 | * Add logging that will be sent with your crash data. This logging will not show up in the system.log
37 | * and will only be visible in your Crashlytics dashboard.
38 | *
39 | **/
40 | OBJC_EXTERN void CLSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
41 | OBJC_EXTERN void CLSLogv(NSString *format, va_list args) NS_FORMAT_FUNCTION(1,0);
42 |
43 | /**
44 | *
45 | * Add logging that will be sent with your crash data. This logging will show up in the system.log
46 | * and your Crashlytics dashboard. It is not recommended for Release builds.
47 | *
48 | **/
49 | OBJC_EXTERN void CLSNSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
50 | OBJC_EXTERN void CLSNSLogv(NSString *format, va_list args) NS_FORMAT_FUNCTION(1,0);
51 |
52 |
53 | @protocol CrashlyticsDelegate;
54 |
55 | @interface Crashlytics : NSObject
56 |
57 | @property (nonatomic, readonly, copy) NSString *apiKey;
58 | @property (nonatomic, readonly, copy) NSString *version;
59 | @property (nonatomic, assign) BOOL debugMode;
60 |
61 | @property (nonatomic, assign) NSObject *delegate;
62 |
63 | /**
64 | *
65 | * The recommended way to install Crashlytics into your application is to place a call
66 | * to +startWithAPIKey: in your -application:didFinishLaunchingWithOptions: method.
67 | *
68 | * This delay defaults to 1 second in order to generally give the application time to
69 | * fully finish launching.
70 | *
71 | **/
72 | + (Crashlytics *)startWithAPIKey:(NSString *)apiKey;
73 | + (Crashlytics *)startWithAPIKey:(NSString *)apiKey afterDelay:(NSTimeInterval)delay;
74 |
75 | /**
76 | *
77 | * If you need the functionality provided by the CrashlyticsDelegate protocol, you can use
78 | * these convenience methods to activate the framework and set the delegate in one call.
79 | *
80 | **/
81 | + (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(NSObject *)delegate;
82 | + (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(NSObject *)delegate afterDelay:(NSTimeInterval)delay;
83 |
84 | /**
85 | *
86 | * Access the singleton Crashlytics instance.
87 | *
88 | **/
89 | + (Crashlytics *)sharedInstance;
90 |
91 | /**
92 | *
93 | * The easiest way to cause a crash - great for testing!
94 | *
95 | **/
96 | - (void)crash;
97 |
98 | /**
99 | *
100 | * Many of our customers have requested the ability to tie crashes to specific end-users of their
101 | * application in order to facilitate responses to support requests or permit the ability to reach
102 | * out for more information. We allow you to specify up to three separate values for display within
103 | * the Crashlytics UI - but please be mindful of your end-user's privacy.
104 | *
105 | * We recommend specifying a user identifier - an arbitrary string that ties an end-user to a record
106 | * in your system. This could be a database id, hash, or other value that is meaningless to a
107 | * third-party observer but can be indexed and queried by you.
108 | *
109 | * Optionally, you may also specify the end-user's name or username, as well as email address if you
110 | * do not have a system that works well with obscured identifiers.
111 | *
112 | * Pursuant to our EULA, this data is transferred securely throughout our system and we will not
113 | * disseminate end-user data unless required to by law. That said, if you choose to provide end-user
114 | * contact information, we strongly recommend that you disclose this in your application's privacy
115 | * policy. Data privacy is of our utmost concern.
116 | *
117 | **/
118 | - (void)setUserIdentifier:(NSString *)identifier;
119 | - (void)setUserName:(NSString *)name;
120 | - (void)setUserEmail:(NSString *)email;
121 |
122 | + (void)setUserIdentifier:(NSString *)identifier;
123 | + (void)setUserName:(NSString *)name;
124 | + (void)setUserEmail:(NSString *)email;
125 |
126 | /**
127 | *
128 | * Set a value for a key to be associated with your crash data.
129 | *
130 | **/
131 | - (void)setObjectValue:(id)value forKey:(NSString *)key;
132 | - (void)setIntValue:(int)value forKey:(NSString *)key;
133 | - (void)setBoolValue:(BOOL)value forKey:(NSString *)key;
134 | - (void)setFloatValue:(float)value forKey:(NSString *)key;
135 |
136 | + (void)setObjectValue:(id)value forKey:(NSString *)key;
137 | + (void)setIntValue:(int)value forKey:(NSString *)key;
138 | + (void)setBoolValue:(BOOL)value forKey:(NSString *)key;
139 | + (void)setFloatValue:(float)value forKey:(NSString *)key;
140 |
141 | @end
142 |
143 | /**
144 | * The CLSCrashReport protocol exposes methods that you can call on crash report objects passed
145 | * to delegate methods. If you want these values or the entire object to stay in memory retain
146 | * them or copy them.
147 | **/
148 | @protocol CLSCrashReport
149 | @required
150 |
151 | /**
152 | * Returns the session identifier for the crash report.
153 | **/
154 | @property (nonatomic, readonly) NSString *identifier;
155 |
156 | /**
157 | * Returns the custom key value data for the crash report.
158 | **/
159 | @property (nonatomic, readonly) NSDictionary *customKeys;
160 |
161 | /**
162 | * Returns the CFBundleVersion of the application that crashed.
163 | **/
164 | @property (nonatomic, readonly) NSString *bundleVersion;
165 |
166 | /**
167 | * Returns the CFBundleShortVersionString of the application that crashed.
168 | **/
169 | @property (nonatomic, readonly) NSString *bundleShortVersionString;
170 |
171 | /**
172 | * Returns the date that the application crashed at.
173 | **/
174 | @property (nonatomic, readonly) NSDate *crashedOnDate;
175 |
176 | /**
177 | * Returns the os version that the application crashed on.
178 | **/
179 | @property (nonatomic, readonly) NSString *OSVersion;
180 |
181 | /**
182 | * Returns the os build version that the application crashed on.
183 | **/
184 | @property (nonatomic, readonly) NSString *OSBuildVersion;
185 |
186 | @end
187 |
188 | /**
189 | *
190 | * The CrashlyticsDelegate protocol provides a mechanism for your application to take
191 | * action on events that occur in the Crashlytics crash reporting system. You can make
192 | * use of these calls by assigning an object to the Crashlytics' delegate property directly,
193 | * or through the convenience startWithAPIKey:delegate:... methods.
194 | *
195 | **/
196 | @protocol CrashlyticsDelegate
197 | @optional
198 |
199 | /**
200 | *
201 | * Called once a Crashlytics instance has determined that the last execution of the
202 | * application ended in a crash. This is called some time after the crash reporting
203 | * process has begun. If you have specified a delay in one of the
204 | * startWithAPIKey:... calls, this will take at least that long to be invoked.
205 | *
206 | **/
207 | - (void)crashlyticsDidDetectCrashDuringPreviousExecution:(Crashlytics *)crashlytics;
208 |
209 | /**
210 | *
211 | * Just like crashlyticsDidDetectCrashDuringPreviousExecution this delegate method is
212 | * called once a Crashlytics instance has determined that the last execution of the
213 | * application ended in a crash. A CLSCrashReport is passed back that contains data about
214 | * the last crash report that was generated. See the CLSCrashReport protocol for method details.
215 | * This method is called after crashlyticsDidDetectCrashDuringPreviousExecution.
216 | *
217 | **/
218 | - (void)crashlytics:(Crashlytics *)crashlytics didDetectCrashDuringPreviousExecution:(id )crash;
219 |
220 | @end
221 |
222 | /**
223 | * `CrashlyticsKit` can be used as a parameter to `[Fabric with:@[CrashlyticsKit]];` in Objective-C. In Swift, simply use `Crashlytics()`
224 | */
225 | #define CrashlyticsKit [Crashlytics sharedInstance]
226 |
--------------------------------------------------------------------------------
/Today/TodayViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // TodayViewController.m
3 | // Today
4 | //
5 | // Created by NIX on 14/12/26.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import "TodayViewController.h"
10 | #import
11 | #import "VPNStations.h"
12 | #import "VCIPsecVPNManager.h"
13 | #import "VPNButton.h"
14 | #import "HydroHelper.h"
15 | #import
16 |
17 | @interface TodayViewController ()
18 |
19 | @property (strong, nonatomic) IBOutletCollection(VPNButton) NSArray *vpnButtons;
20 |
21 | @property (nonatomic, strong) VPNButton *currentButton;
22 |
23 | @property (nonatomic, strong) NSArray *vpnStations;
24 |
25 | @property (nonatomic, strong) VCIPsecVPNManager *vpnManager;
26 |
27 | @property (nonatomic) BOOL isPrepareProfile;
28 |
29 | @end
30 |
31 | @implementation TodayViewController
32 |
33 | - (void)awakeFromNib {
34 | [super awakeFromNib];
35 |
36 | self.preferredContentSize = CGSizeMake(0, 80);
37 |
38 | }
39 |
40 | - (id)initWithCoder:(NSCoder *)aDecoder {
41 | if (self = [super initWithCoder:aDecoder]) {
42 | [[NSNotificationCenter defaultCenter] addObserver:self
43 | selector:@selector(userDefaultsDidChange:)
44 | name:NSUserDefaultsDidChangeNotification
45 | object:nil];
46 | }
47 | return self;
48 | }
49 |
50 | - (void)userDefaultsDidChange:(NSNotification *)notification {
51 |
52 | #ifdef DEBUG
53 | NSLog(@"Active Today");
54 | #endif
55 | [self checkStatus];
56 | }
57 |
58 | -(void)checkStatus
59 | {
60 | NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.catchlab.TodayExtensionSharingDefaults"];
61 | BOOL active = [defaults boolForKey:@"ActiveToday"];
62 |
63 | if (active) {
64 | self.country1.hidden = NO;
65 | self.country2.hidden = NO;
66 | self.country3.hidden = NO;
67 | self.country4.hidden = NO;
68 | self.signInLabel.alpha = 0;
69 | }else{
70 | self.country1.hidden = YES;
71 | self.country2.hidden = YES;
72 | self.country3.hidden = YES;
73 | self.country4.hidden = YES;
74 | self.signInLabel.alpha = 1;
75 | }
76 | }
77 |
78 | - (void)viewDidLoad {
79 | [super viewDidLoad];
80 | // Do any additional setup after loading the view from its nib.
81 | [Crashlytics startWithAPIKey:@"de004490005a062fa95a4d5676a7edbfbe42c582"];
82 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshUI) name:NEVPNStatusDidChangeNotification object:nil];
83 | [self checkStatus];
84 |
85 | if (SCREEN_WIDTH <= 320) {
86 |
87 | #ifdef DEBUG
88 | NSLog(@"Relayout");
89 | #endif
90 | self.country2SpaceConstraint.constant = 7.0;
91 | self.country3SpaceConstraint.constant = 7.0;
92 | self.countrySpaceConstraint.constant = 7.0;
93 |
94 | [self.view layoutIfNeeded];
95 |
96 | }
97 | }
98 |
99 | - (void)dealloc
100 | {
101 | [[NSNotificationCenter defaultCenter] removeObserver:self];
102 | }
103 |
104 | - (NSArray *)vpnStations
105 | {
106 | if (!_vpnStations) {
107 | _vpnStations = [VPNStations sharedInstance].stations;
108 | }
109 | return _vpnStations;
110 | }
111 |
112 | - (VCIPsecVPNManager *)vpnManager
113 | {
114 | if (!_vpnManager) {
115 | _vpnManager = [[VCIPsecVPNManager alloc] init];
116 | }
117 | return _vpnManager;
118 | }
119 |
120 | - (void)widgetPerformUpdateWithCompletionHandler:(void (^)(NCUpdateResult))completionHandler {
121 | // Perform any setup necessary in order to update the view.
122 |
123 | // If an error is encountered, use NCUpdateResultFailed
124 | // If there's no update required, use NCUpdateResultNoData
125 | // If there's an update, use NCUpdateResultNewData
126 |
127 | completionHandler(NCUpdateResultNoData);
128 | }
129 |
130 | - (UIEdgeInsets)widgetMarginInsetsForProposedMarginInsets:(UIEdgeInsets)defaultMarginInsets
131 | {
132 | return UIEdgeInsetsMake(0, defaultMarginInsets.left, 0, 0);
133 | }
134 |
135 | - (void)viewDidLayoutSubviews
136 | {
137 | #ifdef DEBUG
138 | NSLog(@"bounds %@", NSStringFromCGRect(self.view.bounds));
139 | #endif
140 |
141 | [self.vpnButtons enumerateObjectsUsingBlock:^(VPNButton *button, NSUInteger idx, BOOL *stop) {
142 | UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectInset(button.bounds, 13, 13)];
143 | imageView.contentMode = UIViewContentModeScaleAspectFit;
144 | imageView.image = [UIImage imageNamed:[self.vpnStations[idx] valueForKey:@"short_name"]];
145 | [button addSubview:imageView];
146 | }];
147 |
148 | [self.vpnManager prepareWithCompletion:^(NSError *error) {
149 | if (self.vpnManager.vpnManager.connection.status == NEVPNStatusConnected) {
150 |
151 | NSString *host= self.vpnManager.vpnManager.protocol.serverAddress;
152 |
153 | for (NSInteger i = 0; i < self.vpnStations.count; i++) {
154 | NSDictionary *station = self.vpnStations[i];
155 | if ([station[@"host"] isEqualToString:host]) {
156 | self.currentButton = self.vpnButtons[i];
157 |
158 | self.currentButton.buttonState = VPNButtonStateConnected;
159 |
160 | break;
161 | }
162 | }
163 | }
164 | }];
165 | }
166 |
167 | - (void)refreshUI
168 | {
169 |
170 | #ifdef DEBUG
171 | NSLog(@"refreshUI");
172 | #endif
173 |
174 | [self.vpnManager prepareWithCompletion:^(NSError *error) {
175 |
176 | switch (self.vpnManager.vpnManager.connection.status) {
177 | case NEVPNStatusConnecting:
178 | NSLog(@"NEVPNStatusConnecting");
179 | self.currentButton.buttonState = VPNButtonStateConnecting;
180 | break;
181 |
182 | case NEVPNStatusConnected:
183 | NSLog(@"NEVPNStatusConnected");
184 | self.currentButton.buttonState = VPNButtonStateConnected;
185 | break;
186 |
187 | case NEVPNStatusDisconnecting:
188 | NSLog(@"NEVPNStatusDisconnecting");
189 | self.currentButton.buttonState = VPNButtonStateConnecting;
190 | break;
191 |
192 | case NEVPNStatusDisconnected:
193 | NSLog(@"NEVPNStatusDisconnected");
194 | self.currentButton.buttonState = VPNButtonStateNormal;
195 | break;
196 |
197 | case NEVPNStatusReasserting:
198 | NSLog(@"NEVPNStatusReasserting");
199 | self.currentButton.buttonState = VPNButtonStateConnecting;
200 | break;
201 |
202 | case NEVPNStatusInvalid:
203 | NSLog(@"NEVPNStatusReasserting");
204 | self.currentButton.buttonState = VPNButtonStateConnectFailed;
205 |
206 | default:
207 | self.currentButton.buttonState = VPNButtonStateNormal;
208 | break;
209 | }
210 |
211 | }];
212 | }
213 |
214 | - (IBAction)pressedVPNButton:(VPNButton *)sender {
215 |
216 | #ifdef DEBUG
217 | NSLog(@"pressedVPNButton");
218 | #endif
219 |
220 | BOOL isNewButton = NO;
221 |
222 | if (sender != self.currentButton) {
223 | isNewButton = YES;
224 |
225 | [self.vpnButtons enumerateObjectsUsingBlock:^(VPNButton *button, NSUInteger idx, BOOL *stop) {
226 | if (button != sender) {
227 | button.buttonState = VPNButtonStateNormal;
228 | }
229 | }];
230 | }
231 |
232 | self.currentButton = sender;
233 |
234 | NSInteger indexOfButton = [self.vpnButtons indexOfObject:self.currentButton];
235 |
236 | NSDictionary *station = self.vpnStations[indexOfButton % self.vpnStations.count];
237 |
238 | if (self.isPrepareProfile) {
239 | return;
240 | }
241 | self.isPrepareProfile = YES;
242 |
243 | [self.vpnManager prepareWithCompletion:^(NSError *error) {
244 | self.isPrepareProfile = NO;
245 |
246 | if (error) {
247 | self.currentButton.buttonState = VPNButtonStateConnectFailed;
248 | }else {
249 |
250 | if (self.vpnManager.vpnManager.connection.status == NEVPNStatusConnected || self.vpnManager.vpnManager.connection.status == NEVPNStatusConnecting || self.vpnManager.vpnManager.connection.status == NEVPNStatusReasserting || self.vpnManager.vpnManager.connection.status == NEVPNStatusDisconnecting) {
251 |
252 | #ifdef DEBUG
253 | NSLog(@"Dicsonnect VPN");
254 | #endif
255 |
256 | [self.vpnManager.vpnManager.connection stopVPNTunnel];
257 |
258 | } else {
259 |
260 | #ifdef DEBUG
261 | NSLog(@"Connect VPN");
262 | #endif
263 |
264 | [self connectVPNWithStation:station];
265 | }
266 | }
267 |
268 | }];
269 | }
270 |
271 | - (void)connectVPNWithStation:(NSDictionary *)station {
272 |
273 | NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.catchlab.TodayExtensionSharingDefaults"];
274 | BOOL active = [defaults boolForKey:@"ikev2"];
275 |
276 | if (active) {
277 | [self.vpnManager connectIPSecIKEv2WithHost:[station valueForKey:@"host"] andUsername:[[VPNStations sharedInstance].config valueForKey:@"username"] andPassword:[[VPNStations sharedInstance].config valueForKey:@"password"] andPSK:[[VPNStations sharedInstance].config valueForKey:@"psk"] andGroupName:[[VPNStations sharedInstance].config valueForKey:@"groupname"]];
278 | } else {
279 | [self.vpnManager connectIPSecWithHost:[station valueForKey:@"host"] andUsername:[[VPNStations sharedInstance].config valueForKey:@"username"] andPassword:[[VPNStations sharedInstance].config valueForKey:@"password"] andPSK:[[VPNStations sharedInstance].config valueForKey:@"psk"] andGroupName:[[VPNStations sharedInstance].config valueForKey:@"groupname"]];
280 | }
281 |
282 | }
283 |
284 |
285 | @end
286 |
--------------------------------------------------------------------------------
/Hydro/VCIPsecVPNManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // VCIPsecVPNManager.m
3 | // VPNCloud
4 | //
5 | // Created by kevinzhow on 14/11/12.
6 | // Copyright (c) 2014年 Kingaxis Inc. All rights reserved.
7 | //
8 |
9 | #import "VCIPsecVPNManager.h"
10 | #import "VCKetChain.h"
11 |
12 | static NSString * const IKEv1ServiceName = @"Hydro VPN";
13 | static NSString * const IKEv2ServiceName = @"Hydro IKEv2 VPN";
14 |
15 | @implementation VCIPsecVPNManager
16 |
17 | -(id)init
18 | {
19 | self = [super init];
20 | if (self) {
21 | self.vpnManager = [NEVPNManager sharedManager];
22 |
23 | }
24 | return self;
25 |
26 | }
27 |
28 |
29 |
30 | -(void)prepareWithCompletion:(void (^)(NSError *))done
31 | {
32 | // init VPN manager
33 |
34 |
35 | [_vpnManager loadFromPreferencesWithCompletionHandler:^(NSError *error) {
36 |
37 | [self updateServiceStatus];
38 |
39 | done(error);
40 |
41 | }];
42 |
43 | }
44 |
45 | -(void)updateServiceStatus
46 | {
47 | // NSLog(@"VPN is %@ %@",_vpnManager.protocol, [_vpnManager.protocol description]);
48 | if ([[[self.vpnManager.protocol valueForKey:@"type"] description] isEqualToString:@"5"]) {
49 | self.IKEv2Enabled = YES;
50 | self.IKEv1Enabled = NO;
51 | }else if ([[[self.vpnManager.protocol valueForKey:@"type"] description] isEqualToString:@"1"]){
52 | self.IKEv2Enabled = NO;
53 | self.IKEv1Enabled = YES;
54 | }
55 | }
56 |
57 | -(void)connectIPSecIKEv2WithHost:(NSString *)host andUsername:(NSString *)username andPassword:(NSString *)password andPSK:(NSString *)psk andGroupName:(NSString *)groupName
58 |
59 | {
60 | VCKetChain * keychain =[[VCKetChain alloc] initWithService:@"VPNIKEv2PSK" withGroup:nil];
61 |
62 | NSString *key =@"password";
63 | NSData * value = [password dataUsingEncoding:NSUTF8StringEncoding];
64 |
65 | NSString *key2 =@"psk";
66 | NSData * value2 = [psk dataUsingEncoding:NSUTF8StringEncoding];
67 |
68 | if(![keychain find:@"password"] || ![keychain find:@"psk"])
69 | {
70 | if ([keychain insert:key :value]) {
71 | NSLog(@"Successfully added data");
72 | }else{
73 | NSLog(@"Failed to add data");
74 | }
75 |
76 | if ([keychain insert:key2 :value2]) {
77 | NSLog(@"Successfully added data shared key");
78 | }else{
79 | NSLog(@"Failed to add data shared key");
80 | }
81 |
82 | }
83 | else
84 | {
85 | NSLog(@"No need to add data");
86 | }
87 |
88 |
89 | NEVPNProtocolIKEv2 *p = [[NEVPNProtocolIKEv2 alloc] init];
90 | p.username = username;
91 | p.serverAddress = host;
92 | p.passwordReference = [keychain find:@"password"];
93 |
94 |
95 | p.authenticationMethod = NEVPNIKEAuthenticationMethodSharedSecret;
96 | p.sharedSecretReference = [keychain find:@"psk"];
97 |
98 | p.localIdentifier = groupName;
99 | p.remoteIdentifier = host;
100 |
101 | p.useExtendedAuthentication = YES;
102 | p.disconnectOnSleep = NO;
103 |
104 | _vpnManager.protocol = p;
105 | _vpnManager.localizedDescription = IKEv2ServiceName;
106 | _vpnManager.enabled = YES;
107 |
108 |
109 | // NEOnDemandRuleConnect *connectRule = [NEOnDemandRuleConnect new];
110 | // connectRule.interfaceTypeMatch = NEOnDemandRuleInterfaceTypeCellular | NEOnDemandRuleInterfaceTypeWiFi;
111 | //
112 | //
113 | // NEOnDemandRuleEvaluateConnection * domainRule = [NEOnDemandRuleEvaluateConnection new];
114 | //
115 | // NEEvaluateConnectionRule * domainMatch = [[NEEvaluateConnectionRule alloc]
116 | // initWithMatchDomains:
117 | // @[@"*.twitter.com", @"www.twitter.com", @"*.google.com", @"*.google.com.hk", @"*.youtube.com",
118 | // @"*.googleusercontent.com",@"*.gstatic.com", @"*.ggpht.com",@"*.appspot.com", @"*.googleapis.com", @"*.google.cn",
119 | // @"*.fbcdn.net", @"*.staticflickr.com", @"*.twimg.com", @"*.ytimg.com", @"*.feedly.com",@"*.tinypic.com", @"*.instagram.com"] andAction:NEEvaluateConnectionRuleActionConnectIfNeeded];
120 | // domainRule.connectionRules = @[domainMatch];
121 | //
122 | //
123 | // [_vpnManager setOnDemandRules:@[domainRule]];
124 |
125 | // _vpnManager.onDemandEnabled = YES;
126 |
127 | [_vpnManager saveToPreferencesWithCompletionHandler:^(NSError *error) {
128 |
129 | #ifdef DEBUG
130 | NSLog(@"Save config failed [%@]", error.localizedDescription);
131 | #endif
132 | if (!error) {
133 | #ifdef DEBUG
134 | NSLog(@"username: %@", [_vpnManager protocol].username);
135 | NSLog(@"password: %@ %@", [_vpnManager protocol].passwordReference, [keychain find:@"password"]);
136 | #endif
137 | }
138 |
139 | NSError *startError;
140 | [_vpnManager.connection startVPNTunnelAndReturnError:&startError];
141 | if (startError) {
142 |
143 | #ifdef DEBUG
144 | NSLog(@"Start VPN failed: [%@]", startError.localizedDescription);
145 | #endif
146 | }
147 | }];
148 | }
149 |
150 |
151 | -(void)connectIPSecIKEv2WithHost:(NSString *)host andUsername:(NSString *)username andPassword:(NSString *)password andP12Name:(NSString *)p12Name andidentityDataPassword:(NSString *)identityDataPassword andGroupName:(NSString *)groupName
152 | {
153 |
154 | VCKetChain * keychain =[[VCKetChain alloc] initWithService:@"VPNIKEv2" withGroup:nil];
155 |
156 | NSString *key =@"password";
157 | NSData * value = [password dataUsingEncoding:NSUTF8StringEncoding];
158 |
159 | if(![keychain find:@"password"])
160 | {
161 | if ([keychain insert:key :value]) {
162 | NSLog(@"Successfully added data");
163 | }else{
164 | NSLog(@"Failed to add data");
165 | }
166 |
167 | }
168 | else
169 | {
170 | NSLog(@"No need to add data");
171 | }
172 |
173 |
174 | NEVPNProtocolIKEv2 *p = [[NEVPNProtocolIKEv2 alloc] init];
175 | p.username = username;
176 | p.serverAddress = host;
177 | p.serverCertificateIssuerCommonName = @"COMODO RSA Domain Validation Secure Server CA";
178 | p.serverCertificateCommonName = @"*.piner.me";
179 | p.passwordReference = [keychain find:@"password"];
180 |
181 |
182 | p.identityData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@",p12Name] ofType:@"p12"]];
183 | p.identityDataPassword = identityDataPassword;
184 | p.authenticationMethod = NEVPNIKEAuthenticationMethodCertificate;
185 |
186 | p.localIdentifier = groupName;
187 | p.remoteIdentifier = host;
188 |
189 | p.useExtendedAuthentication = YES;
190 | p.disconnectOnSleep = NO;
191 |
192 | _vpnManager.protocol = p;
193 | _vpnManager.localizedDescription = IKEv2ServiceName;
194 | _vpnManager.enabled = YES;
195 |
196 |
197 | // NEOnDemandRuleConnect *connectRule = [NEOnDemandRuleConnect new];
198 | // connectRule.interfaceTypeMatch = NEOnDemandRuleInterfaceTypeCellular | NEOnDemandRuleInterfaceTypeWiFi;
199 | //
200 | //
201 | NEOnDemandRuleEvaluateConnection * domainRule = [NEOnDemandRuleEvaluateConnection new];
202 |
203 | NEEvaluateConnectionRule * domainMatch = [[NEEvaluateConnectionRule alloc]
204 | initWithMatchDomains:
205 | @[@"*.twitter.com", @"www.twitter.com", @"*.google.com", @"*.google.com.hk", @"*.youtube.com",
206 | @"*.googleusercontent.com",@"*.gstatic.com", @"*.ggpht.com",@"*.appspot.com", @"*.googleapis.com", @"*.google.cn",
207 | @"*.fbcdn.net", @"*.staticflickr.com", @"*.twimg.com", @"*.ytimg.com", @"*.feedly.com",@"*.tinypic.com", @"*.instagram.com"] andAction:NEEvaluateConnectionRuleActionConnectIfNeeded];
208 | domainRule.connectionRules = @[domainMatch];
209 |
210 |
211 | [_vpnManager setOnDemandRules:@[domainRule]];
212 |
213 | // _vpnManager.onDemandEnabled = YES;
214 |
215 | [_vpnManager saveToPreferencesWithCompletionHandler:^(NSError *error) {
216 |
217 | #ifdef DEBUG
218 | NSLog(@"Save config failed [%@]", error.localizedDescription);
219 | #endif
220 | if (!error) {
221 | #ifdef DEBUG
222 | NSLog(@"username: %@", [_vpnManager protocol].username);
223 | NSLog(@"password: %@ %@", [_vpnManager protocol].passwordReference, [keychain find:@"password"]);
224 | #endif
225 |
226 | }
227 |
228 | NSError *startError;
229 | [_vpnManager.connection startVPNTunnelAndReturnError:&startError];
230 | if (startError) {
231 |
232 | #ifdef DEBUG
233 | NSLog(@"Start VPN failed: [%@]", startError.localizedDescription);
234 | #endif
235 | }
236 |
237 | }];
238 |
239 | }
240 |
241 |
242 | -(void)connectIPSecWithHost:(NSString *)host andUsername:(NSString *)username andPassword:(NSString *)password andPSK:(NSString *)psk andGroupName:(NSString *)groupName
243 | {
244 |
245 |
246 | VCKetChain * keychain =[[VCKetChain alloc] initWithService:@"VPN" withGroup:nil];
247 |
248 | NSString *key =@"password";
249 | NSData * value = [password dataUsingEncoding:NSUTF8StringEncoding];
250 |
251 | NSString *key2 =@"psk";
252 | NSData * value2 = [psk dataUsingEncoding:NSUTF8StringEncoding];
253 |
254 | if(![keychain find:@"password"] || ![keychain find:@"psk"])
255 | {
256 | if ([keychain insert:key :value]) {
257 | NSLog(@"Successfully added data");
258 | }else{
259 | NSLog(@"Failed to add data");
260 | }
261 |
262 | if ([keychain insert:key2 :value2]) {
263 | NSLog(@"Successfully added data shared key");
264 | }else{
265 | NSLog(@"Failed to add data shared key");
266 | }
267 |
268 | }
269 | else
270 | {
271 | NSLog(@"No need to add data");
272 | }
273 |
274 |
275 | NEVPNProtocolIPSec *p = [[NEVPNProtocolIPSec alloc] init];
276 | p.username = username;
277 | p.serverAddress = host;
278 | p.passwordReference = [keychain find:@"password"];
279 |
280 | // PSK
281 | p.authenticationMethod = NEVPNIKEAuthenticationMethodSharedSecret;
282 | p.sharedSecretReference = [keychain find:@"psk"];
283 |
284 |
285 | /*
286 | // certificate
287 | p.identityData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"client" ofType:@"p12"]];
288 | p.identityDataPassword = @"[Your certificate import password]";
289 | */
290 |
291 | p.remoteIdentifier = host;
292 | p.localIdentifier = groupName;
293 |
294 | p.useExtendedAuthentication = YES;
295 | p.disconnectOnSleep = NO;
296 |
297 | _vpnManager.protocol = p;
298 | _vpnManager.localizedDescription = IKEv1ServiceName;
299 | _vpnManager.enabled = YES;
300 | _vpnManager.onDemandEnabled = NO;
301 |
302 |
303 | NEOnDemandRuleConnect *connectRule = [NEOnDemandRuleConnect new];
304 | connectRule.interfaceTypeMatch = NEOnDemandRuleInterfaceTypeCellular | NEOnDemandRuleInterfaceTypeWiFi;
305 |
306 |
307 |
308 | [_vpnManager setOnDemandRules:@[connectRule]];
309 |
310 |
311 | [_vpnManager saveToPreferencesWithCompletionHandler:^(NSError *error) {
312 |
313 | #ifdef DEBUG
314 | NSLog(@"Save config failed [%@]", error.localizedDescription);
315 | #endif
316 | if (!error) {
317 | #ifdef DEBUG
318 | NSLog(@"username: %@", [_vpnManager protocol].username);
319 | NSLog(@"password: %@ %@", [_vpnManager protocol].passwordReference, [keychain find:@"password"]);
320 | NSLog(@"sharedSecretReference: %@ %@", p.sharedSecretReference, [keychain find:@"psk"]);
321 | #endif
322 |
323 | NSError *startError;
324 | [_vpnManager.connection startVPNTunnelAndReturnError:&startError];
325 | if (startError) {
326 | NSLog(@"Start VPN failed: [%@]", startError.localizedDescription);
327 | }
328 | }
329 | }];
330 |
331 |
332 | }
333 |
334 | @end
335 |
--------------------------------------------------------------------------------
/Today/MainInterface.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
35 |
48 |
61 |
71 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/Hydro/Views/InviteView.m:
--------------------------------------------------------------------------------
1 | //
2 | // InviteView.m
3 | // Hydro
4 | //
5 | // Created by NIX on 14/12/27.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import "InviteView.h"
10 |
11 | @interface InviteView()
12 |
13 | @end
14 |
15 |
16 | @implementation InviteView
17 |
18 | - (instancetype)initWithFrame:(CGRect)frame
19 | {
20 | if (self = [super initWithFrame:frame]) {
21 | [self initUI];
22 | }
23 | return self;
24 | }
25 |
26 | - (void)initUI
27 | {
28 | CGFloat logoSize = 36.0;
29 |
30 | //NSNumber *leftInset = @20;
31 | //NSNumber *rightInset = @30;
32 |
33 | CGFloat fontSize = 18.0;
34 |
35 | #pragma mark - Invite Text Filed
36 |
37 | UILabel *inviteTextLabel = [[UILabel alloc] initWithFrame:CGRectZero];
38 | inviteTextLabel.font = [UIFont fontWithName:@"Avenir-Light" size:fontSize];
39 | inviteTextLabel.textColor = [UIColor colorWithWhite:1.0 alpha:0.9];
40 | inviteTextLabel.text = NSLocalizedString(@"Invite Friend to", nil);
41 | [self addSubview:inviteTextLabel];
42 |
43 | UIImageView *logoImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, logoSize, logoSize)];
44 | logoImageView.contentMode = UIViewContentModeScaleAspectFit;
45 | logoImageView.image = [UIImage imageNamed:@"logo"];
46 | [self addSubview:logoImageView];
47 |
48 | UILabel *hydroLabel = [[UILabel alloc] initWithFrame:CGRectZero];
49 | hydroLabel.font = [UIFont fontWithName:@"Avenir-Medium" size:fontSize];
50 | hydroLabel.textColor = [UIColor whiteColor];
51 | hydroLabel.text = NSLocalizedString(@"Hydro", nil);
52 | [self addSubview:hydroLabel];
53 |
54 | UIView *helperView = [[UIView alloc] init];
55 | [self addSubview:helperView];
56 |
57 | {
58 | inviteTextLabel.translatesAutoresizingMaskIntoConstraints = NO;
59 | logoImageView.translatesAutoresizingMaskIntoConstraints = NO;
60 | hydroLabel.translatesAutoresizingMaskIntoConstraints = NO;
61 | helperView.translatesAutoresizingMaskIntoConstraints = NO;
62 |
63 | NSDictionary *viewsDictionary = @{
64 | @"inviteTextLabel":inviteTextLabel,
65 | @"logoImageView":logoImageView,
66 | @"hydroLabel":hydroLabel,
67 | };
68 |
69 | NSNumber *topOffset = @40;
70 | NSNumber *logoWidth = @(logoSize);
71 | NSNumber *logoHeight = @(logoSize);
72 | NSNumber *labelHeight = @(logoSize);
73 |
74 |
75 | NSArray *constraintH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(>=0)-[inviteTextLabel]-[logoImageView(logoWidth)]-[hydroLabel]-(>=0)-|"
76 | options:0
77 | metrics:@{@"logoWidth": logoWidth,
78 | }
79 | views:viewsDictionary];
80 |
81 |
82 | NSArray *constraintV1 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(topOffset)-[inviteTextLabel(labelHeight)]"
83 | options:0
84 | metrics:@{@"topOffset": topOffset,
85 | @"labelHeight": labelHeight,
86 | }
87 | views:viewsDictionary];
88 |
89 | NSArray *constraintV2 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(topOffset)-[logoImageView(logoHeight)]"
90 | options:0
91 | metrics:@{@"topOffset": topOffset,
92 | @"logoHeight": logoHeight,
93 | }
94 | views:viewsDictionary];
95 |
96 | NSArray *constraintV3 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(topOffset)-[hydroLabel(labelHeight)]"
97 | options:0
98 | metrics:@{@"topOffset": topOffset,
99 | @"labelHeight": labelHeight,
100 | }
101 | views:viewsDictionary];
102 |
103 |
104 |
105 |
106 | NSLayoutConstraint *helpConstraint1 = [NSLayoutConstraint constraintWithItem:helperView
107 | attribute:NSLayoutAttributeLeading
108 | relatedBy:NSLayoutRelationEqual
109 | toItem:inviteTextLabel
110 | attribute:NSLayoutAttributeLeading
111 | multiplier:1
112 | constant:0];
113 |
114 | NSLayoutConstraint *helpConstraint2 = [NSLayoutConstraint constraintWithItem:helperView
115 | attribute:NSLayoutAttributeTrailing
116 | relatedBy:NSLayoutRelationEqual
117 | toItem:hydroLabel
118 | attribute:NSLayoutAttributeTrailing
119 | multiplier:1
120 | constant:0];
121 |
122 | NSLayoutConstraint *helpConstraint3 = [NSLayoutConstraint constraintWithItem:helperView
123 | attribute:NSLayoutAttributeCenterX
124 | relatedBy:NSLayoutRelationEqual
125 | toItem:self
126 | attribute:NSLayoutAttributeCenterX
127 | multiplier:1
128 | constant:0];
129 |
130 | [self addConstraints:constraintH];
131 | [self addConstraints:constraintV1];
132 | [self addConstraints:constraintV2];
133 | [self addConstraints:constraintV3];
134 | [self addConstraint:helpConstraint1];
135 | [self addConstraint:helpConstraint2];
136 | [self addConstraint:helpConstraint3];
137 | }
138 |
139 | #pragma mark - Email Text Filed
140 |
141 | _emailTextField = [[SAMTextField alloc] initWithFrame:CGRectZero];
142 | [_emailTextField setBackground:[UIImage imageNamed:@"EM"]];
143 | _emailTextField.textColor = [UIColor whiteColor];
144 | _emailTextField.font = [UIFont fontWithName:@"Avenir-Medium" size:20.0];
145 | _emailTextField.textAlignment = NSTextAlignmentCenter;
146 | _emailTextField.contentMode = UIViewContentModeScaleAspectFit;
147 | _emailTextField.adjustsFontSizeToFitWidth = YES;
148 | _emailTextField.minimumFontSize = 12;
149 | _emailTextField.tintColor = [UIColor whiteColor];
150 | _emailTextField.returnKeyType = UIReturnKeyDone;
151 |
152 | NSDictionary *attrsDictionary = @{
153 | NSFontAttributeName: [UIFont fontWithName:@"Avenir-Medium" size:22.0],
154 | NSForegroundColorAttributeName: [UIColor colorWithWhite:1.0 alpha:0.8]
155 | };
156 |
157 | NSAttributedString *attrEmailString = [[NSAttributedString alloc] initWithString:@"Email"
158 | attributes:attrsDictionary];
159 |
160 | _emailTextField.attributedPlaceholder = attrEmailString;
161 |
162 | _emailTextField.textEdgeInsets = UIEdgeInsetsMake(0.0f, 40.0f, 5.0f, 10.0f);
163 |
164 | [self addSubview:_emailTextField];
165 |
166 | {
167 | _emailTextField.translatesAutoresizingMaskIntoConstraints = NO;
168 |
169 | NSDictionary *viewsDictionary = @{
170 | @"inviteTextLabel":inviteTextLabel,
171 | @"emailTextField":_emailTextField,
172 | };
173 |
174 | NSArray *constraintH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(>=0)-[emailTextField(240)]-(>=0)-|"
175 | options:0
176 | metrics:nil
177 | views:viewsDictionary];
178 |
179 | NSArray *constraintV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[inviteTextLabel]-(60)-[emailTextField(30)]"
180 | options:0
181 | metrics:nil
182 | views:viewsDictionary];
183 |
184 | NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:_emailTextField
185 | attribute:NSLayoutAttributeCenterX
186 | relatedBy:NSLayoutRelationEqual
187 | toItem:self
188 | attribute:NSLayoutAttributeCenterX
189 | multiplier:1
190 | constant:0];
191 |
192 | [self addConstraints:constraintH];
193 | [self addConstraints:constraintV];
194 | [self addConstraint:constraint];
195 | }
196 |
197 | #pragma mark - Invite Button
198 |
199 | _inviteButton = [UIButton buttonWithType:UIButtonTypeCustom];
200 | [_inviteButton setBackgroundImage:[UIImage imageNamed:@"Button"] forState:UIControlStateNormal];
201 | [_inviteButton setTitle:NSLocalizedString(@"Send invitation", nil) forState:UIControlStateNormal];
202 | _inviteButton.titleLabel.font = [UIFont fontWithName:@"Avenir-Medium" size:fontSize];
203 | [self addSubview:_inviteButton];
204 |
205 | {
206 | _inviteButton.translatesAutoresizingMaskIntoConstraints = NO;
207 |
208 | NSDictionary *viewsDictionary = @{
209 | @"emailTextField":_emailTextField,
210 | @"inviteButton":_inviteButton,
211 | };
212 |
213 | NSArray *constraintH = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(>=0)-[inviteButton(240)]-(>=0)-|"
214 | options:0
215 | metrics:nil
216 | views:viewsDictionary];
217 |
218 | NSArray *constraintV = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[emailTextField]-(60)-[inviteButton(60)]-(>=0)-|"
219 | options:0
220 | metrics:nil
221 | views:viewsDictionary];
222 |
223 | NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:_inviteButton
224 | attribute:NSLayoutAttributeCenterX
225 | relatedBy:NSLayoutRelationEqual
226 | toItem:self
227 | attribute:NSLayoutAttributeCenterX
228 | multiplier:1
229 | constant:0];
230 |
231 | [self addConstraints:constraintH];
232 | [self addConstraints:constraintV];
233 | [self addConstraint:constraint];
234 | }
235 |
236 | }
237 |
238 | @end
239 |
--------------------------------------------------------------------------------
/Hydro/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 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
--------------------------------------------------------------------------------
/Hydro/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // Hydro
4 | //
5 | // Created by kevinzhow on 14/12/25.
6 | // Copyright (c) 2014年 Catch Inc. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 | #import "LoginViewController.h"
11 | #import
12 | #import "StationTableViewCell.h"
13 | #import "GVUserDefaults+Hydro.h"
14 | #import "VPNStations.h"
15 | #import "InviteView.h"
16 | #import
17 | #import
18 |
19 | #define TableViewTopConstraintInitialConstant (-400.0)
20 |
21 | @interface ViewController ()
22 |
23 | @property (weak, nonatomic) IBOutlet NSLayoutConstraint *tableViewTopConstraint;
24 |
25 | @property (nonatomic) NSArray *vpnStations;
26 | @property (nonatomic) NSDictionary *stationDic;
27 |
28 | @property (nonatomic, weak) InviteView *inviteView;
29 |
30 | @property (nonatomic) HydroButton *connectButton;
31 | @property (nonatomic) UIImageView *mapImageVIew;
32 |
33 | @property (nonatomic) UILabel *donaterLabel;
34 |
35 | @property (nonatomic) VCIPsecVPNManager * vpnmanager;
36 |
37 | @property (nonatomic) NSString * domain;
38 |
39 | @property (nonatomic) NSDictionary * currentStationDict;
40 |
41 | @property (nonatomic) stationView * stationViewOne;
42 |
43 | @property (nonatomic) locationView * stationLocationView;
44 |
45 | @property (nonatomic) BOOL userHasLogined;
46 |
47 | @property (nonatomic) BOOL userCanInvite;
48 |
49 | @property (nonatomic) BOOL stationShowed;
50 |
51 | @property (nonatomic) BOOL isPrepareProfile;
52 |
53 |
54 | - (IBAction)doConnect:(id)sender;
55 |
56 | @end
57 |
58 | @implementation ViewController
59 |
60 | - (NSArray *)vpnStations
61 | {
62 | if (!_vpnStations) {
63 | _vpnStations = [VPNStations sharedInstance].stations;
64 | }
65 | return _vpnStations;
66 | }
67 |
68 | - (void)viewDidLoad {
69 | [super viewDidLoad];
70 |
71 | self.mapImageVIew = [[UIImageView alloc] initWithFrame:CGRectMake(0, -100, SCREEN_WIDTH, 267)];
72 | self.mapImageVIew.image = [UIImage imageNamed:@"World Map"];
73 | self.mapImageVIew.contentMode = UIViewContentModeScaleAspectFit;
74 | [self.view addSubview:self.mapImageVIew];
75 |
76 |
77 | UIView * headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, 10)];
78 | headerView.backgroundColor = [UIColor clearColor];
79 | self.stationLocationView = [[locationView alloc] initWithFrame:CGRectMake(self.mapImageVIew.frame.size.width /2.0 - 15.0, self.mapImageVIew.frame.size.height /2.0 - 15.0, 30.0, 30.0)];
80 | self.stationLocationView.alpha = 0.0;
81 | [self.mapImageVIew addSubview:self.stationLocationView];
82 |
83 |
84 | self.stationViewOne = [[stationView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, 210.0)];
85 | [self.view addSubview:self.stationViewOne];
86 | self.stationViewOne.alpha = 0;
87 |
88 | //self.stationDelegate = [[stationsDelegate alloc] init];
89 | self.connectButton = [HydroButton buttonWithType:UIButtonTypeCustom];
90 | [self.connectButton.titleLabel setFont:[UIFont fontWithName:@"Avenir-Medium" size:17.0]];
91 |
92 |
93 |
94 | self.connectButton.frame = CGRectMake(SCREEN_WIDTH/2.0 - 120 , SCREEN_HEIGHT + 140, 240, 60);
95 |
96 | self.donaterLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, (SCREEN_HEIGHT - 160.0) , SCREEN_WIDTH, 30)];
97 | self.donaterLabel.alpha = 0;
98 | self.donaterLabel.textColor = [UIColor colorWithWhite:1.0 alpha:0.6];
99 | self.donaterLabel.textAlignment = NSTextAlignmentCenter;
100 | [self.donaterLabel setFont:[UIFont fontWithName:@"Avenir-Medium" size:14.0]];
101 |
102 | [self.view addSubview:self.donaterLabel];
103 |
104 | [self.connectButton setBackgroundImage:[UIImage imageNamed:@"Button + Connect"] forState:UIControlStateNormal];
105 | [self.view addSubview:self.connectButton];
106 | [self.connectButton addTarget:self action:@selector(doConnect:) forControlEvents:UIControlEventTouchUpInside];
107 | [self.connectButton addTarget:self.connectButton action:@selector(touchDown) forControlEvents:UIControlEventTouchDown];
108 | [self.connectButton addTarget:self.connectButton action:@selector(touchUpInside) forControlEvents:UIControlEventTouchUpInside];
109 | [self.connectButton addTarget:self.connectButton action:@selector(touchUpInside) forControlEvents:UIControlEventTouchDragOutside];
110 |
111 | [self.connectButton setTitle:NSLocalizedString(@"Connect", nil) forState:UIControlStateNormal];
112 | self.connectButton.alpha = 0;
113 |
114 | self.tableViewTopConstraint.constant = TableViewTopConstraintInitialConstant;
115 | self.stationsTableVIew.tableHeaderView = headerView;
116 | self.stationsTableVIew.delegate = self;
117 | self.stationsTableVIew.dataSource = self;
118 | [self.stationsTableVIew reloadData];
119 |
120 | [[NSNotificationCenter defaultCenter] addObserver:self
121 | selector:@selector(filterStationStatus:)
122 | name:CCNFilterStationStatus
123 | object:nil];
124 |
125 | [[NSNotificationCenter defaultCenter] addObserver:self
126 | selector:@selector(fillUserInfo)
127 | name:CCNFillUserInfo
128 | object:nil];
129 |
130 | self.vpnmanager = [[VCIPsecVPNManager alloc] init];
131 | [self addMotionOnMap];
132 |
133 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(vpnConnectionStatusChanged:) name:NEVPNStatusDidChangeNotification object:nil];
134 |
135 |
136 | if (![GVUserDefaults standardUserDefaults].token) {
137 | LoginViewController * loginViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"LoginViewController"];
138 | loginViewController.modalPresentationStyle = UIModalPresentationOverCurrentContext;
139 |
140 | [self presentViewController:loginViewController animated:NO completion:^{
141 |
142 | }];
143 | }else{
144 | NSUserDefaults *sharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.catchlab.TodayExtensionSharingDefaults"];
145 |
146 | [sharedDefaults setBool:YES forKey:@"ActiveToday"];
147 | [sharedDefaults synchronize]; // (!!) This is crucial.
148 | [self checkCanInvite];
149 | [[NSNotificationCenter defaultCenter] postNotificationName:CCNFillUserInfo object:nil];
150 | [self validateUser];
151 | }
152 |
153 | [self.view bringSubviewToFront:self.stationsTableVIew];
154 | [self.view bringSubviewToFront:self.connectButton];
155 |
156 |
157 | }
158 |
159 | -(BOOL)canBecomeFirstResponder {
160 | return YES;
161 | }
162 |
163 | -(void)viewDidAppear:(BOOL)animated {
164 | [super viewDidAppear:animated];
165 | [self becomeFirstResponder];
166 | }
167 |
168 | - (void)viewWillDisappear:(BOOL)animated {
169 | [self resignFirstResponder];
170 | [super viewWillDisappear:animated];
171 | }
172 |
173 | - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
174 | {
175 | if (motion == UIEventSubtypeMotionShake)
176 | {
177 | NSLog(@"Change IKEV");
178 |
179 | NSString * message = @"Choose The Encrypt Protocal";
180 |
181 | UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Make A Change" message:message preferredStyle:UIAlertControllerStyleAlert];
182 |
183 | UIAlertAction* ikev2 = [UIAlertAction actionWithTitle:@"IKEv2" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
184 | [GVUserDefaults standardUserDefaults].ikev2 = YES;
185 | }];
186 |
187 | UIAlertAction* ikev1 = [UIAlertAction actionWithTitle:@"IKEv1" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
188 | [GVUserDefaults standardUserDefaults].ikev2 = NO;
189 | }];
190 |
191 |
192 | NSUserDefaults *sharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.catchlab.TodayExtensionSharingDefaults"];
193 |
194 | [sharedDefaults setBool:[GVUserDefaults standardUserDefaults].ikev2 forKey:@"ikev2"];
195 | [sharedDefaults synchronize]; // (!!) This is crucial.
196 |
197 | [alertController addAction:ikev2];
198 | [alertController addAction:ikev1];
199 |
200 | [self presentViewController:alertController animated:YES completion:nil];
201 | }
202 | }
203 |
204 | -(void)viewWillAppear:(BOOL)animated
205 | {
206 | [super viewWillAppear:animated];
207 | if (self.userHasLogined) {
208 | [self relayout];
209 | [self checkCanInvite];
210 | }
211 |
212 | }
213 |
214 | -(void)checkCanInvite
215 | {
216 | AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
217 | NSDictionary *parameters = @{
218 | @"user_token":[GVUserDefaults standardUserDefaults].token
219 | };
220 | [manager POST:[NSString stringWithFormat:@"%@%@",[[VPNStations sharedInstance].config valueForKey:@"server"], [[VPNStations sharedInstance].config valueForKey:@"can_do_invite"]] parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
221 |
222 | #ifdef DEBUG
223 | NSLog(@"JSON: %@", responseObject);
224 | #endif
225 |
226 | NSString * status = [responseObject valueForKey:@"status"];
227 |
228 | if([status isEqualToString:@"error"]){
229 | self.userCanInvite = NO;
230 | }else{
231 | self.userCanInvite = YES;
232 | }
233 |
234 | } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
235 |
236 | #ifdef DEBUG
237 | NSLog(@"Error: %@", error);
238 | #endif
239 | self.userCanInvite = NO;
240 | }];
241 |
242 |
243 | }
244 |
245 | -(void)addMotionOnMap
246 | {
247 | // Set vertical effect
248 | UIInterpolatingMotionEffect *verticalMotionEffect =
249 | [[UIInterpolatingMotionEffect alloc]
250 | initWithKeyPath:@"center.y"
251 | type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
252 | verticalMotionEffect.minimumRelativeValue = @(-20);
253 | verticalMotionEffect.maximumRelativeValue = @(20);
254 |
255 | // Set horizontal effect
256 | UIInterpolatingMotionEffect *horizontalMotionEffect =
257 | [[UIInterpolatingMotionEffect alloc]
258 | initWithKeyPath:@"center.x"
259 | type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
260 | horizontalMotionEffect.minimumRelativeValue = @(-20);
261 | horizontalMotionEffect.maximumRelativeValue = @(20);
262 |
263 | // Create group to combine both
264 | UIMotionEffectGroup *group = [UIMotionEffectGroup new];
265 | group.motionEffects = @[horizontalMotionEffect, verticalMotionEffect];
266 |
267 | // Add both effects to your view
268 | [self.mapImageVIew addMotionEffect:group];
269 | }
270 |
271 | -(void)vpnConnectionStatusChanged:(NSNotification *)notification
272 | {
273 | [self relayout];
274 | }
275 |
276 | -(void)filterStationStatus:(NSNotification *)notification
277 | {
278 | NSDictionary * dict = notification.object;
279 | self.currentStationDict = dict;
280 | self.domain = [dict valueForKey:@"host"];
281 |
282 | if (![[[GVUserDefaults standardUserDefaults].currentStationDict valueForKey:@"host"] isEqualToString:[dict valueForKey:@"host"]]) {
283 | [GVUserDefaults standardUserDefaults].server = self.domain;
284 | [GVUserDefaults standardUserDefaults].currentStationDict = dict;
285 | }
286 |
287 | [self fillWithStationView:self.stationViewOne];
288 |
289 | [self changeLocation:CGPointMake([[dict valueForKey:@"x"] floatValue], [[dict valueForKey:@"y"] floatValue])];
290 |
291 | #ifdef DEBUG
292 | NSLog(@"Change domian to %@",[GVUserDefaults standardUserDefaults].currentStationDict );
293 | #endif
294 |
295 | }
296 |
297 |
298 | -(void)changeLocation:(CGPoint)point
299 | {
300 |
301 |
302 | #ifdef DEBUG
303 | NSLog(@"Change station to %f %f",point.x, point.y );
304 | #endif
305 |
306 | POPSpringAnimation *animAlpha = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerOpacity];
307 | animAlpha.toValue = @0.0;
308 | animAlpha.springBounciness = 4.0;
309 | animAlpha.springSpeed = 12.0;
310 | animAlpha.completionBlock = ^(POPAnimation *anim, BOOL finished) {
311 | if (finished) {}};
312 | [self.stationLocationView.layer pop_addAnimation:animAlpha forKey:@"AlphaMap"];
313 |
314 | animAlpha.completionBlock = ^(POPAnimation *anim, BOOL finished) {
315 | if (finished) {
316 |
317 | self.stationLocationView.center = CGPointMake((self.mapImageVIew.frame.size.width /0.9) /2.0 + ((self.mapImageVIew.frame.size.width /0.9) /2.0 * point.x) - 15.0, (self.mapImageVIew.frame.size.height/0.9) /2.0 + ((self.mapImageVIew.frame.size.height/0.9) /2.0 * point.y) -15.0);
318 |
319 | POPSpringAnimation *animAlpha = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerOpacity];
320 | animAlpha.toValue = @1.0;
321 | animAlpha.springBounciness = 4.0;
322 | animAlpha.springSpeed = 12.0;
323 | animAlpha.completionBlock = ^(POPAnimation *anim, BOOL finished) {
324 | if (finished) {}};
325 | [self.stationLocationView.layer pop_addAnimation:animAlpha forKey:@"AlphaMap"];
326 |
327 |
328 |
329 | }
330 | };
331 |
332 | }
333 |
334 |
335 |
336 |
337 | - (void)fillUserInfo
338 | {
339 | self.userHasLogined = YES;
340 |
341 | #ifdef DEBUG
342 | NSLog(@"User Do login");
343 | #endif
344 | self.mapImageVIew.image = [UIImage imageNamed:@"World Map"];
345 |
346 | POPSpringAnimation *anim = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerPosition];
347 | anim.toValue = [NSValue valueWithCGPoint:CGPointMake(SCREEN_WIDTH/2.0, (SCREEN_HEIGHT - 240.0) )];
348 | anim.springBounciness = 4.0;
349 | anim.springSpeed = 12.0;
350 | anim.completionBlock = ^(POPAnimation *anim, BOOL finished) {
351 | if (finished) {}};
352 | [self.mapImageVIew.layer pop_addAnimation:anim forKey:@"MoveMap"];
353 |
354 | POPSpringAnimation *animAlpha = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerOpacity];
355 | animAlpha.toValue = @1.0;
356 | animAlpha.springBounciness = 4.0;
357 | animAlpha.springSpeed = 12.0;
358 | animAlpha.completionBlock = ^(POPAnimation *anim, BOOL finished) {
359 | if (finished) {}};
360 | [self.mapImageVIew.layer pop_addAnimation:animAlpha forKey:@"AlphaMap"];
361 |
362 | POPSpringAnimation *animSize = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
363 | animSize.toValue = [NSValue valueWithCGPoint:CGPointMake(0.9, 0.9)];
364 | animSize.springBounciness = 15.0;
365 | animSize.springSpeed = 12.0;
366 | animSize.completionBlock = ^(POPAnimation *anim, BOOL finished) {
367 | if (finished) {
368 |
369 | #ifdef DEBUG
370 | NSLog(@"Update station %@", [GVUserDefaults standardUserDefaults].currentStationDict);
371 | #endif
372 |
373 | if ([GVUserDefaults standardUserDefaults].currentStationDict) {
374 | self.currentStationDict = [GVUserDefaults standardUserDefaults].currentStationDict;
375 | [self changeLocation:CGPointMake([[self.currentStationDict valueForKey:@"x"] floatValue], [[self.currentStationDict valueForKey:@"y"] floatValue])];
376 | [[NSNotificationCenter defaultCenter] postNotificationName:CCNFilterStationStatus object:self.currentStationDict];
377 | }else{
378 | [self changeLocation:CGPointMake(0, 0)];
379 | }
380 |
381 | [self.stationLocationView show];
382 |
383 | POPSpringAnimation *animAlpha = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerOpacity];
384 | animAlpha.toValue = @1.0;
385 | animAlpha.springBounciness = 4.0;
386 | animAlpha.springSpeed = 12.0;
387 | animAlpha.completionBlock = ^(POPAnimation *anim, BOOL finished) {
388 | if (finished) {}};
389 | [self.connectButton.layer pop_addAnimation:animAlpha forKey:@"AlphaMap"];
390 |
391 | POPSpringAnimation *anim = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerPosition];
392 | anim.toValue = [NSValue valueWithCGPoint:CGPointMake(SCREEN_WIDTH/2.0, (SCREEN_HEIGHT - 70.0) )];
393 | anim.springBounciness = 10.0;
394 | anim.springSpeed = 12.0;
395 | anim.completionBlock = ^(POPAnimation *anim, BOOL finished) {
396 | if (finished) {
397 |
398 | [self relayout];
399 |
400 | dispatch_async(dispatch_get_main_queue(), ^{
401 |
402 | [UIView animateWithDuration:0.3 animations:^{
403 |
404 | NSString * sponser = [self.stationDic valueForKey:@"sponser"];
405 |
406 | NSString * name = [self.stationDic valueForKey:@"name"];
407 |
408 | if (![sponser isEqualToString:@""]) {
409 | self.donaterLabel.text = [NSString stringWithFormat:@"%@ sponsored by %@", name, sponser];
410 | self.donaterLabel.alpha = 1.0;
411 | } else {
412 | self.donaterLabel.alpha = 0.0;
413 | }
414 |
415 |
416 | }];
417 |
418 | });
419 |
420 |
421 |
422 | }
423 | };
424 | [self.connectButton.layer pop_addAnimation:anim forKey:@"MoveMap"];
425 |
426 |
427 | [self showStations];
428 |
429 | }
430 | };
431 | [self.mapImageVIew.layer pop_addAnimation:animSize forKey:@"SizeMap"];
432 | }
433 |
434 | - (void)didReceiveMemoryWarning {
435 | [super didReceiveMemoryWarning];
436 | // Dispose of any resources that can be recreated.
437 | }
438 |
439 | - (IBAction)doConnect:(id)sender {
440 |
441 |
442 | // [self bumbButton];
443 | if (self.isPrepareProfile) {
444 | return;
445 | }
446 | self.isPrepareProfile = YES;
447 | [self.vpnmanager prepareWithCompletion:^(NSError *error) {
448 | self.isPrepareProfile = NO;
449 |
450 | if (self.vpnmanager.vpnManager.connection.status != NEVPNStatusDisconnected && self.vpnmanager.vpnManager.connection.status != NEVPNStatusInvalid) {
451 |
452 | [self.vpnmanager.vpnManager.connection stopVPNTunnel];
453 |
454 | [self showStations];
455 |
456 | NSLog(@"Show stations");
457 |
458 | }else{
459 | if (self.domain) {
460 |
461 | [self hideStations];
462 |
463 |
464 | if ([GVUserDefaults standardUserDefaults].ikev2) {
465 | [self.vpnmanager connectIPSecIKEv2WithHost:self.domain andUsername:[[VPNStations sharedInstance].config valueForKey:@"username"] andPassword:[[VPNStations sharedInstance].config valueForKey:@"password"] andPSK:[[VPNStations sharedInstance].config valueForKey:@"psk"] andGroupName:[[VPNStations sharedInstance].config valueForKey:@"groupname"]];
466 | } else {
467 | [self.vpnmanager connectIPSecWithHost:self.domain andUsername:[[VPNStations sharedInstance].config valueForKey:@"username"] andPassword:[[VPNStations sharedInstance].config valueForKey:@"password"] andPSK:[[VPNStations sharedInstance].config valueForKey:@"psk"] andGroupName:[[VPNStations sharedInstance].config valueForKey:@"groupname"]];
468 | }
469 |
470 | }
471 | }
472 |
473 | }];
474 |
475 |
476 | }
477 |
478 | -(void)showStationView
479 | {
480 | [self fillWithStationView:self.stationViewOne];
481 |
482 | POPSpringAnimation *animAlpha = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerOpacity];
483 | animAlpha.toValue = @1.0;
484 | animAlpha.springBounciness = 4.0;
485 | animAlpha.springSpeed = 12.0;
486 | animAlpha.completionBlock = ^(POPAnimation *anim, BOOL finished) {
487 | if (finished) {}};
488 | [self.stationViewOne.layer pop_addAnimation:animAlpha forKey:@"AlphaMap"];
489 |
490 | POPSpringAnimation *anim =
491 | [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
492 | anim.springBounciness = 10;
493 | anim.springSpeed = 20;
494 | anim.fromValue = [NSValue valueWithCGPoint:CGPointMake(0.5, 0.5)];
495 | anim.toValue = [NSValue valueWithCGPoint:CGPointMake(1.0, 1.0)];
496 | [self.stationViewOne.layer pop_addAnimation:anim forKey:@"AnimationScaleBack"];
497 |
498 | self.stationViewOne.displayed = YES;
499 |
500 | }
501 |
502 | -(void)hideStationView
503 | {
504 |
505 | POPSpringAnimation *animAlpha = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerOpacity];
506 | animAlpha.toValue = @0.0;
507 | animAlpha.springBounciness = 4.0;
508 | animAlpha.springSpeed = 12.0;
509 | animAlpha.completionBlock = ^(POPAnimation *anim, BOOL finished) {
510 | if (finished) {}};
511 | [self.stationViewOne.layer pop_addAnimation:animAlpha forKey:@"AlphaMap"];
512 |
513 | POPSpringAnimation *anim =
514 | [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
515 | anim.springBounciness = 10;
516 | anim.springSpeed = 20;
517 | anim.fromValue = [NSValue valueWithCGPoint:CGPointMake(1.0, 1.0)];
518 | anim.toValue = [NSValue valueWithCGPoint:CGPointMake(0.5, 0.5)];
519 | [self.stationViewOne.layer pop_addAnimation:anim forKey:@"AnimationScaleBack"];
520 |
521 | self.stationViewOne.displayed = NO;
522 |
523 | }
524 |
525 | - (void)hideTableView
526 | {
527 |
528 | #ifdef DEBUG
529 | NSLog(@"Hide table view");
530 | #endif
531 | [self.tableViewTopConstraint pop_removeAnimationForKey:@"stationsHideAnimation"];
532 | POPSpringAnimation *stationsHideAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayoutConstraintConstant];
533 | stationsHideAnimation.toValue = @(TableViewTopConstraintInitialConstant);
534 | stationsHideAnimation.springSpeed = 4.0;
535 | stationsHideAnimation.springBounciness = 0.0;
536 | stationsHideAnimation.removedOnCompletion = YES;
537 | [self.tableViewTopConstraint pop_addAnimation:stationsHideAnimation forKey:@"stationsHideAnimation"];
538 |
539 | [self.tableViewTopConstraint pop_removeAnimationForKey:@"AlphaMap"];
540 | POPSpringAnimation *animAlpha = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerOpacity];
541 | animAlpha.toValue = @0.0;
542 | animAlpha.springBounciness = 0.0;
543 | animAlpha.springSpeed = 20.0;
544 | animAlpha.completionBlock = ^(POPAnimation *anim, BOOL finished) {
545 | if (finished) {}};
546 | animAlpha.removedOnCompletion = YES;
547 | [self.stationsTableVIew.layer pop_addAnimation:animAlpha forKey:@"AlphaMap"];
548 | }
549 |
550 | -(void)hideStations
551 | {
552 | [self hideTableView];
553 |
554 | [self showStationView];
555 |
556 | self.stationShowed = NO;
557 | }
558 |
559 | - (void)showTableView
560 | {
561 |
562 | POPSpringAnimation *stationsShowAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayoutConstraintConstant];
563 | stationsShowAnimation.toValue = @0;
564 | stationsShowAnimation.springSpeed = 6.0;
565 | stationsShowAnimation.springBounciness = 10.0;
566 | stationsShowAnimation.removedOnCompletion = YES;
567 | [self.tableViewTopConstraint pop_addAnimation:stationsShowAnimation forKey:@"stationsShowAnimation"];
568 |
569 | POPSpringAnimation *animAlpha = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerOpacity];
570 | animAlpha.toValue = @1.0;
571 | animAlpha.springBounciness = 4.0;
572 | animAlpha.springSpeed = 12.0;
573 | animAlpha.removedOnCompletion = YES;
574 | [self.stationsTableVIew.layer pop_addAnimation:animAlpha forKey:@"AlphaMap"];
575 | }
576 |
577 | -(void)showStations
578 | {
579 | [self showTableView];
580 |
581 | [self hideStationView];
582 |
583 | self.stationShowed = YES;
584 | }
585 |
586 | -(void)relayout
587 | {
588 |
589 | [self.vpnmanager prepareWithCompletion:^(NSError *error) {
590 |
591 | if (self.vpnmanager.vpnManager.connection.status == NEVPNStatusConnected) {
592 |
593 |
594 | [UIView transitionWithView:self.mapImageVIew
595 | duration:0.3
596 | options:UIViewAnimationOptionTransitionCrossDissolve
597 | animations:^{
598 | self.mapImageVIew.image = [UIImage imageNamed:@"Map"];
599 | }
600 | completion:NULL];
601 | self.stationViewOne.status = @"Connected";
602 | // [self activeButtonStatus:self.connectionButton];
603 |
604 | [self.connectButton setTitle:NSLocalizedString(@"Disconnect", nil) forState:UIControlStateNormal];
605 | [self.connectButton setBackgroundImage:[UIImage imageNamed:@"Button_wire"] forState:UIControlStateNormal];
606 |
607 | if (!self.stationViewOne.displayed) {
608 | [self hideStations];
609 | }
610 |
611 | }else if (self.vpnmanager.vpnManager.connection.status == NEVPNStatusConnecting) {
612 |
613 | // [self activeButtonStatus:self.connectionButton];
614 |
615 | self.stationViewOne.status = @"Connecting";
616 | [self.connectButton setTitle:NSLocalizedString(@"Connecting", nil) forState:UIControlStateNormal];
617 | [self.connectButton setBackgroundImage:[UIImage imageNamed:@"Button_wire"] forState:UIControlStateNormal];
618 |
619 | }
620 | else if ( self.vpnmanager.vpnManager.connection.status == NEVPNStatusDisconnecting)
621 | {
622 |
623 | // [self.connectButton setTitle:@"Disconnection" forState:UIControlStateNormal];
624 | }
625 | else if(self.vpnmanager.vpnManager.connection.status == NEVPNStatusDisconnected){
626 |
627 | [UIView transitionWithView:self.mapImageVIew
628 | duration:0.3
629 | options:UIViewAnimationOptionTransitionCrossDissolve
630 | animations:^{
631 | self.mapImageVIew.image = [UIImage imageNamed:@"World Map"];
632 | }
633 | completion:NULL];
634 |
635 | [self.connectButton setTitle:NSLocalizedString(@"Connect", nil) forState:UIControlStateNormal];
636 | [self.connectButton setBackgroundImage:[UIImage imageNamed:@"Button + Connect"] forState:UIControlStateNormal];
637 | if (![self.stationViewOne.status isEqualToString:@"Disconnected"] && !self.stationShowed) {
638 | [SVProgressHUD showInfoWithStatus:@"Connect Failed"];
639 | [self showStations];
640 | }
641 |
642 | self.stationViewOne.status = @"Disconnected";
643 | // [self inactiveButtonStatus:self.connectionButton];
644 | }
645 |
646 |
647 | }];
648 | }
649 |
650 | #pragma mark - Table View
651 |
652 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
653 | {
654 | return 1;
655 | }
656 |
657 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
658 | return self.vpnStations.count;
659 | }
660 |
661 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
662 | {
663 | StationTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"stationCell"];
664 | if (cell == nil) {
665 | cell = [[StationTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"stationCell"];
666 | cell.selectionStyle = UITableViewCellSelectionStyleNone;
667 | }
668 |
669 | NSDictionary * station = [self.vpnStations objectAtIndex:indexPath.row];
670 |
671 | cell.flagImageView.image = [UIImage imageNamed:[station valueForKey:@"short_name"]];
672 | cell.stationNameLabel.text =[station valueForKey:@"name"];
673 | [cell setDomain:[station valueForKey:@"host"] withIndex:indexPath.row];
674 | if([cell.domain isEqualToString:[GVUserDefaults standardUserDefaults].server]){
675 | self.stationDic = [self.vpnStations objectAtIndex:indexPath.row];
676 | }
677 |
678 | cell.stationDic = station;
679 |
680 | #ifdef DEBUG
681 | NSLog(@"Show cell");
682 | #endif
683 |
684 | return cell;
685 | }
686 |
687 | -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
688 | {
689 |
690 |
691 | #ifdef DEBUG
692 | NSLog(@"Did select row");
693 | #endif
694 |
695 | StationTableViewCell *cell = (StationTableViewCell *)[tableView cellForRowAtIndexPath:indexPath];
696 | [cell makeCheck];
697 |
698 | self.stationDic = [self.vpnStations objectAtIndex:indexPath.row];
699 |
700 | [UIView animateWithDuration:0.3 animations:^{
701 |
702 | NSString * sponser = [self.stationDic valueForKey:@"sponser"];
703 |
704 | NSString * name = [self.stationDic valueForKey:@"name"];
705 |
706 | if (![sponser isEqualToString:@""]) {
707 | self.donaterLabel.text = [NSString stringWithFormat:@"%@ sponsored by %@", name, sponser];
708 | self.donaterLabel.alpha = 1.0;
709 | } else {
710 | self.donaterLabel.alpha = 0.0;
711 | }
712 |
713 |
714 |
715 | }];
716 | }
717 |
718 |
719 | -(void)fillWithStationView:(stationView *)view
720 | {
721 | view.stationFlag.image = [UIImage imageNamed:[self.stationDic valueForKey:@"short_name"]];
722 | view.name = [self.stationDic valueForKey:@"name"];
723 | view.status = @"Connecting";
724 | }
725 |
726 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView
727 | {
728 |
729 | #ifdef DEBUG
730 | NSLog(@"scrollView.contentOffset.y: %@", @(scrollView.contentOffset.y));
731 | #endif
732 |
733 | [self.stationsTableVIew.layer pop_removeAnimationForKey:@"stationsShowAnimation"];
734 |
735 | CGFloat thresholdForShowInviteView = 70.0;
736 |
737 | if (self.inviteView) {
738 | // scrollView.alpha = 0.0;
739 | } else if (self.userCanInvite){
740 | scrollView.alpha = 1.0 - (MIN(thresholdForShowInviteView, scrollView.contentOffset.y) / thresholdForShowInviteView);
741 | }
742 |
743 | if (scrollView.contentOffset.y > thresholdForShowInviteView) {
744 |
745 | if (!self.inviteView && self.userCanInvite) {
746 | //scrollView.hidden = YES;
747 | scrollView.scrollEnabled = NO;
748 | //CGPoint contentOffset = scrollView.contentOffset;
749 | //contentOffset.y = thresholdForShowInviteView;
750 | //scrollView.contentOffset = contentOffset;
751 | scrollView.alpha = 0.0;
752 | //scrollView.hidden = NO;
753 | //NSLog(@"do show invite view");
754 | [self showInviteView];
755 | }
756 | }
757 | }
758 |
759 | #pragma mark - Invite View
760 |
761 | - (InviteView *)makeInviteView
762 | {
763 | InviteView *inviteView = [[InviteView alloc] initWithFrame:CGRectMake(0, SCREEN_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT)];
764 | //inviteView.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.2];
765 |
766 | [self.view addSubview:inviteView];
767 |
768 | return inviteView;
769 | }
770 |
771 | - (BOOL)textFieldShouldReturn:(UITextField *)textField
772 | {
773 | [self invite];
774 |
775 | return YES;
776 | }
777 |
778 | - (void)invite
779 | {
780 |
781 | #ifdef DEBUG
782 | NSLog(@"do invite");
783 | #endif
784 | if (!self.inviteView.emailTextField.text.length > 1) {
785 | return;
786 | }
787 |
788 | [SVProgressHUD show];
789 | [self doInviteEmail:self.inviteView.emailTextField.text];
790 | [self hideInviteView];
791 | }
792 |
793 | - (void)showInviteView
794 | {
795 | self.inviteView = [self makeInviteView];
796 |
797 | [self hideTableView];
798 |
799 | POPSpringAnimation *anim = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerPosition];
800 | anim.toValue = [NSValue valueWithCGPoint:CGPointMake(SCREEN_WIDTH * 0.5, (SCREEN_WIDTH * 0.3))];
801 | anim.springBounciness = 4.0;
802 | anim.springSpeed = 12.0;
803 | anim.removedOnCompletion = YES;
804 | [self.mapImageVIew.layer pop_addAnimation:anim forKey:@"MoveMap"];
805 |
806 | POPBasicAnimation *scaleAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
807 | scaleAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(1.2, 1.2)];
808 | scaleAnimation.removedOnCompletion = YES;
809 | [self.mapImageVIew.layer pop_addAnimation:scaleAnimation forKey:@"Scale"];
810 |
811 |
812 | POPSpringAnimation *showInviteViewAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerPosition];
813 | showInviteViewAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(SCREEN_WIDTH * 0.5, (SCREEN_HEIGHT * 0.5))];
814 | showInviteViewAnimation.springBounciness = 4.0;
815 | showInviteViewAnimation.springSpeed = 12.0;
816 | showInviteViewAnimation.removedOnCompletion = YES;
817 | showInviteViewAnimation.completionBlock = ^(POPAnimation *anim, BOOL finished) {
818 | if (finished) {
819 | [_inviteView.emailTextField becomeFirstResponder];
820 | _inviteView.emailTextField.delegate = self;
821 |
822 | [_inviteView.inviteButton addTarget:self action:@selector(invite) forControlEvents:UIControlEventTouchUpInside];
823 |
824 | UISwipeGestureRecognizer *swipeDownGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(hideInviteView)];
825 | swipeDownGestureRecognizer.direction = UISwipeGestureRecognizerDirectionDown;
826 | [_inviteView addGestureRecognizer:swipeDownGestureRecognizer];
827 | }
828 | };
829 |
830 | [_inviteView.layer pop_addAnimation:showInviteViewAnimation forKey:@"showInviteViewAnimation"];
831 | }
832 |
833 | - (void)hideInviteView
834 | {
835 | [self.inviteView.emailTextField resignFirstResponder];
836 |
837 | self.stationsTableVIew.scrollEnabled = YES;
838 |
839 | POPSpringAnimation *hideInviteViewAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerPosition];
840 | hideInviteViewAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(SCREEN_WIDTH * 0.5, (SCREEN_HEIGHT * 1.5))];
841 | hideInviteViewAnimation.springBounciness = 4.0;
842 | hideInviteViewAnimation.springSpeed = 8.0;
843 | hideInviteViewAnimation.removedOnCompletion = YES;
844 |
845 | [_inviteView.layer pop_addAnimation:hideInviteViewAnimation forKey:@"hideInviteViewAnimation"];
846 |
847 | POPBasicAnimation *alphaAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerOpacity];
848 | alphaAnimation.toValue = @0;
849 | alphaAnimation.duration = 0.2;
850 | alphaAnimation.removedOnCompletion = YES;
851 | [self.inviteView.layer pop_addAnimation:alphaAnimation forKey:@"alphaAnimation"];
852 |
853 | POPSpringAnimation *anim = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerPosition];
854 | anim.toValue = [NSValue valueWithCGPoint:CGPointMake(SCREEN_WIDTH * 0.5, (SCREEN_HEIGHT - 240.0))];
855 | anim.springBounciness = 4.0;
856 | anim.springSpeed = 8.0;
857 | anim.removedOnCompletion = YES;
858 | anim.completionBlock = ^(POPAnimation *anim, BOOL finished) {
859 | if (finished) {
860 | [_inviteView removeFromSuperview];
861 | }
862 | };
863 | [self.mapImageVIew.layer pop_addAnimation:anim forKey:@"MoveMap"];
864 |
865 | POPBasicAnimation *scaleAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
866 | scaleAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(0.9, 0.9)];
867 | scaleAnimation.removedOnCompletion = YES;
868 | [self.mapImageVIew.layer pop_addAnimation:scaleAnimation forKey:@"Scale"];
869 |
870 | [self showTableView];
871 | }
872 |
873 | -(void)doInviteEmail:(NSString *)email
874 | {
875 | AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
876 | NSDictionary *parameters = @{
877 | @"email": email,
878 | @"user_token":[GVUserDefaults standardUserDefaults].token
879 | };
880 | [manager POST:[NSString stringWithFormat:@"%@%@",[[VPNStations sharedInstance].config valueForKey:@"server"], [[VPNStations sharedInstance].config valueForKey:@"do_invite"]] parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
881 |
882 | #ifdef DEBUG
883 | NSLog(@"JSON: %@", responseObject);
884 | #endif
885 |
886 | NSString * message = [responseObject valueForKey:@"message"];
887 | NSString * status = [responseObject valueForKey:@"status"];
888 | if([status isEqualToString:@"error"]){
889 | [SVProgressHUD showErrorWithStatus:message];
890 | }else{
891 | [SVProgressHUD showSuccessWithStatus:message];
892 | }
893 |
894 | } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
895 |
896 | #ifdef DEBUG
897 | NSLog(@"Error: %@", error);
898 | #endif
899 |
900 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
901 | // time-consuming task
902 | dispatch_async(dispatch_get_main_queue(), ^{
903 | [SVProgressHUD showErrorWithStatus:[error description]];
904 | });
905 | });
906 | }];
907 |
908 | }
909 |
910 | - (void)validateUser
911 | {
912 | AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
913 | NSDictionary *parameters = @{
914 | @"user_token":[GVUserDefaults standardUserDefaults].token
915 | };
916 | [manager POST:[NSString stringWithFormat:@"%@%@",[[VPNStations sharedInstance].config valueForKey:@"server"], [[VPNStations sharedInstance].config valueForKey:@"validate_user"]] parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
917 |
918 | #ifdef DEBUG
919 | NSLog(@"JSON: %@", responseObject);
920 | #endif
921 |
922 | NSString * status = [responseObject valueForKey:@"status"];
923 | if([status isEqualToString:@"error"]){
924 |
925 | [GVUserDefaults standardUserDefaults].token = nil;
926 | NSUserDefaults *sharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.catchlab.TodayExtensionSharingDefaults"];
927 |
928 | [sharedDefaults setBool:NO forKey:@"ActiveToday"];
929 | [sharedDefaults synchronize]; // (!!) This is crucial.
930 | }
931 |
932 | } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
933 |
934 | #ifdef DEBUG
935 | NSLog(@"Error: %@", error);
936 | #endif
937 | }];
938 | }
939 |
940 | @end
941 |
--------------------------------------------------------------------------------