This commit is contained in:
Fin 2018-06-27 11:29:51 +08:00
parent ced43a61a8
commit 216814ee4f
36 changed files with 1394 additions and 94 deletions

View File

@ -7,22 +7,51 @@
objects = {
/* Begin PBXBuildFile section */
0603706720E1E31600F4CA05 /* Defines.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0603706620E1E31600F4CA05 /* Defines.swift */; };
0603706920E1F89500F4CA05 /* PreviewCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0603706820E1F89500F4CA05 /* PreviewCardCell.swift */; };
0603706B20E20A7C00F4CA05 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0603706A20E20A7C00F4CA05 /* String+Extension.swift */; };
0603706D20E23EC000F4CA05 /* BarkSFSafariViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0603706C20E23EC000F4CA05 /* BarkSFSafariViewController.swift */; };
0604F7DF20620D4900B32F09 /* ServerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0604F7DE20620D4900B32F09 /* ServerManager.swift */; };
0637FA7820E0926D00E80174 /* BarkTargetType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0637FA7720E0926D00E80174 /* BarkTargetType.swift */; };
0637FA7A20E092B300E80174 /* Observable+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0637FA7920E092B300E80174 /* Observable+Extension.swift */; };
0637FA7C20E0930E00E80174 /* BarkApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0637FA7B20E0930E00E80174 /* BarkApi.swift */; };
0637FA7E20E0969800E80174 /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0637FA7D20E0969800E80174 /* Client.swift */; };
0637FA8020E0981E00E80174 /* BarkSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0637FA7F20E0981E00E80174 /* BarkSettings.swift */; };
0637FA8220E09C4B00E80174 /* BarkNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0637FA8120E09C4B00E80174 /* BarkNavigationController.swift */; };
0637FA8620E0AB6600E80174 /* UIColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0637FA8520E0AB6600E80174 /* UIColor+Extension.swift */; };
0637FA8A20E0D58800E80174 /* NewServerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0637FA8920E0D58800E80174 /* NewServerViewController.swift */; };
0637FA8C20E0D7A700E80174 /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0637FA8B20E0D7A700E80174 /* BaseViewController.swift */; };
0661A543204FDA4100965E4E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0661A542204FDA4100965E4E /* AppDelegate.swift */; };
0661A545204FDA4100965E4E /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0661A544204FDA4100965E4E /* ViewController.swift */; };
0661A548204FDA4100965E4E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0661A546204FDA4100965E4E /* Main.storyboard */; };
0661A545204FDA4100965E4E /* HomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0661A544204FDA4100965E4E /* HomeViewController.swift */; };
0661A54A204FDA4100965E4E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0661A549204FDA4100965E4E /* Assets.xcassets */; };
0661A54D204FDA4100965E4E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0661A54B204FDA4100965E4E /* LaunchScreen.storyboard */; };
4A97FDFB8C102B8A492ED65A /* Pods_Bark.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D155DFC7B804DC5518C01D75 /* Pods_Bark.framework */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
0603706620E1E31600F4CA05 /* Defines.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Defines.swift; sourceTree = "<group>"; };
0603706820E1F89500F4CA05 /* PreviewCardCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewCardCell.swift; sourceTree = "<group>"; };
0603706A20E20A7C00F4CA05 /* String+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extension.swift"; sourceTree = "<group>"; };
0603706C20E23EC000F4CA05 /* BarkSFSafariViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BarkSFSafariViewController.swift; sourceTree = "<group>"; };
0604F7DE20620D4900B32F09 /* ServerManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerManager.swift; sourceTree = "<group>"; };
0637FA7720E0926D00E80174 /* BarkTargetType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BarkTargetType.swift; sourceTree = "<group>"; };
0637FA7920E092B300E80174 /* Observable+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Observable+Extension.swift"; sourceTree = "<group>"; };
0637FA7B20E0930E00E80174 /* BarkApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BarkApi.swift; sourceTree = "<group>"; };
0637FA7D20E0969800E80174 /* Client.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Client.swift; sourceTree = "<group>"; };
0637FA7F20E0981E00E80174 /* BarkSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BarkSettings.swift; sourceTree = "<group>"; };
0637FA8120E09C4B00E80174 /* BarkNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BarkNavigationController.swift; sourceTree = "<group>"; };
0637FA8520E0AB6600E80174 /* UIColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Extension.swift"; sourceTree = "<group>"; };
0637FA8920E0D58800E80174 /* NewServerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewServerViewController.swift; sourceTree = "<group>"; };
0637FA8B20E0D7A700E80174 /* BaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = "<group>"; };
0661A53F204FDA4100965E4E /* Bark.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Bark.app; sourceTree = BUILT_PRODUCTS_DIR; };
0661A542204FDA4100965E4E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
0661A544204FDA4100965E4E /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
0661A547204FDA4100965E4E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
0661A544204FDA4100965E4E /* HomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewController.swift; sourceTree = "<group>"; };
0661A549204FDA4100965E4E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
0661A54C204FDA4100965E4E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
0661A54E204FDA4100965E4E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
0683486A2050F1310024B6DA /* Bark.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Bark.entitlements; sourceTree = "<group>"; };
0683487020510FB20024B6DA /* UserNotifications.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotifications.framework; path = System/Library/Frameworks/UserNotifications.framework; sourceTree = SDKROOT; };
0683487220510FB20024B6DA /* UserNotificationsUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotificationsUI.framework; path = System/Library/Frameworks/UserNotificationsUI.framework; sourceTree = SDKROOT; };
1CC985CE300A858FF65E166A /* Pods-Bark.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Bark.release.xcconfig"; path = "Pods/Target Support Files/Pods-Bark/Pods-Bark.release.xcconfig"; sourceTree = "<group>"; };
87D1222A4C6E7283974A44C6 /* Pods-Bark.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Bark.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Bark/Pods-Bark.debug.xcconfig"; sourceTree = "<group>"; };
D155DFC7B804DC5518C01D75 /* Pods_Bark.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Bark.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@ -40,9 +69,48 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
0604F7DB20620D2700B32F09 /* Controller */ = {
isa = PBXGroup;
children = (
0637FA8B20E0D7A700E80174 /* BaseViewController.swift */,
0637FA8120E09C4B00E80174 /* BarkNavigationController.swift */,
0661A544204FDA4100965E4E /* HomeViewController.swift */,
0637FA8920E0D58800E80174 /* NewServerViewController.swift */,
0603706C20E23EC000F4CA05 /* BarkSFSafariViewController.swift */,
);
path = Controller;
sourceTree = "<group>";
};
0604F7DC20620D3400B32F09 /* View */ = {
isa = PBXGroup;
children = (
0603706820E1F89500F4CA05 /* PreviewCardCell.swift */,
);
path = View;
sourceTree = "<group>";
};
0604F7DD20620D3800B32F09 /* Model */ = {
isa = PBXGroup;
children = (
0603706620E1E31600F4CA05 /* Defines.swift */,
0637FA8520E0AB6600E80174 /* UIColor+Extension.swift */,
0603706A20E20A7C00F4CA05 /* String+Extension.swift */,
0637FA7F20E0981E00E80174 /* BarkSettings.swift */,
0604F7DE20620D4900B32F09 /* ServerManager.swift */,
0637FA7720E0926D00E80174 /* BarkTargetType.swift */,
0637FA7920E092B300E80174 /* Observable+Extension.swift */,
0637FA7B20E0930E00E80174 /* BarkApi.swift */,
0637FA7D20E0969800E80174 /* Client.swift */,
);
path = Model;
sourceTree = "<group>";
};
0661A536204FDA4100965E4E = {
isa = PBXGroup;
children = (
0604F7DD20620D3800B32F09 /* Model */,
0604F7DC20620D3400B32F09 /* View */,
0604F7DB20620D2700B32F09 /* Controller */,
0661A541204FDA4100965E4E /* Bark */,
0661A540204FDA4100965E4E /* Products */,
9563D0DB71FE280909AB1C63 /* Pods */,
@ -61,9 +129,8 @@
0661A541204FDA4100965E4E /* Bark */ = {
isa = PBXGroup;
children = (
0683486A2050F1310024B6DA /* Bark.entitlements */,
0661A542204FDA4100965E4E /* AppDelegate.swift */,
0661A544204FDA4100965E4E /* ViewController.swift */,
0661A546204FDA4100965E4E /* Main.storyboard */,
0661A549204FDA4100965E4E /* Assets.xcassets */,
0661A54B204FDA4100965E4E /* LaunchScreen.storyboard */,
0661A54E204FDA4100965E4E /* Info.plist */,
@ -84,6 +151,8 @@
isa = PBXGroup;
children = (
D155DFC7B804DC5518C01D75 /* Pods_Bark.framework */,
0683487020510FB20024B6DA /* UserNotifications.framework */,
0683487220510FB20024B6DA /* UserNotificationsUI.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@ -118,12 +187,17 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 0920;
LastUpgradeCheck = 0930;
ORGANIZATIONNAME = Fin;
TargetAttributes = {
0661A53E204FDA4100965E4E = {
CreatedOnToolsVersion = 9.2;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.Push = {
enabled = 1;
};
};
};
};
};
@ -152,7 +226,6 @@
files = (
0661A54D204FDA4100965E4E /* LaunchScreen.storyboard in Resources */,
0661A54A204FDA4100965E4E /* Assets.xcassets in Resources */,
0661A548204FDA4100965E4E /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -200,26 +273,36 @@
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-Bark/Pods-Bark-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework",
"${BUILT_PRODUCTS_DIR}/DefaultsKit/DefaultsKit.framework",
"${BUILT_PRODUCTS_DIR}/DeviceKit/DeviceKit.framework",
"${BUILT_PRODUCTS_DIR}/FDFullscreenPopGesture/FDFullscreenPopGesture.framework",
"${BUILT_PRODUCTS_DIR}/KVOController/KVOController.framework",
"${BUILT_PRODUCTS_DIR}/MJRefresh/MJRefresh.framework",
"${BUILT_PRODUCTS_DIR}/Material/Material.framework",
"${BUILT_PRODUCTS_DIR}/Motion/Motion.framework",
"${BUILT_PRODUCTS_DIR}/Moya/Moya.framework",
"${BUILT_PRODUCTS_DIR}/ObjectMapper/ObjectMapper.framework",
"${BUILT_PRODUCTS_DIR}/Result/Result.framework",
"${BUILT_PRODUCTS_DIR}/RxSwift/RxSwift.framework",
"${BUILT_PRODUCTS_DIR}/SVProgressHUD/SVProgressHUD.framework",
"${BUILT_PRODUCTS_DIR}/SnapKit/SnapKit.framework",
"${BUILT_PRODUCTS_DIR}/SwiftyJSON/SwiftyJSON.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DefaultsKit.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DeviceKit.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FDFullscreenPopGesture.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/KVOController.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MJRefresh.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Material.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Motion.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Moya.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ObjectMapper.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Result.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxSwift.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SVProgressHUD.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SnapKit.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyJSON.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@ -233,7 +316,21 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0661A545204FDA4100965E4E /* ViewController.swift in Sources */,
0603706920E1F89500F4CA05 /* PreviewCardCell.swift in Sources */,
0637FA8C20E0D7A700E80174 /* BaseViewController.swift in Sources */,
0603706D20E23EC000F4CA05 /* BarkSFSafariViewController.swift in Sources */,
0637FA7820E0926D00E80174 /* BarkTargetType.swift in Sources */,
0637FA7E20E0969800E80174 /* Client.swift in Sources */,
0661A545204FDA4100965E4E /* HomeViewController.swift in Sources */,
0637FA8620E0AB6600E80174 /* UIColor+Extension.swift in Sources */,
0637FA8A20E0D58800E80174 /* NewServerViewController.swift in Sources */,
0637FA8220E09C4B00E80174 /* BarkNavigationController.swift in Sources */,
0637FA7A20E092B300E80174 /* Observable+Extension.swift in Sources */,
0604F7DF20620D4900B32F09 /* ServerManager.swift in Sources */,
0603706720E1E31600F4CA05 /* Defines.swift in Sources */,
0637FA7C20E0930E00E80174 /* BarkApi.swift in Sources */,
0637FA8020E0981E00E80174 /* BarkSettings.swift in Sources */,
0603706B20E20A7C00F4CA05 /* String+Extension.swift in Sources */,
0661A543204FDA4100965E4E /* AppDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -241,14 +338,6 @@
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
0661A546204FDA4100965E4E /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
0661A547204FDA4100965E4E /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
0661A54B204FDA4100965E4E /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
@ -274,6 +363,7 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
@ -281,6 +371,7 @@
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
@ -331,6 +422,7 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
@ -338,6 +430,7 @@
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
@ -372,11 +465,13 @@
baseConfigurationReference = 87D1222A4C6E7283974A44C6 /* Pods-Bark.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = Bark/Bark.entitlements;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 5U8LBRXG3A;
INFOPLIST_FILE = Bark/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = me.fin.Bark;
PRODUCT_BUNDLE_IDENTIFIER = me.fin.bark;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = 1;
@ -388,11 +483,13 @@
baseConfigurationReference = 1CC985CE300A858FF65E166A /* Pods-Bark.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = Bark/Bark.entitlements;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 5U8LBRXG3A;
INFOPLIST_FILE = Bark/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = me.fin.Bark;
PRODUCT_BUNDLE_IDENTIFIER = me.fin.bark;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = 1;

View File

@ -7,7 +7,8 @@
//
import UIKit
import Material
import UserNotifications
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
@ -15,10 +16,37 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.backgroundColor = Color.grey.lighten5
self.window?.rootViewController = BarkSnackbarController(rootViewController: BarkNavigationController(rootViewController: HomeViewController()))
self.window?.makeKeyAndVisible()
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
dispatch_sync_safely_main_queue {
if settings.authorizationStatus == .authorized {
Client.shared.registerForRemoteNotifications()
}
else{
Client.shared.state = .unRegister
}
}
}
return true
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print(error)
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let deviceTokenString = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
Settings[.deviceToken] = deviceTokenString
//
Client.shared.bindDeviceToken()
}
func applicationWillResignActive(_ application: UIApplication) {
// 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.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
@ -30,7 +58,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
if Client.shared.state == .serverError{
Client.shared.bindDeviceToken()
}
}
func applicationDidBecomeActive(_ application: UIApplication) {

View File

@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -0,0 +1,26 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "baseline_file_copy_white_24pt_1x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "baseline_file_copy_white_24pt_2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "baseline_file_copy_white_24pt_3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 B

View File

@ -0,0 +1,26 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "baseline_http_black_24pt_1x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "baseline_http_black_24pt_2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "baseline_http_black_24pt_3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

View File

@ -0,0 +1,26 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "baseline_https_black_24pt_1x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "baseline_https_black_24pt_2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "baseline_https_black_24pt_3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 483 B

8
Bark/Bark.entitlements Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>aps-environment</key>
<string>development</string>
</dict>
</plist>

View File

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" systemVersion="17A277" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>

View File

@ -4,6 +4,8 @@
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Bark</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
@ -15,15 +17,18 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<string>1.0.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
@ -31,8 +36,6 @@
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
@ -41,5 +44,7 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>
</dict>
</plist>

View File

@ -1,25 +0,0 @@
//
// ViewController.swift
// Bark
//
// Created by huangfeng on 2018/3/7.
// Copyright © 2018 Fin. All rights reserved.
//
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

View File

@ -0,0 +1,42 @@
//
// BarkNavigationController.swift
// Bark
//
// Created by huangfeng on 2018/6/25.
// Copyright © 2018 Fin. All rights reserved.
//
import UIKit
import Material
class BarkNavigationController: NavigationController{
override func prepare() {
super.prepare()
isMotionEnabled = true
motionNavigationTransitionType = .autoReverse(presenting: .fade)
guard let v = navigationBar as? NavigationBar else {
return
}
v.depthPreset = .none
v.dividerColor = Color.grey.lighten2
navigationBar.backgroundColor = Color.blue.darken2
statusBarStyle = .lightContent
}
override var childViewControllerForStatusBarStyle: UIViewController?{
get {
return self.topViewController
}
}
}
class BarkSnackbarController: SnackbarController {
override var childViewControllerForStatusBarStyle: UIViewController?{
return self.rootViewController
}
}

View File

@ -0,0 +1,30 @@
//
// BarkSFSafariViewController.swift
// Bark
//
// Created by huangfeng on 2018/6/26.
// Copyright © 2018 Fin. All rights reserved.
//
import UIKit
import SafariServices
class BarkSFSafariViewController: SFSafariViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override var preferredStatusBarStyle: UIStatusBarStyle{
get {
return .default
}
}
}

View File

@ -0,0 +1,26 @@
//
// BaseViewController.swift
// Bark
//
// Created by huangfeng on 2018/6/25.
// Copyright © 2018 Fin. All rights reserved.
//
import UIKit
import Material
class BaseViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.backButton.tintColor = UIColor.white
self.view.backgroundColor = Color.grey.lighten5
navigationItem.titleLabel.textColor = .white
navigationItem.titleLabel.font = UIFont.systemFont(ofSize: 16)
}
override var preferredStatusBarStyle: UIStatusBarStyle{
get {
return .lightContent
}
}
}

View File

@ -0,0 +1,160 @@
//
// ViewController.swift
// Bark
//
// Created by huangfeng on 2018/3/7.
// Copyright © 2018 Fin. All rights reserved.
//
import UIKit
import UserNotifications
import Material
class HomeViewController: BaseViewController {
let newButton: IconButton = {
let btn = IconButton(image: Icon.add, tintColor: .white)
btn.pulseColor = .white
return btn
}()
let startButton = FABButton(title: "注册设备")
let statusButton = IconButton(image: UIImage(named: "baseline_https_black_24pt"), tintColor: .white)
let tableView :UITableView = {
let tableView = UITableView()
tableView.separatorStyle = .none
tableView.backgroundColor = Color.grey.lighten3
tableView.register(PreviewCardCell.self, forCellReuseIdentifier: "\(PreviewCardCell.self)")
return tableView
}()
var dataSource:[PreviewModel] = {
return [
PreviewModel(
body:"这里改成你自己的推送内容",
notice: "点击右上角按钮可以复制测试URL、预览推送效果\nSafari有缓存没收到推送时请刷新页面"),
PreviewModel(
title: "推送标题",
body:"这里改成你自己的推送内容",
notice: "推送标题的字号比推送内容粗一点")
]
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = Color.grey.lighten3
navigationItem.titleLabel.textColor = .white
navigationItem.titleLabel.textAlignment = .left
navigationItem.detailLabel.textAlignment = .left
navigationItem.detailLabel.textColor = .white
newButton.addTarget(self, action: #selector(new), for: .touchUpInside)
navigationItem.rightViews = [newButton]
navigationItem.leftViews = [statusButton]
self.view.addSubview(self.tableView)
self.tableView.snp.makeConstraints { (make ) in
make.top.right.bottom.left.equalToSuperview()
}
self.tableView.delegate = self
self.tableView.dataSource = self
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
if settings.authorizationStatus != .authorized {
dispatch_sync_safely_main_queue {
self.startButton.transition([ .scale(0.75) , .opacity(0)] )
self.startButton.addTarget(self, action: #selector(self.start), for: .touchUpInside)
self.view.addSubview(self.startButton)
self.startButton.snp.makeConstraints { (make) in
make.width.height.equalTo(150)
make.centerX.equalToSuperview()
make.top.equalTo(150)
}
self.tableView.isHidden = true
}
}
}
NotificationCenter.default.addObserver(self, selector: #selector(refreshState), name: Notification.Name(rawValue: "ClientStateChangeds"), object: nil)
}
override func viewWillAppear(_ animated: Bool) {
if let url = URL(string: ServerManager.shared.currentAddress) {
navigationItem.titleLabel.text = url.host
refreshState()
}
}
}
extension HomeViewController : UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataSource.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 200
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "\(PreviewCardCell.self)", for: indexPath) as! PreviewCardCell
cell.bind(model: dataSource[indexPath.row])
cell.copyHandler = {[weak self] in
self?.showSnackbar(text: "复制成功")
}
return cell
}
}
extension HomeViewController {
@objc func new(){
self.navigationController?.pushViewController(NewServerViewController(), animated: true)
}
@objc func start(){
startButton.titleColor = Color.grey.base
startButton.isEnabled = false
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert , .sound , .badge], completionHandler: {(_ granted: Bool, _ error: Error?) -> Void in
// iOS 12 BUGUI
DispatchQueue.global(qos: .default).async {
DispatchQueue.main.sync {
if granted {
UIApplication.shared.registerForRemoteNotifications()
if self.tableView.isHidden{
self.tableView.isHidden = false
}
self.startButton.removeFromSuperview()
}
else{
self.showSnackbar(text: "绑定设备需要推送。请打开推送后重试")
self.startButton.titleColor = Color.blue.base
self.startButton.isEnabled = true
}
}
}
})
}
@objc func refreshState() {
switch Client.shared.state {
case .ok:
if let url = URL(string: ServerManager.shared.currentAddress) {
if url.scheme?.lowercased() == "https" {
navigationItem.detailLabel.text = "HTTPS安全连接"
statusButton.image = UIImage(named: "baseline_https_black_24pt")
}
else {
navigationItem.detailLabel.text = "连接不安全请使用HTTPS安全连接"
statusButton.image = UIImage(named: "baseline_http_black_24pt")
}
self.tableView.reloadData()
}
case .unRegister:
navigationItem.detailLabel.text = "设备未注册,不能使用推送服务"
case .serverError:
navigationItem.detailLabel.text = "服务器错误,不能使用推送服务"
}
}
}

View File

@ -0,0 +1,83 @@
//
// NewServerViewController.swift
// Bark
//
// Created by huangfeng on 2018/6/25.
// Copyright © 2018 Fin. All rights reserved.
//
import UIKit
import Material
import SnapKit
import SafariServices
class NewServerViewController: BaseViewController {
let addressTextField : TextField = {
let textField = TextField()
textField.keyboardType = .URL
textField.placeholder = "服务器地址"
textField.detail = "输入服务器地址,例如: https://api.day.app"
textField.transition([ .scale(0.85) , .opacity(0)] )
textField.detailLabel.transition([ .scale(0.85) , .opacity(0)] )
return textField
}()
let noticeLabel: UILabel = {
let label = UILabel()
label.text = "查看服务端部署教程"
label.textColor = Color.blue.base
label.font = UIFont.systemFont(ofSize: 12)
label.transition([ .scale(0.85) , .opacity(0), .translate(x: 50)] )
return label
}()
let doneButton = IconButton(image: Icon.check, tintColor: .white)
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.titleLabel.text = "添加私有服务器"
doneButton.addTarget(self, action: #selector(done), for: .touchUpInside)
navigationItem.rightViews = [doneButton]
self.view.layout(addressTextField).top(40).left(10).right(10)
self.view.addSubview(noticeLabel)
noticeLabel.snp.makeConstraints { (make) in
make.top.equalTo(self.addressTextField.snp.bottom).offset(40)
make.left.equalTo(self.addressTextField)
}
noticeLabel.isUserInteractionEnabled = true
noticeLabel.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(noticeClick)))
}
override func viewDidAppear(_ animated: Bool) {
_ = self.addressTextField.becomeFirstResponder()
addressTextField.text = "https://"
}
@objc func done(){
self.addressTextField.resignFirstResponder()
if let text = addressTextField.text, let _ = URL(string: text) {
_ = BarkApi.provider.request(.ping(baseURL: text))
.filterResponseError()
.subscribe(onNext: {[weak self] (_) in
self?.navigationController?.popViewController(animated: true)
ServerManager.shared.currentAddress = text
self?.showSnackbar(text: "修改成功!")
Client.shared.bindDeviceToken()
}, onError: {[weak self] (error) in
self?.showSnackbar(text: "填写的服务器无效,请重试!\(error.localizedDescription)")
})
}
else{
self.showSnackbar(text: "输入的URL好像不对劲!")
}
}
@objc func noticeClick(){
self.navigationController?.present(BarkSFSafariViewController(url: URL(string: "https://day.app/2018/06/bark-server-document/")!), animated: true, completion: nil)
}
}

46
Model/BarkApi.swift Normal file
View File

@ -0,0 +1,46 @@
//
// BarkApi.swift
// Bark
//
// Created by huangfeng on 2018/6/25.
// Copyright © 2018 Fin. All rights reserved.
//
import UIKit
enum BarkApi {
case ping(baseURL:String?)
case register(key:String? , devicetoken:String) //
}
extension BarkApi: BarkTargetType {
var baseURL: URL {
if case let .ping(urlStr) = self, let url = URL(string: urlStr ?? "") {
return url
}
return URL(string: ServerManager.shared.currentAddress)!
}
var parameters: [String : Any]? {
switch self {
case let .register(key, devicetoken):
var params = ["devicetoken":devicetoken]
if let key = key {
params["key"] = key
}
return params
default:
return nil
}
}
var path: String {
switch self {
case .ping:
return "/ping"
case .register:
return "/register"
}
}
}

77
Model/BarkSettings.swift Normal file
View File

@ -0,0 +1,77 @@
//
// BarkSettings.swift
// Bark
//
// Created by huangfeng on 2018/6/25.
// Copyright © 2018 Fin. All rights reserved.
//
import UIKit
import DefaultsKit
enum BarkSettingKey:String {
/// key
case key = "me.fin.bark.key"
case servers = "me.fin.bark.servers"
case currentServer = "me.fin.bark.servers.current"
case deviceToken = "me.fin.bark.deviceToken"
}
class BarkSettings{
static let shared = BarkSettings()
private init(){
}
subscript(key:String) -> String? {
get {
let storeKey = Key<String>(key)
return Defaults.shared.get(for: storeKey)
}
set {
let storeKey = Key<String>(key)
if let value = newValue {
Defaults.shared.set(value, for: storeKey)
}
else {
Defaults.shared.clear(storeKey)
}
}
}
subscript(key:BarkSettingKey) -> String? {
get {
return self[key.rawValue]
}
set {
self[key.rawValue] = newValue
}
}
subscript<T : Codable>(key:String) -> T? {
get {
let storeKey = Key<T>(key)
return Defaults.shared.get(for: storeKey)
}
set {
let storeKey = Key<T>(key)
if let value = newValue {
Defaults.shared.set(value, for: storeKey)
}
else {
Defaults.shared.clear(storeKey)
}
}
}
subscript<T : Codable>(key:BarkSettingKey) -> T? {
get {
return self[key.rawValue]
}
set {
self[key.rawValue] = newValue
}
}
}
let Settings = BarkSettings.shared

128
Model/BarkTargetType.swift Normal file
View File

@ -0,0 +1,128 @@
//
// BarkTargetType.swift
// Bark
//
// Created by huangfeng on 2018/6/25.
// Copyright © 2018 Fin. All rights reserved.
//
import UIKit
import Moya
import RxSwift
import Result
//Providers
fileprivate var retainProviders:[String: Any] = [:]
protocol BarkTargetType: TargetType {
var parameters: [String: Any]? { get }
}
extension BarkTargetType {
var headers: [String : String]? {
return nil
}
var baseURL: URL {
return URL(string: ServerManager.shared.currentAddress)!
}
var method: Moya.Method {
return .get
}
var parameterEncoding: ParameterEncoding {
return URLEncoding.default
}
var sampleData: Data {
return Data()
}
var task: Task {
return requestTaskWithParameters
}
var requestTaskWithParameters: Task {
get {
//
var defaultParameters:[String:Any] = [:]
//
if let parameters = self.parameters {
for (key, value) in parameters {
defaultParameters[key] = value
}
}
return Task.requestParameters(parameters: defaultParameters, encoding: parameterEncoding)
}
}
static var networkActivityPlugin: PluginType {
return NetworkActivityPlugin { (change, type) in
switch change {
case .began:
UIApplication.shared.isNetworkActivityIndicatorVisible = true
case .ended:
UIApplication.shared.isNetworkActivityIndicatorVisible = false
}
}
}
/// provider
static var provider: RxSwift.Reactive< MoyaProvider<Self> > {
let key = "\(Self.self)"
if let provider = retainProviders[key] as? RxSwift.Reactive< MoyaProvider<Self> > {
return provider
}
let provider = Self.weakProvider
retainProviders[key] = provider
return provider
}
/// Provider 使
static var weakProvider: RxSwift.Reactive< MoyaProvider<Self> > {
var plugins:[PluginType] = [networkActivityPlugin]
#if DEBUG
plugins.append(LogPlugin())
#endif
let provider = MoyaProvider<Self>(plugins:plugins)
return provider.rx
}
}
extension RxSwift.Reactive where Base: MoyaProviderType {
public func request(_ token: Base.Target, callbackQueue: DispatchQueue? = nil) -> Observable<Response> {
return Single.create { [weak base] single in
let cancellableToken = base?.request(token, callbackQueue: callbackQueue, progress: nil) { result in
switch result {
case let .success(response):
single(.success(response))
case let .failure(error):
single(.error(error))
}
}
return Disposables.create {
cancellableToken?.cancel()
}
}.asObservable()
}
}
fileprivate class LogPlugin: PluginType{
func willSend(_ request: RequestType, target: TargetType) {
print("\n-------------------\n准备请求: \(target.path)")
print("请求方式: \(target.method.rawValue)")
if let params = (target as? BarkTargetType)?.parameters {
print(params)
}
print("\n")
}
func didReceive(_ result: Result<Response, MoyaError>, target: TargetType) {
print("\n-------------------\n请求结束: \(target.path)")
if let data = result.value?.data, let resutl = String(data: data, encoding: String.Encoding.utf8) {
print("请求结果: \(resutl)")
}
print("\n")
}
}

84
Model/Client.swift Normal file
View File

@ -0,0 +1,84 @@
//
// Client.swift
// Bark
//
// Created by huangfeng on 2018/6/25.
// Copyright © 2018 Fin. All rights reserved.
//
import UIKit
import UserNotifications
class Client: NSObject {
static let shared = Client()
private override init() {
super.init()
}
let appVersion:String = {
var version = "0.0.0"
if let infoDict = Bundle.main.infoDictionary {
if let appVersion = infoDict["CFBundleVersion"] as? String {
version = appVersion
}
}
return version
}()
private var _key:String?
var key:String? {
get {
if _key == nil, let aKey = Settings[.key]{
_key = aKey
}
return _key
}
set {
_key = newValue
Settings[.key] = newValue
}
}
enum ClienState {
case ok
case unRegister
case serverError
}
var state = ClienState.ok {
didSet{
NotificationCenter.default.post(name: Notification.Name(rawValue: "ClientStateChangeds"), object: nil)
}
}
func bindDeviceToken(){
if let token = Settings[.deviceToken] , token.count > 0{
_ = BarkApi.provider.request(.register(key: key, devicetoken: token)).filterResponseError().subscribe(onNext: { (json) in
if let key = json["data","key"].rawString() {
Client.shared.key = key
self.state = .ok
}
else{
self.state = .serverError
}
}, onError: { (error) in
self.state = .serverError
})
}
}
func registerForRemoteNotifications() {
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert , .sound , .badge], completionHandler: {(_ granted: Bool, _ error: Error?) -> Void in
if granted {
DispatchQueue.global(qos: .default).async {
DispatchQueue.main.sync {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
else{
print("没有打开推送")
}
})
}
}

28
Model/Defines.swift Normal file
View File

@ -0,0 +1,28 @@
//
// Defines.swift
// Bark
//
// Created by huangfeng on 2018/6/26.
// Copyright © 2018 Fin. All rights reserved.
//
import UIKit
/// 线
func dispatch_sync_safely_main_queue(_ block: ()->()) {
if Thread.isMainThread {
block()
} else {
DispatchQueue.main.sync {
block()
}
}
}
extension UIViewController {
func showSnackbar(text:String) {
self.snackbarController?.snackbar.text = text
self.snackbarController?.animate(snackbar: .visible)
self.snackbarController?.animate(snackbar: .hidden, delay: 3)
}
}

View File

@ -0,0 +1,125 @@
//
// Observable+Extension.swift
// Bark
//
// Created by huangfeng on 2018/6/25.
// Copyright © 2018 Fin. All rights reserved.
//
import UIKit
import UIKit
import RxSwift
import ObjectMapper
import SwiftyJSON
import Moya
public enum ApiError : Swift.Error {
case Error(info: String)
case AccountBanned(info: String)
}
extension Swift.Error {
func rawString() -> String {
guard let err = self as? ApiError else {
return self.localizedDescription
}
switch err {
case let .Error(info):
return info
case let .AccountBanned(info):
return info
}
}
}
extension Observable where Element: Moya.Response {
/// HTTP
func filterHttpError() -> Observable<Element> {
return filter{ response in
if (200...209) ~= response.statusCode {
return true
}
print("网络错误")
throw ApiError.Error(info: "网络错误")
}
}
/// CODE
func filterResponseError() -> Observable<JSON> {
return filterHttpError().map({ (response) -> JSON in
let json = try JSON(data: response.data)
var code = 400
var msg:String?
if let codeStr = json["code"].rawString(), let c = Int(codeStr) {
code = c
}
if json["message"].exists() {
msg = json["message"].rawString()!
}
if (code == 200){
return json
}
switch code {
default: throw ApiError.Error(info: msg ?? "未知错误")
}
})
}
/// Response JSON Model
///
/// - Parameters:
/// - typeName: Model Class
/// - dataPath: ["data","links"]
func mapResponseToObj<T: Mappable>(_ typeName: T.Type , dataPath:[String] = ["data"] ) -> Observable<T> {
return filterResponseError().map{ json in
var rootJson = json
if dataPath.count > 0{
rootJson = rootJson[dataPath]
}
if let model: T = self.resultFromJSON(json: rootJson) {
return model
}
else{
throw ApiError.Error(info: "json 转换失败")
}
}
}
/// Response JSON Model Array
func mapResponseToObjArray<T: Mappable>(_ type: T.Type, dataPath:[String] = ["data"] ) -> Observable<[T]> {
return filterResponseError().map{ json in
var rootJson = json;
if dataPath.count > 0{
rootJson = rootJson[dataPath]
}
var result = [T]()
guard let jsonArray = rootJson.array else{
return result
}
for json in jsonArray{
if let jsonModel: T = self.resultFromJSON(json: json) {
result.append(jsonModel)
}
else{
throw ApiError.Error(info: "json 转换失败")
}
}
return result
}
}
private func resultFromJSON<T: Mappable>(jsonString:String) -> T? {
return T(JSONString: jsonString)
}
private func resultFromJSON<T: Mappable>(json:JSON) -> T? {
if let str = json.rawString(){
return resultFromJSON(jsonString: str)
}
return nil
}
}

51
Model/ServerManager.swift Normal file
View File

@ -0,0 +1,51 @@
//
// ServerManager.swift
// Bark
//
// Created by huangfeng on 2018/3/21.
// Copyright © 2018 Fin. All rights reserved.
//
import UIKit
let defaultServer = "https://api.day.app"
class ServerManager: NSObject {
static let shared = ServerManager()
private override init() {
if let servers:Set<String> = Settings[.servers] {
self.servers = servers
}
if let address = Settings[.currentServer] {
self.currentAddress = address
}
else{
self.currentAddress = self.servers.first ?? defaultServer
}
super.init()
}
var servers:Set<String> = [defaultServer]
var currentAddress:String {
didSet{
Settings[.currentServer] = currentAddress
}
}
func addServer(server:String){
self.servers.insert(server)
Settings[.servers] = self.servers
}
func removeServer(server:String){
self.servers.remove(server)
if self.servers.count <= 0 {
self.servers.insert(defaultServer)
}
Settings[.servers] = self.servers
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

View File

@ -0,0 +1,23 @@
//
// String+Extension.swift
// Bark
//
// Created by huangfeng on 2018/6/26.
// Copyright © 2018 Fin. All rights reserved.
//
import UIKit
extension String {
//urlurl
func urlEncoded() -> String {
let encodeUrlString = self.addingPercentEncoding(withAllowedCharacters:
.urlQueryAllowed)
return encodeUrlString ?? ""
}
//urlurl
func urlDecoded() -> String {
return self.removingPercentEncoding ?? ""
}
}

View File

@ -0,0 +1,29 @@
//
// UIColor+Extension.swift
// Bark
//
// Created by huangfeng on 2018/6/25.
// Copyright © 2018 Fin. All rights reserved.
//
import UIKit
extension UIColor {
convenience public init(r255:CGFloat, g255:CGFloat, b255:CGFloat, a255:CGFloat = 255) {
self.init(red: r255/255, green: g255/255, blue: b255/255, alpha: a255/255)
}
class func image(color:UIColor, size:CGSize = CGSize(width: 1, height: 1)) -> UIImage{
UIGraphicsBeginImageContext(size)
let context = UIGraphicsGetCurrentContext()
context?.setFillColor(color.cgColor)
context?.fill(CGRect(origin: CGPoint.zero, size: size))
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image! //contextget~
}
var image: UIImage {
return UIColor.image(color: self)
}
}

View File

@ -3,12 +3,16 @@ inhibit_all_warnings!
use_frameworks!
def pods
pod 'SnapKit'
pod 'Material'
pod 'KVOController'
pod 'SVProgressHUD'
pod 'MJRefresh'
pod 'FDFullscreenPopGesture'
pod 'Moya/RxSwift'
pod 'ObjectMapper'
pod 'SwiftyJSON'
pod 'DeviceKit'
pod 'DefaultsKit', :git => 'https://github.com/nmdias/DefaultsKit'
end
target 'Bark' do

View File

@ -1,38 +1,66 @@
PODS:
- Alamofire (4.6.0)
- DeviceKit (1.5.0)
- Alamofire (4.7.2)
- DefaultsKit (0.0.9)
- DeviceKit (1.7.0)
- FDFullscreenPopGesture (1.1)
- KVOController (1.2.0)
- MJRefresh (3.1.15.3)
- Moya/Core (11.0.0):
- Material (2.15.0):
- Material/Core (= 2.15.0)
- Material/Core (2.15.0):
- Motion (~> 1.3.0)
- Motion (1.3.5):
- Motion/Core (= 1.3.5)
- Motion/Core (1.3.5)
- Moya/Core (11.0.2):
- Alamofire (~> 4.1)
- Result (~> 3.0)
- Moya/RxSwift (11.0.0):
- Moya/RxSwift (11.0.2):
- Moya/Core
- RxSwift (~> 4.0)
- ObjectMapper (3.3.0)
- Result (3.2.4)
- RxSwift (4.1.2)
- RxSwift (4.2.0)
- SnapKit (4.0.0)
- SVProgressHUD (2.2.5)
- SwiftyJSON (4.1.0)
DEPENDENCIES:
- DefaultsKit (from `https://github.com/nmdias/DefaultsKit`)
- DeviceKit
- FDFullscreenPopGesture
- KVOController
- MJRefresh
- Material
- Moya/RxSwift
- ObjectMapper
- SnapKit
- SVProgressHUD
- SwiftyJSON
EXTERNAL SOURCES:
DefaultsKit:
:git: https://github.com/nmdias/DefaultsKit
CHECKOUT OPTIONS:
DefaultsKit:
:commit: d0ec9bf0e0aa1b44759122c2faf76eb46e1f847f
:git: https://github.com/nmdias/DefaultsKit
SPEC CHECKSUMS:
Alamofire: f41a599bd63041760b26d393ec1069d9d7b917f4
DeviceKit: 883552d64028056216e913a88f892e7e29678e75
Alamofire: e4fa87002c137ba2d8d634d2c51fabcda0d5c223
DefaultsKit: e47d11c54a53c66f9e5c65a1992dead90bc7144f
DeviceKit: 6a5bdeb103c03757bb94aef1ccb01e08bc8ef4ee
FDFullscreenPopGesture: a8a620179e3d9c40e8e00256dcee1c1a27c6d0f0
KVOController: d72ace34afea42468329623b3379ab3cd1d286b6
MJRefresh: b48380ae2b927b46c4ef000de9adb8dc748e1df7
Moya: be29766339783963a70d1279d69c891ab3a1393c
Material: 00e32bb5e61b3f749044897b2d93acd8bf33faa4
Motion: 9f74d115d7f72bb5380a8e3cde2f8a1fc898ac36
Moya: a725035953bc1c0eb1be505ab903984501d82440
ObjectMapper: b612bf8c8e99c4dc0bb6013a51f7c27966ed5da9
Result: d2d07204ce72856f1fd9130bbe42c35a7b0fea10
RxSwift: e49536837d9901277638493ea537394d4b55f570
RxSwift: 99e10317ddfcc7fbe01356aafd118fde4a0be104
SnapKit: a42d492c16e80209130a3379f73596c3454b7694
SVProgressHUD: 1428aafac632c1f86f62aa4243ec12008d7a51d6
SwiftyJSON: c29297daf073d2aa016295d5809cdd68045c39b3
PODFILE CHECKSUM: aff58c4e14741124f994b6d0084c6bf1a2384835
PODFILE CHECKSUM: 9fe640283f4a4f35eff4a390df2c42a64be57c18
COCOAPODS: 1.4.0

161
View/PreviewCardCell.swift Normal file
View File

@ -0,0 +1,161 @@
//
// PreviewCardCell.swift
// Bark
//
// Created by huangfeng on 2018/6/26.
// Copyright © 2018 Fin. All rights reserved.
//
import UIKit
import Material
class PreviewModel: NSObject {
var title:String?
var body:String?
var category:String?
var notice:String?
init(title:String? = nil, body:String? = nil, category:String? = nil, notice:String? = nil) {
self.title = title
self.body = body
self.category = category
self.notice = notice
}
}
class PreviewCardCell: UITableViewCell {
let previewButton = IconButton(image: Icon.cm.skipForward, tintColor: Color.grey.base)
let copyButton = IconButton(image: UIImage(named: "baseline_file_copy_white_24pt"), tintColor: Color.grey.base)
let toolbar = Toolbar()
let noticeLabel: UILabel = {
let label = UILabel()
label.font = RobotoFont.regular(with: 12)
label.textColor = Color.grey.base
label.numberOfLines = 0
return label
}()
let bottomBar = Bar()
let card = Card()
var copyHandler: (() -> Void)?
let contentLabel: UILabel = {
let label = UILabel()
label.numberOfLines = 0
label.font = RobotoFont.regular(with: 14)
return label
}()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.selectionStyle = .none
self.backgroundColor = Color.grey.lighten3
self.transition([ .scale(0.75) , .opacity(0)] )
self.toolbar.rightViews = [copyButton,previewButton]
self.bottomBar.leftViews = [noticeLabel]
toolbar.titleLabel.font = RobotoFont.regular(with: 14)
toolbar.titleLabel.textColor = Color.grey.darken4
toolbar.titleLabel.textAlignment = .left
toolbar.detailLabel.textAlignment = .left
toolbar.detailLabel.textColor = Color.grey.darken2
card.toolbar = toolbar
card.toolbarEdgeInsetsPreset = .square3
card.toolbarEdgeInsets.bottom = 0
card.toolbarEdgeInsets.right = 8
card.contentView = contentLabel
card.contentViewEdgeInsetsPreset = .wideRectangle3
card.bottomBar = bottomBar
card.bottomBarEdgeInsetsPreset = .wideRectangle2
self.layout(card).horizontally(left: 10, right: 10).top(40)
previewButton.addTarget(self, action: #selector(preview), for: .touchUpInside)
copyButton.addTarget(self, action: #selector(copyURL), for: .touchUpInside)
//
if UIScreen.main.bounds.size.width <= 320 {
card.contentViewEdgeInsetsPreset = .wideRectangle2
card.bottomBarEdgeInsetsPreset = .wideRectangle1
toolbar.titleLabel.font = RobotoFont.regular(with: 12)
toolbar.detailLabel.font = RobotoFont.regular(with: 10)
contentLabel.font = RobotoFont.regular(with: 10)
noticeLabel.font = RobotoFont.regular(with: 10)
}
}
@objc func copyURL(){
if let urlStr = self.contentLabel.text{
UIPasteboard.general.string = urlStr
copyHandler?()
}
}
@objc func preview(){
if let urlStr = self.contentLabel.text?.urlEncoded(),
let url = URL(string: urlStr){
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
}
var previewModel:PreviewModel?
func bind(model:PreviewModel) {
self.previewModel = model
var fontSize:CGFloat = 14
if UIScreen.main.bounds.size.width <= 320 {
fontSize = 11
}
let serverUrl = URL(string: ServerManager.shared.currentAddress)!
let attrStr = NSMutableAttributedString(string: "")
attrStr.append(NSAttributedString(string: serverUrl.absoluteString, attributes: [
NSAttributedStringKey.foregroundColor: Color.grey.darken4,
NSAttributedStringKey.font : RobotoFont.regular(with: fontSize)
]))
attrStr.append(NSAttributedString(string: "/\(Client.shared.key ?? "")", attributes: [
NSAttributedStringKey.foregroundColor: Color.grey.darken3,
NSAttributedStringKey.font : RobotoFont.regular(with: fontSize)
]))
if let title = model.title {
attrStr.append(NSAttributedString(string: "/\(title)", attributes: [
NSAttributedStringKey.foregroundColor: Color.grey.darken1,
NSAttributedStringKey.font : RobotoFont.regular(with: fontSize)
]))
self.toolbar.title = title
}
if let body = model.body {
attrStr.append(NSAttributedString(string: "/\(body)", attributes: [
NSAttributedStringKey.foregroundColor: Color.grey.base,
NSAttributedStringKey.font : RobotoFont.regular(with: fontSize)
]))
if model.title == nil {
self.toolbar.title = body
}
else{
self.toolbar.detail = body
}
}
self.contentLabel.attributedText = attrStr
self.noticeLabel.text = model.notice
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}