From c5bd3b2ab4c5e692e1eb6d1a6e5789fb06a17369 Mon Sep 17 00:00:00 2001 From: hext Date: Sat, 15 Jan 2022 22:13:23 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E:=20=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E6=9C=AC=E5=9C=B0=E7=BC=93=E5=AD=98=20/=20=E5=9B=BD=E9=99=85?= =?UTF-8?q?=E5=8C=96(=E8=8B=B1=E6=96=87/=E4=B8=AD=E6=96=87)=20/=20?= =?UTF-8?q?=E5=85=B6=E5=AE=83=E7=BB=86=E8=8A=82=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ios/PushDeer-iOS/Podfile | 2 +- ios/PushDeer-iOS/Podfile.lock | 2 +- .../PushDeer.xcodeproj/project.pbxproj | 95 ++++++++++++++- .../xcschemes/PushDeerClip.xcscheme | 85 ++++++++++++++ ios/PushDeer-iOS/PushDeer/AppDelegate.swift | 5 + ios/PushDeer-iOS/PushDeer/Common/HToast.swift | 6 + .../PushDeer/Model/MessageModel.swift | 87 ++++++++++++++ .../PushDeerData.xcdatamodel/contents | 15 +++ ios/PushDeer-iOS/PushDeer/Model/Result.swift | 18 +-- .../PushDeer/PushDeer.entitlements | 2 + ios/PushDeer-iOS/PushDeer/PushDeerApp.swift | 6 +- .../PushDeer/Service/AppState.swift | 4 +- .../PushDeer/Service/HttpRequest.swift | 8 +- .../PushDeer/Service/Persistence.swift | 39 ++++++ .../PushDeer/Service/PushDeerApi.swift | 5 + .../View/Common/BaseNavigationView.swift | 11 +- .../PushDeer/View/Common/DeletableView.swift | 2 +- .../PushDeer/View/Common/EditableText.swift | 47 ++++++++ .../PushDeer/View/DeviceItemView.swift | 52 ++++++-- .../PushDeer/View/DeviceListView.swift | 22 ++-- .../PushDeer/View/KeyItemView.swift | 75 +++--------- .../PushDeer/View/KeyListView.swift | 4 +- .../PushDeer/View/MessageItemView.swift | 71 +++++++---- .../PushDeer/View/MessageListView.swift | 29 +++-- .../PushDeer/View/SettingsView.swift | 6 +- .../PushDeer/en.lproj/InfoPlist.strings | 6 + .../PushDeer/en.lproj/Localizable.strings | 111 ++++++++++++++++++ .../PushDeer/zh-Hans.lproj/InfoPlist.strings | 1 + .../zh-Hans.lproj/Localizable.strings | 1 + .../PushDeerClip/PushDeerClipApp.swift | 19 --- .../PushDeerClip/en.lproj/InfoPlist.strings | 6 + .../zh-Hans.lproj/InfoPlist.strings | 1 + 32 files changed, 673 insertions(+), 170 deletions(-) create mode 100644 ios/PushDeer-iOS/PushDeer.xcodeproj/xcshareddata/xcschemes/PushDeerClip.xcscheme create mode 100644 ios/PushDeer-iOS/PushDeer/Model/MessageModel.swift create mode 100644 ios/PushDeer-iOS/PushDeer/Model/PushDeerData.xcdatamodeld/PushDeerData.xcdatamodel/contents create mode 100644 ios/PushDeer-iOS/PushDeer/Service/Persistence.swift create mode 100644 ios/PushDeer-iOS/PushDeer/View/Common/EditableText.swift create mode 100644 ios/PushDeer-iOS/PushDeer/en.lproj/InfoPlist.strings create mode 100644 ios/PushDeer-iOS/PushDeer/en.lproj/Localizable.strings create mode 100644 ios/PushDeer-iOS/PushDeer/zh-Hans.lproj/InfoPlist.strings create mode 100644 ios/PushDeer-iOS/PushDeer/zh-Hans.lproj/Localizable.strings delete mode 100644 ios/PushDeer-iOS/PushDeerClip/PushDeerClipApp.swift create mode 100644 ios/PushDeer-iOS/PushDeerClip/en.lproj/InfoPlist.strings create mode 100644 ios/PushDeer-iOS/PushDeerClip/zh-Hans.lproj/InfoPlist.strings diff --git a/ios/PushDeer-iOS/Podfile b/ios/PushDeer-iOS/Podfile index 5255130..d4279af 100644 --- a/ios/PushDeer-iOS/Podfile +++ b/ios/PushDeer-iOS/Podfile @@ -10,7 +10,7 @@ def commonPods pod 'SDWebImageSwiftUI', '~> 2.0.2' pod 'KRProgressHUD', '~> 3.4.7' - # pod 'WoodPeckeriOS', :configurations => ['Debug'] +# pod 'WoodPeckeriOS', :configurations => ['Debug'] end target 'PushDeer' do diff --git a/ios/PushDeer-iOS/Podfile.lock b/ios/PushDeer-iOS/Podfile.lock index aeca252..b9203ec 100644 --- a/ios/PushDeer-iOS/Podfile.lock +++ b/ios/PushDeer-iOS/Podfile.lock @@ -35,6 +35,6 @@ SPEC CHECKSUMS: SDWebImage: 4dc3e42d9ec0c1028b960a33ac6b637bb432207b SDWebImageSwiftUI: 8a3923c95108312b03a599ec1498754af55a6819 -PODFILE CHECKSUM: e462e86a9cce18b92c573f662ef405e7091cd912 +PODFILE CHECKSUM: 06aae1de50f9c1a188e69787835ec8718dd7d543 COCOAPODS: 1.11.2 diff --git a/ios/PushDeer-iOS/PushDeer.xcodeproj/project.pbxproj b/ios/PushDeer-iOS/PushDeer.xcodeproj/project.pbxproj index 3fccecd..5556b02 100644 --- a/ios/PushDeer-iOS/PushDeer.xcodeproj/project.pbxproj +++ b/ios/PushDeer-iOS/PushDeer.xcodeproj/project.pbxproj @@ -15,6 +15,8 @@ 52163EBB277741AC00594190 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52163EBA277741AC00594190 /* SettingsView.swift */; }; 523150D9277875FB00941EDC /* DeletableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 523150D8277875FB00941EDC /* DeletableView.swift */; }; 523150DC2778762B00941EDC /* DeviceItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 523150DB2778762B00941EDC /* DeviceItemView.swift */; }; + 5242C872278C8CBB00FDB27E /* EditableText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5242C871278C8CBB00FDB27E /* EditableText.swift */; }; + 5242C873278C8CBB00FDB27E /* EditableText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5242C871278C8CBB00FDB27E /* EditableText.swift */; }; 52450F3827848243003652D8 /* PushDeerApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52450F3727848243003652D8 /* PushDeerApi.swift */; }; 52450F3927848243003652D8 /* PushDeerApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52450F3727848243003652D8 /* PushDeerApi.swift */; }; 52450F3B278491F8003652D8 /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52450F3A278491F8003652D8 /* AppState.swift */; }; @@ -25,6 +27,13 @@ 52450F432784943F003652D8 /* HttpRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52450F412784943F003652D8 /* HttpRequest.swift */; }; 52483FC2277ED6D5003A100E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52483FC1277ED6D5003A100E /* AppDelegate.swift */; }; 52483FC3277ED6D5003A100E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52483FC1277ED6D5003A100E /* AppDelegate.swift */; }; + 526A1E702791E00400BA2177 /* PushDeerData.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 526A1E6E2791E00400BA2177 /* PushDeerData.xcdatamodeld */; }; + 526A1E712791E00400BA2177 /* PushDeerData.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 526A1E6E2791E00400BA2177 /* PushDeerData.xcdatamodeld */; }; + 526A1E732791E03900BA2177 /* Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 526A1E722791E03900BA2177 /* Persistence.swift */; }; + 526A1E742791E03900BA2177 /* Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 526A1E722791E03900BA2177 /* Persistence.swift */; }; + 526A1E752791E52600BA2177 /* PushDeerApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5292F4F82776BC7900B9A7BB /* PushDeerApp.swift */; }; + 526A1E7D2792B2A600BA2177 /* MessageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 526A1E7C2792B2A600BA2177 /* MessageModel.swift */; }; + 526A1E7E2792B2A600BA2177 /* MessageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 526A1E7C2792B2A600BA2177 /* MessageModel.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 */; }; @@ -34,7 +43,6 @@ 5292F4FD2776BC7A00B9A7BB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5292F4FC2776BC7A00B9A7BB /* 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 */; }; - 52B8CF67277E0B44004CB680 /* PushDeerClipApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B8CF66277E0B44004CB680 /* PushDeerClipApp.swift */; }; 52B8CF6B277E0B46004CB680 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 52B8CF6A277E0B46004CB680 /* 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, ); }; }; @@ -54,6 +62,10 @@ 52B8CF85277E0C12004CB680 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52EB90B22778DA4E0048E0ED /* Line.swift */; }; 52B8CF86277E0C12004CB680 /* BaseNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52EB90AD2778AFD60048E0ED /* BaseNavigationView.swift */; }; 52B8CF87277E0C5C004CB680 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5292F4FC2776BC7A00B9A7BB /* Assets.xcassets */; }; + 52E317D9279305BB000B8BB1 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 52E317D7279305BB000B8BB1 /* InfoPlist.strings */; }; + 52E317DC279305BB000B8BB1 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 52E317DA279305BB000B8BB1 /* Localizable.strings */; }; + 52E317DF279305BB000B8BB1 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 52E317DD279305BB000B8BB1 /* InfoPlist.strings */; }; + 52E317E727930AA4000B8BB1 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 52E317DA279305BB000B8BB1 /* Localizable.strings */; }; 52EB90AC2778ADF80048E0ED /* CardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52EB90AB2778ADF80048E0ED /* CardView.swift */; }; 52EB90AE2778AFD60048E0ED /* BaseNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52EB90AD2778AFD60048E0ED /* BaseNavigationView.swift */; }; 52EB90B02778D67F0048E0ED /* KeyItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52EB90AF2778D67F0048E0ED /* KeyItemView.swift */; }; @@ -97,12 +109,16 @@ 52163EBA277741AC00594190 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; 523150D8277875FB00941EDC /* DeletableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeletableView.swift; sourceTree = ""; }; 523150DB2778762B00941EDC /* DeviceItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceItemView.swift; sourceTree = ""; }; + 5242C871278C8CBB00FDB27E /* EditableText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditableText.swift; sourceTree = ""; }; 52450F3727848243003652D8 /* PushDeerApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushDeerApi.swift; sourceTree = ""; }; 52450F3A278491F8003652D8 /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = ""; }; 52450F3E2784923D003652D8 /* Result.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Result.swift; sourceTree = ""; }; 52450F412784943F003652D8 /* HttpRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HttpRequest.swift; sourceTree = ""; }; 52450F442784A95D003652D8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 52483FC1277ED6D5003A100E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 526A1E6F2791E00400BA2177 /* PushDeerData.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = PushDeerData.xcdatamodel; sourceTree = ""; }; + 526A1E722791E03900BA2177 /* Persistence.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Persistence.swift; sourceTree = ""; }; + 526A1E7C2792B2A600BA2177 /* MessageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageModel.swift; sourceTree = ""; }; 5287FF58278B3AAE00249A0E /* HToast.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HToast.swift; sourceTree = ""; }; 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 = ""; }; @@ -111,11 +127,16 @@ 5292F4FF2776BC7A00B9A7BB /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 52B8CF5E277DE660004CB680 /* AppleSignInButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleSignInButton.swift; sourceTree = ""; }; 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 = ""; }; 52B8CF6A277E0B46004CB680 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 52B8CF6D277E0B46004CB680 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 52B8CF6F277E0B46004CB680 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 52B8CF70277E0B46004CB680 /* PushDeerClip.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = PushDeerClip.entitlements; sourceTree = ""; }; + 52E317D8279305BB000B8BB1 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 52E317DB279305BB000B8BB1 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; + 52E317DE279305BB000B8BB1 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 52E317E827930AD0000B8BB1 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; + 52E317E927930C16000B8BB1 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = ""; }; + 52E317EA27930C21000B8BB1 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = ""; }; 52EB90AB2778ADF80048E0ED /* CardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardView.swift; sourceTree = ""; }; 52EB90AD2778AFD60048E0ED /* BaseNavigationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseNavigationView.swift; sourceTree = ""; }; 52EB90AF2778D67F0048E0ED /* KeyItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyItemView.swift; sourceTree = ""; }; @@ -171,6 +192,7 @@ 52450F3727848243003652D8 /* PushDeerApi.swift */, 52450F3A278491F8003652D8 /* AppState.swift */, 52450F412784943F003652D8 /* HttpRequest.swift */, + 526A1E722791E03900BA2177 /* Persistence.swift */, ); path = Service; sourceTree = ""; @@ -179,6 +201,8 @@ isa = PBXGroup; children = ( 52450F3E2784923D003652D8 /* Result.swift */, + 526A1E7C2792B2A600BA2177 /* MessageModel.swift */, + 526A1E6E2791E00400BA2177 /* PushDeerData.xcdatamodeld */, ); path = Model; sourceTree = ""; @@ -208,6 +232,8 @@ isa = PBXGroup; children = ( 52450F442784A95D003652D8 /* Info.plist */, + 52E317DA279305BB000B8BB1 /* Localizable.strings */, + 52E317D7279305BB000B8BB1 /* InfoPlist.strings */, 52450F362784822C003652D8 /* Service */, 52B8CF5D277DE5FF004CB680 /* Common */, 52450F3D27849228003652D8 /* Model */, @@ -242,9 +268,9 @@ 52B8CF65277E0B44004CB680 /* PushDeerClip */ = { isa = PBXGroup; children = ( - 52B8CF66277E0B44004CB680 /* PushDeerClipApp.swift */, 52B8CF6A277E0B46004CB680 /* Assets.xcassets */, 52B8CF6F277E0B46004CB680 /* Info.plist */, + 52E317DD279305BB000B8BB1 /* InfoPlist.strings */, 52B8CF70277E0B46004CB680 /* PushDeerClip.entitlements */, 52B8CF6C277E0B46004CB680 /* Preview Content */, ); @@ -266,6 +292,7 @@ 523150D8277875FB00941EDC /* DeletableView.swift */, 52EB90AB2778ADF80048E0ED /* CardView.swift */, 52EB90B22778DA4E0048E0ED /* Line.swift */, + 5242C871278C8CBB00FDB27E /* EditableText.swift */, ); path = Common; sourceTree = ""; @@ -371,6 +398,7 @@ knownRegions = ( en, Base, + "zh-Hans", ); mainGroup = 5292F4EC2776BC7900B9A7BB; packageReferences = ( @@ -392,6 +420,8 @@ buildActionMask = 2147483647; files = ( 5292F5002776BC7A00B9A7BB /* Preview Assets.xcassets in Resources */, + 52E317DC279305BB000B8BB1 /* Localizable.strings in Resources */, + 52E317D9279305BB000B8BB1 /* InfoPlist.strings in Resources */, 5292F4FD2776BC7A00B9A7BB /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -400,7 +430,9 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 52E317E727930AA4000B8BB1 /* Localizable.strings in Resources */, 52B8CF6E277E0B46004CB680 /* Preview Assets.xcassets in Resources */, + 52E317DF279305BB000B8BB1 /* InfoPlist.strings in Resources */, 52B8CF87277E0C5C004CB680 /* Assets.xcassets in Resources */, 52B8CF6B277E0B46004CB680 /* Assets.xcassets in Resources */, ); @@ -498,8 +530,10 @@ 523150DC2778762B00941EDC /* DeviceItemView.swift in Sources */, 523150D9277875FB00941EDC /* DeletableView.swift in Sources */, 52163EBB277741AC00594190 /* SettingsView.swift in Sources */, + 5242C872278C8CBB00FDB27E /* EditableText.swift in Sources */, 52163EB327773F8400594190 /* MainView.swift in Sources */, 52EB90B32778DA4E0048E0ED /* Line.swift in Sources */, + 526A1E732791E03900BA2177 /* Persistence.swift in Sources */, 52F2C223277961D7006F08DC /* SettingsItemView.swift in Sources */, 52163EB72777415F00594190 /* DeviceListView.swift in Sources */, 52B8CF5F277DE660004CB680 /* AppleSignInButton.swift in Sources */, @@ -508,12 +542,14 @@ 5287FF59278B3AAE00249A0E /* HToast.swift in Sources */, 52450F3B278491F8003652D8 /* AppState.swift in Sources */, 5292F4F92776BC7900B9A7BB /* PushDeerApp.swift in Sources */, + 526A1E7D2792B2A600BA2177 /* MessageModel.swift in Sources */, 52483FC2277ED6D5003A100E /* AppDelegate.swift in Sources */, 52450F3827848243003652D8 /* PushDeerApi.swift in Sources */, 52EB90AE2778AFD60048E0ED /* BaseNavigationView.swift in Sources */, 52EB90AC2778ADF80048E0ED /* CardView.swift in Sources */, 52EB90B02778D67F0048E0ED /* KeyItemView.swift in Sources */, 52450F3F2784923D003652D8 /* Result.swift in Sources */, + 526A1E702791E00400BA2177 /* PushDeerData.xcdatamodeld in Sources */, 52450F422784943F003652D8 /* HttpRequest.swift in Sources */, 52163EB52777413B00594190 /* MessageListView.swift in Sources */, 52F40D2F277CA05600766C24 /* MessageItemView.swift in Sources */, @@ -528,8 +564,10 @@ 52B8CF78277E0BF1004CB680 /* MainView.swift in Sources */, 52B8CF79277E0BFB004CB680 /* DeviceListView.swift in Sources */, 52B8CF84277E0C12004CB680 /* CardView.swift in Sources */, + 5242C873278C8CBB00FDB27E /* EditableText.swift in Sources */, 52B8CF7E277E0BFB004CB680 /* SettingsView.swift in Sources */, 52B8CF7C277E0BFB004CB680 /* KeyListView.swift in Sources */, + 526A1E742791E03900BA2177 /* Persistence.swift in Sources */, 52B8CF7A277E0BFB004CB680 /* MessageListView.swift in Sources */, 52B8CF83277E0C12004CB680 /* DeletableView.swift in Sources */, 52B8CF81277E0BFB004CB680 /* LoginView.swift in Sources */, @@ -537,13 +575,15 @@ 52450F3C278491F8003652D8 /* AppState.swift in Sources */, 5287FF5A278B3AAE00249A0E /* HToast.swift in Sources */, 52B8CF80277E0BFB004CB680 /* MessageItemView.swift in Sources */, + 526A1E752791E52600BA2177 /* PushDeerApp.swift in Sources */, + 526A1E7E2792B2A600BA2177 /* MessageModel.swift in Sources */, 52483FC3277ED6D5003A100E /* AppDelegate.swift in Sources */, 52450F3927848243003652D8 /* PushDeerApi.swift in Sources */, 52B8CF86277E0C12004CB680 /* BaseNavigationView.swift in Sources */, - 52B8CF67277E0B44004CB680 /* PushDeerClipApp.swift in Sources */, 52FBA09427874879003308C2 /* ContentView.swift in Sources */, 52B8CF85277E0C12004CB680 /* Line.swift in Sources */, 52450F402784923D003652D8 /* Result.swift in Sources */, + 526A1E712791E00400BA2177 /* PushDeerData.xcdatamodeld in Sources */, 52450F432784943F003652D8 /* HttpRequest.swift in Sources */, 52B8CF7B277E0BFB004CB680 /* DeviceItemView.swift in Sources */, 52B8CF7D277E0BFB004CB680 /* KeyItemView.swift in Sources */, @@ -561,11 +601,42 @@ }; /* End PBXTargetDependency section */ +/* Begin PBXVariantGroup section */ + 52E317D7279305BB000B8BB1 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 52E317D8279305BB000B8BB1 /* en */, + 52E317EA27930C21000B8BB1 /* zh-Hans */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 52E317DA279305BB000B8BB1 /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 52E317DB279305BB000B8BB1 /* en */, + 52E317E827930AD0000B8BB1 /* zh-Hans */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + 52E317DD279305BB000B8BB1 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 52E317DE279305BB000B8BB1 /* en */, + 52E317E927930C16000B8BB1 /* zh-Hans */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + /* Begin XCBuildConfiguration section */ 5292F5012776BC7A00B9A7BB /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; @@ -627,6 +698,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; @@ -689,6 +761,7 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"PushDeer/Preview Content\""; DEVELOPMENT_TEAM = Y47WTLML2S; + "ENABLE_HARDENED_RUNTIME[sdk=macosx*]" = YES; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = PushDeer/Info.plist; @@ -722,6 +795,7 @@ CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"PushDeer/Preview Content\""; DEVELOPMENT_TEAM = Y47WTLML2S; + "ENABLE_HARDENED_RUNTIME[sdk=macosx*]" = YES; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = PushDeer/Info.plist; @@ -877,6 +951,19 @@ productName = MarkdownUI; }; /* End XCSwiftPackageProductDependency section */ + +/* Begin XCVersionGroup section */ + 526A1E6E2791E00400BA2177 /* PushDeerData.xcdatamodeld */ = { + isa = XCVersionGroup; + children = ( + 526A1E6F2791E00400BA2177 /* PushDeerData.xcdatamodel */, + ); + currentVersion = 526A1E6F2791E00400BA2177 /* PushDeerData.xcdatamodel */; + path = PushDeerData.xcdatamodeld; + sourceTree = ""; + versionGroupType = wrapper.xcdatamodel; + }; +/* End XCVersionGroup section */ }; rootObject = 5292F4ED2776BC7900B9A7BB /* Project object */; } diff --git a/ios/PushDeer-iOS/PushDeer.xcodeproj/xcshareddata/xcschemes/PushDeerClip.xcscheme b/ios/PushDeer-iOS/PushDeer.xcodeproj/xcshareddata/xcschemes/PushDeerClip.xcscheme new file mode 100644 index 0000000..9c33f85 --- /dev/null +++ b/ios/PushDeer-iOS/PushDeer.xcodeproj/xcshareddata/xcschemes/PushDeerClip.xcscheme @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/PushDeer-iOS/PushDeer/AppDelegate.swift b/ios/PushDeer-iOS/PushDeer/AppDelegate.swift index 1a44355..1ac0cd1 100644 --- a/ios/PushDeer-iOS/PushDeer/AppDelegate.swift +++ b/ios/PushDeer-iOS/PushDeer/AppDelegate.swift @@ -35,6 +35,11 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification) async -> UNNotificationPresentationOptions { print("willPresent:", notification.request.content.userInfo) + Task { + // 收到推送后, 刷新本地消息列表 + let messageItems = try await HttpRequest.getMessages().messages + try MessageModel.saveAndUpdate(messageItems: messageItems) + } return [.sound, .list, .banner] } diff --git a/ios/PushDeer-iOS/PushDeer/Common/HToast.swift b/ios/PushDeer-iOS/PushDeer/Common/HToast.swift index ac5e0f1..a117596 100644 --- a/ios/PushDeer-iOS/PushDeer/Common/HToast.swift +++ b/ios/PushDeer-iOS/PushDeer/Common/HToast.swift @@ -16,6 +16,12 @@ struct HToast { static func showSuccess(_ msg: String?) { KRProgressHUD.showSuccess(withMessage: msg) } + static func showInfo(_ msg: String?) { + KRProgressHUD.showInfo(withMessage: msg) + } + static func showWarning(_ msg: String?) { + KRProgressHUD.showWarning(withMessage: msg) + } static func showError(_ msg: String?) { KRProgressHUD.showError(withMessage: msg) } diff --git a/ios/PushDeer-iOS/PushDeer/Model/MessageModel.swift b/ios/PushDeer-iOS/PushDeer/Model/MessageModel.swift new file mode 100644 index 0000000..4ceaecb --- /dev/null +++ b/ios/PushDeer-iOS/PushDeer/Model/MessageModel.swift @@ -0,0 +1,87 @@ +// +// MessageModel.swift +// PushDeer +// +// Created by HEXT on 2022/1/15. +// + +import Foundation +import CoreData + +extension MessageModel { + convenience init(id: Int64, uid: String, text: String, desp: String, type: String, pushkey_name: String, created_at: String, context: NSManagedObjectContext = PersistenceController.shared.container.viewContext) { + self.init(context: context) + self.id = id + self.uid = uid + self.text = text + self.desp = desp + self.type = type + self.pushkey_name = pushkey_name + self.created_at = created_at + } + convenience init(messageItem: MessageItem, context: NSManagedObjectContext = PersistenceController.shared.container.viewContext) { + self.init( + id: Int64(messageItem.id), + uid: messageItem.uid, + text: messageItem.text, + desp: messageItem.desp, + type: messageItem.type, + pushkey_name: messageItem.pushkey_name, + created_at: messageItem.created_at, + context: context) + } + + var createdDateStr: String { + dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSZ" + let createdDate = dateFormatter.date(from: self.created_at ?? "") ?? Date() + let timeInterval = -createdDate.timeIntervalSinceNow + let minute = Int(floor(timeInterval / 60)) + if minute == 0 { + return "刚刚" + } else if minute <= 30 { + return "\(minute)分钟前" + } else if Calendar.current.isDateInToday(createdDate) { + dateFormatter.dateFormat = "HH:mm:ss" + } else { + dateFormatter.dateFormat = "yyyy/MM/dd HH:mm:ss" + } + return dateFormatter.string(from: createdDate) + } + + static let _viewContext = PersistenceController.shared.container.viewContext + static let _fetchRequest = MessageModel.fetchRequest() + + /// 持久化保存和更新 + static func saveAndUpdate(messageItems: [MessageItem]) throws -> Void { + try messageItems.forEach(saveAndUpdate) + } + + /// 持久化保存和更新 + static func saveAndUpdate(messageItem: MessageItem) throws -> Void { + _fetchRequest.predicate = NSPredicate(format: "id = \(messageItem.id)") + let models = try _viewContext.fetch(_fetchRequest) + if models.isEmpty { + // 如果本地不存在, 就构建一个新的放进 context + _ = MessageModel(messageItem: messageItem, context: _viewContext) + } else { + // 如果存在, 就更新第一个, 删除其它重复的 + models.enumerated().forEach { element in + let messageModel = element.element + let index = element.offset + if index == 0 { + messageModel.id = Int64(messageItem.id); + messageModel.uid = messageItem.uid; + messageModel.text = messageItem.text; + messageModel.desp = messageItem.desp; + messageModel.type = messageItem.type; + messageModel.pushkey_name = messageItem.pushkey_name; + messageModel.created_at = messageItem.created_at; + } else { + _viewContext.delete(messageModel) + } + } + } + // 保存 context 中的所有改动 + try _viewContext.save() + } +} diff --git a/ios/PushDeer-iOS/PushDeer/Model/PushDeerData.xcdatamodeld/PushDeerData.xcdatamodel/contents b/ios/PushDeer-iOS/PushDeer/Model/PushDeerData.xcdatamodeld/PushDeerData.xcdatamodel/contents new file mode 100644 index 0000000..7ede6c5 --- /dev/null +++ b/ios/PushDeer-iOS/PushDeer/Model/PushDeerData.xcdatamodeld/PushDeerData.xcdatamodel/contents @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ios/PushDeer-iOS/PushDeer/Model/Result.swift b/ios/PushDeer-iOS/PushDeer/Model/Result.swift index 1107d68..39c38ef 100644 --- a/ios/PushDeer-iOS/PushDeer/Model/Result.swift +++ b/ios/PushDeer-iOS/PushDeer/Model/Result.swift @@ -34,7 +34,7 @@ struct UserInfoContent: Codable{ struct DeviceItem: Codable, Identifiable{ let id: Int let uid: String - let name: String + var name: String let type: String let device_id: String let is_clip: Int @@ -50,7 +50,7 @@ struct KeyContent: Codable{ struct KeyItem: Codable, Identifiable{ let id: Int - let name: String + var name: String let uid: String let key: String let created_at: String @@ -66,6 +66,7 @@ struct MessageItem: Codable, Identifiable{ let text: String let desp: String let type: String + let pushkey_name: String let created_at: String } @@ -87,16 +88,3 @@ extension KeyItem { 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) - } -} diff --git a/ios/PushDeer-iOS/PushDeer/PushDeer.entitlements b/ios/PushDeer-iOS/PushDeer/PushDeer.entitlements index 2808c6d..acd55e5 100644 --- a/ios/PushDeer-iOS/PushDeer/PushDeer.entitlements +++ b/ios/PushDeer-iOS/PushDeer/PushDeer.entitlements @@ -12,5 +12,7 @@ com.apple.security.network.client + com.apple.security.personal-information.photos-library + diff --git a/ios/PushDeer-iOS/PushDeer/PushDeerApp.swift b/ios/PushDeer-iOS/PushDeer/PushDeerApp.swift index 6689ecb..5b22b54 100644 --- a/ios/PushDeer-iOS/PushDeer/PushDeerApp.swift +++ b/ios/PushDeer-iOS/PushDeer/PushDeerApp.swift @@ -10,10 +10,14 @@ import SwiftUI @main struct PushDeerApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate + let store = AppState.shared + let persistenceController = PersistenceController.shared var body: some Scene { WindowGroup { - ContentView().environmentObject(AppState.shared) + ContentView() + .environmentObject(store) + .environment(\.managedObjectContext, persistenceController.container.viewContext) } } } diff --git a/ios/PushDeer-iOS/PushDeer/Service/AppState.swift b/ios/PushDeer-iOS/PushDeer/Service/AppState.swift index 0d22db1..3f6f01b 100644 --- a/ios/PushDeer-iOS/PushDeer/Service/AppState.swift +++ b/ios/PushDeer-iOS/PushDeer/Service/AppState.swift @@ -20,7 +20,7 @@ class AppState: ObservableObject { /// key 列表 @Published var keys: [KeyItem] = [] /// 消息列表 - @Published var messages: [MessageItem] = [] +// @Published var messages: [MessageItem] = [] /// 选中的 tab 下标 @Published var tabSelectedIndex: Int { didSet { @@ -85,7 +85,7 @@ class AppState: ObservableObject { print(error) } // 登录失败 - throw NSError(domain: "登录失败", code: -1, userInfo: nil) + throw NSError(domain: NSLocalizedString("登录失败", comment: "AppleId登录失败时提示"), code: -1, userInfo: nil) } } diff --git a/ios/PushDeer-iOS/PushDeer/Service/HttpRequest.swift b/ios/PushDeer-iOS/PushDeer/Service/HttpRequest.swift index ccf6b75..722495f 100644 --- a/ios/PushDeer-iOS/PushDeer/Service/HttpRequest.swift +++ b/ios/PushDeer-iOS/PushDeer/Service/HttpRequest.swift @@ -26,9 +26,9 @@ struct HttpRequest { continuation.resume(returning: content) } else if result.code == 80403 { AppState.shared.token = "" - continuation.resume(throwing: NSError(domain: result.error ?? "接口报错", code: result.code, userInfo: nil)) + continuation.resume(throwing: NSError(domain: result.error ?? NSLocalizedString("登录过期", comment: "token失效时提示"), code: result.code, userInfo: nil)) } else { - continuation.resume(throwing: NSError(domain: result.error ?? "接口报错", code: result.code, userInfo: nil)) + continuation.resume(throwing: NSError(domain: result.error ?? NSLocalizedString("接口报错", comment: "接口报错时提示"), code: result.code, userInfo: nil)) } } catch { print(error) @@ -66,7 +66,9 @@ struct HttpRequest { static func rmDevice(id: Int) async throws -> ActionContent { return try await request(.rmDevice(token: AppState.shared.token, id: id), resultType: ActionContent.self) } - + static func renameDevice(id: Int, name: String) async throws -> ActionContent { + return try await request(.renameDevice(token: AppState.shared.token, id: id, name: name), resultType: ActionContent.self) + } static func getDevices() async throws -> DeviceContent { return try await request(.getDevices(token: AppState.shared.token), resultType: DeviceContent.self) } diff --git a/ios/PushDeer-iOS/PushDeer/Service/Persistence.swift b/ios/PushDeer-iOS/PushDeer/Service/Persistence.swift new file mode 100644 index 0000000..d91224d --- /dev/null +++ b/ios/PushDeer-iOS/PushDeer/Service/Persistence.swift @@ -0,0 +1,39 @@ +// +// Persistence.swift +// PushDeer +// +// Created by HEXT on 2022/1/14. +// + +import CoreData + +struct PersistenceController { + + static let shared = PersistenceController() + + let container: NSPersistentContainer + + init(inMemory: Bool = false) { + container = NSPersistentContainer(name: "PushDeerData") + if inMemory { + container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null") + } + container.loadPersistentStores(completionHandler: { (storeDescription, error) in + if let error = error as NSError? { + // Replace this implementation with code to handle the error appropriately. + // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. + + /* + Typical reasons for an error here include: + * The parent directory does not exist, cannot be created, or disallows writing. + * The persistent store is not accessible, due to permissions or data protection when the device is locked. + * The device is out of space. + * The store could not be migrated to the current model version. + Check the error message to determine what the actual problem was. + */ + fatalError("Unresolved error \(error), \(error.userInfo)") + } + }) + container.viewContext.automaticallyMergesChangesFromParent = true + } +} diff --git a/ios/PushDeer-iOS/PushDeer/Service/PushDeerApi.swift b/ios/PushDeer-iOS/PushDeer/Service/PushDeerApi.swift index 6cfa3b8..db35e24 100644 --- a/ios/PushDeer-iOS/PushDeer/Service/PushDeerApi.swift +++ b/ios/PushDeer-iOS/PushDeer/Service/PushDeerApi.swift @@ -15,6 +15,7 @@ enum PushDeerApi { case getUserInfo(token: String) case regDevice(token: String, name: String, device_id: String, is_clip: Int) + case renameDevice(token: String, id: Int, name: String) case getDevices(token: String) case rmDevice(token: String, id: Int) @@ -45,6 +46,8 @@ extension PushDeerApi: TargetType { case .regDevice: return "/device/reg" + case .renameDevice: + return "/device/rename" case .getDevices: return "/device/list" case .rmDevice: @@ -87,6 +90,8 @@ extension PushDeerApi: TargetType { 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) + case let .renameDevice(token, id, name): + return .requestParameters(parameters: ["token": token,"id": id,"name": name], encoding: URLEncoding.queryString) case let .getDevices(token): return .requestParameters(parameters: ["token": token], encoding: URLEncoding.queryString) case let .rmDevice(token, id): diff --git a/ios/PushDeer-iOS/PushDeer/View/Common/BaseNavigationView.swift b/ios/PushDeer-iOS/PushDeer/View/Common/BaseNavigationView.swift index a808aeb..1aa568d 100644 --- a/ios/PushDeer-iOS/PushDeer/View/Common/BaseNavigationView.swift +++ b/ios/PushDeer-iOS/PushDeer/View/Common/BaseNavigationView.swift @@ -10,15 +10,20 @@ import SwiftUI /// 具有导航栏结构的基础容器View, APP内的页面基本上都可以使用它包装 struct BaseNavigationView : View { /// 导航栏标题 - let title: String + let title: LocalizedStringKey /// 页面主体View @ViewBuilder let contentView: Content var body: some View { NavigationView { ZStack { - Spacer() - .frame(width: .infinity, height: .infinity) + // VStack HStack Spacer 组合起来撑到最大 + VStack { + HStack { + Spacer() + } + Spacer() + } contentView } .background( diff --git a/ios/PushDeer-iOS/PushDeer/View/Common/DeletableView.swift b/ios/PushDeer-iOS/PushDeer/View/Common/DeletableView.swift index 17609fe..65a2ab9 100644 --- a/ios/PushDeer-iOS/PushDeer/View/Common/DeletableView.swift +++ b/ios/PushDeer-iOS/PushDeer/View/Common/DeletableView.swift @@ -71,7 +71,7 @@ struct DeletableView : View { struct DeletableView_Previews: PreviewProvider { static var previews: some View { DeletableView(contentView: { - DeviceItemView(name: "未知设备") + DeviceItemView(deviceItem: DeviceItem(id: 0, uid: "", name: "Hext's iPhone 11", type: "", device_id: "", is_clip: 0)) }, deleteAction: { }) diff --git a/ios/PushDeer-iOS/PushDeer/View/Common/EditableText.swift b/ios/PushDeer-iOS/PushDeer/View/Common/EditableText.swift new file mode 100644 index 0000000..ae9b91b --- /dev/null +++ b/ios/PushDeer-iOS/PushDeer/View/Common/EditableText.swift @@ -0,0 +1,47 @@ +// +// EditableText.swift +// PushDeer +// +// Created by HEXT on 2022/1/10. +// + +import SwiftUI + +struct EditableText: View { + var placeholder = "" + @State var value = "" + var onCommit: (_ value: String) -> Void = { value in + + } + + func textField() -> some View { + TextField(placeholder, text: $value, onCommit: { + print("修改文本:", value) + self.onCommit(value) + }) + .font(.system(size: 20)) + .foregroundColor(Color.accentColor) + } + + var body: some View { + if #available(iOS 15.0, *) { + textField() + .submitLabel(.done) + } else { + textField() + } + } +} + +struct EditableText_Previews: PreviewProvider { + static var previews: some View { + VStack { + EditableText(value: "你好") + EditableText(placeholder: "请输入") + EditableText() + EditableText(placeholder: "请输入") { value in + + } + } + } +} diff --git a/ios/PushDeer-iOS/PushDeer/View/DeviceItemView.swift b/ios/PushDeer-iOS/PushDeer/View/DeviceItemView.swift index 70a013f..c5d8e2c 100644 --- a/ios/PushDeer-iOS/PushDeer/View/DeviceItemView.swift +++ b/ios/PushDeer-iOS/PushDeer/View/DeviceItemView.swift @@ -9,16 +9,40 @@ import SwiftUI /// 每个设备项的 View struct DeviceItemView: View { - var name: String + let deviceItem: DeviceItem + @EnvironmentObject private var store: AppState + var body: some View { CardView { HStack{ - Image(systemName: getSystemName(deviceName: name)) - .resizable() - .scaledToFit() - .frame(width: 40, height: 40, alignment: .center) - .padding(EdgeInsets(top: 0, leading: 18, bottom: 0, trailing: 8)) - Text(name) + ZStack{ + Image(systemName: getSystemName(deviceName: deviceItem.name)) + .resizable() + .scaledToFit() + .frame(width: 40, height: 40, alignment: .center) + if deviceItem.is_clip == 1 { + Image(systemName: "appclip") + .resizable() + .scaledToFit() + .frame(width: 12, height: 12, alignment: .center) + } + } + .padding(EdgeInsets(top: 0, leading: 18, bottom: 0, trailing: 8)) + + EditableText(placeholder: NSLocalizedString("输入设备名称", comment: ""), value: deviceItem.name) { value in + Task { + // 调用接口修改 + _ = try await HttpRequest.renameDevice(id: deviceItem.id, name: value) + HToast.showSuccess(NSLocalizedString("已修改设备名称", comment: "")) + // 在此 Item 在列表中的下标 + let index = store.devices.firstIndex { $0.id == deviceItem.id } + if let index = index { + // 更新列表中相应的 Item + store.devices[index].name = value + } + } + } + Text(getInfo(deviceItem: deviceItem)) .font(.system(size: 20)) Spacer() } @@ -26,6 +50,17 @@ struct DeviceItemView: View { } } + func getInfo(deviceItem: DeviceItem) -> String { + var name = "" + // if deviceItem.is_clip == 1 { + // name += " [Clip]" + // } + if deviceItem.device_id == store.deviceToken { + name += NSLocalizedString("(当前设备)", comment: "在设备列表中标识当前设备") + } + return name + } + func getSystemName(deviceName: String) -> String { var deviceName = deviceName.lowercased() deviceName = deviceName.replacingOccurrences(of: " ", with: "") @@ -60,6 +95,7 @@ struct DeviceItemView: View { struct DeviceItemView_Previews: PreviewProvider { static var previews: some View { - DeviceItemView(name: "未知设备") + DeviceItemView(deviceItem: DeviceItem(id: 0, uid: "", name: "Hext's iPhone 11", type: "", device_id: "", is_clip: 1)) + .environmentObject(AppState.shared) } } diff --git a/ios/PushDeer-iOS/PushDeer/View/DeviceListView.swift b/ios/PushDeer-iOS/PushDeer/View/DeviceListView.swift index 080e76a..90cb133 100644 --- a/ios/PushDeer-iOS/PushDeer/View/DeviceListView.swift +++ b/ios/PushDeer-iOS/PushDeer/View/DeviceListView.swift @@ -16,12 +16,12 @@ struct DeviceListView: View { LazyVStack(alignment: .center) { ForEach(store.devices.reversed()) { deviceItem in DeletableView(contentView: { - DeviceItemView(name: getName(deviceItem: deviceItem)) + DeviceItemView(deviceItem: deviceItem) }, deleteAction: { store.devices.removeAll { _deviceItem in _deviceItem.id == deviceItem.id } - HToast.showSuccess("已删除") + HToast.showSuccess(NSLocalizedString("已删除", comment: "删除设备/Key/消息时提示")) Task { do { _ = try await HttpRequest.rmDevice(id: deviceItem.id) @@ -37,11 +37,16 @@ struct DeviceListView: View { } .navigationBarItems(trailing: Button(action: { Task { + let hasContains = store.devices.contains { store.deviceToken == $0.device_id } + if hasContains { + HToast.showInfo(NSLocalizedString("已添加过当前设备", comment: "")) + return; + } let devices = try await HttpRequest.regDevice().devices withAnimation(.easeOut) { store.devices = devices } - HToast.showSuccess("已添加当前设备") + HToast.showSuccess(NSLocalizedString("已添加当前设备", comment: "")) } }, label: { Image(systemName: "plus") @@ -52,17 +57,6 @@ struct DeviceListView: View { 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 { diff --git a/ios/PushDeer-iOS/PushDeer/View/KeyItemView.swift b/ios/PushDeer-iOS/PushDeer/View/KeyItemView.swift index 85ef4c6..cc34e12 100644 --- a/ios/PushDeer-iOS/PushDeer/View/KeyItemView.swift +++ b/ios/PushDeer-iOS/PushDeer/View/KeyItemView.swift @@ -7,60 +7,10 @@ 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 struct KeyItemView: View { let keyItem: KeyItem + @EnvironmentObject private var store: AppState var body: some View { VStack(spacing: 20) { @@ -69,7 +19,19 @@ struct KeyItemView: View { .resizable() .scaledToFit() .frame(width: 38, height: 38) - KeyItemTextField(keyItem: keyItem) + EditableText(placeholder: NSLocalizedString("输入key名称", comment: ""), value: keyItem.name) { value in + Task { + // 调用接口修改 + _ = try await HttpRequest.renameKey(id: keyItem.id, name: value) + HToast.showSuccess(NSLocalizedString("已修改key名称", comment: "")) + // 在此 keyItem 在列表中的下标 + let index = store.keys.firstIndex { $0.id == keyItem.id } + if let index = index { + // 更新列表中相应的 keyItem + store.keys[index].name = value + } + } + } Spacer() Image(systemName: "calendar") .font(.system(size: 14)) @@ -89,13 +51,13 @@ struct KeyItemView: View { HLine().stroke(Color.gray, style: StrokeStyle(lineWidth: 1, dash: [5])) HStack { - Button("重置") { + Button(NSLocalizedString("重置", comment: "重置key的按钮标题")) { print("点击重置") Task { do { _ = try await HttpRequest.regenKey(id: keyItem.id) HttpRequest.loadKeys() - HToast.showSuccess("已重置") + HToast.showSuccess(NSLocalizedString("已重置", comment: "已重置key的提示")) } catch { } @@ -108,10 +70,10 @@ struct KeyItemView: View { Spacer() - Button("复制") { + Button(NSLocalizedString("复制", comment: "复制按钮的标题")) { print("点击复制") UIPasteboard.general.string = keyItem.key - HToast.showSuccess("已复制") + HToast.showSuccess(NSLocalizedString("已复制", comment: "")) } .font(.system(size: 20)) .frame(width: 90, height: 42) @@ -127,5 +89,6 @@ struct KeyItemView: View { struct KeyItemView_Previews: PreviewProvider { static var previews: some View { KeyItemView(keyItem: KeyItem(id: 1, name: "name", uid: "1", key: "Key", created_at: "1111")) + .environmentObject(AppState.shared) } } diff --git a/ios/PushDeer-iOS/PushDeer/View/KeyListView.swift b/ios/PushDeer-iOS/PushDeer/View/KeyListView.swift index 70c5741..e21c1e8 100644 --- a/ios/PushDeer-iOS/PushDeer/View/KeyListView.swift +++ b/ios/PushDeer-iOS/PushDeer/View/KeyListView.swift @@ -24,7 +24,7 @@ struct KeyListView: View { store.keys.removeAll { _keyItem in keyItem.id == _keyItem.id } - HToast.showSuccess("已删除") + HToast.showSuccess(NSLocalizedString("已删除", comment: "删除设备/Key/消息时提示")) Task { do { _ = try await HttpRequest.rmKey(id: keyItem.id) @@ -44,7 +44,7 @@ struct KeyListView: View { withAnimation(.easeOut) { store.keys = keys } - HToast.showSuccess("已添加新Key") + HToast.showSuccess(NSLocalizedString("已添加新Key", comment: "")) } }, label: { Image(systemName: "plus") diff --git a/ios/PushDeer-iOS/PushDeer/View/MessageItemView.swift b/ios/PushDeer-iOS/PushDeer/View/MessageItemView.swift index cc1a977..013da96 100644 --- a/ios/PushDeer-iOS/PushDeer/View/MessageItemView.swift +++ b/ios/PushDeer-iOS/PushDeer/View/MessageItemView.swift @@ -11,7 +11,7 @@ import SDWebImageSwiftUI import Photos struct MessageItemView: View { - let messageItem: MessageItem + let messageItem: MessageModel /// 删除按钮点击的回调 let deleteAction : () -> () @@ -24,7 +24,7 @@ struct MessageItemView: View { .resizable() .scaledToFit() .frame(width: 38, height: 38) - Text("key名字") + Text(messageItem.pushkey_name ?? "") .font(.system(size: 14)) .foregroundColor(Color(UIColor.darkGray)) Text(messageItem.createdDateStr) @@ -45,7 +45,7 @@ struct MessageItemView: View { } struct MessageContentView: View { - let messageItem: MessageItem + let messageItem: MessageModel @State private var image: PlatformImage? = nil var body: some View { @@ -53,15 +53,15 @@ struct MessageContentView: View { case "markdown": CardView { VStack(alignment: .leading, spacing: 5) { - Markdown(Document(messageItem.text)) + Markdown(Document(messageItem.text ?? "")) .markdownStyle( DefaultMarkdownStyle( font: .system(size: 14), foregroundColor: UIColor.darkGray ) ) - if !messageItem.desp.isEmpty { - Markdown(Document(messageItem.desp)) + if !(messageItem.desp?.isEmpty ?? true) { + Markdown(Document(messageItem.desp!)) .markdownStyle( DefaultMarkdownStyle( font: .system(size: 14), @@ -74,31 +74,52 @@ struct MessageContentView: View { } case "image": - WebImage(url: URL(string: messageItem.text)) + WebImage(url: URL(string: messageItem.text ?? "")) .onSuccess { image, data, cacheType in - self.image = image + DispatchQueue.main.async { + self.image = image + } } .resizable() + .placeholder(content: { + ZStack { + Color.gray.opacity(0.5) + Image(systemName: "photo") + .foregroundColor(.gray) + .font(.system(size: 100)) + } + .frame(width: nil, height: 200, alignment: .center) + }) + .indicator(.activity) + .transition(.fade(duration: 0.5)) .scaledToFill() + .background(Color.white) .contextMenu { Button { + guard let image = image else { + HToast.showWarning(NSLocalizedString("图片未加载成功", comment: "")) + return + } UIPasteboard.general.image = image - HToast.showSuccess("已拷贝") + HToast.showSuccess(NSLocalizedString("已拷贝", comment: "")) } label: { Label("拷贝图片",systemImage: "doc.on.doc") } Button { - guard let image = image else { return } + guard let image = image else { + HToast.showWarning(NSLocalizedString("图片未加载成功", comment: "")) + return + } PHPhotoLibrary.shared().performChanges { PHAssetChangeRequest.creationRequestForAsset(from: image) } completionHandler: { (isSuccess, error) in DispatchQueue.main.async { if isSuccess {// 成功 print("Success") - HToast.showSuccess("保存成功") + HToast.showSuccess(NSLocalizedString("保存成功", comment: "")) } else { print(error as Any) - HToast.showError("保存失败") + HToast.showError(NSLocalizedString("保存失败", comment: "")) } } } @@ -111,13 +132,13 @@ struct MessageContentView: View { CardView { VStack(alignment: .leading, spacing: 5) { HStack{ - Text(messageItem.text) + Text(messageItem.text ?? "") .font(.system(size: 14)) .foregroundColor(Color(UIColor.darkGray)) Spacer(minLength: 0) } - if !messageItem.desp.isEmpty { - Text(messageItem.desp) + if !(messageItem.desp?.isEmpty ?? true) { + Text(messageItem.desp ?? "") .font(.system(size: 14)) .foregroundColor(Color(UIColor.darkGray)) } @@ -125,8 +146,8 @@ struct MessageContentView: View { .padding() .contextMenu { Button { - UIPasteboard.general.string = messageItem.text + messageItem.desp - HToast.showSuccess("已复制") + UIPasteboard.general.string = (messageItem.text ?? "") + (messageItem.desp ?? "") + HToast.showSuccess(NSLocalizedString("已复制", comment: "")) } label: { Label("复制",systemImage: "doc.on.doc") } @@ -139,18 +160,18 @@ struct MessageContentView: View { struct MessageItemView_Previews: PreviewProvider { static var previews: some View { VStack { - 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: "纯文本的效果纯文本的效果纯文本的效果纯文本的效果纯文本的效果纯文本的效果纯文本的效果", 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: """ + MessageItemView(messageItem: MessageModel(id: 1, uid: "1", text: "纯文本的效果", desp: "你好呀", type: "text", pushkey_name: "Key", created_at: "2022-01-08T18:00:48.000000Z")){} + MessageItemView(messageItem: MessageModel(id: 1, uid: "1", text: "纯文本的效果纯文本的效果纯文本的效果纯文本的效果纯文本的效果纯文本的效果纯文本的效果", desp: "", type: "text", pushkey_name: "Key", created_at: "2022-01-08T18:00:48.000000Z")){} + MessageItemView(messageItem: MessageModel(id: 1, uid: "1", text: "https://blog.wskfz.com/usr/uploads/2018/06/2498727457.png", desp: "", type: "image", pushkey_name: "Key1", created_at: "2022-01-08T18:00:48.000000Z")){} + MessageItemView(messageItem: MessageModel(id: 1, uid: "1", text: "https://blog.wskfz.com/usr/uploads/2018/06/2151130181.png", desp: "", type: "image", pushkey_name: "Key2", created_at: "2022-01-08T18:00:48.000000Z")){} + MessageItemView(messageItem: MessageModel(id: 1, uid: "1", text: "https://blog.wskfz.com/usr/uploads/2018/06/1718629805.png", desp: "", type: "image", pushkey_name: "Key2", created_at: "2022-01-08T18:00:48.000000Z")){} + MessageItemView(messageItem: MessageModel(id: 1, uid: "1", text: "*MarkDown*的**效果**", desp: "*MarkDown*的**效果**", type: "markdown", pushkey_name: "Key", created_at: "2021-12-28T13:44:48.000000Z")){} + MessageItemView(messageItem: MessageModel(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")){} +""", desp: "", type: "markdown", pushkey_name: "3", created_at: "2021-12-28T13:44:48.000000Z")){} Spacer() } } diff --git a/ios/PushDeer-iOS/PushDeer/View/MessageListView.swift b/ios/PushDeer-iOS/PushDeer/View/MessageListView.swift index 5cda46b..16c6bfe 100644 --- a/ios/PushDeer-iOS/PushDeer/View/MessageListView.swift +++ b/ios/PushDeer-iOS/PushDeer/View/MessageListView.swift @@ -10,7 +10,11 @@ import SwiftUI /// 消息界面 struct MessageListView: View { @EnvironmentObject private var store: AppState + @Environment(\.managedObjectContext) private var viewContext + @FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \MessageModel.created_at, ascending: false)], animation: .default) + private var messages: FetchedResults + var body: some View { BaseNavigationView(title: "消息") { ScrollView { @@ -18,15 +22,15 @@ struct MessageListView: View { if store.isShowTestPush { TestPushView() } - ForEach(store.messages) { messageItem in + ForEach(messages) { messageItem in MessageItemView(messageItem: messageItem) { - store.messages.removeAll { _messageItem in - _messageItem.id == messageItem.id - } - HToast.showSuccess("已删除") + let id = messageItem.id + viewContext.delete(messageItem) + try? viewContext.save() + HToast.showSuccess(NSLocalizedString("已删除", comment: "删除设备/Key/消息时提示")) Task { do { - _ = try await HttpRequest.rmMessage(id: messageItem.id) + _ = try await HttpRequest.rmMessage(id: Int(id)) } catch { } @@ -47,7 +51,8 @@ struct MessageListView: View { } .onAppear { Task { - store.messages = try await HttpRequest.getMessages().messages + let messageItems = try await HttpRequest.getMessages().messages + try MessageModel.saveAndUpdate(messageItems: messageItems) } } } @@ -65,7 +70,7 @@ struct TestPushView: View { Button("推送测试") { print("点击推送测试") if testText.isEmpty { - HToast.showError("推送失败, 请先输入推送内容") + HToast.showError(NSLocalizedString("推送失败, 请先输入推送内容", comment: "")) return } Task { @@ -75,13 +80,13 @@ struct TestPushView: View { 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 + HToast.showSuccess(NSLocalizedString("推送成功", comment: "")) + let messageItems = try await HttpRequest.getMessages().messages withAnimation(.easeOut) { - store.messages = messages + try? MessageModel.saveAndUpdate(messageItems: messageItems) } } else { - HToast.showError("推送失败, 请先添加一个Key") + HToast.showError(NSLocalizedString("推送失败, 请先添加一个Key", comment: "")) } } } diff --git a/ios/PushDeer-iOS/PushDeer/View/SettingsView.swift b/ios/PushDeer-iOS/PushDeer/View/SettingsView.swift index d717acd..81e31dd 100644 --- a/ios/PushDeer-iOS/PushDeer/View/SettingsView.swift +++ b/ios/PushDeer-iOS/PushDeer/View/SettingsView.swift @@ -15,17 +15,17 @@ struct SettingsView: View { var body: some View { BaseNavigationView(title: "设置") { VStack { - SettingsItemView(title: "登录为 \(store.userInfo?.name ?? "--")", button: "退出") { + SettingsItemView(title: NSLocalizedString("登录为", comment: "") + " \(store.userInfo?.name ?? "--")", button: NSLocalizedString("退出", comment: "退出登录按钮上的文字")) { store.token = "" } .padding(EdgeInsets(top: 18, leading: 20, bottom: 0, trailing: 20)) - SettingsItemView(title: "自定义服务器", button: "扫码") { + SettingsItemView(title: NSLocalizedString("自定义服务器", comment: ""), button: NSLocalizedString("扫码", comment: "")) { } .disabled(true) .padding(EdgeInsets(top: 18, leading: 20, bottom: 0, trailing: 20)) - SettingsItemView(title: "喜欢PushDeer?", button: "评分") { + SettingsItemView(title: NSLocalizedString("喜欢PushDeer?", comment: ""), button: NSLocalizedString("评分", comment: "")) { let urlStr = "itms-apps://itunes.apple.com/app/id\(1596771139)?action=write-review" UIApplication.shared.open(URL(string: urlStr)!, options: [:], completionHandler: nil) // 直接弹出系统评分控件, 不过一年最多3次, 用户还可以在系统设置里面关 diff --git a/ios/PushDeer-iOS/PushDeer/en.lproj/InfoPlist.strings b/ios/PushDeer-iOS/PushDeer/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..946db78 --- /dev/null +++ b/ios/PushDeer-iOS/PushDeer/en.lproj/InfoPlist.strings @@ -0,0 +1,6 @@ +/* Privacy - Local Network Usage Description */ +"NSLocalNetworkUsageDescription" = "APP needs access to the local network for debugging (only when developing)"; + +/* Privacy - Photo Library Additions Usage Description */ +"NSPhotoLibraryAddUsageDescription" = "APP provides you with the function of saving pictures to albums"; + diff --git a/ios/PushDeer-iOS/PushDeer/en.lproj/Localizable.strings b/ios/PushDeer-iOS/PushDeer/en.lproj/Localizable.strings new file mode 100644 index 0000000..fe70404 --- /dev/null +++ b/ios/PushDeer-iOS/PushDeer/en.lproj/Localizable.strings @@ -0,0 +1,111 @@ +/* 在设备列表中标识当前设备 */ +"(当前设备)" = "(current device)"; + +/* No comment provided by engineer. */ +"保存成功" = "Saved successfully"; + +/* No comment provided by engineer. */ +"保存失败" = "Saved failed"; + +/* No comment provided by engineer. */ +"保存图片" = "Save picture"; + +/* No comment provided by engineer. */ +"标题" = "Title"; + +/* token失效时提示 */ +"登录过期" = "Login expired"; + +/* AppleId登录失败时提示 */ +"登录失败" = "Login failed"; + +/* No comment provided by engineer. */ +"登录为" = "Login as"; + +/* 复制按钮的标题 */ +"复制" = "Copy"; + +/* 接口报错时提示 */ +"接口报错" = "Interface error"; + +/* No comment provided by engineer. */ +"拷贝图片" = "Copy image"; + +/* No comment provided by engineer. */ +"内容" = "Content"; + +/* No comment provided by engineer. */ +"评分" = "Score"; + +/* No comment provided by engineer. */ +"扫码" = "Scan"; + +/* No comment provided by engineer. */ +"设备" = "Devices"; + +/* No comment provided by engineer. */ +"设置" = "Settings"; + +/* No comment provided by engineer. */ +"输入设备名称" = "Enter device name"; + +/* No comment provided by engineer. */ +"输入key名称" = "Enter key name"; + +/* No comment provided by engineer. */ +"图片未加载成功" = "Image did not load successfully"; + +/* No comment provided by engineer. */ +"推送测试" = "Push Test"; + +/* No comment provided by engineer. */ +"推送成功" = "Push successfully"; + +/* No comment provided by engineer. */ +"推送失败, 请先输入推送内容" = "Push failed, please enter push content first"; + +/* No comment provided by engineer. */ +"推送失败, 请先添加一个Key" = "Push failed, please add a Key first"; + +/* 退出登录按钮上的文字 */ +"退出" = "Logout"; + +/* No comment provided by engineer. */ +"喜欢PushDeer?" = "Like PushDeer?"; + +/* No comment provided by engineer. */ +"消息" = "Messages"; + +/* No comment provided by engineer. */ +"已复制" = "Copied successfully"; + +/* No comment provided by engineer. */ +"已拷贝" = "Copied successfully"; + +/* 删除设备/Key/消息时提示 */ +"已删除" = "Deleted successfully"; + +/* No comment provided by engineer. */ +"已添加当前设备" = "Current device added"; + +/* No comment provided by engineer. */ +"已添加过当前设备" = "The current device has been added"; + +/* No comment provided by engineer. */ +"已添加新Key" = "A new key has been added"; + +/* No comment provided by engineer. */ +"已修改设备名称" = "Device name modified"; + +/* No comment provided by engineer. */ +"已修改key名称" = "The key name has been modified"; + +/* 已重置key的提示 */ +"已重置" = "Reset successfully"; + +/* 重置key的按钮标题 */ +"重置" = "Reset"; + +/* No comment provided by engineer. */ +"自定义服务器" = "Custom server"; + diff --git a/ios/PushDeer-iOS/PushDeer/zh-Hans.lproj/InfoPlist.strings b/ios/PushDeer-iOS/PushDeer/zh-Hans.lproj/InfoPlist.strings new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/ios/PushDeer-iOS/PushDeer/zh-Hans.lproj/InfoPlist.strings @@ -0,0 +1 @@ + diff --git a/ios/PushDeer-iOS/PushDeer/zh-Hans.lproj/Localizable.strings b/ios/PushDeer-iOS/PushDeer/zh-Hans.lproj/Localizable.strings new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/ios/PushDeer-iOS/PushDeer/zh-Hans.lproj/Localizable.strings @@ -0,0 +1 @@ + diff --git a/ios/PushDeer-iOS/PushDeerClip/PushDeerClipApp.swift b/ios/PushDeer-iOS/PushDeerClip/PushDeerClipApp.swift deleted file mode 100644 index 292aa1d..0000000 --- a/ios/PushDeer-iOS/PushDeerClip/PushDeerClipApp.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// PushDeerClipApp.swift -// PushDeerClip -// -// Created by HEXT on 2021/12/30. -// - -import SwiftUI - -@main -struct PushDeerClipApp: App { - @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate - - var body: some Scene { - WindowGroup { - ContentView().environmentObject(AppState.shared) - } - } -} diff --git a/ios/PushDeer-iOS/PushDeerClip/en.lproj/InfoPlist.strings b/ios/PushDeer-iOS/PushDeerClip/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..946db78 --- /dev/null +++ b/ios/PushDeer-iOS/PushDeerClip/en.lproj/InfoPlist.strings @@ -0,0 +1,6 @@ +/* Privacy - Local Network Usage Description */ +"NSLocalNetworkUsageDescription" = "APP needs access to the local network for debugging (only when developing)"; + +/* Privacy - Photo Library Additions Usage Description */ +"NSPhotoLibraryAddUsageDescription" = "APP provides you with the function of saving pictures to albums"; + diff --git a/ios/PushDeer-iOS/PushDeerClip/zh-Hans.lproj/InfoPlist.strings b/ios/PushDeer-iOS/PushDeerClip/zh-Hans.lproj/InfoPlist.strings new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/ios/PushDeer-iOS/PushDeerClip/zh-Hans.lproj/InfoPlist.strings @@ -0,0 +1 @@ +