Merge pull request #10 from Hext123/main

完成全部主体功能, iOS已经可以正常使用
This commit is contained in:
Easy 2022-01-10 21:35:43 +08:00 committed by GitHub
commit 52038fbd7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 763 additions and 141 deletions

View File

@ -7,6 +7,10 @@ use_frameworks!
def commonPods def commonPods
# Pods for common # Pods for common
pod 'Moya', '~> 15.0' pod 'Moya', '~> 15.0'
pod 'SDWebImageSwiftUI', '~> 2.0.2'
pod 'KRProgressHUD', '~> 3.4.7'
# pod 'WoodPeckeriOS', :configurations => ['Debug']
end end
target 'PushDeer' do target 'PushDeer' do

View File

@ -1,22 +1,40 @@
PODS: PODS:
- Alamofire (5.5.0) - Alamofire (5.5.0)
- KRActivityIndicatorView (3.0.7)
- KRProgressHUD (3.4.7):
- KRActivityIndicatorView (= 3.0.7)
- Moya (15.0.0): - Moya (15.0.0):
- Moya/Core (= 15.0.0) - Moya/Core (= 15.0.0)
- Moya/Core (15.0.0): - Moya/Core (15.0.0):
- Alamofire (~> 5.0) - Alamofire (~> 5.0)
- SDWebImage (5.12.1):
- SDWebImage/Core (= 5.12.1)
- SDWebImage/Core (5.12.1)
- SDWebImageSwiftUI (2.0.2):
- SDWebImage (~> 5.10)
DEPENDENCIES: DEPENDENCIES:
- KRProgressHUD (~> 3.4.7)
- Moya (~> 15.0) - Moya (~> 15.0)
- SDWebImageSwiftUI (~> 2.0.2)
SPEC REPOS: SPEC REPOS:
trunk: trunk:
- Alamofire - Alamofire
- KRActivityIndicatorView
- KRProgressHUD
- Moya - Moya
- SDWebImage
- SDWebImageSwiftUI
SPEC CHECKSUMS: SPEC CHECKSUMS:
Alamofire: 1c4fb5369c3fe93d2857c780d8bbe09f06f97e7c Alamofire: 1c4fb5369c3fe93d2857c780d8bbe09f06f97e7c
KRActivityIndicatorView: ad69e89c4ce40c986cf580595be4829dcad0e35a
KRProgressHUD: a248f0bc6c9c2aed40a37b76e03ffecc7f85c887
Moya: 138f0573e53411fb3dc17016add0b748dfbd78ee Moya: 138f0573e53411fb3dc17016add0b748dfbd78ee
SDWebImage: 4dc3e42d9ec0c1028b960a33ac6b637bb432207b
SDWebImageSwiftUI: 8a3923c95108312b03a599ec1498754af55a6819
PODFILE CHECKSUM: 71abdebce610eefe1a0299d0a0bd00a463b0a79c PODFILE CHECKSUM: e462e86a9cce18b92c573f662ef405e7091cd912
COCOAPODS: 1.11.2 COCOAPODS: 1.11.2

View File

@ -25,13 +25,16 @@
52450F432784943F003652D8 /* HttpRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52450F412784943F003652D8 /* HttpRequest.swift */; }; 52450F432784943F003652D8 /* HttpRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52450F412784943F003652D8 /* HttpRequest.swift */; };
52483FC2277ED6D5003A100E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52483FC1277ED6D5003A100E /* AppDelegate.swift */; }; 52483FC2277ED6D5003A100E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52483FC1277ED6D5003A100E /* AppDelegate.swift */; };
52483FC3277ED6D5003A100E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52483FC1277ED6D5003A100E /* AppDelegate.swift */; }; 52483FC3277ED6D5003A100E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52483FC1277ED6D5003A100E /* AppDelegate.swift */; };
5287FF52278ADC8C00249A0E /* MarkdownUI in Frameworks */ = {isa = PBXBuildFile; productRef = 5287FF51278ADC8C00249A0E /* MarkdownUI */; };
5287FF54278AEA5B00249A0E /* MarkdownUI in Frameworks */ = {isa = PBXBuildFile; productRef = 5287FF53278AEA5B00249A0E /* MarkdownUI */; };
5287FF59278B3AAE00249A0E /* HToast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5287FF58278B3AAE00249A0E /* HToast.swift */; };
5287FF5A278B3AAE00249A0E /* HToast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5287FF58278B3AAE00249A0E /* HToast.swift */; };
5292F4F92776BC7900B9A7BB /* PushDeerApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5292F4F82776BC7900B9A7BB /* PushDeerApp.swift */; }; 5292F4F92776BC7900B9A7BB /* PushDeerApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5292F4F82776BC7900B9A7BB /* PushDeerApp.swift */; };
5292F4FB2776BC7900B9A7BB /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5292F4FA2776BC7900B9A7BB /* ContentView.swift */; }; 5292F4FB2776BC7900B9A7BB /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5292F4FA2776BC7900B9A7BB /* ContentView.swift */; };
5292F4FD2776BC7A00B9A7BB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5292F4FC2776BC7A00B9A7BB /* Assets.xcassets */; }; 5292F4FD2776BC7A00B9A7BB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5292F4FC2776BC7A00B9A7BB /* Assets.xcassets */; };
5292F5002776BC7A00B9A7BB /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5292F4FF2776BC7A00B9A7BB /* Preview Assets.xcassets */; }; 5292F5002776BC7A00B9A7BB /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5292F4FF2776BC7A00B9A7BB /* Preview Assets.xcassets */; };
52B8CF5F277DE660004CB680 /* AppleSignInButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B8CF5E277DE660004CB680 /* AppleSignInButton.swift */; }; 52B8CF5F277DE660004CB680 /* AppleSignInButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B8CF5E277DE660004CB680 /* AppleSignInButton.swift */; };
52B8CF67277E0B44004CB680 /* PushDeerClipApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B8CF66277E0B44004CB680 /* PushDeerClipApp.swift */; }; 52B8CF67277E0B44004CB680 /* PushDeerClipApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B8CF66277E0B44004CB680 /* PushDeerClipApp.swift */; };
52B8CF69277E0B44004CB680 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B8CF68277E0B44004CB680 /* ContentView.swift */; };
52B8CF6B277E0B46004CB680 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 52B8CF6A277E0B46004CB680 /* Assets.xcassets */; }; 52B8CF6B277E0B46004CB680 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 52B8CF6A277E0B46004CB680 /* Assets.xcassets */; };
52B8CF6E277E0B46004CB680 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 52B8CF6D277E0B46004CB680 /* Preview Assets.xcassets */; }; 52B8CF6E277E0B46004CB680 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 52B8CF6D277E0B46004CB680 /* Preview Assets.xcassets */; };
52B8CF73277E0B46004CB680 /* PushDeerClip.app in Embed App Clips */ = {isa = PBXBuildFile; fileRef = 52B8CF64277E0B44004CB680 /* PushDeerClip.app */; platformFilter = ios; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 52B8CF73277E0B46004CB680 /* PushDeerClip.app in Embed App Clips */ = {isa = PBXBuildFile; fileRef = 52B8CF64277E0B44004CB680 /* PushDeerClip.app */; platformFilter = ios; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
@ -58,6 +61,7 @@
52F0243F277737470071D861 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F0243E277737470071D861 /* LoginView.swift */; }; 52F0243F277737470071D861 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F0243E277737470071D861 /* LoginView.swift */; };
52F2C223277961D7006F08DC /* SettingsItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F2C222277961D7006F08DC /* SettingsItemView.swift */; }; 52F2C223277961D7006F08DC /* SettingsItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F2C222277961D7006F08DC /* SettingsItemView.swift */; };
52F40D2F277CA05600766C24 /* MessageItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F40D2E277CA05600766C24 /* MessageItemView.swift */; }; 52F40D2F277CA05600766C24 /* MessageItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F40D2E277CA05600766C24 /* MessageItemView.swift */; };
52FBA09427874879003308C2 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5292F4FA2776BC7900B9A7BB /* ContentView.swift */; };
64B0C15E70CCC382B480F76E /* Pods_PushDeer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E380A18349DE4D26071E913E /* Pods_PushDeer.framework */; }; 64B0C15E70CCC382B480F76E /* Pods_PushDeer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E380A18349DE4D26071E913E /* Pods_PushDeer.framework */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
@ -99,6 +103,7 @@
52450F412784943F003652D8 /* HttpRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HttpRequest.swift; sourceTree = "<group>"; }; 52450F412784943F003652D8 /* HttpRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HttpRequest.swift; sourceTree = "<group>"; };
52450F442784A95D003652D8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; }; 52450F442784A95D003652D8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
52483FC1277ED6D5003A100E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 52483FC1277ED6D5003A100E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
5287FF58278B3AAE00249A0E /* HToast.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HToast.swift; sourceTree = "<group>"; };
5292F4F52776BC7900B9A7BB /* PushDeer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PushDeer.app; sourceTree = BUILT_PRODUCTS_DIR; }; 5292F4F52776BC7900B9A7BB /* PushDeer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PushDeer.app; sourceTree = BUILT_PRODUCTS_DIR; };
5292F4F82776BC7900B9A7BB /* PushDeerApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushDeerApp.swift; sourceTree = "<group>"; }; 5292F4F82776BC7900B9A7BB /* PushDeerApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushDeerApp.swift; sourceTree = "<group>"; };
5292F4FA2776BC7900B9A7BB /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; }; 5292F4FA2776BC7900B9A7BB /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
@ -107,7 +112,6 @@
52B8CF5E277DE660004CB680 /* AppleSignInButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleSignInButton.swift; sourceTree = "<group>"; }; 52B8CF5E277DE660004CB680 /* AppleSignInButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleSignInButton.swift; sourceTree = "<group>"; };
52B8CF64277E0B44004CB680 /* PushDeerClip.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PushDeerClip.app; sourceTree = BUILT_PRODUCTS_DIR; }; 52B8CF64277E0B44004CB680 /* PushDeerClip.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PushDeerClip.app; sourceTree = BUILT_PRODUCTS_DIR; };
52B8CF66277E0B44004CB680 /* PushDeerClipApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushDeerClipApp.swift; sourceTree = "<group>"; }; 52B8CF66277E0B44004CB680 /* PushDeerClipApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushDeerClipApp.swift; sourceTree = "<group>"; };
52B8CF68277E0B44004CB680 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
52B8CF6A277E0B46004CB680 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; 52B8CF6A277E0B46004CB680 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
52B8CF6D277E0B46004CB680 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; }; 52B8CF6D277E0B46004CB680 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
52B8CF6F277E0B46004CB680 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 52B8CF6F277E0B46004CB680 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@ -134,6 +138,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
64B0C15E70CCC382B480F76E /* Pods_PushDeer.framework in Frameworks */, 64B0C15E70CCC382B480F76E /* Pods_PushDeer.framework in Frameworks */,
5287FF52278ADC8C00249A0E /* MarkdownUI in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -142,6 +147,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
4812F19BB0BFEFE089BC253E /* Pods_PushDeerClip.framework in Frameworks */, 4812F19BB0BFEFE089BC253E /* Pods_PushDeerClip.framework in Frameworks */,
5287FF54278AEA5B00249A0E /* MarkdownUI in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -227,6 +233,7 @@
52B8CF5D277DE5FF004CB680 /* Common */ = { 52B8CF5D277DE5FF004CB680 /* Common */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
5287FF58278B3AAE00249A0E /* HToast.swift */,
52B8CF5E277DE660004CB680 /* AppleSignInButton.swift */, 52B8CF5E277DE660004CB680 /* AppleSignInButton.swift */,
); );
path = Common; path = Common;
@ -236,7 +243,6 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
52B8CF66277E0B44004CB680 /* PushDeerClipApp.swift */, 52B8CF66277E0B44004CB680 /* PushDeerClipApp.swift */,
52B8CF68277E0B44004CB680 /* ContentView.swift */,
52B8CF6A277E0B46004CB680 /* Assets.xcassets */, 52B8CF6A277E0B46004CB680 /* Assets.xcassets */,
52B8CF6F277E0B46004CB680 /* Info.plist */, 52B8CF6F277E0B46004CB680 /* Info.plist */,
52B8CF70277E0B46004CB680 /* PushDeerClip.entitlements */, 52B8CF70277E0B46004CB680 /* PushDeerClip.entitlements */,
@ -311,6 +317,9 @@
52B8CF72277E0B46004CB680 /* PBXTargetDependency */, 52B8CF72277E0B46004CB680 /* PBXTargetDependency */,
); );
name = PushDeer; name = PushDeer;
packageProductDependencies = (
5287FF51278ADC8C00249A0E /* MarkdownUI */,
);
productName = PushDeer; productName = PushDeer;
productReference = 5292F4F52776BC7900B9A7BB /* PushDeer.app */; productReference = 5292F4F52776BC7900B9A7BB /* PushDeer.app */;
productType = "com.apple.product-type.application"; productType = "com.apple.product-type.application";
@ -330,6 +339,9 @@
dependencies = ( dependencies = (
); );
name = PushDeerClip; name = PushDeerClip;
packageProductDependencies = (
5287FF53278AEA5B00249A0E /* MarkdownUI */,
);
productName = PushDeerClip; productName = PushDeerClip;
productReference = 52B8CF64277E0B44004CB680 /* PushDeerClip.app */; productReference = 52B8CF64277E0B44004CB680 /* PushDeerClip.app */;
productType = "com.apple.product-type.application.on-demand-install-capable"; productType = "com.apple.product-type.application.on-demand-install-capable";
@ -361,6 +373,9 @@
Base, Base,
); );
mainGroup = 5292F4EC2776BC7900B9A7BB; mainGroup = 5292F4EC2776BC7900B9A7BB;
packageReferences = (
5287FF50278ADC8C00249A0E /* XCRemoteSwiftPackageReference "MarkdownUI" */,
);
productRefGroup = 5292F4F62776BC7900B9A7BB /* Products */; productRefGroup = 5292F4F62776BC7900B9A7BB /* Products */;
projectDirPath = ""; projectDirPath = "";
projectRoot = ""; projectRoot = "";
@ -490,6 +505,7 @@
52B8CF5F277DE660004CB680 /* AppleSignInButton.swift in Sources */, 52B8CF5F277DE660004CB680 /* AppleSignInButton.swift in Sources */,
52163EB92777417900594190 /* KeyListView.swift in Sources */, 52163EB92777417900594190 /* KeyListView.swift in Sources */,
5292F4FB2776BC7900B9A7BB /* ContentView.swift in Sources */, 5292F4FB2776BC7900B9A7BB /* ContentView.swift in Sources */,
5287FF59278B3AAE00249A0E /* HToast.swift in Sources */,
52450F3B278491F8003652D8 /* AppState.swift in Sources */, 52450F3B278491F8003652D8 /* AppState.swift in Sources */,
5292F4F92776BC7900B9A7BB /* PushDeerApp.swift in Sources */, 5292F4F92776BC7900B9A7BB /* PushDeerApp.swift in Sources */,
52483FC2277ED6D5003A100E /* AppDelegate.swift in Sources */, 52483FC2277ED6D5003A100E /* AppDelegate.swift in Sources */,
@ -509,7 +525,6 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
52B8CF82277E0C06004CB680 /* AppleSignInButton.swift in Sources */, 52B8CF82277E0C06004CB680 /* AppleSignInButton.swift in Sources */,
52B8CF69277E0B44004CB680 /* ContentView.swift in Sources */,
52B8CF78277E0BF1004CB680 /* MainView.swift in Sources */, 52B8CF78277E0BF1004CB680 /* MainView.swift in Sources */,
52B8CF79277E0BFB004CB680 /* DeviceListView.swift in Sources */, 52B8CF79277E0BFB004CB680 /* DeviceListView.swift in Sources */,
52B8CF84277E0C12004CB680 /* CardView.swift in Sources */, 52B8CF84277E0C12004CB680 /* CardView.swift in Sources */,
@ -520,11 +535,13 @@
52B8CF81277E0BFB004CB680 /* LoginView.swift in Sources */, 52B8CF81277E0BFB004CB680 /* LoginView.swift in Sources */,
52B8CF7F277E0BFB004CB680 /* SettingsItemView.swift in Sources */, 52B8CF7F277E0BFB004CB680 /* SettingsItemView.swift in Sources */,
52450F3C278491F8003652D8 /* AppState.swift in Sources */, 52450F3C278491F8003652D8 /* AppState.swift in Sources */,
5287FF5A278B3AAE00249A0E /* HToast.swift in Sources */,
52B8CF80277E0BFB004CB680 /* MessageItemView.swift in Sources */, 52B8CF80277E0BFB004CB680 /* MessageItemView.swift in Sources */,
52483FC3277ED6D5003A100E /* AppDelegate.swift in Sources */, 52483FC3277ED6D5003A100E /* AppDelegate.swift in Sources */,
52450F3927848243003652D8 /* PushDeerApi.swift in Sources */, 52450F3927848243003652D8 /* PushDeerApi.swift in Sources */,
52B8CF86277E0C12004CB680 /* BaseNavigationView.swift in Sources */, 52B8CF86277E0C12004CB680 /* BaseNavigationView.swift in Sources */,
52B8CF67277E0B44004CB680 /* PushDeerClipApp.swift in Sources */, 52B8CF67277E0B44004CB680 /* PushDeerClipApp.swift in Sources */,
52FBA09427874879003308C2 /* ContentView.swift in Sources */,
52B8CF85277E0C12004CB680 /* Line.swift in Sources */, 52B8CF85277E0C12004CB680 /* Line.swift in Sources */,
52450F402784923D003652D8 /* Result.swift in Sources */, 52450F402784923D003652D8 /* Result.swift in Sources */,
52450F432784943F003652D8 /* HttpRequest.swift in Sources */, 52450F432784943F003652D8 /* HttpRequest.swift in Sources */,
@ -739,6 +756,10 @@
DEVELOPMENT_ASSET_PATHS = "\"PushDeerClip/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"PushDeerClip/Preview Content\"";
DEVELOPMENT_TEAM = Y47WTLML2S; DEVELOPMENT_TEAM = Y47WTLML2S;
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
"APPCLIP=1",
);
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = PushDeerClip/Info.plist; INFOPLIST_FILE = PushDeerClip/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = PushDeer; INFOPLIST_KEY_CFBundleDisplayName = PushDeer;
@ -753,6 +774,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
OTHER_SWIFT_FLAGS = "$(inherited) -D APPCLIP";
PRODUCT_BUNDLE_IDENTIFIER = com.wskfz.pushdeer.ios.Clip; PRODUCT_BUNDLE_IDENTIFIER = com.wskfz.pushdeer.ios.Clip;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
@ -773,6 +795,10 @@
DEVELOPMENT_ASSET_PATHS = "\"PushDeerClip/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"PushDeerClip/Preview Content\"";
DEVELOPMENT_TEAM = Y47WTLML2S; DEVELOPMENT_TEAM = Y47WTLML2S;
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
"APPCLIP=1",
);
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = PushDeerClip/Info.plist; INFOPLIST_FILE = PushDeerClip/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = PushDeer; INFOPLIST_KEY_CFBundleDisplayName = PushDeer;
@ -787,6 +813,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
OTHER_SWIFT_FLAGS = "$(inherited) -D APPCLIP";
PRODUCT_BUNDLE_IDENTIFIER = com.wskfz.pushdeer.ios.Clip; PRODUCT_BUNDLE_IDENTIFIER = com.wskfz.pushdeer.ios.Clip;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_EMIT_LOC_STRINGS = YES;
@ -826,6 +853,30 @@
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
/* End XCConfigurationList section */ /* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
5287FF50278ADC8C00249A0E /* XCRemoteSwiftPackageReference "MarkdownUI" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/gonzalezreal/MarkdownUI";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 0.5.2;
};
};
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
5287FF51278ADC8C00249A0E /* MarkdownUI */ = {
isa = XCSwiftPackageProductDependency;
package = 5287FF50278ADC8C00249A0E /* XCRemoteSwiftPackageReference "MarkdownUI" */;
productName = MarkdownUI;
};
5287FF53278AEA5B00249A0E /* MarkdownUI */ = {
isa = XCSwiftPackageProductDependency;
package = 5287FF50278ADC8C00249A0E /* XCRemoteSwiftPackageReference "MarkdownUI" */;
productName = MarkdownUI;
};
/* End XCSwiftPackageProductDependency section */
}; };
rootObject = 5292F4ED2776BC7900B9A7BB /* Project object */; rootObject = 5292F4ED2776BC7900B9A7BB /* Project object */;
} }

View File

@ -0,0 +1,70 @@
{
"object": {
"pins": [
{
"package": "AttributedText",
"repositoryURL": "https://github.com/gonzalezreal/AttributedText",
"state": {
"branch": null,
"revision": "c345033e22d5a1cd0e9fe0ec405cc809a8349586",
"version": "0.3.1"
}
},
{
"package": "combine-schedulers",
"repositoryURL": "https://github.com/pointfreeco/combine-schedulers",
"state": {
"branch": null,
"revision": "4cf088c29a20f52be0f2ca54992b492c54e0076b",
"version": "0.5.3"
}
},
{
"package": "MarkdownUI",
"repositoryURL": "https://github.com/gonzalezreal/MarkdownUI",
"state": {
"branch": null,
"revision": "29d94710545952dd4c724cc2ca901848eef54ded",
"version": "0.5.2"
}
},
{
"package": "NetworkImage",
"repositoryURL": "https://github.com/gonzalezreal/NetworkImage",
"state": {
"branch": null,
"revision": "04167e81ed89a14b5da9b856ead306b969bb5abd",
"version": "3.1.2"
}
},
{
"package": "cmark",
"repositoryURL": "https://github.com/SwiftDocOrg/swift-cmark.git",
"state": {
"branch": null,
"revision": "9c8096a23f44794bde297452d87c455fc4f76d42",
"version": "0.29.0+20210102.9c8096a"
}
},
{
"package": "SwiftCommonMark",
"repositoryURL": "https://github.com/gonzalezreal/SwiftCommonMark",
"state": {
"branch": null,
"revision": "ed60da54305c244d0f77bc8d08495e04161e96a4",
"version": "0.1.2"
}
},
{
"package": "xctest-dynamic-overlay",
"repositoryURL": "https://github.com/pointfreeco/xctest-dynamic-overlay",
"state": {
"branch": null,
"revision": "50a70a9d3583fe228ce672e8923010c8df2deddd",
"version": "0.2.1"
}
}
]
},
"version": 1
}

View File

@ -10,8 +10,6 @@ import UserNotifications
class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate { class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate {
static var deviceToken: String = ""
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
let center = UNUserNotificationCenter.current() let center = UNUserNotificationCenter.current()
@ -23,9 +21,7 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele
Task { Task {
// APP, , . () // APP, , . ()
let result = try await HttpRequest.fake() _ = try await HttpRequest.fake()
AppState.shared.token = result.token
HttpRequest.getDevices()
} }
return true return true
@ -34,7 +30,7 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)}) let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
print("deviceToken: ", deviceTokenString) print("deviceToken: ", deviceTokenString)
AppDelegate.deviceToken = deviceTokenString; AppState.shared.deviceToken = deviceTokenString
} }
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification) async -> UNNotificationPresentationOptions { func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification) async -> UNNotificationPresentationOptions {

View File

@ -13,12 +13,12 @@ import AuthenticationServices
/// Apple , 仿 SwiftUI SignInWithAppleButton /// Apple , 仿 SwiftUI SignInWithAppleButton
/// ///
/// 使? , SignInWithAppleButton macOS , iOS . /// 使? , SignInWithAppleButton macOS , iOS .
struct AppleSignInButton: UIViewRepresentable { @MainActor struct AppleSignInButton: UIViewRepresentable {
var type = ASAuthorizationAppleIDButton.ButtonType.signIn var type = ASAuthorizationAppleIDButton.ButtonType.signIn
var style = ASAuthorizationAppleIDButton.Style.black var style = ASAuthorizationAppleIDButton.Style.black
let onRequest: (ASAuthorizationAppleIDRequest) -> Void let onRequest: (ASAuthorizationAppleIDRequest) -> Void
let onCompletion: (Result<ASAuthorization, Error>) -> Void let onCompletion: (Result<ASAuthorization, Error>) async -> Void
func makeUIView(context: Context) -> ASAuthorizationAppleIDButton { func makeUIView(context: Context) -> ASAuthorizationAppleIDButton {
let signInButton = ASAuthorizationAppleIDButton(type: type, style: style) let signInButton = ASAuthorizationAppleIDButton(type: type, style: style)
@ -40,11 +40,11 @@ struct AppleSignInButton: UIViewRepresentable {
class AppleSignInCoordinator: NSObject, ASAuthorizationControllerDelegate { class AppleSignInCoordinator: NSObject, ASAuthorizationControllerDelegate {
let onRequest: (ASAuthorizationAppleIDRequest) -> Void let onRequest: (ASAuthorizationAppleIDRequest) -> Void
let onCompletion: (Result<ASAuthorization, Error>) -> Void let onCompletion: (Result<ASAuthorization, Error>) async -> Void
init( init(
onRequest: @escaping (ASAuthorizationAppleIDRequest) -> Void, onRequest: @escaping (ASAuthorizationAppleIDRequest) -> Void,
onCompletion: @escaping (Result<ASAuthorization, Error>) -> Void onCompletion: @escaping (Result<ASAuthorization, Error>) async -> Void
) { ) {
self.onRequest = onRequest self.onRequest = onRequest
self.onCompletion = onCompletion self.onCompletion = onCompletion
@ -61,11 +61,15 @@ class AppleSignInCoordinator: NSObject, ASAuthorizationControllerDelegate {
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) { func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
print(authorization.debugDescription) print(authorization.debugDescription)
onCompletion(.success(authorization)) Task {
await onCompletion(.success(authorization))
}
} }
func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) { func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
print(error.localizedDescription) print(error.localizedDescription)
onCompletion(.failure(error)) Task {
await onCompletion(.failure(error))
}
} }
} }

View File

@ -0,0 +1,29 @@
//
// HToast.swift
// LotusDesktop
//
// Created by HEXT on 2020/9/26.
// Copyright © 2020 HEXT. All rights reserved.
//
import UIKit
import KRProgressHUD
struct HToast {
static func showText(_ msg: String) {
KRProgressHUD.showMessage(msg)
}
static func showSuccess(_ msg: String?) {
KRProgressHUD.showSuccess(withMessage: msg)
}
static func showError(_ msg: String?) {
KRProgressHUD.showError(withMessage: msg)
}
static func showLoading(_ msg: String?) {
KRProgressHUD.show(withMessage: msg)
}
static func dismiss() {
KRProgressHUD.dismiss()
}
}

View File

@ -8,10 +8,16 @@
import SwiftUI import SwiftUI
struct ContentView: View { struct ContentView: View {
@EnvironmentObject private var store: AppState
var body: some View { var body: some View {
// LoginView() if store.token.isEmpty {
LoginView()
} else {
MainView() MainView()
} }
}
} }
struct ContentView_Previews: PreviewProvider { struct ContentView_Previews: PreviewProvider {

View File

@ -2,14 +2,24 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>APP为您提供保存图片到相册的功能</string>
<key>CFBundleAllowMixedLocalizations</key>
<true/>
<key>NSAppTransportSecurity</key> <key>NSAppTransportSecurity</key>
<dict> <dict>
<key>NSAllowsArbitraryLoads</key> <key>NSAllowsArbitraryLoads</key>
<true/> <true/>
</dict> </dict>
<key>NSBonjourServices</key>
<array>
<string>_adhp._tcp</string>
</array>
<key>UIBackgroundModes</key> <key>UIBackgroundModes</key>
<array> <array>
<string>remote-notification</string> <string>remote-notification</string>
</array> </array>
<key>NSLocalNetworkUsageDescription</key>
<string>APP需要访问本地网络以供调试(仅在开发时)</string>
</dict> </dict>
</plist> </plist>

View File

@ -20,6 +20,17 @@ struct TokenContent: Codable{
let token: String let token: String
} }
struct UserInfoContent: Codable{
let id: Int
let name: String
let email: String
let apple_id: String
let wechat_id: String?
let level: Int
let created_at: String
let updated_at: String
}
struct DeviceItem: Codable, Identifiable{ struct DeviceItem: Codable, Identifiable{
let id: Int let id: Int
let uid: String let uid: String
@ -39,7 +50,10 @@ struct KeyContent: Codable{
struct KeyItem: Codable, Identifiable{ struct KeyItem: Codable, Identifiable{
let id: Int let id: Int
let name: String
let uid: String
let key: String let key: String
let created_at: String
} }
struct MessageContent: Codable{ struct MessageContent: Codable{
@ -52,8 +66,37 @@ struct MessageItem: Codable, Identifiable{
let text: String let text: String
let desp: String let desp: String
let type: String let type: String
let created_at: String
} }
struct ActionContent: Codable{ struct ActionContent: Codable{
let message: String let message: String
} }
struct PushResultContent: Codable{
let result: Array<String>
}
let dateFormatter = DateFormatter()
extension KeyItem {
var createdDateStr: String {
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSZ"
let createdDate = dateFormatter.date(from: self.created_at)
dateFormatter.dateFormat = "yyyy/MM/dd"
return dateFormatter.string(from: createdDate ?? Date())
}
}
extension MessageItem {
var createdDateStr: String {
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSZ"
let createdDate = dateFormatter.date(from: self.created_at) ?? Date()
if Calendar.current.isDateInToday(createdDate) {
dateFormatter.dateFormat = "HH:mm:ss"
} else {
dateFormatter.dateFormat = "yyyy/MM/dd HH:mm:ss"
}
return dateFormatter.string(from: createdDate)
}
}

View File

@ -6,14 +6,86 @@
// //
import Foundation import Foundation
import AuthenticationServices
class AppState: ObservableObject { class AppState: ObservableObject {
@Published var token : String? = nil /// token
@Published var token : String {
didSet {
UserDefaults.standard.set(token, forKey: "PushDeer_token")
}
}
///
@Published var devices: [DeviceItem] = [] @Published var devices: [DeviceItem] = []
/// key
@Published var keys: [KeyItem] = [] @Published var keys: [KeyItem] = []
///
@Published var messages: [MessageItem] = [] @Published var messages: [MessageItem] = []
@Published var tab_selected: Int = 1 /// tab
@Published var device_token: String = "" @Published var tabSelectedIndex: Int {
didSet {
UserDefaults.standard.set(tabSelectedIndex, forKey: "PushDeer_tabSelectedIndex")
}
}
/// token
@Published var deviceToken: String = ""
///
@Published var userInfo: UserInfoContent?
/// UI
@Published var isShowTestPush: Bool {
didSet {
UserDefaults.standard.set(isShowTestPush, forKey: "PushDeer_isShowTestPush")
}
}
var isAppClip: Bool {
#if APPCLIP
return true
#else
return false
#endif
}
static let shared = AppState() static let shared = AppState()
private init() {} private init() {
let _token = UserDefaults.standard.string(forKey: "PushDeer_token")
let _tabSelectedIndex = UserDefaults.standard.integer(forKey: "PushDeer_tabSelectedIndex")
let _isShowTestPush = UserDefaults.standard.object(forKey: "PushDeer_isShowTestPush")
token = _token ?? ""
tabSelectedIndex = _tabSelectedIndex
isShowTestPush = _isShowTestPush as? Bool ?? true
}
func appleIdLogin(_ result: Result<ASAuthorization, Error>) async throws -> TokenContent {
switch result {
case let .success(authorization):
if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
// IDAPP
print(appleIDCredential.user) // 000791.7a323f1326dd4674bc16d32fd6339875.1424
// emailfullName->Apple ID->->使AppleIDApp APP
print(appleIDCredential.email as Any) // easychen@qq.com
print(appleIDCredential.fullName as Any) // givenName: lijie familyName: chen
// JWTtoken.3, base64
let idToken = String(data:appleIDCredential.identityToken!, encoding: .utf8)
print(idToken as Any)
do {
//
let result = try await HttpRequest.login(idToken: idToken!)
print(result)
//
return result
} catch {
print(error)
}
}
case let .failure(error):
print(error)
}
//
throw NSError(domain: "登录失败", code: -1, userInfo: nil)
}
} }

View File

@ -8,6 +8,7 @@
import Foundation import Foundation
import Moya import Moya
@MainActor
struct HttpRequest { struct HttpRequest {
static let provider = MoyaProvider<PushDeerApi>(callbackQueue: DispatchQueue.main) static let provider = MoyaProvider<PushDeerApi>(callbackQueue: DispatchQueue.main)
@ -23,6 +24,9 @@ struct HttpRequest {
print(result) print(result)
if let content = result.content, result.code == 0 { if let content = result.content, result.code == 0 {
continuation.resume(returning: content) continuation.resume(returning: content)
} else if result.code == 80403 {
AppState.shared.token = ""
continuation.resume(throwing: NSError(domain: result.error ?? "接口报错", code: result.code, userInfo: nil))
} else { } else {
continuation.resume(throwing: NSError(domain: result.error ?? "接口报错", code: result.code, userInfo: nil)) continuation.resume(throwing: NSError(domain: result.error ?? "接口报错", code: result.code, userInfo: nil))
} }
@ -46,10 +50,68 @@ struct HttpRequest {
return try await request(.login(idToken: idToken), resultType: TokenContent.self) return try await request(.login(idToken: idToken), resultType: TokenContent.self)
} }
@MainActor static func getDevices() { static func getUserInfo() async throws -> UserInfoContent {
return try await request(.getUserInfo(token: AppState.shared.token), resultType: UserInfoContent.self)
}
static func regDevice() async throws -> DeviceContent {
return try await request(.regDevice(
token: AppState.shared.token,
name: UIDevice.current.name,
device_id: AppState.shared.deviceToken,
is_clip: AppState.shared.isAppClip ? 1 : 0
), resultType: DeviceContent.self)
}
static func rmDevice(id: Int) async throws -> ActionContent {
return try await request(.rmDevice(token: AppState.shared.token, id: id), resultType: ActionContent.self)
}
static func getDevices() async throws -> DeviceContent {
return try await request(.getDevices(token: AppState.shared.token), resultType: DeviceContent.self)
}
static func loadDevices() {
_Concurrency.Task { _Concurrency.Task {
let result = try await request(.getDevices(token: AppState.shared.token ?? ""), resultType: DeviceContent.self) let result = try await getDevices()
AppState.shared.devices = result.devices AppState.shared.devices = result.devices
} }
} }
static func genKey() async throws -> KeyContent {
return try await request(.genKey(token: AppState.shared.token), resultType: KeyContent.self)
}
static func regenKey(id: Int) async throws -> ActionContent {
return try await request(.regenKey(token: AppState.shared.token, id: id), resultType: ActionContent.self)
}
static func renameKey(id: Int, name: String) async throws -> ActionContent {
return try await request(.renameKey(token: AppState.shared.token, id: id, name: name), resultType: ActionContent.self)
}
static func rmKey(id: Int) async throws -> ActionContent {
return try await request(.rmKey(token: AppState.shared.token, id: id), resultType: ActionContent.self)
}
static func getKeys() async throws -> KeyContent {
return try await request(.getKeys(token: AppState.shared.token), resultType: KeyContent.self)
}
static func loadKeys() {
_Concurrency.Task {
let result = try await getKeys()
AppState.shared.keys = result.keys
}
}
static func push(pushkey: String, text: String, desp: String, type: String) async throws -> PushResultContent {
return try await request(.push(pushkey: pushkey, text: text, desp: desp, type: type), resultType: PushResultContent.self)
}
static func getMessages() async throws -> MessageContent {
return try await request(.getMessages(token: AppState.shared.token, limit: 100), resultType: MessageContent.self)
}
static func rmMessage(id: Int) async throws -> ActionContent {
return try await request(.rmMessage(token: AppState.shared.token, id: id), resultType: ActionContent.self)
}
} }

View File

@ -12,6 +12,7 @@ enum PushDeerApi {
case fake case fake
case login(idToken: String) case login(idToken: String)
case getUserInfo(token: String)
case regDevice(token: String, name: String, device_id: String, is_clip: Int) case regDevice(token: String, name: String, device_id: String, is_clip: Int)
case getDevices(token: String) case getDevices(token: String)
@ -39,6 +40,8 @@ extension PushDeerApi: TargetType {
return "/login/fake" return "/login/fake"
case .login: case .login:
return "/login/idtoken" return "/login/idtoken"
case .getUserInfo:
return "/user/info"
case .regDevice: case .regDevice:
return "/device/reg" return "/device/reg"
@ -79,6 +82,8 @@ extension PushDeerApi: TargetType {
return .requestParameters(parameters: [:], encoding: URLEncoding.queryString) return .requestParameters(parameters: [:], encoding: URLEncoding.queryString)
case let .login(idToken): case let .login(idToken):
return .requestParameters(parameters: ["idToken": idToken], encoding: URLEncoding.queryString) return .requestParameters(parameters: ["idToken": idToken], encoding: URLEncoding.queryString)
case let .getUserInfo(token):
return .requestParameters(parameters: ["token": token], encoding: URLEncoding.queryString)
case let .regDevice(token, name, device_id, is_clip): case let .regDevice(token, name, device_id, is_clip):
return .requestParameters(parameters: ["token": token,"name": name, "device_id": device_id,"is_clip": is_clip], encoding: URLEncoding.queryString) return .requestParameters(parameters: ["token": token,"name": name, "device_id": device_id,"is_clip": is_clip], encoding: URLEncoding.queryString)

View File

@ -13,7 +13,7 @@ struct DeviceItemView: View {
var body: some View { var body: some View {
CardView { CardView {
HStack{ HStack{
Image(systemName: "ipad.and.iphone") Image(systemName: getSystemName(deviceName: name))
.resizable() .resizable()
.scaledToFit() .scaledToFit()
.frame(width: 40, height: 40, alignment: .center) .frame(width: 40, height: 40, alignment: .center)
@ -25,6 +25,37 @@ struct DeviceItemView: View {
.frame(height: 80) .frame(height: 80)
} }
} }
func getSystemName(deviceName: String) -> String {
var deviceName = deviceName.lowercased()
deviceName = deviceName.replacingOccurrences(of: " ", with: "")
// if deviceName.contains("clip") {
// return "appclip"
// }
if deviceName.contains("iphone") {
return "iphone"
}
if deviceName.contains("ipad") {
return "ipad.landscape"
}
if deviceName.contains("macbook") {
return "laptopcomputer"
}
if deviceName.contains("imac") {
return "desktopcomputer"
}
if deviceName.contains("macpro") {
return "macpro.gen3"
}
if deviceName.contains("macmini") {
return "macmini"
}
if deviceName.contains("mac") {
return "macwindow"
}
return "ipad.and.iphone"
}
} }
struct DeviceItemView_Previews: PreviewProvider { struct DeviceItemView_Previews: PreviewProvider {

View File

@ -14,13 +14,21 @@ struct DeviceListView: View {
BaseNavigationView(title: "设备") { BaseNavigationView(title: "设备") {
ScrollView { ScrollView {
LazyVStack(alignment: .center) { LazyVStack(alignment: .center) {
ForEach(store.devices, id: \.id) { deviceItem in ForEach(store.devices.reversed()) { deviceItem in
DeletableView(contentView: { DeletableView(contentView: {
DeviceItemView(name: deviceItem.name) DeviceItemView(name: getName(deviceItem: deviceItem))
}, deleteAction: { }, deleteAction: {
store.devices.removeAll { _deviceItem in store.devices.removeAll { _deviceItem in
_deviceItem.id == deviceItem.id _deviceItem.id == deviceItem.id
} }
HToast.showSuccess("已删除")
Task {
do {
_ = try await HttpRequest.rmDevice(id: deviceItem.id)
} catch {
}
}
}) })
.padding(EdgeInsets(top: 18, leading: 26, bottom: 0, trailing: 24)) .padding(EdgeInsets(top: 18, leading: 26, bottom: 0, trailing: 24))
} }
@ -28,8 +36,12 @@ struct DeviceListView: View {
} }
} }
.navigationBarItems(trailing: Button(action: { .navigationBarItems(trailing: Button(action: {
Task {
let devices = try await HttpRequest.regDevice().devices
withAnimation(.easeOut) { withAnimation(.easeOut) {
// store.devices.insert(DeviceItem(), at: 0) store.devices = devices
}
HToast.showSuccess("已添加当前设备")
} }
}, label: { }, label: {
Image(systemName: "plus") Image(systemName: "plus")
@ -37,13 +49,24 @@ struct DeviceListView: View {
})) }))
} }
.onAppear { .onAppear {
HttpRequest.getDevices() HttpRequest.loadDevices()
} }
} }
func getName(deviceItem: DeviceItem) -> String {
var name = deviceItem.name
if deviceItem.is_clip == 1 {
name += " [Clip]"
}
if deviceItem.device_id == store.deviceToken {
name += " (当前设备)"
}
return name
}
} }
struct DeviceView_Previews: PreviewProvider { struct DeviceView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
DeviceListView() DeviceListView().environmentObject(AppState.shared)
} }
} }

View File

@ -7,6 +7,57 @@
import SwiftUI import SwiftUI
struct KeyItemTextField: View {
let keyItem: KeyItem
@State private var value = ""
@EnvironmentObject private var store: AppState
init(keyItem: KeyItem) {
self.keyItem = keyItem
self._value = State(initialValue: keyItem.name)
}
func textField() -> some View {
TextField("输入key名称", text: $value, onCommit: {
Task {
do {
//
_ = try await HttpRequest.renameKey(id: keyItem.id, name: value)
HToast.showSuccess("已修改key名称")
// keyItem
let index = store.keys.firstIndex { _keyItem in
_keyItem.id == keyItem.id
}
if let index = index {
let _keyItem = store.keys[index]
// keyItem
store.keys[index] = KeyItem(
id: _keyItem.id,
name: value,
uid: _keyItem.uid,
key: _keyItem.key,
created_at: _keyItem.created_at
)
}
} catch {
}
}
})
.font(.system(size: 20))
.foregroundColor(Color.accentColor)
}
var body: some View {
if #available(iOS 15.0, *) {
textField()
.submitLabel(.done)
} else {
textField()
}
}
}
/// Key View /// Key View
struct KeyItemView: View { struct KeyItemView: View {
let keyItem: KeyItem let keyItem: KeyItem
@ -18,14 +69,12 @@ struct KeyItemView: View {
.resizable() .resizable()
.scaledToFit() .scaledToFit()
.frame(width: 38, height: 38) .frame(width: 38, height: 38)
Text("Key \(keyItem.id)") KeyItemTextField(keyItem: keyItem)
.font(.system(size: 20))
.foregroundColor(Color.accentColor)
Spacer() Spacer()
Image(systemName: "calendar") Image(systemName: "calendar")
.font(.system(size: 14)) .font(.system(size: 14))
.foregroundColor(Color.gray) .foregroundColor(Color.gray)
Text("2021/12/01") Text(keyItem.createdDateStr)
.font(.system(size: 14)) .font(.system(size: 14))
.foregroundColor(Color.gray) .foregroundColor(Color.gray)
} }
@ -42,6 +91,15 @@ struct KeyItemView: View {
HStack { HStack {
Button("重置") { Button("重置") {
print("点击重置") print("点击重置")
Task {
do {
_ = try await HttpRequest.regenKey(id: keyItem.id)
HttpRequest.loadKeys()
HToast.showSuccess("已重置")
} catch {
}
}
} }
.font(.system(size: 20)) .font(.system(size: 20))
.frame(width: 90, height: 42) .frame(width: 90, height: 42)
@ -53,6 +111,7 @@ struct KeyItemView: View {
Button("复制") { Button("复制") {
print("点击复制") print("点击复制")
UIPasteboard.general.string = keyItem.key UIPasteboard.general.string = keyItem.key
HToast.showSuccess("已复制")
} }
.font(.system(size: 20)) .font(.system(size: 20))
.frame(width: 90, height: 42) .frame(width: 90, height: 42)
@ -67,6 +126,6 @@ struct KeyItemView: View {
struct KeyItemView_Previews: PreviewProvider { struct KeyItemView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
KeyItemView(keyItem: KeyItem(id: 1, key: "Key")) KeyItemView(keyItem: KeyItem(id: 1, name: "name", uid: "1", key: "Key", created_at: "1111"))
} }
} }

View File

@ -9,26 +9,29 @@ import SwiftUI
/// Key /// Key
struct KeyListView: View { struct KeyListView: View {
@State private var keyItems = [ @EnvironmentObject private var store: AppState
KeyItem(id: 1, key: UUID().uuidString),
KeyItem(id: 2, key: UUID().uuidString),
KeyItem(id: 3, key: UUID().uuidString),
KeyItem(id: 4, key: UUID().uuidString),
]
var body: some View { var body: some View {
BaseNavigationView(title: "Key") { BaseNavigationView(title: "Key") {
ScrollView { ScrollView {
LazyVStack(alignment: .center) { LazyVStack(alignment: .center) {
ForEach(keyItems) { keyItem in ForEach(store.keys.reversed()) { keyItem in
DeletableView(contentView: { DeletableView(contentView: {
CardView { CardView {
KeyItemView(keyItem: keyItem) KeyItemView(keyItem: keyItem)
} }
}, deleteAction: { }, deleteAction: {
keyItems.removeAll { _keyItem in store.keys.removeAll { _keyItem in
keyItem.id == _keyItem.id keyItem.id == _keyItem.id
} }
HToast.showSuccess("已删除")
Task {
do {
_ = try await HttpRequest.rmKey(id: keyItem.id)
} catch {
}
}
}) })
.padding(EdgeInsets(top: 18, leading: 26, bottom: 0, trailing: 24)) .padding(EdgeInsets(top: 18, leading: 26, bottom: 0, trailing: 24))
} }
@ -36,20 +39,26 @@ struct KeyListView: View {
} }
} }
.navigationBarItems(trailing: Button(action: { .navigationBarItems(trailing: Button(action: {
let keyItem = KeyItem(id: Int(arc4random_uniform(1000)), key: UUID().uuidString) Task {
let keys = try await HttpRequest.genKey().keys
withAnimation(.easeOut) { withAnimation(.easeOut) {
keyItems.insert(keyItem, at: 0) store.keys = keys
}
HToast.showSuccess("已添加新Key")
} }
}, label: { }, label: {
Image(systemName: "plus") Image(systemName: "plus")
.foregroundColor(Color(UIColor.lightGray)) .foregroundColor(Color(UIColor.lightGray))
})) }))
} }
.onAppear {
HttpRequest.loadKeys()
}
} }
} }
struct KeyView_Previews: PreviewProvider { struct KeyView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
KeyListView() KeyListView().environmentObject(AppState.shared)
} }
} }

View File

@ -10,6 +10,10 @@ import AuthenticationServices
/// ///
struct LoginView: View { struct LoginView: View {
@EnvironmentObject private var store: AppState
@State private var showLoading = false
var body: some View { var body: some View {
VStack{ VStack{
Spacer() Spacer()
@ -17,40 +21,28 @@ struct LoginView: View {
.resizable() .resizable()
.scaledToFit() .scaledToFit()
Spacer() Spacer()
if showLoading {
ProgressView()
.scaleEffect(1.5)
.frame(height: 64)
} else {
AppleSignInButton( AppleSignInButton(
onRequest: { request in onRequest: { request in
request.requestedScopes = [.fullName, .email] request.requestedScopes = [.fullName, .email]
}, },
onCompletion: { result in onCompletion: { result in
switch result {
case let .success(authorization):
if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
// IDAPP
print(appleIDCredential.user) // 000791.7a323f1326dd4674bc16d32fd6339875.1424
// emailfullName->Apple ID->->使AppleIDApp APP
print(appleIDCredential.email as Any) // easychen@qq.com
print(appleIDCredential.fullName as Any) // givenName: lijie familyName: chen
// JWTtoken.3, base64
let idToken = String(data:appleIDCredential.identityToken!, encoding: .utf8)
print(idToken as Any)
Task {
do { do {
let result = try await HttpRequest.login(idToken: idToken!) showLoading = true
store.token = try await store.appleIdLogin(result).token
print(result) //
} catch { } catch {
print(error) showLoading = false
}
}
}
case let .failure(error):
print(error)
} }
} }
) )
.frame(maxWidth: 375, minHeight: 64, maxHeight: 64) .frame(maxWidth: 375, minHeight: 64, maxHeight: 64)
.padding() .padding()
}
Spacer() Spacer()
} }
.padding() .padding()

View File

@ -9,32 +9,38 @@ import SwiftUI
/// APP /// APP
struct MainView: View { struct MainView: View {
@EnvironmentObject private var store: AppState
var body: some View { var body: some View {
TabView { TabView.init(selection: $store.tabSelectedIndex) {
DeviceListView() DeviceListView()
.tabItem { .tabItem {
Label("设备",systemImage: "ipad.and.iphone") Label("设备",systemImage: "ipad.and.iphone")
} }
.tag(0)
KeyListView() KeyListView()
.tabItem{ .tabItem{
Label("Key",systemImage: "key") Label("Key",systemImage: "key")
} }
.tag(1)
MessageListView() MessageListView()
.tabItem({Label("消息",systemImage: "message")}).onTapGesture { .tabItem({Label("消息",systemImage: "message")}).onTapGesture {
} }
.tag(2)
SettingsView() SettingsView()
.tabItem{ .tabItem{
Label("设置",systemImage: "gearshape") Label("设置",systemImage: "gearshape")
} }
.tag(3)
} }
} }
} }
struct MainView_Previews: PreviewProvider { struct MainView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
MainView() MainView().environmentObject(AppState.shared)
} }
} }

View File

@ -6,8 +6,12 @@
// //
import SwiftUI import SwiftUI
import MarkdownUI
import SDWebImageSwiftUI
import Photos
struct MessageItemView: View { struct MessageItemView: View {
let messageItem: MessageItem
/// ///
let deleteAction : () -> () let deleteAction : () -> ()
@ -23,7 +27,7 @@ struct MessageItemView: View {
Text("key名字") Text("key名字")
.font(.system(size: 14)) .font(.system(size: 14))
.foregroundColor(Color(UIColor.darkGray)) .foregroundColor(Color(UIColor.darkGray))
Text("· 5分钟前") Text(messageItem.createdDateStr)
.font(.system(size: 12)) .font(.system(size: 12))
.foregroundColor(Color(UIColor.darkGray)) .foregroundColor(Color(UIColor.darkGray))
HLine().stroke(Color(UIColor.lightGray)) HLine().stroke(Color(UIColor.lightGray))
@ -31,33 +35,122 @@ struct MessageItemView: View {
} }
DeletableView(contentView: { DeletableView(contentView: {
CardView { MessageContentView(messageItem: messageItem)
HStack{
Text("纯文本的效果")
.font(.system(size: 14))
.foregroundColor(Color(UIColor.darkGray))
.padding()
Spacer(minLength: 0)
}
.contextMenu {
Button("复制") {
UIPasteboard.general.string = "someText"
}
}
}
}, deleteAction: deleteAction) }, deleteAction: deleteAction)
.padding(EdgeInsets(top: 10, leading: 26, bottom: 0, trailing: 24)) .padding(messageItem.type == "image" ? EdgeInsets.init() : EdgeInsets(top: 10, leading: 26, bottom: 0, trailing: 24))
} }
.padding(.top, 25) .padding(.top, 25)
} }
} }
struct MessageContentView: View {
let messageItem: MessageItem
@State private var image: PlatformImage? = nil
var body: some View {
switch messageItem.type {
case "markdown":
CardView {
VStack(alignment: .leading, spacing: 5) {
Markdown(Document(messageItem.text))
.markdownStyle(
DefaultMarkdownStyle(
font: .system(size: 14),
foregroundColor: UIColor.darkGray
)
)
if !messageItem.desp.isEmpty {
Markdown(Document(messageItem.desp))
.markdownStyle(
DefaultMarkdownStyle(
font: .system(size: 14),
foregroundColor: UIColor.darkGray
)
)
}
}
.padding()
}
case "image":
WebImage(url: URL(string: messageItem.text))
.onSuccess { image, data, cacheType in
self.image = image
}
.resizable()
.scaledToFill()
.contextMenu {
Button {
UIPasteboard.general.image = image
HToast.showSuccess("已拷贝")
} label: {
Label("拷贝图片",systemImage: "doc.on.doc")
}
Button {
guard let image = image else { return }
PHPhotoLibrary.shared().performChanges {
PHAssetChangeRequest.creationRequestForAsset(from: image)
} completionHandler: { (isSuccess, error) in
DispatchQueue.main.async {
if isSuccess {//
print("Success")
HToast.showSuccess("保存成功")
} else {
print(error as Any)
HToast.showError("保存失败")
}
}
}
} label: {
Label("保存图片",systemImage: "square.and.arrow.down")
}
}
default:
CardView {
VStack(alignment: .leading, spacing: 5) {
HStack{
Text(messageItem.text)
.font(.system(size: 14))
.foregroundColor(Color(UIColor.darkGray))
Spacer(minLength: 0)
}
if !messageItem.desp.isEmpty {
Text(messageItem.desp)
.font(.system(size: 14))
.foregroundColor(Color(UIColor.darkGray))
}
}
.padding()
.contextMenu {
Button {
UIPasteboard.general.string = messageItem.text + messageItem.desp
HToast.showSuccess("已复制")
} label: {
Label("复制",systemImage: "doc.on.doc")
}
}
}
}
}
}
struct MessageItemView_Previews: PreviewProvider { struct MessageItemView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
VStack { VStack {
MessageItemView(){} MessageItemView(messageItem: MessageItem(id: 1, uid: "1", text: "纯文本的效果", desp: "你好呀", type: "text", created_at: "2022-01-08T18:00:48.000000Z")){}
MessageItemView(){} MessageItemView(messageItem: MessageItem(id: 1, uid: "1", text: "纯文本的效果纯文本的效果纯文本的效果纯文本的效果纯文本的效果纯文本的效果纯文本的效果", desp: "", type: "text", created_at: "2022-01-08T18:00:48.000000Z")){}
MessageItemView(messageItem: MessageItem(id: 1, uid: "1", text: "https://blog.wskfz.com/usr/uploads/2018/06/2498727457.png", desp: "", type: "image", created_at: "2022-01-08T18:00:48.000000Z")){}
MessageItemView(messageItem: MessageItem(id: 1, uid: "1", text: "https://blog.wskfz.com/usr/uploads/2018/06/2151130181.png", desp: "", type: "image", created_at: "2022-01-08T18:00:48.000000Z")){}
MessageItemView(messageItem: MessageItem(id: 1, uid: "1", text: "https://blog.wskfz.com/usr/uploads/2018/06/1718629805.png", desp: "", type: "image", created_at: "2022-01-08T18:00:48.000000Z")){}
MessageItemView(messageItem: MessageItem(id: 1, uid: "1", text: "*MarkDown*的**效果**", desp: "*MarkDown*的**效果**", type: "markdown", created_at: "2021-12-28T13:44:48.000000Z")){}
MessageItemView(messageItem: MessageItem(id: 1, uid: "1", text: """
It's very easy to make some words **bold** and other words *italic* with Markdown.
**Want to experiment with Markdown?** Play with the [reference CommonMark
implementation](https://spec.commonmark.org/dingus/).
""", desp: "", type: "markdown", created_at: "2021-12-28T13:44:48.000000Z")){}
Spacer() Spacer()
} }
} }

View File

@ -9,21 +9,27 @@ import SwiftUI
/// ///
struct MessageListView: View { struct MessageListView: View {
@EnvironmentObject private var store: AppState
@State private var messages = Array(0..<10)
@State private var isShowTest = true
var body: some View { var body: some View {
BaseNavigationView(title: "消息") { BaseNavigationView(title: "消息") {
ScrollView { ScrollView {
LazyVStack(alignment: .leading) { LazyVStack(alignment: .leading) {
if isShowTest { if store.isShowTestPush {
TestPushView() TestPushView()
} }
ForEach(messages, id: \.self) { msg in ForEach(store.messages) { messageItem in
MessageItemView { MessageItemView(messageItem: messageItem) {
messages.removeAll { _msg in store.messages.removeAll { _messageItem in
_msg == msg _messageItem.id == messageItem.id
}
HToast.showSuccess("已删除")
Task {
do {
_ = try await HttpRequest.rmMessage(id: messageItem.id)
} catch {
}
} }
} }
} }
@ -32,17 +38,23 @@ struct MessageListView: View {
} }
.navigationBarItems(trailing: Button(action: { .navigationBarItems(trailing: Button(action: {
withAnimation(.easeOut) { withAnimation(.easeOut) {
isShowTest = !isShowTest store.isShowTestPush = !store.isShowTestPush
} }
}, label: { }, label: {
Image(systemName: isShowTest ? "chevron.up" : "chevron.down") Image(systemName: store.isShowTestPush ? "chevron.up" : "chevron.down")
.foregroundColor(Color(UIColor.lightGray)) .foregroundColor(Color(UIColor.lightGray))
})) }))
} }
.onAppear {
Task {
store.messages = try await HttpRequest.getMessages().messages
}
}
} }
} }
struct TestPushView: View { struct TestPushView: View {
@EnvironmentObject private var store: AppState
@State private var testText = "" @State private var testText = ""
var body: some View { var body: some View {
TextEditor(text: $testText) TextEditor(text: $testText)
@ -52,6 +64,26 @@ struct TestPushView: View {
Button("推送测试") { Button("推送测试") {
print("点击推送测试") print("点击推送测试")
if testText.isEmpty {
HToast.showError("推送失败, 请先输入推送内容")
return
}
Task {
if store.keys.isEmpty {
store.keys = try await HttpRequest.getKeys().keys
}
if let keyItem = store.keys.first {
_ = try await HttpRequest.push(pushkey: keyItem.key, text: testText, desp: "", type: "")
testText = ""
HToast.showSuccess("推送成功")
let messages = try await HttpRequest.getMessages().messages
withAnimation(.easeOut) {
store.messages = messages
}
} else {
HToast.showError("推送失败, 请先添加一个Key")
}
}
} }
.font(.system(size: 20)) .font(.system(size: 20))
.frame(width: 104, height: 42) .frame(width: 104, height: 42)

View File

@ -18,8 +18,8 @@ struct SettingsItemView: View {
Text(title) Text(title)
.font(.system(size: 18)) .font(.system(size: 18))
.foregroundColor(Color(UIColor.darkGray)) .foregroundColor(Color(UIColor.darkGray))
.padding() .padding(.leading, 16)
Spacer() Spacer(minLength: 0)
Button(button) { Button(button) {
print("点击\(button)") print("点击\(button)")
action() action()

View File

@ -6,32 +6,49 @@
// //
import SwiftUI import SwiftUI
//import StoreKit
/// ///
struct SettingsView: View { struct SettingsView: View {
@EnvironmentObject private var store: AppState
var body: some View { var body: some View {
BaseNavigationView(title: "设置") { BaseNavigationView(title: "设置") {
VStack { VStack {
SettingsItemView(title: "登录为 Hext", button: "退出") { SettingsItemView(title: "登录为 \(store.userInfo?.name ?? "--")", button: "退出") {
store.token = ""
} }
.padding(EdgeInsets(top: 18, leading: 20, bottom: 0, trailing: 20)) .padding(EdgeInsets(top: 18, leading: 20, bottom: 0, trailing: 20))
SettingsItemView(title: "自定义服务器", button: "扫码") { SettingsItemView(title: "自定义服务器", button: "扫码") {
} }
.disabled(true)
.padding(EdgeInsets(top: 18, leading: 20, bottom: 0, trailing: 20)) .padding(EdgeInsets(top: 18, leading: 20, bottom: 0, trailing: 20))
SettingsItemView(title: "喜欢PushDeer?", button: "评分") { SettingsItemView(title: "喜欢PushDeer?", button: "评分") {
let urlStr = "itms-apps://itunes.apple.com/app/id\(1596771139)?action=write-review"
UIApplication.shared.open(URL(string: urlStr)!, options: [:], completionHandler: nil)
// , 3,
// SKStoreReviewController.requestReview()
} }
.padding(EdgeInsets(top: 18, leading: 20, bottom: 0, trailing: 20)) .padding(EdgeInsets(top: 18, leading: 20, bottom: 0, trailing: 20))
Spacer() Spacer()
} }
} }
.onAppear {
if store.userInfo != nil {
return
}
Task {
store.userInfo = try await HttpRequest.getUserInfo()
}
}
} }
} }
struct SettingsView_Previews: PreviewProvider { struct SettingsView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
SettingsView() SettingsView().environmentObject(AppState.shared)
} }
} }

View File

@ -1,20 +0,0 @@
//
// ContentView.swift
// PushDeerClip
//
// Created by HEXT on 2021/12/30.
//
import SwiftUI
struct ContentView: View {
var body: some View {
MainView()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

View File

@ -2,11 +2,6 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSAppClip</key> <key>NSAppClip</key>
<dict> <dict>
<key>NSAppClipRequestEphemeralUserNotification</key> <key>NSAppClipRequestEphemeralUserNotification</key>
@ -14,5 +9,20 @@
<key>NSAppClipRequestLocationConfirmation</key> <key>NSAppClipRequestLocationConfirmation</key>
<false/> <false/>
</dict> </dict>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSBonjourServices</key>
<array>
<string>_adhp._tcp</string>
</array>
<key>NSLocalNetworkUsageDescription</key>
<string>APP需要访问本地网络以供调试(仅在开发时)</string>
<key>CFBundleAllowMixedLocalizations</key>
<true/>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>APP为您提供保存图片到相册的功能</string>
</dict> </dict>
</plist> </plist>