diff --git a/Podfile b/Podfile index b47ac35d..7d1baccd 100644 --- a/Podfile +++ b/Podfile @@ -3,28 +3,21 @@ install! 'cocoapods', :generate_multiple_pod_projects => true inhibit_all_warnings! platform :osx, '10.12' - -post_install do |installer| - # Sign the Sparkle helper binaries to pass App Notarization. - system("codesign --force -o runtime -s 'Developer ID Application' Pods/Sparkle/Sparkle.framework/Resources/Autoupdate.app/Contents/MacOS/Autoupdate") - system("codesign --force -o runtime -s 'Developer ID Application' Pods/Sparkle/Sparkle.framework/Resources/Autoupdate.app/Contents/MacOS/fileop") -end - target 'uPic' do # Comment the next line if you're not using Swift and don't want to use dynamic frameworks use_frameworks! pod 'SwiftyJSON' - pod 'Alamofire', '~> 5.0.2' + pod 'Alamofire' pod 'MASShortcut' pod 'CryptoSwift', :git => "https://github.com/krzyzanowskim/CryptoSwift", :branch => "master" pod "SwiftyXMLParser", :git => 'https://github.com/yahoojapan/SwiftyXMLParser.git' - pod 'Sparkle' pod 'Kingfisher' - pod 'SnapKit', '~> 5.0.0' + pod 'SnapKit' pod 'LoginServiceKit', :git => 'https://github.com/Clipy/LoginServiceKit.git' pod "libminipng" pod 'WCDB.swift' + pod 'libwebp', '~> 1.0' end diff --git a/Podfile.lock b/Podfile.lock index 51db45c1..15d19ff5 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,32 +1,38 @@ PODS: - - Alamofire (5.0.5) - - CryptoSwift (1.3.3) - - Kingfisher (5.15.4): - - Kingfisher/Core (= 5.15.4) - - Kingfisher/Core (5.15.4) + - Alamofire (5.4.3) + - CryptoSwift (1.4.0) + - Kingfisher (6.3.0) - libminipng (0.5.6) - - LoginServiceKit (2.2.0) + - libwebp (1.2.0): + - libwebp/demux (= 1.2.0) + - libwebp/mux (= 1.2.0) + - libwebp/webp (= 1.2.0) + - libwebp/demux (1.2.0): + - libwebp/webp + - libwebp/mux (1.2.0): + - libwebp/demux + - libwebp/webp (1.2.0) + - LoginServiceKit (2.2.1) - MASShortcut (2.4.0) - SnapKit (5.0.1) - - Sparkle (1.23.0) - SQLiteRepairKit (1.2.2): - WCDBOptimizedSQLCipher (~> 1.2.0) - - SwiftyJSON (5.0.0) - - SwiftyXMLParser (5.1.0) + - SwiftyJSON (5.0.1) + - SwiftyXMLParser (5.3.0) - WCDB.swift (1.0.8.2): - SQLiteRepairKit (~> 1.2.0) - WCDBOptimizedSQLCipher (~> 1.2.0) - WCDBOptimizedSQLCipher (1.2.1) DEPENDENCIES: - - Alamofire (~> 5.0.2) + - Alamofire - CryptoSwift (from `https://github.com/krzyzanowskim/CryptoSwift`, branch `master`) - Kingfisher - libminipng + - libwebp (~> 1.0) - LoginServiceKit (from `https://github.com/Clipy/LoginServiceKit.git`) - MASShortcut - - SnapKit (~> 5.0.0) - - Sparkle + - SnapKit - SwiftyJSON - SwiftyXMLParser (from `https://github.com/yahoojapan/SwiftyXMLParser.git`) - WCDB.swift @@ -36,9 +42,9 @@ SPEC REPOS: - Alamofire - Kingfisher - libminipng + - libwebp - MASShortcut - SnapKit - - Sparkle - SQLiteRepairKit - SwiftyJSON - WCDB.swift @@ -55,30 +61,30 @@ EXTERNAL SOURCES: CHECKOUT OPTIONS: CryptoSwift: - :commit: e2bc81be54d71d566a52ca17c3983d141c30aa70 + :commit: 54b2acbb619953e641486e535389b0d6e5e76dce :git: https://github.com/krzyzanowskim/CryptoSwift LoginServiceKit: - :commit: cf58b91b0ac247bd8bf5dccb5434ca60a930c1e1 + :commit: e35be754ca2409ceada3825ac80461ecbad3c11f :git: https://github.com/Clipy/LoginServiceKit.git SwiftyXMLParser: - :commit: ec7f183642adf429babd867d1a38c5c6912408ba + :commit: b7beef45ecba2df71ac831245f71141ec0efb1fb :git: https://github.com/yahoojapan/SwiftyXMLParser.git SPEC CHECKSUMS: - Alamofire: df2f8f826963b08b9a870791ad48e07a10090b2e - CryptoSwift: fedfc9f8362163ca381a78897ad810982e18d464 - Kingfisher: 657dc1077e5bbbfff864194c79f29e35b722d062 + Alamofire: e447a2774a40c996748296fa2c55112fdbbc42f9 + CryptoSwift: 7cc902df1784de3b389a387756c7d710f197730c + Kingfisher: 6c3df386db71d82c0817a429d2c9421a77396529 libminipng: a44c35d06b9d54d6640acdf97f4500c034748abb - LoginServiceKit: 3c86ce2f2bcd1e373326839d6d863d8a6a5915b4 + libwebp: e90b9c01d99205d03b6bb8f2c8c415e5a4ef66f0 + LoginServiceKit: e39022a6ea6169b3716fc3c43e89b2e7fd12f222 MASShortcut: d9e4909e878661cc42877cc9d6efbe638273ab57 SnapKit: 97b92857e3df3a0c71833cce143274bf6ef8e5eb - Sparkle: 55b1a87ba69d56913375a281546b7c82dec95bb0 SQLiteRepairKit: 35aaae5a8838adb85f5b1eb4d796055be6060a4b - SwiftyJSON: 36413e04c44ee145039d332b4f4e2d3e8d6c4db7 - SwiftyXMLParser: 23b5a9321a8adf72aae29046ea58c3d097b4ac17 + SwiftyJSON: 2f33a42c6fbc52764d96f13368585094bfd8aa5e + SwiftyXMLParser: 0985085180f1ee01916cd9b5c1a4f0a8f493c084 WCDB.swift: 05d509d7a0e60fb6e11c34eb7e4027c0fab5849f WCDBOptimizedSQLCipher: baf44493b0c7a3d49e97bc5b64a3856f6428ddd1 -PODFILE CHECKSUM: 4101e450e6b2d21bac70b5245d209294f573f3bb +PODFILE CHECKSUM: cf202d987302b5e2459f9dcb4717a722392dab1e -COCOAPODS: 1.10.0 +COCOAPODS: 1.10.1 diff --git a/uPic.xcodeproj/project.pbxproj b/uPic.xcodeproj/project.pbxproj index 7bce9274..38cd4b83 100644 --- a/uPic.xcodeproj/project.pbxproj +++ b/uPic.xcodeproj/project.pbxproj @@ -7,12 +7,23 @@ objects = { /* Begin PBXBuildFile section */ + 039BE362267887F400CE0549 /* CGImage+Drawing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039BE355267887F400CE0549 /* CGImage+Drawing.swift */; }; + 039BE363267887F400CE0549 /* FileTypeUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039BE356267887F400CE0549 /* FileTypeUtil.swift */; }; + 039BE364267887F400CE0549 /* ImageIOEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039BE358267887F400CE0549 /* ImageIOEncoder.swift */; }; + 039BE365267887F400CE0549 /* ImageIODecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039BE359267887F400CE0549 /* ImageIODecoder.swift */; }; + 039BE366267887F400CE0549 /* WebPDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039BE35A267887F400CE0549 /* WebPDecoder.swift */; }; + 039BE367267887F400CE0549 /* CodecUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039BE35B267887F400CE0549 /* CodecUtil.swift */; }; + 039BE368267887F400CE0549 /* CommonImageCodec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039BE35C267887F400CE0549 /* CommonImageCodec.swift */; }; + 039BE369267887F400CE0549 /* BaseCodec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039BE35D267887F400CE0549 /* BaseCodec.swift */; }; + 039BE36A267887F400CE0549 /* WebPEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039BE35E267887F400CE0549 /* WebPEncoder.swift */; }; + 039BE36B267887F400CE0549 /* CommonImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039BE360267887F400CE0549 /* CommonImage.swift */; }; 1602ED9722ADEFB200AA8638 /* BaseUploader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1602ED9622ADEFB200AA8638 /* BaseUploader.swift */; }; 1602ED9922ADF43800AA8638 /* SmmsUploader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1602ED9822ADF43800AA8638 /* SmmsUploader.swift */; }; 16068C7522AEC1D1004D39B7 /* PreferencesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16068C7422AEC1D1004D39B7 /* PreferencesViewController.swift */; }; 16068C7822AECB34004D39B7 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16068C7722AECB34004D39B7 /* PreferencesWindowController.swift */; }; 16068C7C22AECD9F004D39B7 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16068C7B22AECD9F004D39B7 /* Constants.swift */; }; 160CAA2522B1ED6F00D04FBD /* PreferenceKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 160CAA2422B1ED6F00D04FBD /* PreferenceKey.swift */; }; + 1613D88725C9826B009E348A /* AutoGenStrings.py in Resources */ = {isa = PBXBuildFile; fileRef = 1613D88625C9826B009E348A /* AutoGenStrings.py */; }; 161539122408EC7B00CC662F /* LskyProUploader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 161539102408E7F200CC662F /* LskyProUploader.swift */; }; 161539132408EC7D00CC662F /* LskyProHostConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 161539112408E7F200CC662F /* LskyProHostConfig.swift */; }; 161539152408F0E200CC662F /* LskyProConfigView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 161539142408F0E200CC662F /* LskyProConfigView.swift */; }; @@ -25,8 +36,10 @@ 161C3BE122C483380092114F /* CustomUploader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 161C3BE022C4831B0092114F /* CustomUploader.swift */; }; 161C3BE322C483560092114F /* CustomHostConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 161C3BE222C483560092114F /* CustomHostConfig.swift */; }; 161C3BE522C4870C0092114F /* CustomConfigView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 161C3BE422C4870B0092114F /* CustomConfigView.swift */; }; + 161D7F9125B9037100FC76D5 /* ScreenUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 161D7F9025B9037100FC76D5 /* ScreenUtil.swift */; }; 1623612322AB951E00E4025C /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1623612522AB951E00E4025C /* Localizable.strings */; }; 16248E32230673B6002131BB /* NotificationExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16248E31230673B6002131BB /* NotificationExt.swift */; }; + 1629470B25B672CF00CCB3C8 /* DiskPermissionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1629470A25B672CF00CCB3C8 /* DiskPermissionManager.swift */; }; 163632EF22B2749000805E7F /* NSTextFieldCell+VerticallyCentered.swift in Sources */ = {isa = PBXBuildFile; fileRef = 163632EE22B2749000805E7F /* NSTextFieldCell+VerticallyCentered.swift */; }; 163632F122B274B400805E7F /* Date+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 163632F022B274B400805E7F /* Date+Extension.swift */; }; 163632F322B2751D00805E7F /* BoolType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 163632F222B2751D00805E7F /* BoolType.swift */; }; @@ -48,6 +61,7 @@ 1657019F22C897A400C57EE9 /* WeiboConfigView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1657019E22C897A400C57EE9 /* WeiboConfigView.swift */; }; 165701A122C8A6E600C57EE9 /* Regex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 165701A022C8A6E600C57EE9 /* Regex.swift */; }; 165701A322C8AE0A00C57EE9 /* WeiboUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 165701A222C8AE0A00C57EE9 /* WeiboUtil.swift */; }; + 165C86D325B91F8000C538AD /* ScreenshotAuthorizationHelp.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 165C86D525B91F8000C538AD /* ScreenshotAuthorizationHelp.storyboard */; }; 165D908622C333740096FF38 /* PasteboardType+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 165D908522C333740096FF38 /* PasteboardType+Extension.swift */; }; 1660FCBA22C11C2300372950 /* TencentHostConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1660FCB922C11BA000372950 /* TencentHostConfig.swift */; }; 1660FCBB22C11C7200372950 /* TencentUploader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1660FCB722C11BA000372950 /* TencentUploader.swift */; }; @@ -99,6 +113,7 @@ 16AFDB3424E50DD30008E5A7 /* S3Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16AFDB3324E50DD30008E5A7 /* S3Util.swift */; }; 16AFDB3624E50F0A0008E5A7 /* S3ConfigView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16AFDB3524E50F0A0008E5A7 /* S3ConfigView.swift */; }; 16AFDB3824E50F450008E5A7 /* S3Region.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16AFDB3724E50F450008E5A7 /* S3Region.swift */; }; + 16B4314625BC8D2F00651BE0 /* ScreenshotAuthorizationHelpViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16B4314525BC8D2F00651BE0 /* ScreenshotAuthorizationHelpViewController.swift */; }; 16B4F0BC23ADCFAC00846BD3 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 164745EF22B65FE900F9575D /* String+Extension.swift */; }; 16B4F0BE23ADD09300846BD3 /* String+Crypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16B4F0BD23ADCFFF00846BD3 /* String+Crypto.swift */; }; 16BDDDFF22EA96AE0080E467 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 16BDDDFE22EA96AE0080E467 /* Assets.xcassets */; }; @@ -114,8 +129,8 @@ 16D20B58238390F2006D8D01 /* BaiduUploader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16D20B57238390F2006D8D01 /* BaiduUploader.swift */; }; 16D20B5A238390F4006D8D01 /* BaiduUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16D20B59238390F4006D8D01 /* BaiduUtil.swift */; }; 16D20B5C238392C9006D8D01 /* BaiduConfigView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16D20B5B238392C9006D8D01 /* BaiduConfigView.swift */; }; + 16E3B57925B5342000D4234F /* OutputFormatModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16E3B57825B5341F00D4234F /* OutputFormatModel.swift */; }; 16EA205C22AF8FB90006FB9C /* ConfigManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16EA205B22AF8FB90006FB9C /* ConfigManager.swift */; }; - 16ECAA742413AE6000F9236B /* info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 16ECAA732413AE6000F9236B /* info.plist */; }; 16ECAA962413B6C200F9236B /* FinderUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16ECAA952413B6C200F9236B /* FinderUtil.swift */; }; 16ECAA972413B77800F9236B /* FinderUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16ECAA952413B6C200F9236B /* FinderUtil.swift */; }; 16F04EE423BCC45F00CCA2FE /* Console.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16F04EDE23BCC45F00CCA2FE /* Console.swift */; }; @@ -123,7 +138,6 @@ 16F04EE623BCC45F00CCA2FE /* Option.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16F04EE123BCC45F00CCA2FE /* Option.swift */; }; 16F04EE723BCC45F00CCA2FE /* StringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16F04EE223BCC45F00CCA2FE /* StringExtensions.swift */; }; 16F04EE823BCC45F00CCA2FE /* Cli.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16F04EE323BCC45F00CCA2FE /* Cli.swift */; }; - 16F04EEA23BCC49000CCA2FE /* OutputType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16F04EE923BCC49000CCA2FE /* OutputType.swift */; }; 16F04EEC23BCC4B200CCA2FE /* FileManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16F04EEB23BCC4B200CCA2FE /* FileManagerExtension.swift */; }; 16F04EEE23BCC4C500CCA2FE /* URLSchemeExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16F04EED23BCC4C500CCA2FE /* URLSchemeExt.swift */; }; 16F7467422E994A300480A62 /* FinderSync.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16F7467322E994A300480A62 /* FinderSync.swift */; }; @@ -143,6 +157,10 @@ 4BEFD813238BB2F200BBE64D /* HistoryPreviewCustomScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BEFD812238BB2F200BBE64D /* HistoryPreviewCustomScrollView.swift */; }; 8E879700A97E9294450D524F /* Pods_uPic.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A116EF79D38D9092D34EFCF5 /* Pods_uPic.framework */; }; 965A5E5225ADBD8F00AB88FF /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1623612522AB951E00E4025C /* Localizable.strings */; }; + 965E817125B721650031A01F /* WelcomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 965E817025B721650031A01F /* WelcomeViewController.swift */; }; + 965E819B25B7274E0031A01F /* WelcomeWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 965E819A25B7274E0031A01F /* WelcomeWindowController.swift */; }; + 96767C02266C8AEB00867727 /* UPic.sdef in Resources */ = {isa = PBXBuildFile; fileRef = 96767C01266C8AEB00867727 /* UPic.sdef */; }; + 96767C09266CABC800867727 /* AppleScriptCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96767C08266CABC800867727 /* AppleScriptCommand.swift */; }; 968ECC07240DFCF900B2D78C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 968ECC09240DFCF900B2D78C /* InfoPlist.strings */; }; 96B6C3F125AD89F200B1A584 /* icon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 96B6C3F025AD89F200B1A584 /* icon.icns */; }; 96B6C3F325AD89F200B1A584 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96B6C3F225AD89F200B1A584 /* ShareViewController.swift */; }; @@ -150,6 +168,9 @@ 96B6C3FB25AD89F200B1A584 /* uPicShareExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 96B6C3EE25AD89F200B1A584 /* uPicShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 96B6C41125AD8AFB00B1A584 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 96B6C41325AD8AFB00B1A584 /* InfoPlist.strings */; }; 96B6C42025AD934B00B1A584 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 164745EF22B65FE900F9575D /* String+Extension.swift */; }; + 96B8520325B80D0300424535 /* Welcome.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 96B8520525B80D0300424535 /* Welcome.storyboard */; }; + 96CA5B8A25B41B1F00855629 /* OutputFormatCustomization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96CA5B8925B41B1F00855629 /* OutputFormatCustomization.swift */; }; + 96DBE27D25B7B7A7006F02FE /* WindowManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96DBE27C25B7B7A7006F02FE /* WindowManager.swift */; }; 96F633EE25AEBE5E005514EB /* DatabaseWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96F633ED25AEBE5E005514EB /* DatabaseWindowController.swift */; }; 96F633F625AEC3C7005514EB /* DatabaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96F633F525AEC3C6005514EB /* DatabaseViewController.swift */; }; 96F633FF25AF008F005514EB /* Database.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 96F6340125AF008F005514EB /* Database.storyboard */; }; @@ -197,6 +218,16 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 039BE355267887F400CE0549 /* CGImage+Drawing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGImage+Drawing.swift"; sourceTree = ""; }; + 039BE356267887F400CE0549 /* FileTypeUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileTypeUtil.swift; sourceTree = ""; }; + 039BE358267887F400CE0549 /* ImageIOEncoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageIOEncoder.swift; sourceTree = ""; }; + 039BE359267887F400CE0549 /* ImageIODecoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageIODecoder.swift; sourceTree = ""; }; + 039BE35A267887F400CE0549 /* WebPDecoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebPDecoder.swift; sourceTree = ""; }; + 039BE35B267887F400CE0549 /* CodecUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CodecUtil.swift; sourceTree = ""; }; + 039BE35C267887F400CE0549 /* CommonImageCodec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommonImageCodec.swift; sourceTree = ""; }; + 039BE35D267887F400CE0549 /* BaseCodec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseCodec.swift; sourceTree = ""; }; + 039BE35E267887F400CE0549 /* WebPEncoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebPEncoder.swift; sourceTree = ""; }; + 039BE360267887F400CE0549 /* CommonImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommonImage.swift; sourceTree = ""; }; 1602ED9622ADEFB200AA8638 /* BaseUploader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseUploader.swift; sourceTree = ""; }; 1602ED9822ADF43800AA8638 /* SmmsUploader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmmsUploader.swift; sourceTree = ""; }; 1605DDD8246D993C00262C89 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Main.strings"; sourceTree = ""; }; @@ -207,6 +238,7 @@ 16068C7722AECB34004D39B7 /* PreferencesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = ""; }; 16068C7B22AECD9F004D39B7 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; 160CAA2422B1ED6F00D04FBD /* PreferenceKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferenceKey.swift; sourceTree = ""; }; + 1613D88625C9826B009E348A /* AutoGenStrings.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = AutoGenStrings.py; sourceTree = ""; }; 161539102408E7F200CC662F /* LskyProUploader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LskyProUploader.swift; sourceTree = ""; }; 161539112408E7F200CC662F /* LskyProHostConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LskyProHostConfig.swift; sourceTree = ""; }; 161539142408F0E200CC662F /* LskyProConfigView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LskyProConfigView.swift; sourceTree = ""; }; @@ -216,10 +248,12 @@ 161C3BE022C4831B0092114F /* CustomUploader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomUploader.swift; sourceTree = ""; }; 161C3BE222C483560092114F /* CustomHostConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomHostConfig.swift; sourceTree = ""; }; 161C3BE422C4870B0092114F /* CustomConfigView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomConfigView.swift; sourceTree = ""; }; + 161D7F9025B9037100FC76D5 /* ScreenUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenUtil.swift; sourceTree = ""; }; 1623612422AB951E00E4025C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 1623612622AB951F00E4025C /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; 16248E31230673B6002131BB /* NotificationExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationExt.swift; sourceTree = ""; }; 1626E8C622AAB6B1006DCF0F /* Alamofire.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Alamofire.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 1629470A25B672CF00CCB3C8 /* DiskPermissionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiskPermissionManager.swift; sourceTree = ""; }; 163632EE22B2749000805E7F /* NSTextFieldCell+VerticallyCentered.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSTextFieldCell+VerticallyCentered.swift"; sourceTree = ""; }; 163632F022B274B400805E7F /* Date+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Extension.swift"; sourceTree = ""; }; 163632F222B2751D00805E7F /* BoolType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BoolType.swift; sourceTree = ""; }; @@ -242,6 +276,10 @@ 1657019E22C897A400C57EE9 /* WeiboConfigView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeiboConfigView.swift; sourceTree = ""; }; 165701A022C8A6E600C57EE9 /* Regex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Regex.swift; sourceTree = ""; }; 165701A222C8AE0A00C57EE9 /* WeiboUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeiboUtil.swift; sourceTree = ""; }; + 165C86D425B91F8000C538AD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/ScreenshotAuthorizationHelp.storyboard; sourceTree = ""; }; + 165C86E625B926B100C538AD /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/ScreenshotAuthorizationHelp.strings; sourceTree = ""; }; + 165C86E825B926B400C538AD /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/ScreenshotAuthorizationHelp.strings"; sourceTree = ""; }; + 165C86EA25B926B700C538AD /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/ScreenshotAuthorizationHelp.strings"; sourceTree = ""; }; 165D908522C333740096FF38 /* PasteboardType+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PasteboardType+Extension.swift"; sourceTree = ""; }; 1660FCB622C11BA000372950 /* TencentRegion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TencentRegion.swift; sourceTree = ""; }; 1660FCB722C11BA000372950 /* TencentUploader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TencentUploader.swift; sourceTree = ""; }; @@ -285,6 +323,9 @@ 169F073622AF4549008E8525 /* AboutPreferencesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AboutPreferencesViewController.swift; sourceTree = ""; }; 169F073C22AF53DE008E8525 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Preferences.storyboard; sourceTree = ""; }; 169F074322AF7A3D008E8525 /* StatusMenuController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusMenuController.swift; sourceTree = ""; }; + 16A0480325B18300000F1323 /* uPicDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = uPicDebug.entitlements; sourceTree = ""; }; + 16A0480425B18308000F1323 /* uPicFinderExtensionDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = uPicFinderExtensionDebug.entitlements; sourceTree = ""; }; + 16A0480525B18317000F1323 /* uPicShareExtensionDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = uPicShareExtensionDebug.entitlements; sourceTree = ""; }; 16A6DC5722AA375700813706 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 16A6DC6022AA375800813706 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 16A6DC6122AA375800813706 /* uPic.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = uPic.entitlements; sourceTree = ""; }; @@ -293,6 +334,7 @@ 16AFDB3324E50DD30008E5A7 /* S3Util.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = S3Util.swift; sourceTree = ""; }; 16AFDB3524E50F0A0008E5A7 /* S3ConfigView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = S3ConfigView.swift; sourceTree = ""; }; 16AFDB3724E50F450008E5A7 /* S3Region.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = S3Region.swift; sourceTree = ""; }; + 16B4314525BC8D2F00651BE0 /* ScreenshotAuthorizationHelpViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenshotAuthorizationHelpViewController.swift; sourceTree = ""; }; 16B4F0BD23ADCFFF00846BD3 /* String+Crypto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Crypto.swift"; sourceTree = ""; }; 16BDDDFE22EA96AE0080E467 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 16BDDE0222EAA2920080E467 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -307,6 +349,7 @@ 16D20B57238390F2006D8D01 /* BaiduUploader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaiduUploader.swift; sourceTree = ""; }; 16D20B59238390F4006D8D01 /* BaiduUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaiduUtil.swift; sourceTree = ""; }; 16D20B5B238392C9006D8D01 /* BaiduConfigView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaiduConfigView.swift; sourceTree = ""; }; + 16E3B57825B5341F00D4234F /* OutputFormatModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutputFormatModel.swift; sourceTree = ""; }; 16EA205B22AF8FB90006FB9C /* ConfigManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigManager.swift; sourceTree = ""; }; 16EC9A0222ABBBB4001B6C89 /* uPic.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = uPic.app; sourceTree = BUILT_PRODUCTS_DIR; }; 16ECAA732413AE6000F9236B /* info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = info.plist; sourceTree = ""; }; @@ -316,7 +359,6 @@ 16F04EE123BCC45F00CCA2FE /* Option.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Option.swift; sourceTree = ""; }; 16F04EE223BCC45F00CCA2FE /* StringExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringExtensions.swift; sourceTree = ""; }; 16F04EE323BCC45F00CCA2FE /* Cli.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cli.swift; sourceTree = ""; }; - 16F04EE923BCC49000CCA2FE /* OutputType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutputType.swift; sourceTree = ""; }; 16F04EEB23BCC4B200CCA2FE /* FileManagerExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileManagerExtension.swift; sourceTree = ""; }; 16F04EED23BCC4C500CCA2FE /* URLSchemeExt.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLSchemeExt.swift; sourceTree = ""; }; 16F7467122E994A300480A62 /* uPicFinderExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = uPicFinderExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -335,9 +377,14 @@ 4BC11BDD238CFD53001641A6 /* HistoryThumbnailTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryThumbnailTimer.swift; sourceTree = ""; }; 4BEFD810238B738E00BBE64D /* HistoryThumbnailConstant.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryThumbnailConstant.swift; sourceTree = ""; }; 4BEFD812238BB2F200BBE64D /* HistoryPreviewCustomScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryPreviewCustomScrollView.swift; sourceTree = ""; }; + 9637625F25B6E32B0097452B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Database.strings; sourceTree = ""; }; + 965E817025B721650031A01F /* WelcomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeViewController.swift; sourceTree = ""; }; + 965E819A25B7274E0031A01F /* WelcomeWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeWindowController.swift; sourceTree = ""; }; + 96767C01266C8AEB00867727 /* UPic.sdef */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = UPic.sdef; sourceTree = ""; }; + 96767C08266CABC800867727 /* AppleScriptCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleScriptCommand.swift; sourceTree = ""; }; 968ECC08240DFCF900B2D78C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 968ECC0A240DFCFA00B2D78C /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = ""; }; - 969018A3240D998400B545B2 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Preferences.strings; sourceTree = ""; }; + 96AA47FE25B88BE3006B4DAE /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Preferences.strings; sourceTree = ""; }; 96B6C3EE25AD89F200B1A584 /* uPicShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = uPicShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 96B6C3F025AD89F200B1A584 /* icon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = icon.icns; sourceTree = ""; }; 96B6C3F225AD89F200B1A584 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = ""; }; @@ -347,11 +394,16 @@ 96B6C41225AD8AFB00B1A584 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 96B6C41425AD8AFF00B1A584 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = ""; }; 96B6C41825AD8B0000B1A584 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/InfoPlist.strings"; sourceTree = ""; }; + 96B8520425B80D0300424535 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Welcome.storyboard; sourceTree = ""; }; + 96B8520A25B80D0700424535 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Welcome.strings; sourceTree = ""; }; + 96B8520C25B80D0700424535 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Welcome.strings"; sourceTree = ""; }; + 96B8520E25B80D0800424535 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Welcome.strings"; sourceTree = ""; }; + 96CA5B8925B41B1F00855629 /* OutputFormatCustomization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutputFormatCustomization.swift; sourceTree = ""; }; + 96DBE27C25B7B7A7006F02FE /* WindowManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowManager.swift; sourceTree = ""; }; 96F633ED25AEBE5E005514EB /* DatabaseWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseWindowController.swift; sourceTree = ""; }; 96F633F525AEC3C6005514EB /* DatabaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseViewController.swift; sourceTree = ""; }; 96F633FE25AF0066005514EB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Main.strings; sourceTree = ""; }; 96F6340025AF008F005514EB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Database.storyboard; sourceTree = ""; }; - 96F6340625AF0093005514EB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Database.strings; sourceTree = ""; }; 96F6340825AF0093005514EB /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Database.strings"; sourceTree = ""; }; 96F6340A25AF0094005514EB /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Database.strings"; sourceTree = ""; }; A116EF79D38D9092D34EFCF5 /* Pods_uPic.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_uPic.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -387,6 +439,47 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 039BE352267887F400CE0549 /* ImageCodec */ = { + isa = PBXGroup; + children = ( + 039BE354267887F400CE0549 /* Extension */, + 039BE357267887F400CE0549 /* Codec */, + 039BE35F267887F400CE0549 /* Model */, + ); + path = ImageCodec; + sourceTree = ""; + }; + 039BE354267887F400CE0549 /* Extension */ = { + isa = PBXGroup; + children = ( + 039BE355267887F400CE0549 /* CGImage+Drawing.swift */, + 039BE356267887F400CE0549 /* FileTypeUtil.swift */, + ); + path = Extension; + sourceTree = ""; + }; + 039BE357267887F400CE0549 /* Codec */ = { + isa = PBXGroup; + children = ( + 039BE358267887F400CE0549 /* ImageIOEncoder.swift */, + 039BE359267887F400CE0549 /* ImageIODecoder.swift */, + 039BE35A267887F400CE0549 /* WebPDecoder.swift */, + 039BE35B267887F400CE0549 /* CodecUtil.swift */, + 039BE35C267887F400CE0549 /* CommonImageCodec.swift */, + 039BE35D267887F400CE0549 /* BaseCodec.swift */, + 039BE35E267887F400CE0549 /* WebPEncoder.swift */, + ); + path = Codec; + sourceTree = ""; + }; + 039BE35F267887F400CE0549 /* Model */ = { + isa = PBXGroup; + children = ( + 039BE360267887F400CE0549 /* CommonImage.swift */, + ); + path = Model; + sourceTree = ""; + }; 16068C7622AECB26004D39B7 /* PreferencesWindow */ = { isa = PBXGroup; children = ( @@ -398,10 +491,19 @@ 16068C7422AEC1D1004D39B7 /* PreferencesViewController.swift */, 16068C7722AECB34004D39B7 /* PreferencesWindowController.swift */, 164745EA22B618D700F9575D /* HostPreferencesViewController.swift */, + 96CA5B8925B41B1F00855629 /* OutputFormatCustomization.swift */, ); path = PreferencesWindow; sourceTree = ""; }; + 1613D88525C98256009E348A /* Script */ = { + isa = PBXGroup; + children = ( + 1613D88625C9826B009E348A /* AutoGenStrings.py */, + ); + path = Script; + sourceTree = ""; + }; 1615390E2408E7DE00CC662F /* LskyPro */ = { isa = PBXGroup; children = ( @@ -425,6 +527,7 @@ 163632ED22B2745A00805E7F /* Basic */ = { isa = PBXGroup; children = ( + 039BE352267887F400CE0549 /* ImageCodec */, 16CD34F823BC8966005B52F2 /* Swime */, 16B4F0BD23ADCFFF00846BD3 /* String+Crypto.swift */, 163632EE22B2749000805E7F /* NSTextFieldCell+VerticallyCentered.swift */, @@ -440,21 +543,13 @@ path = Basic; sourceTree = ""; }; - 163F241E22B12E6700F81D03 /* General */ = { - isa = PBXGroup; - children = ( - 16068C7B22AECD9F004D39B7 /* Constants.swift */, - 163F242022B12EB900F81D03 /* Utils */, - 163F241F22B12EAE00F81D03 /* Managers */, - ); - path = General; - sourceTree = ""; - }; 163F241F22B12EAE00F81D03 /* Managers */ = { isa = PBXGroup; children = ( + 1629470A25B672CF00CCB3C8 /* DiskPermissionManager.swift */, 16EA205B22AF8FB90006FB9C /* ConfigManager.swift */, 161ABBDC23B1F1EB00805C5B /* DBManager.swift */, + 96DBE27C25B7B7A7006F02FE /* WindowManager.swift */, ); path = Managers; sourceTree = ""; @@ -465,6 +560,8 @@ 1675516922ACAA5900D3EB6F /* AppPublic.swift */, 160CAA2422B1ED6F00D04FBD /* PreferenceKey.swift */, 1647474422B66E3400F9575D /* Util.swift */, + 16068C7B22AECD9F004D39B7 /* Constants.swift */, + 161D7F9025B9037100FC76D5 /* ScreenUtil.swift */, ); path = Utils; sourceTree = ""; @@ -545,12 +642,12 @@ 1672762122AFF63A007299C3 /* Models */ = { isa = PBXGroup; children = ( + 16E3B57825B5341F00D4234F /* OutputFormatModel.swift */, 1602ED9622ADEFB200AA8638 /* BaseUploader.swift */, 1675EC5222FB38240038DA33 /* BaseUploaderUtil.swift */, 1672762222AFF655007299C3 /* Host.swift */, 167D7F4822B4D2F500DD0A7A /* HostConfig.swift */, 167D7F4A22B4D31300DD0A7A /* HostType.swift */, - 16F04EE923BCC49000CCA2FE /* OutputType.swift */, 68BBB87F2C3AEBDF2C914131 /* Aliyun */, 16D20B522383887E006D8D01 /* Baidu */, 161C3BDF22C4830A0092114F /* Custom */, @@ -650,18 +747,22 @@ 16A6DC5622AA375700813706 /* uPic */ = { isa = PBXGroup; children = ( + 96767C3A266CBC2000867727 /* AppleScript */, + 1613D88525C98256009E348A /* Script */, 1648A214238E742600B99B9D /* Main.storyboard */, 16BDDE0222EAA2920080E467 /* Assets.xcassets */, 16A6DC5722AA375700813706 /* AppDelegate.swift */, + 169F074322AF7A3D008E8525 /* StatusMenuController.swift */, 1623612522AB951E00E4025C /* Localizable.strings */, 16F04EDD23BCC45F00CCA2FE /* Cli */, 163632ED22B2745A00805E7F /* Basic */, 1675516522AC165600D3EB6F /* Extensions */, - 163F241E22B12E6700F81D03 /* General */, + 163F242022B12EB900F81D03 /* Utils */, + 163F241F22B12EAE00F81D03 /* Managers */, 1672762122AFF63A007299C3 /* Models */, 164C39FE22B2AA5E003ADE39 /* Notifier */, - 16A6DC6822AA3AD900813706 /* Supporting Files */, 16ADBE5E22D1D74D00E6C605 /* Views */, + 16A6DC6822AA3AD900813706 /* Supporting Files */, ); path = uPic; sourceTree = ""; @@ -671,6 +772,7 @@ children = ( 16A6DC6022AA375800813706 /* Info.plist */, 16A6DC6122AA375800813706 /* uPic.entitlements */, + 16A0480325B18300000F1323 /* uPicDebug.entitlements */, ); path = "Supporting Files"; sourceTree = ""; @@ -678,7 +780,8 @@ 16ADBE5E22D1D74D00E6C605 /* Views */ = { isa = PBXGroup; children = ( - 169F074322AF7A3D008E8525 /* StatusMenuController.swift */, + 16CB0A6225B91B0800259677 /* ScreenshotAuthorizationHelpWindow */, + 965E817525B721690031A01F /* WelcomeView */, 16068C7622AECB26004D39B7 /* PreferencesWindow */, 4B66A851235F02A000DED242 /* HistoryRecord */, 96F633EC25AEBE10005514EB /* DatabaseWindow */, @@ -697,6 +800,15 @@ path = S3; sourceTree = ""; }; + 16CB0A6225B91B0800259677 /* ScreenshotAuthorizationHelpWindow */ = { + isa = PBXGroup; + children = ( + 165C86D525B91F8000C538AD /* ScreenshotAuthorizationHelp.storyboard */, + 16B4314525BC8D2F00651BE0 /* ScreenshotAuthorizationHelpViewController.swift */, + ); + path = ScreenshotAuthorizationHelpWindow; + sourceTree = ""; + }; 16CD34F823BC8966005B52F2 /* Swime */ = { isa = PBXGroup; children = ( @@ -740,6 +852,7 @@ 16F7467222E994A300480A62 /* uPicFinderExtension */ = { isa = PBXGroup; children = ( + 16A0480425B18308000F1323 /* uPicFinderExtensionDebug.entitlements */, 16F7467322E994A300480A62 /* FinderSync.swift */, 16F7467622E994A300480A62 /* uPicFinderExtension.entitlements */, 16BDDDFE22EA96AE0080E467 /* Assets.xcassets */, @@ -777,9 +890,29 @@ path = Aliyun; sourceTree = ""; }; + 965E817525B721690031A01F /* WelcomeView */ = { + isa = PBXGroup; + children = ( + 96B8520525B80D0300424535 /* Welcome.storyboard */, + 965E817025B721650031A01F /* WelcomeViewController.swift */, + 965E819A25B7274E0031A01F /* WelcomeWindowController.swift */, + ); + path = WelcomeView; + sourceTree = ""; + }; + 96767C3A266CBC2000867727 /* AppleScript */ = { + isa = PBXGroup; + children = ( + 96767C01266C8AEB00867727 /* UPic.sdef */, + 96767C08266CABC800867727 /* AppleScriptCommand.swift */, + ); + path = AppleScript; + sourceTree = ""; + }; 96B6C3EF25AD89F200B1A584 /* uPicShareExtension */ = { isa = PBXGroup; children = ( + 16A0480525B18317000F1323 /* uPicShareExtensionDebug.entitlements */, 96B6C3F025AD89F200B1A584 /* icon.icns */, 96B6C3F225AD89F200B1A584 /* ShareViewController.swift */, 96B6C3F425AD89F200B1A584 /* ShareViewController.xib */, @@ -832,6 +965,7 @@ 8B11FF3895E709812B771F7E /* [CP] Embed Pods Frameworks */, 16EA205922AF8C680006FB9C /* CopyFiles */, 16F7467D22E994A300480A62 /* Embed App Extensions */, + 1613D88B25C98273009E348A /* ShellScript */, ); buildRules = ( ); @@ -950,9 +1084,13 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 96B8520325B80D0300424535 /* Welcome.storyboard in Resources */, 1623612322AB951E00E4025C /* Localizable.strings in Resources */, 1648A216238E742600B99B9D /* Main.storyboard in Resources */, 96F633FF25AF008F005514EB /* Database.storyboard in Resources */, + 165C86D325B91F8000C538AD /* ScreenshotAuthorizationHelp.storyboard in Resources */, + 1613D88725C9826B009E348A /* AutoGenStrings.py in Resources */, + 96767C02266C8AEB00867727 /* UPic.sdef in Resources */, 169F073B22AF53DE008E8525 /* Preferences.storyboard in Resources */, 16BDDE0322EAA2920080E467 /* Assets.xcassets in Resources */, ); @@ -962,7 +1100,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 16ECAA742413AE6000F9236B /* info.plist in Resources */, 1618D1A622E99BB800831601 /* Preferences.storyboard in Resources */, 16BDDDFF22EA96AE0080E467 /* Assets.xcassets in Resources */, 1618D1A522E99BAA00831601 /* Localizable.strings in Resources */, @@ -984,6 +1121,23 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 1613D88B25C98273009E348A /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "#!/bin/bash\npython ${SRCROOT}/${TARGET_NAME}/Script/AutoGenStrings.py ${SRCROOT}/${TARGET_NAME}\n"; + }; 8B11FF3895E709812B771F7E /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -1030,6 +1184,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 039BE366267887F400CE0549 /* WebPDecoder.swift in Sources */, 16CD34F723BC88E2005B52F2 /* SmmsConfigView.swift in Sources */, 4BB6C412236295DC0046FDC0 /* HistoryThumbnailModel.swift in Sources */, 165701A322C8AE0A00C57EE9 /* WeiboUtil.swift in Sources */, @@ -1045,9 +1200,13 @@ 161ABBDD23B1F1EB00805C5B /* DBManager.swift in Sources */, 16995A3422B6008000B1F923 /* UpYunHostConfig.swift in Sources */, 1672762322AFF655007299C3 /* Host.swift in Sources */, + 039BE363267887F400CE0549 /* FileTypeUtil.swift in Sources */, 167DDBF122C7784900B03357 /* GithubConfigView.swift in Sources */, + 039BE367267887F400CE0549 /* CodecUtil.swift in Sources */, 16F04EE523BCC45F00CCA2FE /* CommandLine.swift in Sources */, + 039BE362267887F400CE0549 /* CGImage+Drawing.swift in Sources */, 1602ED9922ADF43800AA8638 /* SmmsUploader.swift in Sources */, + 039BE365267887F400CE0549 /* ImageIODecoder.swift in Sources */, 164745F022B65FE900F9575D /* String+Extension.swift in Sources */, 16AFDB3224E5094A0008E5A7 /* S3HostConfig.swift in Sources */, 4B2B3354236BC5AB00C9F2CA /* NSButtonExtension.swift in Sources */, @@ -1055,9 +1214,11 @@ 166B4A5722B9D118001288ED /* PreferencesNotifier.swift in Sources */, 16D20B5523838AB1006D8D01 /* BaiduRegion.swift in Sources */, 1646B80E22C7C082009271DF /* ConfigView.swift in Sources */, + 96767C09266CABC800867727 /* AppleScriptCommand.swift in Sources */, 16D20B5A238390F4006D8D01 /* BaiduUtil.swift in Sources */, 161539122408EC7B00CC662F /* LskyProUploader.swift in Sources */, 1690E7EB22BF2D9400FC81F8 /* QiniuUploader.swift in Sources */, + 965E819B25B7274E0031A01F /* WelcomeWindowController.swift in Sources */, 1657019B22C8934000C57EE9 /* WeiboqQuality.swift in Sources */, 165D908622C333740096FF38 /* PasteboardType+Extension.swift in Sources */, 16A6DC5822AA375700813706 /* AppDelegate.swift in Sources */, @@ -1068,16 +1229,18 @@ 163632F322B2751D00805E7F /* BoolType.swift in Sources */, 1646B80722C79346009271DF /* GiteeHostConfig.swift in Sources */, 4BC11BDC238CD8CD001641A6 /* HistoryThumbnailLabel.swift in Sources */, + 16E3B57925B5342000D4234F /* OutputFormatModel.swift in Sources */, 1618D1A822E99E2100831601 /* UploadNotifier.swift in Sources */, 4B09F11423695F8D000208BD /* HistoryThumbnailContentView.swift in Sources */, 163632EF22B2749000805E7F /* NSTextFieldCell+VerticallyCentered.swift in Sources */, 4B2B3356236C3B6400C9F2CA /* NSViewExtension.swift in Sources */, 164745EB22B618D700F9575D /* HostPreferencesViewController.swift in Sources */, + 161D7F9125B9037100FC76D5 /* ScreenUtil.swift in Sources */, + 039BE36B267887F400CE0549 /* CommonImage.swift in Sources */, 161C3BE322C483560092114F /* CustomHostConfig.swift in Sources */, 167D08AA22ED8A27000F3BC0 /* AliyunHostConfig.swift in Sources */, 1660FCBD22C11C7800372950 /* TencentRegion.swift in Sources */, 167D7F4922B4D2F500DD0A7A /* HostConfig.swift in Sources */, - 16F04EEA23BCC49000CCA2FE /* OutputType.swift in Sources */, 161539152408F0E200CC662F /* LskyProConfigView.swift in Sources */, 164C3A0222B2AB22003ADE39 /* ConfigNotifier.swift in Sources */, 164C3A0022B2AA6C003ADE39 /* Notifier.swift in Sources */, @@ -1086,11 +1249,15 @@ 1690E7ED22BF2E4F00FC81F8 /* QiniuUtil.swift in Sources */, 1647474322B66ACE00F9575D /* Data+Extension.swift in Sources */, 167D7F4B22B4D31300DD0A7A /* HostType.swift in Sources */, + 039BE368267887F400CE0549 /* CommonImageCodec.swift in Sources */, 167620EE23081B0C008F8363 /* ImgurUploader.swift in Sources */, + 16B4314625BC8D2F00651BE0 /* ScreenshotAuthorizationHelpViewController.swift in Sources */, 1690E7E422BF111500FC81F8 /* QiniuConfigView.swift in Sources */, 1690E7E922BF1A6D00FC81F8 /* QiniuRegion.swift in Sources */, + 965E817125B721650031A01F /* WelcomeViewController.swift in Sources */, 168A831122B606C000344E77 /* UpYunUploader.swift in Sources */, 165701A122C8A6E600C57EE9 /* Regex.swift in Sources */, + 039BE36A267887F400CE0549 /* WebPEncoder.swift in Sources */, 4B6C62FA23613AEF008E3735 /* NSImageExtension.swift in Sources */, 163632F122B274B400805E7F /* Date+Extension.swift in Sources */, 4B66A850235ED44600DED242 /* HistoryThumbnailView.swift in Sources */, @@ -1107,8 +1274,10 @@ 167620ED230819C0008F8363 /* ImgurHostConfig.swift in Sources */, 1657019F22C897A400C57EE9 /* WeiboConfigView.swift in Sources */, 161539132408EC7D00CC662F /* LskyProHostConfig.swift in Sources */, + 96CA5B8A25B41B1F00855629 /* OutputFormatCustomization.swift in Sources */, 16F04EE723BCC45F00CCA2FE /* StringExtensions.swift in Sources */, 16AFDB3624E50F0A0008E5A7 /* S3ConfigView.swift in Sources */, + 039BE369267887F400CE0549 /* BaseCodec.swift in Sources */, 4BC11BDE238CFD53001641A6 /* HistoryThumbnailTimer.swift in Sources */, 1662AC7122C0AC53003AC924 /* AliyunConfigView.swift in Sources */, 1675516A22ACAA5900D3EB6F /* AppPublic.swift in Sources */, @@ -1122,6 +1291,7 @@ 1646B80622C79337009271DF /* GiteeUploader.swift in Sources */, 16068C7522AEC1D1004D39B7 /* PreferencesViewController.swift in Sources */, 161C3BE122C483380092114F /* CustomUploader.swift in Sources */, + 039BE364267887F400CE0549 /* ImageIOEncoder.swift in Sources */, 169F073A22AF4549008E8525 /* AboutPreferencesViewController.swift in Sources */, 4BEFD811238B738E00BBE64D /* HistoryThumbnailConstant.swift in Sources */, 1690E7E722BF174300FC81F8 /* QiniuHostConfig.swift in Sources */, @@ -1136,12 +1306,14 @@ 167DDBEB22C76F5000B03357 /* GithubUploader.swift in Sources */, 169F073922AF4549008E8525 /* GeneralPreferencesViewController.swift in Sources */, 16068C7C22AECD9F004D39B7 /* Constants.swift in Sources */, + 96DBE27D25B7B7A7006F02FE /* WindowManager.swift in Sources */, 16ECAA962413B6C200F9236B /* FinderUtil.swift in Sources */, 161C3BE522C4870C0092114F /* CustomConfigView.swift in Sources */, 16AFDB3424E50DD30008E5A7 /* S3Util.swift in Sources */, 1660FCBC22C11C7500372950 /* TencentUtil.swift in Sources */, 1660FCBA22C11C2300372950 /* TencentHostConfig.swift in Sources */, 16248E32230673B6002131BB /* NotificationExt.swift in Sources */, + 1629470B25B672CF00CCB3C8 /* DiskPermissionManager.swift in Sources */, 16F04EE423BCC45F00CCA2FE /* Console.swift in Sources */, 167DDBEF22C7722200B03357 /* GithubUtil.swift in Sources */, 16F04EEE23BCC4C500CCA2FE /* URLSchemeExt.swift in Sources */, @@ -1211,13 +1383,24 @@ name = Main.storyboard; sourceTree = ""; }; + 165C86D525B91F8000C538AD /* ScreenshotAuthorizationHelp.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 165C86D425B91F8000C538AD /* Base */, + 165C86E625B926B100C538AD /* en */, + 165C86E825B926B400C538AD /* zh-Hans */, + 165C86EA25B926B700C538AD /* zh-Hant */, + ); + name = ScreenshotAuthorizationHelp.storyboard; + sourceTree = ""; + }; 169F073D22AF53DE008E8525 /* Preferences.storyboard */ = { isa = PBXVariantGroup; children = ( 169F073C22AF53DE008E8525 /* Base */, 161ABBE323B212C800805C5B /* zh-Hans */, - 969018A3240D998400B545B2 /* en */, 1605DDD9246D993C00262C89 /* zh-Hant */, + 96AA47FE25B88BE3006B4DAE /* en */, ); name = Preferences.storyboard; sourceTree = ""; @@ -1250,13 +1433,24 @@ name = InfoPlist.strings; sourceTree = ""; }; + 96B8520525B80D0300424535 /* Welcome.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 96B8520425B80D0300424535 /* Base */, + 96B8520A25B80D0700424535 /* en */, + 96B8520C25B80D0700424535 /* zh-Hans */, + 96B8520E25B80D0800424535 /* zh-Hant */, + ); + name = Welcome.storyboard; + sourceTree = ""; + }; 96F6340125AF008F005514EB /* Database.storyboard */ = { isa = PBXVariantGroup; children = ( 96F6340025AF008F005514EB /* Base */, - 96F6340625AF0093005514EB /* en */, 96F6340825AF0093005514EB /* zh-Hans */, 96F6340A25AF0094005514EB /* zh-Hant */, + 9637625F25B6E32B0097452B /* en */, ); name = Database.storyboard; sourceTree = ""; @@ -1388,13 +1582,14 @@ baseConfigurationReference = B31C410193F6C634ECBC8F5F /* Pods-uPic.debug.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + APPLICATION_EXTENSION_API_ONLY = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = "uPic/Supporting Files/uPic.entitlements"; - CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_ENTITLEMENTS = "uPic/Supporting Files/uPicDebug.entitlements"; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 20201211; + CURRENT_PROJECT_VERSION = 11; DEVELOPMENT_TEAM = W863J6W8DZ; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = "$(SRCROOT)/uPic/Supporting Files/Info.plist"; @@ -1403,8 +1598,8 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.12; - MARKETING_VERSION = 0.21.1; - PRODUCT_BUNDLE_IDENTIFIER = com.svend.uPic; + MARKETING_VERSION = 1.2.0; + PRODUCT_BUNDLE_IDENTIFIER = com.svend.uPic.macos; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = ""; @@ -1418,13 +1613,14 @@ baseConfigurationReference = FA1B39CC17103449CC5099AD /* Pods-uPic.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + APPLICATION_EXTENSION_API_ONLY = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = "uPic/Supporting Files/uPic.entitlements"; - CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 20201211; + CURRENT_PROJECT_VERSION = 11; DEVELOPMENT_TEAM = W863J6W8DZ; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = "$(SRCROOT)/uPic/Supporting Files/Info.plist"; @@ -1433,8 +1629,8 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.12; - MARKETING_VERSION = 0.21.1; - PRODUCT_BUNDLE_IDENTIFIER = com.svend.uPic; + MARKETING_VERSION = 1.2.0; + PRODUCT_BUNDLE_IDENTIFIER = com.svend.uPic.macos; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OBJC_BRIDGING_HEADER = ""; @@ -1445,12 +1641,12 @@ 16F7467B22E994A300480A62 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - APPLICATION_EXTENSION_API_ONLY = NO; - CODE_SIGN_ENTITLEMENTS = uPicFinderExtension/uPicFinderExtension.entitlements; - CODE_SIGN_IDENTITY = "Apple Development"; + APPLICATION_EXTENSION_API_ONLY = YES; + CODE_SIGN_ENTITLEMENTS = uPicFinderExtension/uPicFinderExtensionDebug.entitlements; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 20201211; + CURRENT_PROJECT_VERSION = 11; DEVELOPMENT_TEAM = W863J6W8DZ; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = uPicFinderExtension/Info.plist; @@ -1460,8 +1656,8 @@ "@executable_path/../../../../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.12; - MARKETING_VERSION = 0.21.1; - PRODUCT_BUNDLE_IDENTIFIER = com.svend.uPic.uPicFinderExtension; + MARKETING_VERSION = 1.2.0; + PRODUCT_BUNDLE_IDENTIFIER = com.svend.uPic.macos.uPicFinderExtension; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SKIP_INSTALL = YES; @@ -1472,12 +1668,12 @@ 16F7467C22E994A300480A62 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - APPLICATION_EXTENSION_API_ONLY = NO; + APPLICATION_EXTENSION_API_ONLY = YES; CODE_SIGN_ENTITLEMENTS = uPicFinderExtension/uPicFinderExtension.entitlements; - CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 20201211; + CURRENT_PROJECT_VERSION = 11; DEVELOPMENT_TEAM = W863J6W8DZ; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = uPicFinderExtension/Info.plist; @@ -1487,8 +1683,8 @@ "@executable_path/../../../../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.12; - MARKETING_VERSION = 0.21.1; - PRODUCT_BUNDLE_IDENTIFIER = com.svend.uPic.uPicFinderExtension; + MARKETING_VERSION = 1.2.0; + PRODUCT_BUNDLE_IDENTIFIER = com.svend.uPic.macos.uPicFinderExtension; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SKIP_INSTALL = YES; @@ -1499,11 +1695,11 @@ 96B6C3FD25AD89F200B1A584 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_ENTITLEMENTS = uPicShareExtension/uPicShareExtension.entitlements; - CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_ENTITLEMENTS = uPicShareExtension/uPicShareExtensionDebug.entitlements; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 20201211; + CURRENT_PROJECT_VERSION = 11; DEVELOPMENT_TEAM = W863J6W8DZ; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = uPicShareExtension/Info.plist; @@ -1513,9 +1709,10 @@ "@executable_path/../../../../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.12; - MARKETING_VERSION = 0.21.1; - PRODUCT_BUNDLE_IDENTIFIER = com.svend.uPic.uPicShareExtension; + MARKETING_VERSION = 1.2.0; + PRODUCT_BUNDLE_IDENTIFIER = com.svend.uPic.macos.uPicShareExtension; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; }; @@ -1525,10 +1722,10 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_ENTITLEMENTS = uPicShareExtension/uPicShareExtension.entitlements; - CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 20201211; + CURRENT_PROJECT_VERSION = 11; DEVELOPMENT_TEAM = W863J6W8DZ; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = uPicShareExtension/Info.plist; @@ -1538,8 +1735,8 @@ "@executable_path/../../../../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.12; - MARKETING_VERSION = 0.21.1; - PRODUCT_BUNDLE_IDENTIFIER = com.svend.uPic.uPicShareExtension; + MARKETING_VERSION = 1.2.0; + PRODUCT_BUNDLE_IDENTIFIER = com.svend.uPic.macos.uPicShareExtension; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; diff --git a/uPic.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/uPic.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 0d991ea9..919434a6 100644 --- a/uPic.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/uPic.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/uPic.xcodeproj/xcshareddata/xcschemes/uPic.xcscheme b/uPic.xcodeproj/xcshareddata/xcschemes/uPic.xcscheme index b0ee0b81..9cc6cbde 100644 --- a/uPic.xcodeproj/xcshareddata/xcschemes/uPic.xcscheme +++ b/uPic.xcodeproj/xcshareddata/xcschemes/uPic.xcscheme @@ -1,6 +1,6 @@ NSDragOperation { + self.draggingData = sender.draggedFromBrowserData + + if sender.draggedFileUrls.count > 0 || draggingData != nil || sender.draggedFromBrowserUrl != nil { + if let statusItem = statusItem, let button = statusItem.button { + button.image = NSImage(named: "uploadIcon") + } + return .copy + } + return .generic + } + + func performDragOperation(_ sender: NSDraggingInfo) -> Bool { + if sender.draggedFileUrls.count > 0 || self.draggingData != nil || sender.draggedFromBrowserUrl != nil { + self.setStatusBarIcon(isIndicator: false) + if sender.draggedFileUrls.count > 0 { + self.uploadFiles(sender.draggedFileUrls) + return true + } else if let imageData = self.draggingData { + self.uploadFiles([imageData]) + self.draggingData = nil + return true + } else if let url = sender.draggedFromBrowserUrl { + self.uploadFiles([url]) + return true + } + } + return false + } - /// Upload multiple file paths separated by \n + func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool { + return true + } + + func draggingExited(_ sender: NSDraggingInfo?) { + self.setStatusBarIcon(isIndicator: false) + } + + func draggingEnded(_ sender: NSDraggingInfo) { + } + +} + +// 上传方法 +extension AppDelegate { + // 解析以 \n 分割的多个文件路径并上传 func uploadFilesFromPaths(_ pathStr: String) { let paths = pathStr.split(separator: Character("\n")) @@ -312,8 +380,9 @@ extension AppDelegate { for path in paths { let sPath = String(path) - if (fileExtensions.count == 0 || fileExtensions.contains(sPath.pathExtension.lowercased())) { - let url = URL(fileURLWithPath: sPath) + let url = URL(fileURLWithPath: sPath) + + if (fileExtensions.count == 0 || fileExtensions.contains(url.pathExtension.lowercased())) { urls.append(url) } } @@ -326,8 +395,7 @@ extension AppDelegate { self.uploadFiles(urls) } - // 上传多个文件 - // MARK: - Cli Support + // 上传多个文件,所有上传方式的入口 func uploadFiles(_ files: [Any], _ uploadSourceType: UploadSourceType? = .normal) { var uploadFiles = files @@ -337,6 +405,7 @@ extension AppDelegate { var uploadUrls: [URL] = [] for url in urls { let path = url.path + if FileManager.directoryIsExists(path: path) { let directoryName = path.lastPathComponent let enumerator = FileManager.default.enumerator(atPath: path) @@ -367,9 +436,18 @@ extension AppDelegate { self.resultUrls.removeAll() if self.needUploadFiles.count == 0 { + // MARK: - Cli Support + if self.uploadSourceType == UploadSourceType.cli { + DispatchQueue.main.async { + exit(EX_OK) + } + } return } + // 开始磁盘授权访问 + _ = DiskPermissionManager.shared.startDirectoryAccessing() + self.uploding = true self.tickFileToUpload() } @@ -384,6 +462,11 @@ extension AppDelegate { let firstFile = self.needUploadFiles.first self.needUploadFiles.removeFirst() if firstFile is URL { + if !FileManager.default.isReadableFile(atPath: (firstFile as! URL).path) { + NotificationExt.shared.postFileNoAccessNotice() + tickFileToUpload() + return + } BaseUploader.upload(url: firstFile as! URL) } else if firstFile is Data { BaseUploader.upload(data: firstFile as! Data) @@ -440,6 +523,7 @@ extension AppDelegate { } func uploadCancel() { + self.setStatusBarIcon(isIndicator: false) BaseUploader.cancelUpload() self.needUploadFiles.removeAll() self.resultUrls.removeAll() @@ -447,6 +531,9 @@ extension AppDelegate { } func uploadDone() { + // 停止磁盘授权访问 + DiskPermissionManager.shared.stopDirectoryAccessing() + self.uploding = false // MARK: - Cli Support if uploadSourceType == UploadSourceType.cli { @@ -472,69 +559,6 @@ extension AppDelegate { } } -// MARK: - Drag and drop file upload -extension AppDelegate: NSWindowDelegate, NSDraggingDestination { - func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation { - self.draggingData = sender.draggedFromBrowserData - - if sender.draggedFileUrls.count > 0 || draggingData != nil || sender.draggedFromBrowserUrl != nil { - if let statusItem = statusItem, let button = statusItem.button { - button.image = NSImage(named: "uploadIcon") - } - return .copy - } - return .generic - } - - func performDragOperation(_ sender: NSDraggingInfo) -> Bool { - if sender.draggedFileUrls.count > 0 || self.draggingData != nil || sender.draggedFromBrowserUrl != nil { - self.setStatusBarIcon(isIndicator: false) - if sender.draggedFileUrls.count > 0 { - self.uploadFiles(sender.draggedFileUrls) - return true - } else if let imageData = self.draggingData { - self.uploadFiles([imageData]) - self.draggingData = nil - return true - } else if let url = sender.draggedFromBrowserUrl { - self.uploadFiles([url]) - return true - } - } - return false - } - - func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool { - return true - } - - func draggingExited(_ sender: NSDraggingInfo?) { - self.setStatusBarIcon(isIndicator: false) - } - - func draggingEnded(_ sender: NSDraggingInfo) { - } - -} - -extension AppDelegate { - // sponsor - - func sponsorByPaypal() { - guard let url = URL(string: "https://paypal.me/geeee1k") else { return } - NSWorkspace.shared.open(url) - } - - func sponsorByAlipay() { - guard let url = URL(string: "https://raw.githubusercontent.com/gee1k/oss/master/qrcode/alipay.JPG") else { return } - NSWorkspace.shared.open(url) - } - - func sponsorByWechatPay() { - guard let url = URL(string: "https://raw.githubusercontent.com/gee1k/oss/master/qrcode/wechat_pay.JPG") else { return } - NSWorkspace.shared.open(url) - } -} // MARK: - Global shortcut extension AppDelegate { diff --git a/uPic/AppleScript/AppleScriptCommand.swift b/uPic/AppleScript/AppleScriptCommand.swift new file mode 100644 index 00000000..fca5e0bd --- /dev/null +++ b/uPic/AppleScript/AppleScriptCommand.swift @@ -0,0 +1,25 @@ +// +// AppleScriptCommand.swift +// uPic +// +// Created by Licardo on 2021/6/6. +// Copyright © 2021 Svend Jin. All rights reserved. +// + +import Cocoa + +@objc(AppleScriptCommand) class AppleScriptCommand: NSScriptCommand { + override func performDefaultImplementation() -> Any? { + + if let fileURL = directParameter as? NSString { + let encodeUrl = "uPic://files?\(fileURL)".urlEncoded() + + if let url = URL(string: encodeUrl) { + NSWorkspace.shared.open(url) + } + } + + return nil + } +} + diff --git a/uPic/AppleScript/UPic.sdef b/uPic/AppleScript/UPic.sdef new file mode 100644 index 00000000..9ad402c2 --- /dev/null +++ b/uPic/AppleScript/UPic.sdef @@ -0,0 +1,273 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/uPic/Assets.xcassets/about.imageset/about.png b/uPic/Assets.xcassets/about.imageset/about.png deleted file mode 100644 index dbf58673..00000000 Binary files a/uPic/Assets.xcassets/about.imageset/about.png and /dev/null differ diff --git a/uPic/Assets.xcassets/about.imageset/about@2x.png b/uPic/Assets.xcassets/about.imageset/about@2x.png deleted file mode 100644 index 59d16142..00000000 Binary files a/uPic/Assets.xcassets/about.imageset/about@2x.png and /dev/null differ diff --git a/uPic/Assets.xcassets/about.imageset/about@3x.png b/uPic/Assets.xcassets/about.imageset/about@3x.png deleted file mode 100644 index 3e9c2801..00000000 Binary files a/uPic/Assets.xcassets/about.imageset/about@3x.png and /dev/null differ diff --git a/uPic/Assets.xcassets/finderRestart.imageset/Contents.json b/uPic/Assets.xcassets/finderRestart.imageset/Contents.json new file mode 100644 index 00000000..5e357b82 --- /dev/null +++ b/uPic/Assets.xcassets/finderRestart.imageset/Contents.json @@ -0,0 +1,56 @@ +{ + "images" : [ + { + "filename" : "finderRestart-light.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "finderRestart-dark.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "finderRestart-light@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "finderRestart-dark@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "finderRestart-light@3x.png", + "idiom" : "universal", + "scale" : "3x" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "finderRestart-dark@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/uPic/Assets.xcassets/finderRestart.imageset/finderRestart-dark.png b/uPic/Assets.xcassets/finderRestart.imageset/finderRestart-dark.png new file mode 100644 index 00000000..36a6d60b Binary files /dev/null and b/uPic/Assets.xcassets/finderRestart.imageset/finderRestart-dark.png differ diff --git a/uPic/Assets.xcassets/finderRestart.imageset/finderRestart-dark@2x.png b/uPic/Assets.xcassets/finderRestart.imageset/finderRestart-dark@2x.png new file mode 100644 index 00000000..96196d8c Binary files /dev/null and b/uPic/Assets.xcassets/finderRestart.imageset/finderRestart-dark@2x.png differ diff --git a/uPic/Assets.xcassets/finderRestart.imageset/finderRestart-dark@3x.png b/uPic/Assets.xcassets/finderRestart.imageset/finderRestart-dark@3x.png new file mode 100644 index 00000000..bab88472 Binary files /dev/null and b/uPic/Assets.xcassets/finderRestart.imageset/finderRestart-dark@3x.png differ diff --git a/uPic/Assets.xcassets/finderRestart.imageset/finderRestart-light.png b/uPic/Assets.xcassets/finderRestart.imageset/finderRestart-light.png new file mode 100644 index 00000000..1ffd7450 Binary files /dev/null and b/uPic/Assets.xcassets/finderRestart.imageset/finderRestart-light.png differ diff --git a/uPic/Assets.xcassets/finderRestart.imageset/finderRestart-light@2x.png b/uPic/Assets.xcassets/finderRestart.imageset/finderRestart-light@2x.png new file mode 100644 index 00000000..8d09a1a4 Binary files /dev/null and b/uPic/Assets.xcassets/finderRestart.imageset/finderRestart-light@2x.png differ diff --git a/uPic/Assets.xcassets/finderRestart.imageset/finderRestart-light@3x.png b/uPic/Assets.xcassets/finderRestart.imageset/finderRestart-light@3x.png new file mode 100644 index 00000000..832d7dfb Binary files /dev/null and b/uPic/Assets.xcassets/finderRestart.imageset/finderRestart-light@3x.png differ diff --git a/uPic/Assets.xcassets/screenshotAuthorizationHelp/Contents.json b/uPic/Assets.xcassets/screenshotAuthorizationHelp/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/uPic/Assets.xcassets/screenshotAuthorizationHelp/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/uPic/Assets.xcassets/screenshotAuthorizationHelp/screenshotHelp1.imageset/1.png b/uPic/Assets.xcassets/screenshotAuthorizationHelp/screenshotHelp1.imageset/1.png new file mode 100644 index 00000000..7c3b1fca Binary files /dev/null and b/uPic/Assets.xcassets/screenshotAuthorizationHelp/screenshotHelp1.imageset/1.png differ diff --git a/uPic/Assets.xcassets/screenshotAuthorizationHelp/screenshotHelp1.imageset/Contents.json b/uPic/Assets.xcassets/screenshotAuthorizationHelp/screenshotHelp1.imageset/Contents.json new file mode 100644 index 00000000..736228e5 --- /dev/null +++ b/uPic/Assets.xcassets/screenshotAuthorizationHelp/screenshotHelp1.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "1.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/uPic/Assets.xcassets/screenshotAuthorizationHelp/screenshotHelp2.imageset/2.png b/uPic/Assets.xcassets/screenshotAuthorizationHelp/screenshotHelp2.imageset/2.png new file mode 100644 index 00000000..5922d383 Binary files /dev/null and b/uPic/Assets.xcassets/screenshotAuthorizationHelp/screenshotHelp2.imageset/2.png differ diff --git a/uPic/Assets.xcassets/screenshotAuthorizationHelp/screenshotHelp2.imageset/Contents.json b/uPic/Assets.xcassets/screenshotAuthorizationHelp/screenshotHelp2.imageset/Contents.json new file mode 100644 index 00000000..939e04af --- /dev/null +++ b/uPic/Assets.xcassets/screenshotAuthorizationHelp/screenshotHelp2.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "2.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "original" + } +} diff --git a/uPic/Assets.xcassets/uPicForiOS.imageset/uPicForiOS.png b/uPic/Assets.xcassets/uPicForiOS.imageset/uPicForiOS.png deleted file mode 100644 index 9497d13d..00000000 Binary files a/uPic/Assets.xcassets/uPicForiOS.imageset/uPicForiOS.png and /dev/null differ diff --git a/uPic/Assets.xcassets/uPicForiOS.imageset/uPicForiOS@2x.png b/uPic/Assets.xcassets/uPicForiOS.imageset/uPicForiOS@2x.png deleted file mode 100644 index 36f1425a..00000000 Binary files a/uPic/Assets.xcassets/uPicForiOS.imageset/uPicForiOS@2x.png and /dev/null differ diff --git a/uPic/Assets.xcassets/uPicForiOS.imageset/uPicForiOS@3x.png b/uPic/Assets.xcassets/uPicForiOS.imageset/uPicForiOS@3x.png deleted file mode 100644 index 5d5057ef..00000000 Binary files a/uPic/Assets.xcassets/uPicForiOS.imageset/uPicForiOS@3x.png and /dev/null differ diff --git a/uPic/Assets.xcassets/welcome/Contents.json b/uPic/Assets.xcassets/welcome/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/uPic/Assets.xcassets/welcome/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/uPic/Assets.xcassets/uPicForiOS.imageset/Contents.json b/uPic/Assets.xcassets/welcome/dragToUpload.imageset/Contents.json similarity index 68% rename from uPic/Assets.xcassets/uPicForiOS.imageset/Contents.json rename to uPic/Assets.xcassets/welcome/dragToUpload.imageset/Contents.json index facf14d4..ba5e9c17 100644 --- a/uPic/Assets.xcassets/uPicForiOS.imageset/Contents.json +++ b/uPic/Assets.xcassets/welcome/dragToUpload.imageset/Contents.json @@ -1,17 +1,17 @@ { "images" : [ { - "filename" : "uPicForiOS.png", + "filename" : "dragToUpload.png", "idiom" : "universal", "scale" : "1x" }, { - "filename" : "uPicForiOS@2x.png", + "filename" : "dragToUpload@2x.png", "idiom" : "universal", "scale" : "2x" }, { - "filename" : "uPicForiOS@3x.png", + "filename" : "dragToUpload@3x.png", "idiom" : "universal", "scale" : "3x" } diff --git a/uPic/Assets.xcassets/welcome/dragToUpload.imageset/dragToUpload.png b/uPic/Assets.xcassets/welcome/dragToUpload.imageset/dragToUpload.png new file mode 100644 index 00000000..1a32d555 Binary files /dev/null and b/uPic/Assets.xcassets/welcome/dragToUpload.imageset/dragToUpload.png differ diff --git a/uPic/Assets.xcassets/welcome/dragToUpload.imageset/dragToUpload@2x.png b/uPic/Assets.xcassets/welcome/dragToUpload.imageset/dragToUpload@2x.png new file mode 100644 index 00000000..1a849643 Binary files /dev/null and b/uPic/Assets.xcassets/welcome/dragToUpload.imageset/dragToUpload@2x.png differ diff --git a/uPic/Assets.xcassets/welcome/dragToUpload.imageset/dragToUpload@3x.png b/uPic/Assets.xcassets/welcome/dragToUpload.imageset/dragToUpload@3x.png new file mode 100644 index 00000000..d2dcfa21 Binary files /dev/null and b/uPic/Assets.xcassets/welcome/dragToUpload.imageset/dragToUpload@3x.png differ diff --git a/uPic/Assets.xcassets/welcome/finderExtensionUpload.imageset/Contents.json b/uPic/Assets.xcassets/welcome/finderExtensionUpload.imageset/Contents.json new file mode 100644 index 00000000..85615372 --- /dev/null +++ b/uPic/Assets.xcassets/welcome/finderExtensionUpload.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "finderExtensionUpload.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "finderExtensionUpload@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "finderExtensionUpload@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/uPic/Assets.xcassets/welcome/finderExtensionUpload.imageset/finderExtensionUpload.png b/uPic/Assets.xcassets/welcome/finderExtensionUpload.imageset/finderExtensionUpload.png new file mode 100644 index 00000000..a8464fd8 Binary files /dev/null and b/uPic/Assets.xcassets/welcome/finderExtensionUpload.imageset/finderExtensionUpload.png differ diff --git a/uPic/Assets.xcassets/welcome/finderExtensionUpload.imageset/finderExtensionUpload@2x.png b/uPic/Assets.xcassets/welcome/finderExtensionUpload.imageset/finderExtensionUpload@2x.png new file mode 100644 index 00000000..089567e5 Binary files /dev/null and b/uPic/Assets.xcassets/welcome/finderExtensionUpload.imageset/finderExtensionUpload@2x.png differ diff --git a/uPic/Assets.xcassets/welcome/finderExtensionUpload.imageset/finderExtensionUpload@3x.png b/uPic/Assets.xcassets/welcome/finderExtensionUpload.imageset/finderExtensionUpload@3x.png new file mode 100644 index 00000000..9e4eacbf Binary files /dev/null and b/uPic/Assets.xcassets/welcome/finderExtensionUpload.imageset/finderExtensionUpload@3x.png differ diff --git a/uPic/Assets.xcassets/about.imageset/Contents.json b/uPic/Assets.xcassets/welcome/grantPermission.imageset/Contents.json similarity index 56% rename from uPic/Assets.xcassets/about.imageset/Contents.json rename to uPic/Assets.xcassets/welcome/grantPermission.imageset/Contents.json index 24f07f57..2fe12d51 100644 --- a/uPic/Assets.xcassets/about.imageset/Contents.json +++ b/uPic/Assets.xcassets/welcome/grantPermission.imageset/Contents.json @@ -1,23 +1,23 @@ { "images" : [ { + "filename" : "grantPermission.png", "idiom" : "universal", - "filename" : "about.png", "scale" : "1x" }, { + "filename" : "grantPermission@2x.png", "idiom" : "universal", - "filename" : "about@2x.png", "scale" : "2x" }, { + "filename" : "grantPermission@3x.png", "idiom" : "universal", - "filename" : "about@3x.png", "scale" : "3x" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/uPic/Assets.xcassets/welcome/grantPermission.imageset/grantPermission.png b/uPic/Assets.xcassets/welcome/grantPermission.imageset/grantPermission.png new file mode 100644 index 00000000..83707c5b Binary files /dev/null and b/uPic/Assets.xcassets/welcome/grantPermission.imageset/grantPermission.png differ diff --git a/uPic/Assets.xcassets/welcome/grantPermission.imageset/grantPermission@2x.png b/uPic/Assets.xcassets/welcome/grantPermission.imageset/grantPermission@2x.png new file mode 100644 index 00000000..dfba160a Binary files /dev/null and b/uPic/Assets.xcassets/welcome/grantPermission.imageset/grantPermission@2x.png differ diff --git a/uPic/Assets.xcassets/welcome/grantPermission.imageset/grantPermission@3x.png b/uPic/Assets.xcassets/welcome/grantPermission.imageset/grantPermission@3x.png new file mode 100644 index 00000000..4092bafd Binary files /dev/null and b/uPic/Assets.xcassets/welcome/grantPermission.imageset/grantPermission@3x.png differ diff --git a/uPic/Assets.xcassets/welcome/leftButton.imageset/Contents.json b/uPic/Assets.xcassets/welcome/leftButton.imageset/Contents.json new file mode 100644 index 00000000..dd7f41ee --- /dev/null +++ b/uPic/Assets.xcassets/welcome/leftButton.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "leftButton.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "leftButton@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "leftButton@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/uPic/Assets.xcassets/welcome/leftButton.imageset/leftButton.png b/uPic/Assets.xcassets/welcome/leftButton.imageset/leftButton.png new file mode 100644 index 00000000..aee784b7 Binary files /dev/null and b/uPic/Assets.xcassets/welcome/leftButton.imageset/leftButton.png differ diff --git a/uPic/Assets.xcassets/welcome/leftButton.imageset/leftButton@2x.png b/uPic/Assets.xcassets/welcome/leftButton.imageset/leftButton@2x.png new file mode 100644 index 00000000..83f9d335 Binary files /dev/null and b/uPic/Assets.xcassets/welcome/leftButton.imageset/leftButton@2x.png differ diff --git a/uPic/Assets.xcassets/welcome/leftButton.imageset/leftButton@3x.png b/uPic/Assets.xcassets/welcome/leftButton.imageset/leftButton@3x.png new file mode 100644 index 00000000..4b1844dc Binary files /dev/null and b/uPic/Assets.xcassets/welcome/leftButton.imageset/leftButton@3x.png differ diff --git a/uPic/Assets.xcassets/welcome/multipleServices.imageset/Contents.json b/uPic/Assets.xcassets/welcome/multipleServices.imageset/Contents.json new file mode 100644 index 00000000..e16a1b63 --- /dev/null +++ b/uPic/Assets.xcassets/welcome/multipleServices.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "multipleServices.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "multipleServices@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "multipleServices@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/uPic/Assets.xcassets/welcome/multipleServices.imageset/multipleServices.png b/uPic/Assets.xcassets/welcome/multipleServices.imageset/multipleServices.png new file mode 100644 index 00000000..764852f0 Binary files /dev/null and b/uPic/Assets.xcassets/welcome/multipleServices.imageset/multipleServices.png differ diff --git a/uPic/Assets.xcassets/welcome/multipleServices.imageset/multipleServices@2x.png b/uPic/Assets.xcassets/welcome/multipleServices.imageset/multipleServices@2x.png new file mode 100644 index 00000000..e01f28c6 Binary files /dev/null and b/uPic/Assets.xcassets/welcome/multipleServices.imageset/multipleServices@2x.png differ diff --git a/uPic/Assets.xcassets/welcome/multipleServices.imageset/multipleServices@3x.png b/uPic/Assets.xcassets/welcome/multipleServices.imageset/multipleServices@3x.png new file mode 100644 index 00000000..f5458d3b Binary files /dev/null and b/uPic/Assets.xcassets/welcome/multipleServices.imageset/multipleServices@3x.png differ diff --git a/uPic/Assets.xcassets/welcome/rightButton.imageset/Contents.json b/uPic/Assets.xcassets/welcome/rightButton.imageset/Contents.json new file mode 100644 index 00000000..0c21e197 --- /dev/null +++ b/uPic/Assets.xcassets/welcome/rightButton.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "rightButton.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "rightButton@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "rightButton@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "template-rendering-intent" : "template" + } +} diff --git a/uPic/Assets.xcassets/welcome/rightButton.imageset/rightButton.png b/uPic/Assets.xcassets/welcome/rightButton.imageset/rightButton.png new file mode 100644 index 00000000..e4094560 Binary files /dev/null and b/uPic/Assets.xcassets/welcome/rightButton.imageset/rightButton.png differ diff --git a/uPic/Assets.xcassets/welcome/rightButton.imageset/rightButton@2x.png b/uPic/Assets.xcassets/welcome/rightButton.imageset/rightButton@2x.png new file mode 100644 index 00000000..4ce6f185 Binary files /dev/null and b/uPic/Assets.xcassets/welcome/rightButton.imageset/rightButton@2x.png differ diff --git a/uPic/Assets.xcassets/welcome/rightButton.imageset/rightButton@3x.png b/uPic/Assets.xcassets/welcome/rightButton.imageset/rightButton@3x.png new file mode 100644 index 00000000..e5112f3d Binary files /dev/null and b/uPic/Assets.xcassets/welcome/rightButton.imageset/rightButton@3x.png differ diff --git a/uPic/Assets.xcassets/welcome/screenshotUpload.imageset/Contents.json b/uPic/Assets.xcassets/welcome/screenshotUpload.imageset/Contents.json new file mode 100644 index 00000000..e40697c8 --- /dev/null +++ b/uPic/Assets.xcassets/welcome/screenshotUpload.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "screenshotUpload.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "screenshotUpload@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "screenshotUpload@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/uPic/Assets.xcassets/welcome/screenshotUpload.imageset/screenshotUpload.png b/uPic/Assets.xcassets/welcome/screenshotUpload.imageset/screenshotUpload.png new file mode 100644 index 00000000..06a4c1ab Binary files /dev/null and b/uPic/Assets.xcassets/welcome/screenshotUpload.imageset/screenshotUpload.png differ diff --git a/uPic/Assets.xcassets/welcome/screenshotUpload.imageset/screenshotUpload@2x.png b/uPic/Assets.xcassets/welcome/screenshotUpload.imageset/screenshotUpload@2x.png new file mode 100644 index 00000000..9a8ce299 Binary files /dev/null and b/uPic/Assets.xcassets/welcome/screenshotUpload.imageset/screenshotUpload@2x.png differ diff --git a/uPic/Assets.xcassets/welcome/screenshotUpload.imageset/screenshotUpload@3x.png b/uPic/Assets.xcassets/welcome/screenshotUpload.imageset/screenshotUpload@3x.png new file mode 100644 index 00000000..6caeddad Binary files /dev/null and b/uPic/Assets.xcassets/welcome/screenshotUpload.imageset/screenshotUpload@3x.png differ diff --git a/uPic/Assets.xcassets/welcome/shareExtensionUpload.imageset/Contents.json b/uPic/Assets.xcassets/welcome/shareExtensionUpload.imageset/Contents.json new file mode 100644 index 00000000..f9f44899 --- /dev/null +++ b/uPic/Assets.xcassets/welcome/shareExtensionUpload.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "shareExtensionUpload.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "shareExtensionUpload@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "shareExtensionUpload@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/uPic/Assets.xcassets/welcome/shareExtensionUpload.imageset/shareExtensionUpload.png b/uPic/Assets.xcassets/welcome/shareExtensionUpload.imageset/shareExtensionUpload.png new file mode 100644 index 00000000..45d436ee Binary files /dev/null and b/uPic/Assets.xcassets/welcome/shareExtensionUpload.imageset/shareExtensionUpload.png differ diff --git a/uPic/Assets.xcassets/welcome/shareExtensionUpload.imageset/shareExtensionUpload@2x.png b/uPic/Assets.xcassets/welcome/shareExtensionUpload.imageset/shareExtensionUpload@2x.png new file mode 100644 index 00000000..65352bc0 Binary files /dev/null and b/uPic/Assets.xcassets/welcome/shareExtensionUpload.imageset/shareExtensionUpload@2x.png differ diff --git a/uPic/Assets.xcassets/welcome/shareExtensionUpload.imageset/shareExtensionUpload@3x.png b/uPic/Assets.xcassets/welcome/shareExtensionUpload.imageset/shareExtensionUpload@3x.png new file mode 100644 index 00000000..a11cfcc7 Binary files /dev/null and b/uPic/Assets.xcassets/welcome/shareExtensionUpload.imageset/shareExtensionUpload@3x.png differ diff --git a/uPic/Base.lproj/Main.storyboard b/uPic/Base.lproj/Main.storyboard index 9d0eab2f..12db225e 100644 --- a/uPic/Base.lproj/Main.storyboard +++ b/uPic/Base.lproj/Main.storyboard @@ -62,7 +62,7 @@ - + @@ -113,7 +113,6 @@ - @@ -173,6 +172,12 @@ + + + + + + @@ -219,12 +224,6 @@ - - - - - - @@ -246,31 +245,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/uPic/Basic/Data+Extension.swift b/uPic/Basic/Data+Extension.swift index 02676b7d..fc05ab1e 100644 --- a/uPic/Basic/Data+Extension.swift +++ b/uPic/Basic/Data+Extension.swift @@ -20,7 +20,7 @@ extension Data { } func toBase64() -> String { - return self.bytes.toBase64()! + return self.bytes.toBase64() } func toSha1() -> String { diff --git a/uPic/Basic/ImageCodec/Codec/BaseCodec.swift b/uPic/Basic/ImageCodec/Codec/BaseCodec.swift new file mode 100644 index 00000000..b9c73245 --- /dev/null +++ b/uPic/Basic/ImageCodec/Codec/BaseCodec.swift @@ -0,0 +1,36 @@ +// +// Created by Bq Lin on 2021/5/18. +// Copyright (c) 2021 Bq. All rights reserved. +// + +import Foundation +import CoreGraphics + +// MARK: Decoder + +public protocol ImageDecoder { + func decode(data: Data) -> CommonImage? +} + +public protocol ImageDecoderSettings { + /// 只解码第一帧 + var firstFrameOnly: Bool { get set } + /// 不存储原图,仅当原图大小超过maxWidth、maxHeight大小时有效 + var ignoreOriginalImage: Bool { get set } + /// 限制最大宽度 + var maxWidth: Int? { get set } + /// 限制最大高度 + var maxHeight: Int? { get set } +} + +// MARK: Encoder + +public protocol ImageEncoder { + func encode(image: CommonImage) -> Data? + func encode(image: CGImage) -> Data? +} + +public protocol ImageEncoderSettings { + /// 只编码第一帧 + var firstFrameOnly: Bool { get set } +} diff --git a/uPic/Basic/ImageCodec/Codec/CodecUtil.swift b/uPic/Basic/ImageCodec/Codec/CodecUtil.swift new file mode 100644 index 00000000..e4be59c1 --- /dev/null +++ b/uPic/Basic/ImageCodec/Codec/CodecUtil.swift @@ -0,0 +1,45 @@ +// +// Created by Bq Lin on 2021/5/19. +// Copyright (c) 2021 Bq. All rights reserved. +// + +import Foundation +import CoreGraphics + +class CodecUtil { + typealias SizeTuple = (width: T, height: T) + typealias SizeTupleOptional = (width: T?, height: T?) + + static func sizeLimited(src: SizeTupleOptional? = nil, des: SizeTupleOptional) -> Bool { + if let value = des.width, value > 0 { + if let src = src?.width { + if src > value { return true } + } else { + return true + } + } + if let value = des.height, value > 0 { + if let src = src?.height { + if src > value { return true } + } else { + return true + } + } + return false + } + + static func convertedSize(src: SizeTuple, des: SizeTupleOptional) -> SizeTuple { + var size = src + if let maxWidth = des.width, size.width > maxWidth { + size.width = maxWidth + let value = Double(size.width) / Double(src.width) * Double(src.height) + size.height = Int(value) + } + if let maxHeight = des.height, size.height > maxHeight { + size.height = maxHeight + let value = Double(size.height) / Double(src.height) * Double(src.width) + size.width = Int(value) + } + return size + } +} diff --git a/uPic/Basic/ImageCodec/Codec/CommonImageCodec.swift b/uPic/Basic/ImageCodec/Codec/CommonImageCodec.swift new file mode 100644 index 00000000..c4846d35 --- /dev/null +++ b/uPic/Basic/ImageCodec/Codec/CommonImageCodec.swift @@ -0,0 +1,99 @@ +// +// Created by Bq Lin on 2021/5/19. +// Copyright (c) 2021 Bq. All rights reserved. +// + +import Foundation + +public class CommonImageCodec: ImageDecoderSettings, ImageEncoderSettings { + public var firstFrameOnly: Bool = false + public var ignoreOriginalImage: Bool = true + public var maxWidth: Int? + public var maxHeight: Int? + public init() {} +} + +public extension CommonImageCodec { + /// 目前支持 .jpg, .png, .gif, .tif, .bmp, .ico, .webp 格式相互转换 + func convert(data: Data, toType: FileType) -> Data? { + guard let mine = Swime.mimeType(data: data) else { return nil } + let fromType = mine.type + + guard let decoder = makeDecoder(type: fromType) else { return nil } + guard let image = decoder.decode(data: data) else { return nil } + let encodeForType = fromType != toType + let encodeForFirstFrameOnly = firstFrameOnly && image.hasAnimation + let encodeForMaxWidth: Bool = { + var shouldEncode = false + if let maxWidth = maxWidth { + shouldEncode = image.originalWidth > maxWidth + } + return shouldEncode + }() + let encodeForMaxHeight: Bool = { + var shouldEncode = false + if let maxHeight = maxHeight { + shouldEncode = image.originalHeight > maxHeight + } + return shouldEncode + }() + if !encodeForType, !encodeForFirstFrameOnly, !encodeForMaxWidth, !encodeForMaxHeight { + debugPrint("无需转换,原样输出") + return data + } + + guard let encoder = makeEncoder(type: toType) else { return nil } + return encoder.encode(image: image) + } +} + +extension CommonImageCodec { + func usingWebp(type: FileType) -> Bool { + type == .webp + } + + func usingImageIO(type: FileType) -> Bool { + switch type { + case .jpg, .png, .gif, .tif, .bmp, .ico: + return true + default: + return false + } + } + + func makeDecoder(type: FileType) -> ImageDecoder? { + var decoder: (ImageDecoder & ImageDecoderSettings)! + if false { + } else if usingWebp(type: type) { + let _coder = WebPDecoder() + decoder = _coder + } else if usingImageIO(type: type) { + let _coder = ImageIODecoder() + decoder = _coder + } + guard decoder != nil else { return nil } + + decoder.firstFrameOnly = firstFrameOnly + decoder.ignoreOriginalImage = ignoreOriginalImage + decoder.maxHeight = maxHeight + decoder.maxWidth = maxWidth + return decoder + } + + func makeEncoder(type: FileType) -> ImageEncoder? { + var encoder: (ImageEncoder & ImageEncoderSettings)! + if false { + } else if usingWebp(type: type) { + let _coder = WebPEncoder() + encoder = _coder + } else if usingImageIO(type: type) { + let _coder = ImageIOEncoder() + _coder.outputUTI = type.UTI + encoder = _coder + } + guard encoder != nil else { return nil } + + encoder.firstFrameOnly = firstFrameOnly + return encoder + } +} diff --git a/uPic/Basic/ImageCodec/Codec/ImageIODecoder.swift b/uPic/Basic/ImageCodec/Codec/ImageIODecoder.swift new file mode 100644 index 00000000..05b1927a --- /dev/null +++ b/uPic/Basic/ImageCodec/Codec/ImageIODecoder.swift @@ -0,0 +1,144 @@ +// +// Created by Bq Lin on 2021/5/18. +// Copyright (c) 2021 Bq. All rights reserved. +// + +import Foundation +import ImageIO + +public class ImageIODecoder: ImageDecoder, ImageDecoderSettings { + // MARK: 配置 + public var firstFrameOnly: Bool = false + public var ignoreOriginalImage: Bool = true + + public var maxWidth: Int? { + set { + _maxWidth = newValue + } + get { + guard let value = _maxWidth else { return nil } + return value > 0 ? value : nil + } + } + + public var maxHeight: Int? { + set { + _maxHeight = newValue + } + get { + guard let value = _maxHeight else { return nil } + return value > 0 ? value : nil + } + } + + private var _maxWidth: Int? + private var _maxHeight: Int? + + public init() { + contextInfo = ContextInfo() + contextInfo.baseOptions = [ + // kCGImageSourceShouldCacheImmediately: true, + // kCGImageSourceShouldCache: true, + kCGImageSourceCreateThumbnailWithTransform: true, + ] + } + + var contextInfo: ContextInfo! + + public func decode(data: Data) -> CommonImage? { + guard let source = CGImageSourceCreateWithData(data as CFData, nil) else { return nil } + let frameCount = CGImageSourceGetCount(source) + guard frameCount > 0 else { return nil } + + if firstFrameOnly || frameCount == 1 { + guard let frame = makeFrame(from: source, index: 0) else { return nil } + return CommonImage(frame) + } + + var loopCount = 0 + if let sourceInfo = CGImageSourceCopyProperties(source, nil) as? [CFString: Any] { + if let gifInfo = sourceInfo[kCGImagePropertyGIFDictionary] as? [CFString: Any] { + if let loop = gifInfo[kCGImagePropertyGIFLoopCount] as? Int { + loopCount = loop + } + } + } + + var frames = [CommonImage.Frame]() + for i in 0 ..< frameCount { + guard let frame = makeFrame(from: source, index: i) else { continue } + frames.append(frame) + } + return CommonImage(frames: frames, loopCount: loopCount) + } + + func makeFrame(from source: CGImageSource, index: Int) -> CommonImage.Frame? { + var frame = CommonImage.Frame() + guard let sourceFrameInfo = CGImageSourceCopyPropertiesAtIndex(source, index, nil) as? [CFString: Any] else { return nil } + let width = sourceFrameInfo[kCGImagePropertyPixelWidth] as? Int ?? 0 + let height = sourceFrameInfo[kCGImagePropertyPixelHeight] as? Int ?? 0 + let exifOrientation = sourceFrameInfo[kCGImagePropertyOrientation] as? CGImagePropertyOrientation + // uttype + //_ = CGImageSourceGetType(source) + + frame.originalInfo[InfoKey.orientation] = exifOrientation ?? CGImagePropertyOrientation.up + + var image: CGImage! + var originalImage: CGImage? + + func makeOriginalImage() -> CGImage? { + CGImageSourceCreateImageAtIndex(source, index, options as CFDictionary) + } + + // TODO: 处理图像方向 + var options = contextInfo.baseOptions + let sizeLimited = CodecUtil.sizeLimited(src: (width, height), des: (maxWidth, maxHeight)) + if sizeLimited { + let size = CodecUtil.convertedSize(src: (width, height), des: (maxWidth, maxHeight)) + let maxPixelSize = max(size.width, size.height) + if maxPixelSize > 0 { + options[kCGImageSourceThumbnailMaxPixelSize] = maxPixelSize + options[kCGImageSourceCreateThumbnailFromImageAlways] = true + } + + let limitedImage = CGImageSourceCreateThumbnailAtIndex(source, index, options as CFDictionary) + + image = limitedImage + if !ignoreOriginalImage { + originalImage = makeOriginalImage() + } + } else { + image = makeOriginalImage() + if !ignoreOriginalImage { + originalImage = image + } + } + + if let gifInfo = sourceFrameInfo[kCGImagePropertyGIFDictionary] as? [CFString: Any] { + if let duration = gifInfo[kCGImagePropertyGIFUnclampedDelayTime] as? Double { + frame.duration = duration + } else if let duration = gifInfo[kCGImagePropertyGIFDelayTime] as? Double { + frame.duration = duration + } + } + + if let originalImage = originalImage { + frame.originalInfo[CommonInfoKey.originalImage] = originalImage + } + frame.image = image + frame.originalInfo[CommonInfoKey.width] = width + frame.originalInfo[CommonInfoKey.height] = height + + return frame + } +} + +extension ImageIODecoder { + struct ContextInfo { + var baseOptions: [CFString: Any] = [:] + } + + struct InfoKey { + static let orientation = "orientation" + } +} diff --git a/uPic/Basic/ImageCodec/Codec/ImageIOEncoder.swift b/uPic/Basic/ImageCodec/Codec/ImageIOEncoder.swift new file mode 100644 index 00000000..3776d382 --- /dev/null +++ b/uPic/Basic/ImageCodec/Codec/ImageIOEncoder.swift @@ -0,0 +1,92 @@ +// +// Created by Bq Lin on 2021/5/19. +// Copyright (c) 2021 Bq. All rights reserved. +// + +import Foundation +import ImageIO +import CoreServices + +public class ImageIOEncoder: ImageEncoder, ImageEncoderSettings { + public var firstFrameOnly: Bool = false + + public var outputUTI: CFString? + public let supportedUTIs = CGImageDestinationCopyTypeIdentifiers() as! [CFString] + let animationUTI: Set = [kUTTypeGIF, kUTTypePNG] + + public init() { + outputUTI = kUTTypePNG + // print("supportedType: \(supportedUTIs)") + // kUTTypeImage(抽象类):kUTTypeJPEG、kUTTypePNG、kUTTypeGIF、kUTTypeTIFF、kUTTypePDF + } + + public func encode(image: CommonImage) -> Data? { + guard let outputUTI = outputUTI else { return nil } + guard supportedUTIs.contains(outputUTI) else { return nil } + + guard image.coverImage != nil else { return nil } + if firstFrameOnly || !image.hasAnimation || !allowAnimation(for: outputUTI) { + return encode(image: image.coverImage!) + } + + let data = NSMutableData() + guard let destination = makeDestination(image: image, data: data as CFMutableData) else { return nil } + for frame in image.frames { + encode(frame: frame, destination: destination) + } + guard CGImageDestinationFinalize(destination) else { return nil } + + return (data.copy() as! Data) + } + + /// 编码单帧图片 + public func encode(image: CGImage) -> Data? { + guard let outputUTI = outputUTI else { return nil } + + let data = NSMutableData() + guard let destination = CGImageDestinationCreateWithData(data as CFMutableData, outputUTI, 1, nil) else { return nil } + CGImageDestinationAddImage(destination, image, nil) + guard CGImageDestinationFinalize(destination) else { return nil } + + return (data.copy() as! Data) + } + + func allowAnimation(for uti: CFString) -> Bool { animationUTI.contains(uti) } + + // 多帧 + func encode(frame: CommonImage.Frame, destination: CGImageDestination) { + guard let outputUTI = outputUTI else { return } + + var info = [CFString: Any]() + switch outputUTI { + case kUTTypeGIF: + if let duration = frame.duration { + info[kCGImagePropertyGIFDictionary] = [kCGImagePropertyGIFDelayTime: duration] + } + case kUTTypePNG: + if let duration = frame.duration { + info[kCGImagePropertyPNGDictionary] = [kCGImagePropertyAPNGDelayTime: duration] + } + default: break + } + CGImageDestinationAddImage(destination, frame.image, info as CFDictionary) + } + + func makeDestination(image: CommonImage, data: CFMutableData) -> CGImageDestination? { + guard let outputUTI = outputUTI else { return nil } + guard image.frames.count > 0 else { return nil } + guard let destination = CGImageDestinationCreateWithData(data, outputUTI, image.hasAnimation ? image.frames.count : 1, nil) else { return nil } + + var info = [CFString: Any]() + switch outputUTI { + case kUTTypeGIF: + info[kCGImagePropertyGIFDictionary] = [kCGImagePropertyGIFLoopCount: image.loopCount] + case kUTTypePNG: + info[kCGImagePropertyPNGDictionary] = [kCGImagePropertyAPNGLoopCount: image.loopCount] + default: break + } + CGImageDestinationSetProperties(destination, info as CFDictionary) + + return destination + } +} diff --git a/uPic/Basic/ImageCodec/Codec/WebPDecoder.swift b/uPic/Basic/ImageCodec/Codec/WebPDecoder.swift new file mode 100644 index 00000000..dfdfda0b --- /dev/null +++ b/uPic/Basic/ImageCodec/Codec/WebPDecoder.swift @@ -0,0 +1,243 @@ +// +// Created by Bq Lin on 2021/5/17. +// Copyright (c) 2021 Bq. All rights reserved. +// + +import CoreGraphics +import Foundation +import libwebp + +public class WebPDecoder: ImageDecoder, ImageDecoderSettings { + // MARK: 配置 + public var firstFrameOnly: Bool = false + public var ignoreOriginalImage: Bool = true + public var maxWidth: Int? { + set { + _maxWidth = newValue + } + get { + guard let value = _maxWidth else { return nil } + return value > 0 ? value : nil + } + } + + public var maxHeight: Int? { + set { + _maxHeight = newValue + } + get { + guard let value = _maxHeight else { return nil } + return value > 0 ? value : nil + } + } + + private var _maxWidth: Int? + private var _maxHeight: Int? + + public init() {} + + // MARK: + + private var contextInfo: ContextInfo! + + public func decode(data: Data) -> CommonImage? { + data.withUnsafeBytes { [weak self] (pointer: UnsafeRawBufferPointer) in + guard let self = self else { return nil } + + let size = pointer.count + let baseAddress = pointer.baseAddress!.assumingMemoryBound(to: UInt8.self) + var data = WebPData(bytes: baseAddress, size: size) + let demuxer = WebPDemux(&data) + defer { + WebPDemuxDelete(demuxer) + } + + let flags = WebPDemuxGetI(demuxer, WEBP_FF_FORMAT_FLAGS) + let hasAnimation = flags & ANIMATION_FLAG.rawValue != 0 + + let colorSpace = self.makeColorSpace(demuxer: demuxer) + let originalWidth = Int(WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_WIDTH)) + let originalHeight = Int(WebPDemuxGetI(demuxer, WEBP_FF_CANVAS_HEIGHT)) + let frameCount = Int(WebPDemuxGetI(demuxer, WEBP_FF_FRAME_COUNT)) + let loopCount = Int(WebPDemuxGetI(demuxer, WEBP_FF_LOOP_COUNT)) + guard frameCount > 0, originalWidth > 0, originalHeight > 0 else { return nil } + + contextInfo = ContextInfo(colorSpace: colorSpace, originalWidth: originalWidth, originalHeight: originalHeight) + + // TODO: + // let imageSize = self.convertedSize(CGSize(width: originalWidth, height: originalHeight)) + + var iter = WebPIterator() + defer { + WebPDemuxReleaseIterator(&iter) + } + guard WebPDemuxGetFrame(demuxer, 1, &iter) != 0 else { + return nil + } + + // 首帧 + if !hasAnimation || firstFrameOnly { + return makeCoverImage(webpData: iter.fragment) + } + + // 多帧动画 + let bitmapInfo = CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue + guard let blendCanvas = CGContext(data: nil, width: originalWidth, height: originalHeight, bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: bitmapInfo) else { return nil } + var frames = [CommonImage.Frame]() + repeat { + guard let frame = makeFrameImage(blendCanvas: blendCanvas, iterator: iter) else { continue } + frames.append(frame) + } while WebPDemuxNextFrame(&iter) != 0 + guard frames.count == frameCount else { + print("fail to decode some frame!") + return nil + } + + let sizeLimited = CodecUtil.sizeLimited(src: (originalWidth, originalHeight), des: (maxWidth, maxHeight)) + if sizeLimited { + let size = CodecUtil.convertedSize(src: (originalWidth, originalHeight), des: (maxWidth, maxHeight)) + frames = frames.map { frame in + var frame = frame + if let resizeImage = frame.image.draw.makeImage(toSize: size) { + frame.image = resizeImage + } + return frame + } + } + + return CommonImage(frames: frames, loopCount: loopCount) + } + } + + private func makeColorSpace(demuxer: OpaquePointer!) -> CGColorSpace { + var colorSpace: CGColorSpace! + let flags = WebPDemuxGetI(demuxer, WEBP_FF_FORMAT_FLAGS) + if flags & ICCP_FLAG.rawValue != 0 { + var chunkIter = WebPChunkIterator() + let result = WebPDemuxGetChunk(demuxer, "ICCP", 1, &chunkIter) + if result != 0 { + let profileData = Data(bytes: chunkIter.chunk.bytes, count: chunkIter.chunk.size) + //colorSpace = CGColorSpace(iccProfileData: profileData as CFData) + colorSpace = CGColorSpace(iccData: profileData as CFTypeRef) + WebPDemuxReleaseChunkIterator(&chunkIter) + // 排除RGB以外的颜色模型 + if colorSpace.model != .rgb { + colorSpace = nil + } + } + } + + return colorSpace ?? CGColorSpaceCreateDeviceRGB() + } + + private func makeCoverImage(webpData: WebPData) -> CommonImage? { + var hasAlpha = false + guard let originalImage = makeOriginalImage(webpData: webpData, hasAlpha: &hasAlpha) else { return nil } + let width = originalImage.width + let height = originalImage.height + let sizeLimited = CodecUtil.sizeLimited(src: (width, height), des: (maxWidth, maxHeight)) + if sizeLimited { + let size = CodecUtil.convertedSize(src: (width, height), des: (maxWidth, maxHeight)) + if let image = originalImage.draw.makeImage(toSize: size) { + var frame = CommonImage.Frame() + frame.originalInfo[CommonInfoKey.width] = width + frame.originalInfo[CommonInfoKey.height] = height + if !ignoreOriginalImage { + frame.originalInfo[CommonInfoKey.originalImage] = originalImage + } + frame.image = image + return CommonImage(frame) + } + } + + return CommonImage(originalImage) + } + + private func makeOriginalImage(webpData: WebPData, hasAlpha: inout Bool) -> CGImage? { + var config = WebPDecoderConfig() + guard WebPInitDecoderConfig(&config) != 0 else { return nil } + + guard WebPGetFeatures(webpData.bytes, webpData.size, &config.input) == VP8_STATUS_OK else { return nil } + + hasAlpha = config.input.has_alpha != 0 + var bitmapInfo = CGBitmapInfo.byteOrder32Little.rawValue + bitmapInfo |= (hasAlpha ? CGImageAlphaInfo.premultipliedFirst.rawValue : CGImageAlphaInfo.noneSkipFirst.rawValue) + config.output.colorspace = MODE_bgrA + config.options.use_threads = 1 + // 这里做大小限制怕因offset影响,所以不在这里限制 + // config.options.use_scaling = 1 + // config.options.scaled_width = 100 + + guard WebPDecode(webpData.bytes, webpData.size, &config) == VP8_STATUS_OK else { return nil } + + let provider = CGDataProvider(dataInfo: nil, data: config.output.u.RGBA.rgba, size: config.output.u.RGBA.size) { _, data, _ in + data.deallocate() + } + guard provider != nil else { return nil } + + let w = Int(config.output.width) + let h = Int(config.output.height) + let bpc = 8 + let bpp = 32 + let bpr = Int(config.output.u.RGBA.stride) + guard let image = CGImage(width: w, height: h, bitsPerComponent: bpc, bitsPerPixel: bpp, bytesPerRow: bpr, space: contextInfo.colorSpace, bitmapInfo: CGBitmapInfo(rawValue: bitmapInfo), provider: provider!, decode: nil, shouldInterpolate: false, intent: .defaultIntent) else { return nil } + return image + } + + private func makeFrameImage(blendCanvas: CGContext, iterator iter: WebPIterator) -> CommonImage.Frame? { + var frame = CommonImage.Frame() + + var duration = TimeInterval(iter.duration) + if duration <= 10 { + duration = 100 + } + duration /= 1000 + frame.duration = duration + + var hasAlpha = false + guard let originalImage = makeOriginalImage(webpData: iter.fragment, hasAlpha: &hasAlpha) else { return nil } + if !ignoreOriginalImage { + frame.originalInfo[CommonInfoKey.originalImage] = originalImage + } + + let frameWidth = Int(iter.width) + let frameHeight = Int(iter.height) + let offsetX = Int(iter.x_offset) + let offsetY = contextInfo.originalHeight - frameHeight - Int(iter.y_offset) + let frameRect = CGRect(x: offsetX, y: offsetY, width: frameWidth, height: frameHeight) + frame.originalInfo[CommonInfoKey.width] = frameWidth + frame.originalInfo[CommonInfoKey.height] = frameHeight + + let shouldBlend = iter.blend_method == WEBP_MUX_BLEND + if !shouldBlend { + blendCanvas.clear(frameRect) + } + blendCanvas.draw(originalImage, in: frameRect) + guard let image = blendCanvas.makeImage() else { return nil } + frame.image = image + + defer { + if iter.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND { + blendCanvas.clear(frameRect) + } + } + + return frame + } +} + +extension WebPDecoder { + struct ContextInfo { + let colorSpace: CGColorSpace + let originalWidth: Int + let originalHeight: Int + + var size: CGSize { + CGSize(width: originalWidth, height: originalHeight) + } + + var bounds: CGRect { + CGRect(origin: .zero, size: size) + } + } +} diff --git a/uPic/Basic/ImageCodec/Codec/WebPEncoder.swift b/uPic/Basic/ImageCodec/Codec/WebPEncoder.swift new file mode 100644 index 00000000..2effd2d7 --- /dev/null +++ b/uPic/Basic/ImageCodec/Codec/WebPEncoder.swift @@ -0,0 +1,139 @@ +// +// Created by Bq Lin on 2021/5/17. +// Copyright (c) 2021 Bq. All rights reserved. +// + +import Foundation +import CoreGraphics +import Accelerate +import libwebp + +public class WebPEncoder: ImageEncoder, ImageEncoderSettings { + public var firstFrameOnly: Bool = false + + public init() {} + + public func encode(image: CommonImage) -> Data? { + if firstFrameOnly || image.frames.count == 1 { + return encode(image: image.coverImage!) + } else { + guard let mux = WebPMuxNew() else { return nil } + defer { + WebPMuxDelete(mux) + } + + for (_, frame) in image.frames.enumerated() { + guard let imageData = encode(image: frame.image) else { continue } + + let duration = Int(frame.duration! * 1000) + var frameInfo = WebPMuxFrameInfo() + frameInfo.bitstream = WebPData(bytes: (imageData as NSData).bytes.assumingMemoryBound(to: UInt8.self), size: imageData.count) + frameInfo.duration = Int32(duration) + frameInfo.id = WEBP_CHUNK_ANMF + frameInfo.dispose_method = WEBP_MUX_DISPOSE_BACKGROUND + frameInfo.blend_method = WEBP_MUX_NO_BLEND + guard WebPMuxPushFrame(mux, &frameInfo, 0) == WEBP_MUX_OK else { return nil } + } + + var params = WebPMuxAnimParams() + params.bgcolor = 0 + params.loop_count = Int32(image.loopCount) + guard WebPMuxSetAnimationParams(mux, ¶ms) == WEBP_MUX_OK else { return nil } + + var outputData = WebPData() + guard WebPMuxAssemble(mux, &outputData) == WEBP_MUX_OK else { return nil } + defer { + WebPDataClear(&outputData) + } + + return Data(bytes: outputData.bytes, count: outputData.size) + } + } + + public func encode(image: CGImage) -> Data? { + let width = image.width + let height = image.height + let colorSpace = CGColorSpaceCreateDeviceRGB() + + let alphaInfo = image.alphaInfo + let hasAlpha: Bool = { + switch alphaInfo { + case .none, .noneSkipFirst, .noneSkipLast: + return false + default: + return true + } + }() + + var srcFormat = vImage_CGImageFormat() + srcFormat.bitsPerComponent = UInt32(image.bitsPerComponent) + srcFormat.bitsPerPixel = UInt32(image.bitsPerPixel) + srcFormat.colorSpace = Unmanaged.passUnretained(image.colorSpace!) + srcFormat.bitmapInfo = image.bitmapInfo + + let desBitmapInfo = hasAlpha ? CGImageAlphaInfo.last.rawValue : CGImageAlphaInfo.none.rawValue + var desFormat = vImage_CGImageFormat() + desFormat.bitsPerComponent = 8 + desFormat.bitsPerPixel = hasAlpha ? 32 : 24 + desFormat.colorSpace = Unmanaged.passUnretained(colorSpace) + desFormat.bitmapInfo = CGBitmapInfo(rawValue: desBitmapInfo) + + var error: vImage_Error = 0 + let convertor = vImageConverter_CreateWithCGImageFormat(&srcFormat, &desFormat, nil, vImage_Flags(kvImagePrintDiagnosticsToConsole), &error).takeRetainedValue() + + var src = vImage_Buffer() + error = vImageBuffer_InitWithCGImage(&src, &srcFormat, nil, image, 0) + guard error == 0 else { return nil } + defer { + src.data.deallocate() + } + + var des = vImage_Buffer() + error = vImageBuffer_Init(&des, vImagePixelCount(height), vImagePixelCount(width), desFormat.bitsPerPixel, 0) + guard error == 0 else { return nil } + defer { + des.data.deallocate() + } + + error = vImageConvert_AnyToAny(convertor, &src, &des, nil, 0) + guard error == 0 else { return nil } + + let rgbaRaw = des.data + let rgba = rgbaRaw?.assumingMemoryBound(to: UInt8.self) + let bpr = des.rowBytes + + var config = WebPConfig() + var picture = WebPPicture() + var writer = WebPMemoryWriter() + + guard WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, 100) != 0, WebPPictureInit(&picture) != 0 else { return nil } + + config.thread_level = 1 + + picture.use_argb = 0 + picture.width = Int32(width) + picture.height = Int32(height) + picture.writer = WebPMemoryWrite + picture.custom_ptr = withUnsafeMutablePointer(to: &writer) { UnsafeMutableRawPointer($0) } + WebPMemoryWriterInit(&writer) + defer { + WebPMemoryWriterClear(&writer) + } + + var result: Int32 = 0 + if hasAlpha { + result = WebPPictureImportRGBA(&picture, rgba, Int32(bpr)) + } else { + result = WebPPictureImportRGB(&picture, rgba, Int32(bpr)) + } + guard result != 0 else { return nil } + result = WebPEncode(&config, &picture) + WebPPictureFree(&picture) + + if result != 0 { + return Data(bytes: writer.mem, count: writer.size) + } + + return nil + } +} diff --git a/uPic/Basic/ImageCodec/Extension/CGImage+Drawing.swift b/uPic/Basic/ImageCodec/Extension/CGImage+Drawing.swift new file mode 100644 index 00000000..65faa8d3 --- /dev/null +++ b/uPic/Basic/ImageCodec/Extension/CGImage+Drawing.swift @@ -0,0 +1,99 @@ +// +// Created by Bq Lin on 2021/5/18. +// Copyright (c) 2021 Bq. All rights reserved. +// + +import Foundation +import CoreGraphics + +struct TypeWrapper { + let base: Base + + init(_ base: Base) { self.base = base } +} + +protocol Drawable: AnyObject { + associatedtype Base: AnyObject + static var draw: TypeWrapper.Type { get } + var draw: TypeWrapper { get } +} + +extension Drawable { + static var draw: TypeWrapper.Type { TypeWrapper.self } + var draw: TypeWrapper { TypeWrapper(self) } +} + +extension CGImage: Drawable {} + +extension TypeWrapper where Base: CGImage { + func makeImage(backgroundColor: CGColor) -> CGImage? { + let canvas = makeCanvas() + canvas.setFillColor(backgroundColor) + let rect = self.rect + canvas.fill(rect) + canvas.draw(base, in: rect) + + return canvas.makeImage() + } + + func makeImage(toSize: CodecUtil.SizeTuple) -> CGImage? { + let canvas = makeCanvas(size: toSize) + canvas.draw(base, in: CGRect(x: 0, y: 0, width: toSize.width, height: toSize.height)) + + return canvas.makeImage() + } + + func makeCanvas(size: CodecUtil.SizeTuple? = nil, hasAlpha: Bool? = nil) -> CGContext { + let width = size?.width ?? base.width + let height = size?.height ?? base.height + + var canvas: CGContext? + if hasAlpha == nil { + canvas = CGContext( + data: nil, + width: width, + height: height, + bitsPerComponent: base.bitsPerComponent, + bytesPerRow: 0, + space: base.colorSpace ?? CGColorSpaceCreateDeviceRGB(), + bitmapInfo: base.bitmapInfo.rawValue + ) + } + + let hasAlpha = hasAlpha ?? self.hasAlpha + // let components = hasAlpha ? 4 : 3 + var bitmapInfo = CGBitmapInfo.byteOrder32Little.rawValue + bitmapInfo |= hasAlpha ? CGImageAlphaInfo.premultipliedFirst.rawValue : CGImageAlphaInfo.noneSkipFirst.rawValue + if canvas == nil { + canvas = CGContext( + data: nil, + width: width, + height: height, + bitsPerComponent: 8, + bytesPerRow: 0, + space: CGColorSpaceCreateDeviceRGB(), + bitmapInfo: bitmapInfo + ) + } + + canvas?.setShouldAntialias(true) + canvas?.setAllowsAntialiasing(true) + canvas?.interpolationQuality = .high + + return canvas! + } + + var rect: CGRect { + CGRect(x: 0, y: 0, width: base.width, height: base.height) + } + + var hasAlpha: Bool { + switch base.alphaInfo { + case .premultipliedLast, .premultipliedFirst, .last, .first: + return true + default: + return false + } + } +} + diff --git a/uPic/Basic/ImageCodec/Extension/FileTypeUtil.swift b/uPic/Basic/ImageCodec/Extension/FileTypeUtil.swift new file mode 100644 index 00000000..daf0606c --- /dev/null +++ b/uPic/Basic/ImageCodec/Extension/FileTypeUtil.swift @@ -0,0 +1,27 @@ +// +// Created by Bq Lin on 2021/6/15. +// Copyright (c) 2021 Bq. All rights reserved. +// + +import Foundation +import CoreServices + +let UTIMap: [FileType: CFString] = [ + .tif: kUTTypeTIFF, + .ico: kUTTypeICO, + .bmp: kUTTypeBMP, + .gif: kUTTypeGIF, + .png: kUTTypePNG, + .jpg: kUTTypeJPEG, +] + +public extension FileType { + var ext: String { + MimeType.all.first { $0.type == self }!.ext + } + + var UTI: CFString? { + UTIMap[self] + } +} + diff --git a/uPic/Basic/ImageCodec/Model/CommonImage.swift b/uPic/Basic/ImageCodec/Model/CommonImage.swift new file mode 100644 index 00000000..55714aec --- /dev/null +++ b/uPic/Basic/ImageCodec/Model/CommonImage.swift @@ -0,0 +1,62 @@ +// +// Created by Bq Lin on 2021/5/16. +// Copyright (c) 2021 Bq. All rights reserved. +// + +import CoreGraphics +import Foundation + +public class CommonImage { + var loopCount: Int = 0 + var frames = [Frame]() + + var coverImage: CGImage? { + frames.first?.image + } + + var hasAnimation: Bool { + frames.count > 1 && totalDuration != nil + } + + var totalDuration: TimeInterval? { + let duration: TimeInterval = frames.reduce(0) { (result, frame: Frame) in + result + (frame.duration ?? 0) + } + return duration == 0 ? nil : duration + } + + init(_ image: CGImage) { + var frame = Frame(image: image) + frame.originalInfo[CommonInfoKey.width] = image.width + frame.originalInfo[CommonInfoKey.height] = image.height + frames = [frame] + } + + init(_ frame: Frame) { + frames = [frame] + } + + init(frames: [Frame], loopCount: Int) { + self.frames = frames + self.loopCount = loopCount + } +} + +extension CommonImage { + struct Frame { + var image: CGImage! + var duration: TimeInterval? + var originalInfo: [String: Any] = [:] + } +} + +struct CommonInfoKey { + static let width = "width" // Int + static let height: String = "height" // Int + static let originalImage = "originalImage" // CGImage +} + +public extension CommonImage { + var originalWidth: Int { frames.first?.originalInfo[CommonInfoKey.width] as! Int? ?? 0 } + var originalHeight: Int { frames.first?.originalInfo[CommonInfoKey.height] as! Int? ?? 0 } +} diff --git a/uPic/Basic/String+Crypto.swift b/uPic/Basic/String+Crypto.swift index 041980f3..baac43f9 100644 --- a/uPic/Basic/String+Crypto.swift +++ b/uPic/Basic/String+Crypto.swift @@ -21,7 +21,7 @@ extension String { } func toBase64() -> String { - return self.bytes.toBase64()! + return self.bytes.toBase64() } func toSha1() -> String { diff --git a/uPic/Cli/Cli.swift b/uPic/Cli/Cli.swift index 334ae385..4349451c 100644 --- a/uPic/Cli/Cli.swift +++ b/uPic/Cli/Cli.swift @@ -29,9 +29,9 @@ class Cli { private var resultUrls: [String] = [] - func handleCommandLine() -> Bool { + func getFilePaths() -> [String]? { let arguments = CommandLine.arguments - guard arguments.count > 1 else { return false } + guard arguments.count > 1 else { return nil } cliKit = CommandLineKit(arguments: arguments) @@ -48,17 +48,14 @@ class Cli { try cliKit.parse() } catch { cliKit.printUsage(error) - return false + return nil } - if let paths = upload.value { - startUpload(paths) - return true - } else { + guard let paths = upload.value else { cliKit.printUsage() + return nil } - - return false + return paths } } @@ -66,7 +63,7 @@ class Cli { extension Cli { /// start upload /// - Parameter paths: file paths or URLs - private func startUpload(_ paths: [String]) { + func startUpload(_ paths: [String]) { allPathList = paths for path in paths { @@ -93,8 +90,39 @@ extension Cli { /// Upload progress /// - Parameter url: current url func uploadProgress(_ url: String) { - let outputType = OutputType(value: output?.value) - resultUrls.append(outputType.formatUrl(url.urlEncoded())) + var outputUrl = "" + if let output = output?.value?.lowercased() { + var formatUrl = url + if Defaults[.outputFormatEncoded] { + formatUrl = url.urlEncoded() + } + var filename = url.lastPathComponent.deletingPathExtension.trim() + let tempArr = filename.components(separatedBy: .whitespaces).map{ $0.trim() }.filter{ !$0.isEmpty } + filename = tempArr.joined(separator: "") + switch output { + case "url": + outputUrl = formatUrl + break + case "html": + outputUrl = "\(filename)" + break + case "md": + outputUrl = "![\(filename)](\(formatUrl))" + break + case "markdown": + outputUrl = "![\(filename)](\(formatUrl))" + break + case "ubb": + outputUrl = "[img]\(formatUrl)[/img]" + break + default: + outputUrl = OutputFormatModel.formatUrl(url, outputFormat: nil) + } + } else { + outputUrl = OutputFormatModel.formatUrl(url, outputFormat: nil) + } + + resultUrls.append(outputUrl) progress += 1 Console.write("Uploading \(progress)/\(allDataList.count)") } diff --git a/uPic/Extensions/NotificationExt.swift b/uPic/Extensions/NotificationExt.swift index eb9d807c..ce53800b 100644 --- a/uPic/Extensions/NotificationExt.swift +++ b/uPic/Extensions/NotificationExt.swift @@ -41,6 +41,11 @@ class NotificationExt:NSObject { info: "The file does not exist or has been deleted!".localized) } + func postFileNoAccessNotice() { + self.post(title: "Upload failed".localized, + info: "No access to file!".localized) + } + func postUplodingNotice(_ body: String? = "") { self.post(title: "The current upload task is not complete".localized, info: body!) diff --git a/uPic/General/Managers/ConfigManager.swift b/uPic/Managers/ConfigManager.swift similarity index 92% rename from uPic/General/Managers/ConfigManager.swift rename to uPic/Managers/ConfigManager.swift index 1327e080..53fd90ce 100644 --- a/uPic/General/Managers/ConfigManager.swift +++ b/uPic/Managers/ConfigManager.swift @@ -34,6 +34,7 @@ public class ConfigManager { guard firstUsage == ._true else { return } + Defaults[.compressFactor] = 100 Defaults.synchronize() @@ -87,12 +88,17 @@ extension ConfigManager { } extension ConfigManager { - func getOutputType() -> OutputType { - OutputType(value: Defaults[.outputFormat]) + func getOutputType() -> OutputFormatModel? { + let id = Defaults[.outputFormat] + let outputFormatList = DBManager.shared.getOutputFormatList() + guard let idx = outputFormatList.firstIndex(where: {$0.identifier == id}) else { + return outputFormatList.first + } + return outputFormatList[idx] } - func setOutputType(_ outputType: OutputType) { - Defaults[.outputFormat] = outputType.rawValue + func setOutputType(_ outputFormat: OutputFormatModel) { + Defaults[.outputFormat] = outputFormat.identifier } func setOutputType(_ outputTypeRawValue: Int) { @@ -104,7 +110,7 @@ extension ConfigManager { extension ConfigManager { public var historyLimit: Int { get { - let defaultLimit = 100 + let defaultLimit = 10000 let limit = Defaults[.historyLimit] if (limit == nil || limit == 0) { return defaultLimit @@ -122,16 +128,6 @@ extension ConfigManager { if historyList != nil { return historyList } - - // FIXME: - workaround 转移旧版历史记录到 db - if let historyList = Defaults[.historyList] { - let oldHistoryListModel: [HistoryThumbnailModel] = historyList.map({ (item) -> HistoryThumbnailModel in - return HistoryThumbnailModel.keyValue(keyValue: item) - }) - - DBManager.shared.insertHistorys(oldHistoryListModel) - Defaults.removeObject(forKey: Keys.historyList) - } historyList = DBManager.shared.getHistoryList() return historyList diff --git a/uPic/General/Managers/DBManager.swift b/uPic/Managers/DBManager.swift similarity index 50% rename from uPic/General/Managers/DBManager.swift rename to uPic/Managers/DBManager.swift index 9d182772..5da2f4ad 100644 --- a/uPic/General/Managers/DBManager.swift +++ b/uPic/Managers/DBManager.swift @@ -26,8 +26,10 @@ public class DBManager { print("[WCDB][ERROR] \(error.description)") } }) + debugPrintOnly("数据库地址:\(Constants.CachePath.databasePath)") database = Database(withPath: Constants.CachePath.databasePath) createHistoryTable() + createOutputFormatTable() } deinit { @@ -82,3 +84,58 @@ extension DBManager { try? database.delete(fromTable: Constants.CachePath.historyTableName, where: nil, orderBy: [HistoryThumbnailModel.Properties.identifier.asOrder(by: .ascending)], limit: k) } } + +// MARK: OutputFormat +extension DBManager { + private func createOutputFormatTable() { + do { + try database.create(table: Constants.CachePath.outputFormatTableTableName, of: OutputFormatModel.self) + } catch let error as NSError { + print ("Error: \(error.domain)") + } + } + + func insertOutputFormat(_ model: OutputFormatModel) { + do { + try database.insert(objects: model, intoTable: Constants.CachePath.outputFormatTableTableName) + } catch let error as NSError { + print ("Error: \(error.domain)") + } + } + + func saveOutputFormats(_ models: [OutputFormatModel]) { + do { + try database.delete(fromTable: Constants.CachePath.outputFormatTableTableName) + try database.insert(objects: models, intoTable: Constants.CachePath.outputFormatTableTableName) + } catch let error as NSError { + print ("Error: \(error.domain)") + } + } + + func getOutputFormatList() -> [OutputFormatModel] { + var list: [OutputFormatModel] = [] + do { + list = try database.getObjects(on: OutputFormatModel.Properties.all, fromTable: Constants.CachePath.outputFormatTableTableName, orderBy: [OutputFormatModel.Properties.identifier.asOrder(by: .ascending)]) + + // 检查是否存在输出格式数据 + if (list.count == 0) { + list = OutputFormatModel.getDefaultOutputFormats() + saveOutputFormats(list) + } + } catch let error as NSError { + print ("Error: \(error.domain)") + } + return list + } + + func getOutputFormat(_ identifier: Int) -> OutputFormatModel? { + return try? database.getObject(on: OutputFormatModel.Properties.all, fromTable: Constants.CachePath.outputFormatTableTableName, where: OutputFormatModel.Properties.identifier == identifier) + } + + func deleteOutputFormat(_ identifier: Int) { + try? database.delete(fromTable: Constants.CachePath.outputFormatTableTableName, + where: OutputFormatModel.Properties.identifier == identifier, + orderBy: [OutputFormatModel.Properties.identifier.asOrder(by: .ascending)] + ) + } +} diff --git a/uPic/Managers/DiskPermissionManager.swift b/uPic/Managers/DiskPermissionManager.swift new file mode 100644 index 00000000..cd4bd55a --- /dev/null +++ b/uPic/Managers/DiskPermissionManager.swift @@ -0,0 +1,160 @@ +// +// DiskPermissionManager.swift +// uPic +// +// Created by Svend Jin on 2021/01/19. +// Copyright © 2021 Svend Jin. All rights reserved. +// + +import Foundation +import Cocoa + +public class DiskPermissionManager { + + // static + public static var shared = DiskPermissionManager() + + // 储存当前开始授权访问的 URL 对象 + private var workingDirectoryBookmarkUrl: URL? + + + private func promptForWorkingDirectoryPermission(for directoryURL: URL = URL(fileURLWithPath: "/", isDirectory: true)) -> URL? { + let openPanel = NSOpenPanel() + openPanel.message = "Authorize".localized + openPanel.prompt = "Authorize".localized + openPanel.allowedFileTypes = ["none"] + openPanel.allowsOtherFileTypes = false + openPanel.canChooseFiles = false + openPanel.canCreateDirectories = false + openPanel.canChooseDirectories = true + openPanel.directoryURL = directoryURL + + openPanel.runModal() + return openPanel.urls.first + } + + private func saveBookmarkData(for workDir: URL, defaultKey: DefaultsKey) { + do { + let bookmarkData = try workDir.bookmarkData(options: .withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil) + + // save in UserDefaults + Defaults[defaultKey] = bookmarkData + } catch { + print("Failed to save bookmark data for \(workDir)", error) + } + } + + private func restoreFileAccess(with bookmarkData: Data, defaultKey: DefaultsKey) -> URL? { + do { + var isStale = false + let url = try URL(resolvingBookmarkData: bookmarkData, options: .withSecurityScope, relativeTo: nil, bookmarkDataIsStale: &isStale) + if isStale { + // bookmarks could become stale as the OS changes + print("Bookmark is stale, need to save a new one... ") + saveBookmarkData(for: url, defaultKey: defaultKey) + } + return url + } catch { + print("Error resolving bookmark:", error) + return nil + } + } + +} + +// Utils +extension DiskPermissionManager { + +// func initializeRequestDiskPermissions() { +// if !Defaults[.requestedAuthorization] { +// Defaults[.requestedAuthorization] = true +// alertInfo(withText: "Full Disk Access".localized, withMessage: "Full Disk Access Message".localized, oKButtonTitle: "Authorize".localized, cancelButtonTitle: "Later".localized){ [self] in +// requestFullDiskPermissions() +// } +// } else { +// guard let data = Defaults[.workingDirectoryBookmark], let url = restoreFileAccess(with: data) else { +// return +// } +// _ = url.startAccessingSecurityScopedResource() +// } +// +// } + + func checkFullDiskAuthorizationStatus() -> Bool { + guard let data = Defaults[.rootDirectoryBookmark] else { + return false + } + do { + var isStale = true + let url = try URL(resolvingBookmarkData: data, options: .withSecurityScope, relativeTo: nil, bookmarkDataIsStale: &isStale) + if isStale { + // bookmarks could become stale as the OS changes + print("Bookmark is stale, need to save a new one... ") + return false + } + return url.path == "/" + } catch { + print("Error resolving bookmark:", error) + return false + } + } + + func requestFullDiskPermissions() { + debugPrintOnly("开始授权根目录权限") + guard let url = self.promptForWorkingDirectoryPermission() else { + return + } + self.saveBookmarkData(for: url, defaultKey: .rootDirectoryBookmark) + debugPrintOnly("授权根目录权限成功") + } + + func cancelFullDiskPermissions() { + debugPrintOnly("取消授权根目录权限") + Defaults[.rootDirectoryBookmark] = nil + debugPrintOnly("取消根目录权限成功") + } + + func requestHomeDirectoryPermissions() { + debugPrintOnly("开始授权主目录权限") + guard let url = self.promptForWorkingDirectoryPermission(for: URL(fileURLWithPath: "~/", isDirectory: true)) else { + return + } + self.saveBookmarkData(for: url, defaultKey: .homeDirectoryBookmark) + debugPrintOnly("授权主目录权限成功") + } + + // 获取安全授权,根目录授权优先获取,无根目录书签时获取主目录书签 + func startDirectoryAccessing() -> Bool { + debugPrintOnly("开始获取安全授权") + + stopDirectoryAccessing() + + // 获取根目录授权书签 + if let data = Defaults[.rootDirectoryBookmark], let url = restoreFileAccess(with: data, defaultKey: .rootDirectoryBookmark) { + + workingDirectoryBookmarkUrl = url + let flag = url.startAccessingSecurityScopedResource() + debugPrintOnly("开始获取安全授权完成--根目录") + return flag + } else if let data = Defaults[.homeDirectoryBookmark], let url = restoreFileAccess(with: data, defaultKey: .homeDirectoryBookmark) { + // 获取主目录授权书签 + + workingDirectoryBookmarkUrl = url + let flag = url.startAccessingSecurityScopedResource() + debugPrintOnly("开始获取安全授权完成--用户主目录") + return flag + } + + return false + } + + func stopDirectoryAccessing() { + debugPrintOnly("开始停止获取安全授权") + guard let url = workingDirectoryBookmarkUrl else { + return + } + url.stopAccessingSecurityScopedResource() + workingDirectoryBookmarkUrl = nil + debugPrintOnly("停止获取安全授权完成") + } +} diff --git a/uPic/Managers/WindowManager.swift b/uPic/Managers/WindowManager.swift new file mode 100644 index 00000000..e5c47d33 --- /dev/null +++ b/uPic/Managers/WindowManager.swift @@ -0,0 +1,39 @@ +// +// WindowManager.swift +// uPic +// +// Created by Licardo on 2021/1/20. +// Copyright © 2021 Svend Jin. All rights reserved. +// + +import Cocoa + +class WindowManager { + static let shared = WindowManager() + init() { + print("Class 'WindowManager' is initialized") + } +} + +extension WindowManager { + func instantiateControllerFromStoryboard(storyboard name: String, withIdentifier identifier: String) -> Controller { + let storyboard = NSStoryboard(name: name, bundle: nil) + guard let controller = storyboard.instantiateController(withIdentifier: identifier) as? Controller else { + fatalError("Can't find Controller: \(identifier)") + } + return controller + } + + // 显示对应 Identifier 的窗口 + func showWindow(storyboard name: String, withIdentifier identifier: String, withTitle title: String? = nil) -> NSWindowController { + let windowController = instantiateControllerFromStoryboard(storyboard: name, withIdentifier: identifier) as NSWindowController + if let windowTitle = title { + windowController.window?.title = windowTitle + } + + windowController.showWindow(self) + windowController.window?.makeKeyAndOrderFront(self) + NSApp.activate(ignoringOtherApps: true) + return windowController + } +} diff --git a/uPic/Managers/emplate/DiskPermissionManager.swift b/uPic/Managers/emplate/DiskPermissionManager.swift new file mode 100644 index 00000000..c7fa1a7b --- /dev/null +++ b/uPic/Managers/emplate/DiskPermissionManager.swift @@ -0,0 +1,9 @@ +// +// DiskPermissionManager.swift +// uPic +// +// Created by Svend Jin on 2021/1/19. +// Copyright © 2021 Svend Jin. All rights reserved. +// + +import Foundation diff --git a/uPic/Models/Aliyun/AliyunHostConfig.swift b/uPic/Models/Aliyun/AliyunHostConfig.swift index 53a6cfc0..dacb3644 100644 --- a/uPic/Models/Aliyun/AliyunHostConfig.swift +++ b/uPic/Models/Aliyun/AliyunHostConfig.swift @@ -60,9 +60,7 @@ class AliyunHostConfig: HostConfig { } let data = str.data(using: String.Encoding.utf8) let json = try! JSON(data: data!) - /// FIXME: 将旧版区域转为新版格式,几个版本的迭代后需删除 - config.region = AliyunRegion.upgradeFromOld(json["region"].stringValue) - // config.region = json["region"].stringValue + config.region = json["region"].stringValue config.bucket = json["bucket"].stringValue config.accessKey = json["accessKey"].stringValue config.secretKey = json["secretKey"].stringValue diff --git a/uPic/Models/Aliyun/AliyunRegion.swift b/uPic/Models/Aliyun/AliyunRegion.swift index 8bee2dca..7787d138 100644 --- a/uPic/Models/Aliyun/AliyunRegion.swift +++ b/uPic/Models/Aliyun/AliyunRegion.swift @@ -18,9 +18,12 @@ class AliyunRegion { "oss-cn-beijing": ["cname": "华北 2(北京)"], "oss-cn-zhangjiakou": ["cname": "华北 3(张家口)"], "oss-cn-huhehaote": ["cname": "华北 5(呼和浩特)"], + "oss-cn-wulanchabu": ["cname": "华北 6(乌兰察布)"], "oss-cn-shenzhen": ["cname": "华南 1(深圳)"], + "oss-cn-heyuan": ["cname": "华南 2(河源)"], + "oss-cn-guangzhou": ["cname": "华南 3(广州)"], "oss-cn-chengdu": ["cname": "西南 1(成都)"], - "oss-cn-hongkong": ["cname": "香港"], + "oss-cn-hongkong": ["cname": "中国(香港)"], "oss-us-west-1": ["cname": "美国西部 1(硅谷)"], "oss-us-east-1": ["cname": "美国东部 1(弗吉尼亚)"], "oss-ap-southeast-1": ["cname": "亚太东南 1(新加坡)"], @@ -54,17 +57,4 @@ class AliyunRegion { } return AliyunRegion.allRegion.keys.first! } - - /// FIXME: 将旧版区域转为新版格式,几个版本的迭代后需删除 - public static func upgradeFromOld(_ oldRegion: String) -> String { - if (oldRegion.starts(with: "oss-")) { - return oldRegion - } - - if oldRegion.isEmpty { - return "" - } - return "oss-\(oldRegion.replacingOccurrences(of: "_", with: "-"))" - - } } diff --git a/uPic/Models/Aliyun/AliyunUtil.swift b/uPic/Models/Aliyun/AliyunUtil.swift index 20ff3966..0677aac6 100644 --- a/uPic/Models/Aliyun/AliyunUtil.swift +++ b/uPic/Models/Aliyun/AliyunUtil.swift @@ -29,7 +29,7 @@ public class AliyunUtil { static func computeSignature(accessKeySecret: String, encodePolicy: String) -> String { - return encodePolicy.calculateHMACByKey(key: accessKeySecret).toBase64() ?? "" + return encodePolicy.calculateHMACByKey(key: accessKeySecret).toBase64() } static func computeUrl(bucket: String, region: String) -> String { diff --git a/uPic/Models/BaseUploader.swift b/uPic/Models/BaseUploader.swift index 3b3f874c..89941299 100644 --- a/uPic/Models/BaseUploader.swift +++ b/uPic/Models/BaseUploader.swift @@ -37,7 +37,8 @@ class BaseUploader { if thumbnailFileData == nil { return } - + + let size = thumbnailFileData.count var thumbnailData: Data? var previewWidth: CGFloat = 0 var previewHeight: CGFloat = 0 @@ -72,6 +73,8 @@ class BaseUploader { previewModel.previewWidth = Double(previewWidth) previewModel.previewHeight = Double(previewHeight) previewModel.thumbnailData = thumbnailData + previewModel.size = size + previewModel.host = Defaults[.defaultHostId] previewModel.isImage = isImage ConfigManager.shared.addHistory(previewModel) diff --git a/uPic/Models/BaseUploaderUtil.swift b/uPic/Models/BaseUploaderUtil.swift index 6ac68027..217ebbff 100644 --- a/uPic/Models/BaseUploaderUtil.swift +++ b/uPic/Models/BaseUploaderUtil.swift @@ -243,22 +243,17 @@ class BaseUploaderUtil { /// Format output URL /// - Parameter url: Original url /// - Parameter outputType: output type - static func formatOutputURL(_ url: String, _ outputType: OutputType? = nil) -> String { - var outputType: OutputType? = outputType - if outputType == nil { - outputType = ConfigManager.shared.getOutputType() - } - - return outputType!.formatUrl(url) + static func formatOutputURL(_ url: String, _ outputType: OutputFormatModel? = nil) -> String { + return OutputFormatModel.formatUrl(url, outputFormat: outputType) } /// Format output URL /// - Parameter urls: Original urls /// - Parameter outputType: output type - static func formatOutputUrls(_ urls: [String], _ outputType: OutputType? = nil) -> [String] { + static func formatOutputUrls(_ urls: [String], _ outputType: OutputFormatModel? = nil) -> [String] { let outputUrls = urls.map{ (item) in - return BaseUploaderUtil.formatOutputURL(item, outputType) + return OutputFormatModel.formatUrl(item, outputFormat: outputType) } return outputUrls } diff --git a/uPic/Models/OutputFormatModel.swift b/uPic/Models/OutputFormatModel.swift new file mode 100644 index 00000000..12a22dfd --- /dev/null +++ b/uPic/Models/OutputFormatModel.swift @@ -0,0 +1,78 @@ +// +// OutputType.swift +// uPic +// +// Created by Svend Jin on 2021/01/19. +// Copyright © 2021 Svend Jin. All rights reserved. +// + +import Foundation +import WCDBSwift + +class OutputFormatModel: TableCodable { + var identifier: Int? = nil + var name: String = "" + var value: String = "" + + enum CodingKeys: String, CodingTableKey { + typealias Root = OutputFormatModel + static let objectRelationalMapping = TableBinding(CodingKeys.self) + case identifier + case name + case value + + + + static var columnConstraintBindings: [CodingKeys: ColumnConstraintBinding]? { + return [ + identifier: ColumnConstraintBinding(isPrimary: true), + ] + } + } + + init() { + self.name = "" + self.value = "" + } + + init(name: String , value: String) { + self.name = name + self.value = value + } + + public var debugDescription: String { + return "ID: \(identifier ?? 0), NAME: \(name), VALUE: \(value)" + } + + static func getDefaultOutputFormats() -> [OutputFormatModel] { + return [ + OutputFormatModel(name: "URL", value: "{url}"), + OutputFormatModel(name: "HTML", value: "\"{filename}\"/"), + OutputFormatModel(name: "Markdown", value: "![{filename}]({url})"), + OutputFormatModel(name: "UBB", value: "[img]{url}[/img]") + ] + } + + static func formatUrl(_ url: String, outputFormat: OutputFormatModel?) -> String { + var formatUrl = url + if Defaults[.outputFormatEncoded] { + formatUrl = url.urlEncoded() + } + var filename = url.lastPathComponent.deletingPathExtension.trim() + let tempArr = filename.components(separatedBy: .whitespaces).map{ $0.trim() }.filter{ !$0.isEmpty } + filename = tempArr.joined(separator: "") + + var output = outputFormat + if output == nil { + output = ConfigManager.shared.getOutputType() + } + + if output == nil { + return formatUrl + } else { + return output!.value.replacingOccurrences(of: "{url}", with: formatUrl).replacingOccurrences(of: "{filename}", with: filename) + } + + + } +} diff --git a/uPic/Models/OutputType.swift b/uPic/Models/OutputType.swift deleted file mode 100644 index 3782cbc8..00000000 --- a/uPic/Models/OutputType.swift +++ /dev/null @@ -1,73 +0,0 @@ -// -// OutputType.swift -// uPic -// -// Created by Svend Jin on 2019/12/26. -// Copyright © 2019 Svend Jin. All rights reserved. -// - -import Foundation - -enum OutputType: Int { - case url = 0 - case html = 1 - case markdown = 2 - case ubb = 3 - - init(value: Int? = 0) { - switch value { - case 1: self = .html - case 2: self = .markdown - case 3: self = .ubb - default: self = .url - } - } - - init(value: String? = "url") { - switch value { - case "html": self = .html - case "markdown": self = .markdown - case "md": self = .markdown - case "ubb": self = .ubb - default: self = .url - } - } - - var title: String { - switch self { - case .url: - return "URL" - case .html: - return "HTML" - case .markdown: - return "Markdown" - case .ubb: - return "UBB" - } - } - - func formatUrl(_ url: String) -> String { - var formatUrl = url - if Defaults[.outputFormatEncoded]! { - formatUrl = url.urlEncoded() - } - var filename = url.lastPathComponent.deletingPathExtension.trim() - let tempArr = filename.components(separatedBy: .whitespaces).map{ $0.trim() }.filter{ !$0.isEmpty } - filename = tempArr.joined(separator: "") - var outputUrl = "" - switch self { - case .html: - outputUrl = "\(filename)" - break - case .markdown: - outputUrl = "![\(filename)](\(formatUrl))" - break - case .ubb: - outputUrl = "[img]\(formatUrl)[/img]" - break - default: - outputUrl = formatUrl - } - return outputUrl - } -} diff --git a/uPic/Models/Qiniu/QiniuUtil.swift b/uPic/Models/Qiniu/QiniuUtil.swift index ef26a2c8..68169572 100644 --- a/uPic/Models/Qiniu/QiniuUtil.swift +++ b/uPic/Models/Qiniu/QiniuUtil.swift @@ -26,7 +26,7 @@ public class QiniuUtil { let hmac = base64String.calculateHMACByKey(key: secretKey) let encodeString = hmac.toBase64() - let encodedSignString = encodeString!.urlSafeBase64() + let encodedSignString = encodeString.urlSafeBase64() return "\(accessKey):\(encodedSignString):\(base64String)" } } diff --git a/uPic/Models/S3/S3HostConfig.swift b/uPic/Models/S3/S3HostConfig.swift index 421ec7b4..a800a899 100644 --- a/uPic/Models/S3/S3HostConfig.swift +++ b/uPic/Models/S3/S3HostConfig.swift @@ -11,7 +11,7 @@ import SwiftyJSON @objcMembers class S3HostConfig: HostConfig { - dynamic var region: String = "" + dynamic var region: String? dynamic var endpoint: String? dynamic var bucket: String = "" dynamic var accessKey: String = "" diff --git a/uPic/Models/S3/S3Region.swift b/uPic/Models/S3/S3Region.swift index 20c76640..a22b981c 100644 --- a/uPic/Models/S3/S3Region.swift +++ b/uPic/Models/S3/S3Region.swift @@ -19,23 +19,24 @@ public class S3Region { "us-east-2": ["cname": "美国东部(俄亥俄州)", "name": "US East (Ohio)"], "us-west-1": ["cname": "美国西部(加利福尼亚北部)", "name": "US West (N. California)"], "us-west-2": ["cname": "美国西部(俄勒冈)", "name": "US West (Oregon)"], + "af-south-1": ["cname": "非洲(开普敦)", "name": "Africa (Cape Town)"], + "ap-east-1": ["cname": "亚太地区(香港)", "name": "Asia Pacific (Hong Kong)"], "ap-south-1": ["cname": "亚太地区(孟买)", "name": "Asia Pacific (Mumbai)"], + "ap-northeast-3": ["cname": "亚太区域 (大阪当地)", "name": "Asia Pacific (Osaka-Local)"], "ap-northeast-2": ["cname": "亚太区域(首尔)", "name": "Asia Pacific (Seoul)"], "ap-southeast-1": ["cname": "亚太区域(新加坡)", "name": "Asia Pacific (Singapore)"], "ap-southeast-2": ["cname": "亚太区域(悉尼)", "name": "Asia Pacific (Sydney)"], "ap-northeast-1": ["cname": "亚太区域(东京)", "name": "Asia Pacific (Tokyo)"], - "ap-northeast-3": ["cname": "亚太区域 (大阪当地)", "name": "Asia Pacific (Osaka-Local)"], - "ap-east-1": ["cname": "亚太地区(香港)", "name": "Asia Pacific (Hong Kong)"], "ca-central-1": ["cname": "加拿大 (中部)", "name": "Canada (Central)"], + // + "eu-central-1": ["cname": "欧洲(法兰克福)", "name": "Europe (Frankfurt)"], "eu-west-1": ["cname": "欧洲(爱尔兰)", "name": "Europe (Ireland)"], - "eu-west-3": ["cname": "欧洲 (巴黎)", "name": "Europe (Paris)"], "eu-west-2": ["cname": "欧洲(伦敦)", "name": "Europe (London)"], - "eu-central-1": ["cname": "欧洲(法兰克福)", "name": "Europe (Frankfurt)"], - "eu-north-1": ["cname": "欧洲(斯德哥尔摩)", "name": "Europe (Stockholm)"], "eu-south-1": ["cname": "欧洲(米兰)", "name": "Europe (Milan)"], - "sa-east-1": ["cname": "南美洲(圣保罗)", "name": "South America (São Paulo)"], + "eu-west-3": ["cname": "欧洲 (巴黎)", "name": "Europe (Paris)"], + "eu-north-1": ["cname": "欧洲(斯德哥尔摩)", "name": "Europe (Stockholm)"], "me-south-1": ["cname": "中东(巴林)", "name": "Middle East (Bahrain)"], - "af-south-1": ["cname": "非洲(开普敦)", "name": "Africa (Cape Town)"], + "sa-east-1": ["cname": "南美洲(圣保罗)", "name": "South America (São Paulo)"], // 中国 "cn-north-1": ["cname": "中国(北京)", "name": "China (Beijing)"], "cn-northwest-1": ["cname": "中国 (宁夏)", "name": "China (Ningxia)"] @@ -54,8 +55,8 @@ public class S3Region { return regionDict["name"] ?? key } - public static func endPoint(_ key: String) -> String { - if key.isEmpty { + public static func endPoint(_ key: String?) -> String { + guard let key = key, !key.isEmpty else { return "" } if key == "cn-north-1" || key == "cn-northwest-1" { diff --git a/uPic/Models/S3/S3Uploader.swift b/uPic/Models/S3/S3Uploader.swift index 42dab2b0..4b6e24dd 100644 --- a/uPic/Models/S3/S3Uploader.swift +++ b/uPic/Models/S3/S3Uploader.swift @@ -32,11 +32,13 @@ class S3Uploader: BaseUploader { let accessKey = config.accessKey let secretKey = config.secretKey let domain = config.domain - let region = AWSSDKSwiftCore.Region(rawValue: config.region) + var region = config.region == nil ? .useast1 : AWSSDKSwiftCore.Region(rawValue: config.region!) var endpoint = config.endpoint - if !customize { + if customize { + region = .useast1 + } else { endpoint = S3Region.endPoint(config.region) } @@ -85,6 +87,8 @@ class S3Uploader: BaseUploader { case .failure(let e): if let s3Error = e as? S3ErrorType { super.faild(errorMsg: s3Error.description) + } else if let s3Error = e as? AWSResponseError { + super.faild(errorMsg: s3Error.message) } else { super.faild(errorMsg: e.localizedDescription) } diff --git a/uPic/Models/S3/S3Util.swift b/uPic/Models/S3/S3Util.swift index d55b91a9..21e09663 100644 --- a/uPic/Models/S3/S3Util.swift +++ b/uPic/Models/S3/S3Util.swift @@ -12,7 +12,7 @@ import SwiftyJSON public class S3Util { private static let schema = "https://" - static func computeUrl(bucket: String, region: String, customize: Bool, endpoint: String?) -> String { + static func computeUrl(bucket: String, region: String?, customize: Bool, endpoint: String?) -> String { if customize, let endpoint = endpoint { if (endpoint.last == "/") { diff --git a/uPic/Models/Tencent/TencentHostConfig.swift b/uPic/Models/Tencent/TencentHostConfig.swift index a0d4fd84..d5692bcf 100644 --- a/uPic/Models/Tencent/TencentHostConfig.swift +++ b/uPic/Models/Tencent/TencentHostConfig.swift @@ -60,10 +60,8 @@ class TencentHostConfig: HostConfig { } let data = str.data(using: String.Encoding.utf8) let json = try! JSON(data: data!) - // FIXME: 将旧版区域转为新版格式,几个版本的迭代后需删除 - config.region = TencentRegion.upgradeFromOld(json["region"].stringValue) -// config.region = json["region"].stringValue + config.region = json["region"].stringValue config.bucket = json["bucket"].stringValue config.secretId = json["secretId"].stringValue config.secretKey = json["secretKey"].stringValue diff --git a/uPic/Models/Tencent/TencentRegion.swift b/uPic/Models/Tencent/TencentRegion.swift index a9738b5d..71690fa9 100644 --- a/uPic/Models/Tencent/TencentRegion.swift +++ b/uPic/Models/Tencent/TencentRegion.swift @@ -15,14 +15,14 @@ class TencentRegion { "ap-beijing-1": ["cname": "北京一区"], "ap-beijing": ["cname": "北京"], "ap-nanjing": ["cname": "南京"], - "ap-shanghai": ["cname": "上海(华东)"], - "ap-guangzhou": ["cname": "广州(华南)"], - "ap-chengdu": ["cname": "成都(西南)"], + "ap-shanghai": ["cname": "上海"], + "ap-guangzhou": ["cname": "广州"], + "ap-chengdu": ["cname": "成都"], "ap-chongqing": ["cname": "重庆"], "ap-shenzhen-fsi": ["cname": "深圳金融"], "ap-shanghai-fsi": ["cname": "上海金融"], "ap-beijing-fsi": ["cname": "北京金融"], - "ap-hongkong": ["cname": "香港"], + "ap-hongkong": ["cname": "中国香港"], "ap-singapore": ["cname": "新加坡"], "ap-mumbai": ["cname": "孟买"], "ap-seoul": ["cname": "首尔"], @@ -55,13 +55,4 @@ class TencentRegion { } return AliyunRegion.allRegion.keys.first! } - - /// FIXME: 将旧版区域转为新版格式,几个版本的迭代后需删除 - public static func upgradeFromOld(_ oldRegion: String) -> String { - if oldRegion.isEmpty { - return "" - } - return oldRegion.replacingOccurrences(of: "_", with: "-") - - } } diff --git a/uPic/Models/UpYun/UpYunUploader.swift b/uPic/Models/UpYun/UpYunUploader.swift index 584f6726..b25f653d 100644 --- a/uPic/Models/UpYun/UpYunUploader.swift +++ b/uPic/Models/UpYun/UpYunUploader.swift @@ -58,7 +58,7 @@ class UpYunUploader: BaseUploader { let signatureParams = ["POST", "/\(bucket)", policy] let signatureStr = signatureParams.joined(separator: "&") let hmac = signatureStr.calculateHMACByKey(key: password.toMd5()) - let signature = hmac.toBase64()! + let signature = hmac.toBase64() // MARK: 生成 authorization let authorization = "UPYUN \(operatorName):\(signature)" diff --git a/uPic/Models/emplate/OutputFormat.swift b/uPic/Models/emplate/OutputFormat.swift new file mode 100644 index 00000000..3cdf275d --- /dev/null +++ b/uPic/Models/emplate/OutputFormat.swift @@ -0,0 +1,9 @@ +// +// OutputFormat.swift +// uPic +// +// Created by Svend Jin on 2021/1/18. +// Copyright © 2021 Svend Jin. All rights reserved. +// + +import Foundation diff --git a/uPic/Notifier/Notifier.swift b/uPic/Notifier/Notifier.swift index d6fe5360..3453115c 100644 --- a/uPic/Notifier/Notifier.swift +++ b/uPic/Notifier/Notifier.swift @@ -36,8 +36,7 @@ public extension Notifier where Notification.RawValue == String { static func postNotification(_ notification: Notification, object: String? = nil, userInfo: [AnyHashable: Any]? = nil) { let name = nameFor(notification: notification) - DistributedNotificationCenter.default() - .postNotificationName(NSNotification.Name(rawValue: name), object: object, userInfo: userInfo, deliverImmediately: true) + NotificationCenter.default.post(name: NSNotification.Name(rawValue: name), object: object, userInfo: userInfo) } // addObserver @@ -45,8 +44,7 @@ public extension Notifier where Notification.RawValue == String { static func addObserver(observer: AnyObject, selector: Selector, notification: Notification, object: String? = nil) { let name = nameFor(notification: notification) - DistributedNotificationCenter.default() - .addObserver(observer, selector: selector, name: NSNotification.Name(rawValue: name), object: object) + NotificationCenter.default.addObserver(observer, selector: selector, name: NSNotification.Name(rawValue: name), object: object) } // removeObserver @@ -54,7 +52,6 @@ public extension Notifier where Notification.RawValue == String { static func removeObserver(observer: AnyObject, notification: Notification, object: String? = nil) { let name = nameFor(notification: notification) - DistributedNotificationCenter.default() - .removeObserver(observer, name: NSNotification.Name(rawValue: name), object: object) + NotificationCenter.default.removeObserver(observer, name: NSNotification.Name(rawValue: name), object: object) } } diff --git a/uPic/Script/AutoGenStrings.py b/uPic/Script/AutoGenStrings.py new file mode 100644 index 00000000..0e19aafd --- /dev/null +++ b/uPic/Script/AutoGenStrings.py @@ -0,0 +1,242 @@ +#!/usr/bin/env python +# encoding: utf-8 + +""" +AutoGenStrings.py +Created by linyu on 2015-02-13. +Modify by wz on 2017-06-02. +Copyright (c) 2017 __MyCompanyName__. All rights reserved. + +""" + +import imp +import sys +import os +import glob +import string +import re +import time + +imp.reload(sys) +sys.setdefaultencoding('utf-8') #设置默认编码,只能是utf-8,下面\u4e00-\u9fa5要求的 + +KTargetFile = '*.lproj/*.strings' + +KGenerateStringsFile = 'TempfileOfStoryboardNew.strings' + +ColonRegex = ur'["](.*?)["]' + +KeyParamRegex = ur'["](.*?)["](\s*)=(\s*)["](.*?)["];' + +AnotationRegexPrefix = ur'/(.*?)/' + +def getCharaset(string_txt): + filedata = bytearray(string_txt[:4]) + if len(filedata) < 4 : + return 0 + if (filedata[0] == 0xEF) and (filedata[1] == 0xBB) and (filedata[2] == 0xBF): + print 'utf-8' + return 1 + elif (filedata[0] == 0xFF) and (filedata[1] == 0xFE) and (filedata[2] == 0x00) and (filedata[3] == 0x00): + print 'utf-32/UCS-4,little endian' + return 3 + elif (filedata[0] == 0x00) and (filedata[1] == 0x00) and (filedata[2] == 0xFE) and (filedata[3] == 0xFF): + print 'utf-32/UCS-4,big endian' + return 3 + elif (filedata[0] == 0xFE) and (filedata[1] == 0xFF): + print 'utf-16/UCS-2,little endian' + return 2 + elif (filedata[0] == 0xFF) and (filedata[1] == 0xFE): + print 'utf-16/UCS-2,big endian' + return 2 + else: + print 'can not recognize!' + return 0 + +def decoder(string_txt): + var = getCharaset(string_txt) + if var == 1: + return string_txt.decode("utf-8") + elif var == 2: + return string_txt.decode("utf-16") + elif var == 3: + return string_txt.decode("utf-32") + else: + return string_txt + +def constructAnotationRegex(str): + return AnotationRegexPrefix + '\n' + str + +def getAnotationOfString(string_txt,suffix): + anotationRegex = constructAnotationRegex(suffix) + anotationMatch = re.search(anotationRegex,string_txt) + anotationString = '' + if anotationMatch: + match = re.search(AnotationRegexPrefix,anotationMatch.group(0)) + if match: + anotationString = match.group(0) + return anotationString + +def compareWithFilePath(newStringPath,originalStringPath): + print(newStringPath) + print(originalStringPath) + #read newStringfile + nspf=open(newStringPath,"r") + #newString_txt = str(nspf.read(5000000)).decode("utf-16") + newString_txt = decoder(str(nspf.read(5000000))) + nspf.close() + newString_dic = {} + anotation_dic = {} + for stfmatch in re.finditer(KeyParamRegex , newString_txt): + linestr = stfmatch.group(0) + anotationString = getAnotationOfString(newString_txt,linestr) + linematchs = re.findall(ColonRegex, linestr) + if len(linematchs) == 2: + leftvalue = linematchs[0] + rightvalue = linematchs[1] + newString_dic[leftvalue] = rightvalue + anotation_dic[leftvalue] = anotationString + #read originalStringfile + ospf=open(originalStringPath,"r") + originalString_txt = decoder(str(ospf.read(5000000))) + ospf.close() + originalString_dic = {} + for stfmatch in re.finditer(KeyParamRegex , originalString_txt): + linestr = stfmatch.group(0) + linematchs = re.findall(ColonRegex, linestr) + if len(linematchs) == 2: + leftvalue = linematchs[0] + rightvalue = linematchs[1] + originalString_dic[leftvalue] = rightvalue + #compare and remove the useless param in original string + for key in originalString_dic: + if(key not in newString_dic): + keystr = '"%s"'%key + replacestr = '//'+keystr + match = re.search(replacestr , originalString_txt) + if match is None: + originalString_txt = originalString_txt.replace(keystr,replacestr) + #compare and add new param to original string + executeOnce = 1 + for key in newString_dic: + values = (key, newString_dic[key]) + if(key not in originalString_dic): + newline = '' + if executeOnce == 1: + timestamp = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())) + newline = '\n//##################################################################################\n' + newline +='//# AutoGenStrings '+timestamp+'\n' + newline +='//##################################################################################\n' + executeOnce = 0 + newline += '\n'+anotation_dic[key] + newline += '\n"%s" = "%s";\n'%values + originalString_txt += newline + #write into origial file + sbfw=open(originalStringPath,"w") + sbfw.write(originalString_txt) + sbfw.close() + +def extractFileName(file_path): + seg = file_path.split('/') + lastindex = len(seg) - 1 + return seg[lastindex] + +def extractFilePrefix(file_path): + seg = file_path.split('/') + lastindex = len(seg) - 1 + prefix = seg[lastindex].split('.')[0] + return prefix + +def generateStoryboardStringsfile(storyboard_path,tempstrings_path): + cmdstring = 'ibtool '+storyboard_path+' --generate-strings-file '+tempstrings_path + if os.system(cmdstring) == 0: + return 1 + +def generateLocalizableFiles(filePath ,sourceFilePath): + print ('-------> sourceFilePath: ' + sourceFilePath + ' filePath: ' + filePath) + sourceFile_list = glob.glob(sourceFilePath) + if len(sourceFile_list) == 0: + print 'error dictionary,you should choose the dic upper the Base.lproj' + return + targetFilePath = filePath + '/' + KTargetFile + targetFile_list = glob.glob(targetFilePath) + tempFile_Path = filePath + '/' + KGenerateStringsFile + if len(targetFile_list) == 0: + print 'error framework , no .lproj dic was found' + return + for sourcePath in sourceFile_list: + sourceprefix = extractFilePrefix(sourcePath) + sourcename = extractFileName(sourcePath) + print 'init with %s'%sourcename + if generateStoryboardStringsfile(sourcePath,tempFile_Path) == 1: + print '- - genstrings %s successfully'%sourcename + for targetPath in targetFile_list: + targetprefix = extractFilePrefix(targetPath) + targetname = extractFileName(targetPath) + if cmp(sourceprefix,targetprefix) == 0: + print '- - dealing with %s'%targetPath + compareWithFilePath(tempFile_Path,targetPath) + print 'finish with %s'%sourcename + os.remove(tempFile_Path) + else: + print '- - genstrings %s error'%sourcename + + + +#根据项目根目录遍历所有的xib和storyboard的文件路径 +def getAllNibSrcPathFor(dir): + sourceFilePaths = [] + #三个参数:1.父目录 2.所有文件夹名字(不含路径) 3.所有文件名字 + for parent,dirnames,filenames in os.walk(dir): + for filename in filenames: #输出文件信息 + print filename + if (('.xib' in filename) | ('.storyboard' in filename)): + filePath = os.path.join(parent) + if filePath not in sourceFilePaths: + sourceFilePaths.append(filePath) + #print sourceFilePaths + return sourceFilePaths + + +def main(): + print(sys.argv) + if len(sys.argv) == 1 : + #如果在终端运行,注意要修改自己需要国际化的项目文件夹的路径! + filePath = '/Users/wz/Documents/git/AutoLocalization/AutoLocalization/' + else: + filePath = sys.argv[1] + # if filePath == None or filePath == '': + # print('[Error] filePath can not None!') + # exit(1) + sourceFilePaths = getAllNibSrcPathFor(filePath) + + # *.storyboard 国际化 + for sourceFilePath in sourceFilePaths: + baseStrIdx = 0 + try: + baseStrIdx = sourceFilePath.index('Base.lproj') + except Exception as e: + pass + else: + sourceFilePathName = sourceFilePath + '/*.storyboard' + upperFilePath = sourceFilePath[0:(baseStrIdx-1)] + #print upperFilePath + generateLocalizableFiles(upperFilePath, sourceFilePathName) + # *.xib 国际化 + for sourceFilePath in sourceFilePaths: + baseStrIdx = 0 + try: + baseStrIdx = sourceFilePath.index('Base.lproj') + except Exception as e: + pass + else: + sourceFilePathName = sourceFilePath + '/*.xib' + upperFilePath = sourceFilePath[0:(baseStrIdx-1)] + #print upperFilePath + generateLocalizableFiles(upperFilePath, sourceFilePathName) + + + + +if __name__ == '__main__': + main() diff --git a/uPic/Views/StatusMenuController.swift b/uPic/StatusMenuController.swift similarity index 88% rename from uPic/Views/StatusMenuController.swift rename to uPic/StatusMenuController.swift index dcd68dd3..42d1c088 100644 --- a/uPic/Views/StatusMenuController.swift +++ b/uPic/StatusMenuController.swift @@ -122,21 +122,6 @@ class StatusMenuController: NSObject, NSMenuDelegate { @IBAction func exportHostsMenuItemClicked(_ sender: NSMenuItem) { ConfigManager.shared.exportHosts() } - - // support -- paypal - @IBAction func paypalMenuItemClicked(_ sender: Any) { - (NSApplication.shared.delegate as? AppDelegate)?.sponsorByPaypal() - } - - // support -- alipay - @IBAction func alipayMenuItemClicked(_ sender: Any) { - (NSApplication.shared.delegate as? AppDelegate)?.sponsorByAlipay() - } - - // support -- wechat pay - @IBAction func wechatPayMenuItemClicked(_ sender: Any) { - (NSApplication.shared.delegate as? AppDelegate)?.sponsorByWechatPay() - } // quit app @IBAction func quitMenuItemClicked(_ sender: NSMenuItem) { @@ -161,6 +146,11 @@ class StatusMenuController: NSObject, NSMenuDelegate { } self.setDefaultHost(id: hostId) } + + // change current output + @objc func changeDefaultOutputFormat(_ sender: NSMenuItem) { + self.setDefaultOutput(id: sender.tag) + } // change compress factor @objc func changeCompressFactor(_ sender: NSMenuItem) { @@ -200,6 +190,13 @@ class StatusMenuController: NSObject, NSMenuDelegate { menuItem.target = self compressFactorMenuItem.submenu?.addItem(menuItem) } + + // TinyPNG +// let menuItem = NSMenuItem(title: "TinyPNG", action: #selector(changeCompressFactor(_:)), keyEquivalent: "") +// menuItem.tag = -1 +// menuItem.isEnabled = true +// menuItem.target = self +// compressFactorMenuItem.submenu?.addItem(menuItem) compressFactorMenuItem.submenu?.delegate = self self.refreshCompressFactor() @@ -259,18 +256,51 @@ class StatusMenuController: NSObject, NSMenuDelegate { // refresh output format to select func refreshOutputFormat() { - let outputType = ConfigManager.shared.getOutputType() - for item in outputFormatMenuItem.submenu!.items { - if item.tag == outputType.rawValue { + let outputFormatList = DBManager.shared.getOutputFormatList() + + outputFormatMenuItem.submenu?.removeAllItems() + for item in outputFormatList { + let menuItem = NSMenuItem(title: item.name, action: #selector(changeDefaultOutputFormat(_:)), keyEquivalent: "") + menuItem.identifier = NSUserInterfaceItemIdentifier("\(item.identifier ?? 0)") + menuItem.tag = item.identifier ?? 0 + menuItem.isEnabled = true + menuItem.target = self + outputFormatMenuItem.submenu?.addItem(menuItem) + } + outputFormatMenuItem.submenu?.delegate = self + + refreshDefaultOutputFormat() + } + + // refresh current format to select + func refreshDefaultOutputFormat() { + let defaultOutput = Defaults[.outputFormat] + + var hasDefault = false + let items = outputFormatMenuItem.submenu!.items + for item in items { + if item.tag == defaultOutput { item.state = .on + hasDefault = true + + } else { item.state = .off } } - let title = outputType.title - - self.setOutputFormatMenuTitle(factorTitle: title) + if let id = items.first?.tag, !hasDefault { + self.setDefaultOutput(id: id) + } + + if let output = ConfigManager.shared.getOutputType() { + self.setOutputFormatMenuTitle(factorTitle: output.name) + } + } + + func setDefaultOutput(id: Int) { + Defaults[.outputFormat] = id + self.refreshDefaultOutputFormat() } func setOutputFormatMenuTitle(factorTitle: String?) { @@ -297,7 +327,7 @@ class StatusMenuController: NSObject, NSMenuDelegate { } } - let title = Defaults[.outputFormatEncoded]! ? "On".localized : "Off".localized + let title = Defaults[.outputFormatEncoded] ? "On".localized : "Off".localized self.setOutputFormatEncodedMenuTitle(factorTitle: title) } diff --git a/uPic/Supporting Files/Info.plist b/uPic/Supporting Files/Info.plist index 81c77858..d050bf8b 100644 --- a/uPic/Supporting Files/Info.plist +++ b/uPic/Supporting Files/Info.plist @@ -44,18 +44,16 @@ NSAllowsArbitraryLoads + NSAppleScriptEnabled + NSHumanReadableCopyright - Copyright © 2020 Svend Jin. All rights reserved. + Copyright © 2021 Svend Jin. All rights reserved. NSMainStoryboardFile Main NSPrincipalClass NSApplication - SUEnableAutomaticChecks - - SUFeedURL - https://gee1k.github.io/uPic/appcast.xml - SUPublicEDKey - vUMkY2STUDaVpL98q1m9zE3VugD/sdejNO4MPo1hu5Y= + OSAScriptingDefinition + UPic.sdef TeamIdentifierPrefix $(TeamIdentifierPrefix) diff --git a/uPic/Supporting Files/uPic.entitlements b/uPic/Supporting Files/uPic.entitlements index c0baff1d..2cb223a6 100644 --- a/uPic/Supporting Files/uPic.entitlements +++ b/uPic/Supporting Files/uPic.entitlements @@ -2,10 +2,20 @@ + com.apple.security.app-sandbox + com.apple.security.application-groups $(TeamIdentifierPrefix)com.svend.uPic + com.apple.security.cs.disable-library-validation + + com.apple.security.files.bookmarks.app-scope + + com.apple.security.files.user-selected.read-write + + com.apple.security.network.client + com.apple.security.temporary-exception.mach-register.global-name com.apple.screencapture.interactive diff --git a/uPic/Supporting Files/uPicDebug.entitlements b/uPic/Supporting Files/uPicDebug.entitlements new file mode 100644 index 00000000..2cb223a6 --- /dev/null +++ b/uPic/Supporting Files/uPicDebug.entitlements @@ -0,0 +1,22 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.application-groups + + $(TeamIdentifierPrefix)com.svend.uPic + + com.apple.security.cs.disable-library-validation + + com.apple.security.files.bookmarks.app-scope + + com.apple.security.files.user-selected.read-write + + com.apple.security.network.client + + com.apple.security.temporary-exception.mach-register.global-name + com.apple.screencapture.interactive + + diff --git a/uPic/General/Utils/AppPublic.swift b/uPic/Utils/AppPublic.swift similarity index 86% rename from uPic/General/Utils/AppPublic.swift rename to uPic/Utils/AppPublic.swift index a18f0a50..b8b9ce45 100644 --- a/uPic/General/Utils/AppPublic.swift +++ b/uPic/Utils/AppPublic.swift @@ -37,3 +37,10 @@ func alertInfo(withText messageText: String, withMessage message: String, oKButt okHandler() } } + + +func debugPrintOnly(_ items: Any..., separator: String = " ", terminator: String = "\n") { + #if DEBUG + debugPrint(items, separator: separator, terminator: terminator) + #endif +} diff --git a/uPic/General/Constants.swift b/uPic/Utils/Constants.swift similarity index 92% rename from uPic/General/Constants.swift rename to uPic/Utils/Constants.swift index e34aaa99..0e476321 100644 --- a/uPic/General/Constants.swift +++ b/uPic/Utils/Constants.swift @@ -15,6 +15,7 @@ struct Constants { struct CachePath { static let historyTableName: String = "historyTable" + static let outputFormatTableTableName: String = "outputFormatTableTable" static var databasePath: String { let cachePaths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.cachesDirectory, FileManager.SearchPathDomainMask.userDomainMask, true) diff --git a/uPic/General/Utils/PreferenceKey.swift b/uPic/Utils/PreferenceKey.swift similarity index 84% rename from uPic/General/Utils/PreferenceKey.swift rename to uPic/Utils/PreferenceKey.swift index b1f80d49..86b7b42b 100644 --- a/uPic/General/Utils/PreferenceKey.swift +++ b/uPic/Utils/PreferenceKey.swift @@ -24,6 +24,10 @@ struct Keys { static let historyRecordPadding = "uPic_HistoryRecordPadding" static let historyRecordFileNameScrollSpeed = "uPic_HistoryRecordFileNameScrollSpeed" static let historyRecordFileNameScrollWaitTime = "uPic_HistoryRecordFileNameScrollWaitTime" + + static let requestedAuthorization = "uPic_RequestedAuthorization" + static let rootDirectoryBookmark = "uPic_RootDirectoryBookmark" + static let homeDirectoryBookmark = "uPic_HomeDirectoryBookmark" } class DefaultsKeys { @@ -51,7 +55,6 @@ extension DefaultsKeys { static let defaultHostId = DefaultsKey(Keys.defaultHostId) static let outputFormat = DefaultsKey(Keys.outputFormat) static let outputFormatEncoded = DefaultsKey(Keys.outputFormatEncoded) - static let historyList = DefaultsKey<[[String: Any]]>(Keys.historyList) static let historyLimit = DefaultsKey(Keys.historyLimit) static let compressFactor = DefaultsKey(Keys.compressFactor) static let historyRecordWidth = DefaultsKey(Keys.historyRecordWidth) @@ -60,15 +63,23 @@ extension DefaultsKeys { static let historyRecordPadding = DefaultsKey(Keys.historyRecordPadding) static let historyRecordFileNameScrollSpeed = DefaultsKey(Keys.historyRecordFileNameScrollSpeed) static let historyRecordFileNameScrollWaitTime = DefaultsKey(Keys.historyRecordFileNameScrollWaitTime) + + + // 是否是请求授权过 + static let requestedAuthorization = DefaultsKey(Keys.requestedAuthorization) + // 根目录授权书签 + static let rootDirectoryBookmark = DefaultsKey(Keys.rootDirectoryBookmark) + // 主目录授权书签 + static let homeDirectoryBookmark = DefaultsKey(Keys.homeDirectoryBookmark) } let Defaults = UserDefaults.standard extension UserDefaults { - subscript(key: DefaultsKey) -> Bool? { + subscript(key: DefaultsKey) -> Bool { get { - bool(forKey: key._key) + bool(forKey: key._key) } set { set(newValue, forKey: key._key) @@ -110,6 +121,15 @@ extension UserDefaults { set(newValue, forKey: key._key) } } + + subscript(key: DefaultsKey) -> Data? { + get { + return data(forKey: key._key) + } + set { + set(newValue, forKey: key._key) + } + } subscript(key: DefaultsKey<[Host]>) -> [Host]? { get { diff --git a/uPic/Utils/ScreenUtil.swift b/uPic/Utils/ScreenUtil.swift new file mode 100644 index 00000000..a953e89f --- /dev/null +++ b/uPic/Utils/ScreenUtil.swift @@ -0,0 +1,56 @@ +// +// ScreenUtil.swift +// uPic +// +// Created by Svend Jin on 2021/1/21. +// Copyright © 2021 Svend Jin. All rights reserved. +// + +import Cocoa + +class ScreenUtil { + static func screeningRecordPermissionCheck() -> Bool { + if #available(macOS 10.15, *) { + let runningApplication = NSRunningApplication.current + let processIdentifier = runningApplication.processIdentifier + guard let windows = CGWindowListCopyWindowInfo([.optionOnScreenOnly], kCGNullWindowID) + as? [[String: AnyObject]], + let _ = windows.first(where: { (window) -> Bool in + guard let windowProcessIdentifier = (window[kCGWindowOwnerPID as String] as? Int).flatMap(pid_t.init), + windowProcessIdentifier != processIdentifier, + let windowRunningApplication = NSRunningApplication(processIdentifier: windowProcessIdentifier), + windowRunningApplication.executableURL?.lastPathComponent != "Dock", + let _ = window[String(kCGWindowName)] as? String else { + return false + } + + return true + }) else { + return false + } + } + return true + } + + /// 请求屏幕权限 + static func requestRecordScreenPermissions() { + if #available(macOS 10.15, *) { + CGWindowListCreateImage( + CGRect(x: 0, y: 0, width: 1, height: 1), + .optionOnScreenOnly, + kCGNullWindowID, + [] + ) + } + } + + /// 打开屏幕权限设置页 + static func openPrivacyScreenCapture() { + if #available(macOS 10.15, *) { + guard let url = URL(string: "x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture") else { + return + } + NSWorkspace.shared.open(url) + } + } +} diff --git a/uPic/General/Utils/Util.swift b/uPic/Utils/Util.swift similarity index 100% rename from uPic/General/Utils/Util.swift rename to uPic/Utils/Util.swift diff --git a/uPic/Views/DatabaseWindow/Base.lproj/Database.storyboard b/uPic/Views/DatabaseWindow/Base.lproj/Database.storyboard index 6a45b5a7..f3f7c197 100644 --- a/uPic/Views/DatabaseWindow/Base.lproj/Database.storyboard +++ b/uPic/Views/DatabaseWindow/Base.lproj/Database.storyboard @@ -12,8 +12,8 @@ - - + + @@ -22,21 +22,21 @@ - + - + - + @@ -71,17 +71,17 @@ - + - + - + @@ -98,26 +98,30 @@ - + - - - - + + + + + + + + - + @@ -130,59 +134,136 @@ - + - - - - + + + + + + + + - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - + + - - - - + + + + + + + + - + - + @@ -195,19 +276,23 @@ - + - - - - + + + + + + + + @@ -224,10 +309,9 @@ - - + @@ -254,7 +338,7 @@ - + @@ -275,9 +359,10 @@ + + + - - - + diff --git a/uPic/Views/DatabaseWindow/DatabaseViewController.swift b/uPic/Views/DatabaseWindow/DatabaseViewController.swift index 5f79bfb4..6dc970c3 100644 --- a/uPic/Views/DatabaseWindow/DatabaseViewController.swift +++ b/uPic/Views/DatabaseWindow/DatabaseViewController.swift @@ -9,12 +9,11 @@ import Cocoa class DatabaseViewController: NSViewController { - @IBOutlet weak var databaseTableView: NSTableView! + @IBOutlet weak var tableView: NSTableView! + var hostItems: [Host] = [] var items: [HistoryThumbnailModel] = [] - var sortOrder: SortOrder = SortOrder.ID - var selectedRow: Set = [] - var selectionDidChange = false + var sortOrder: SortOrder = SortOrder.Name var sortAscending = false override func viewDidLoad() { @@ -24,27 +23,85 @@ class DatabaseViewController: NSViewController { NSApp.setActivationPolicy(.regular) } - databaseTableView.dataSource = self - databaseTableView.delegate = self + tableView.dataSource = self + tableView.delegate = self + tableView.doubleAction = #selector(copyURL) - items = DBManager.shared.getHistoryList() sortConfig() - databaseTableView.reloadData() + + updateHostList() + updateHistoryList() } - @IBAction func didClickRefreshButton(_ sender: NSToolbarItem) { - items = DBManager.shared.getHistoryList() - databaseTableView.reloadData() + + override func viewDidAppear() { + super.viewDidAppear() + + ConfigNotifier.addObserver(observer: self, selector: #selector(updateHostList), notification: .changeHostItems) + ConfigNotifier.addObserver(observer: self, selector: #selector(updateHistoryList), notification: .updateHistoryList) } - @IBAction func didClickCopyButton(_ sender: NSToolbarItem) { - var urls: [String] = [] + override func viewDidDisappear() { + super.viewDidDisappear() - for row in selectedRow.sorted() { - urls.append(items[row].url) + ConfigNotifier.removeObserver(observer: self, notification: .changeHostItems) + ConfigNotifier.removeObserver(observer: self, notification: .updateHistoryList) + } + + override func rightMouseDown(with event: NSEvent) { + let menu = NSMenu() + + let copyMenuItem = NSMenuItem() + copyMenuItem.title = "Copy".localized + " (" + "\(tableView.selectedRowIndexes.count)" + "items".localized + ")" + copyMenuItem.isEnabled = false + copyMenuItem.action = #selector(copyURL) + + menu.addItem(copyMenuItem) + + NSMenu.popUpContextMenu(menu, with: event, for: tableView) + } + + func enableCopyMenu() { + if let mainMenu = NSApp.mainMenu, let editMenu = mainMenu.item(at: 2)?.submenu { + for item in editMenu.items { + if item.identifier?.rawValue == "copy" { + item.action = #selector(didClickCopyButton(_:)) + } + } + } + } + + // 根据 ID 获取图床 + func getHostById(_ id: String?) -> Host? { + guard let id = id else { + return nil } + return hostItems.first(where: {$0.id == id}) + } + + // 更新上传历史 + @objc func updateHistoryList() { + items = DBManager.shared.getHistoryList() + tableView.reloadData() - let outputUrl = (NSApplication.shared.delegate as? AppDelegate)?.copyUrls(urls: urls) - NotificationExt.shared.postCopySuccessfulNotice(outputUrl) + // 更新窗口 Title 中的数量 + if #available(OSX 11.0, *) { + view.window?.subtitle = "\(items.count) " + "items".localized + } else { + view.window?.title += " \(items.count) " + "items".localized + } + } + + // 更新图床列表 + @objc func updateHostList() { + hostItems = ConfigManager.shared.getHostItems() + } + + @IBAction func didClickRefreshButton(_ sender: NSToolbarItem) { + updateHistoryList() + } + + @IBAction func didClickCopyButton(_ sender: NSToolbarItem) { + copyURL() } @IBAction func didClickDeleteButton(_ sender: NSToolbarItem) { @@ -56,25 +113,41 @@ class DatabaseViewController: NSViewController { alert.addButton(withTitle: "Cancel".localized) alert.window.titlebarAppearsTransparent = true let response = alert.runModal() - + if response == .alertFirstButtonReturn { ConfigManager.shared.clearHistoryList() - items = ConfigManager.shared.getHistoryList() - databaseTableView.reloadData() + updateHistoryList() } else if response == .alertSecondButtonReturn { NSLog("Cancel") } } + @objc func copyURL() { + guard tableView.selectedRowIndexes.count > 0 else { + return + } + var urls: [String] = [] + + for row in tableView.selectedRowIndexes.sorted() { + urls.append(items[row].url) + } + + let outputUrl = (NSApplication.shared.delegate as? AppDelegate)?.copyUrls(urls: urls) + NotificationExt.shared.postCopySuccessfulNotice(outputUrl) + } func sortConfig() { - let descriptorName = NSSortDescriptor(key: SortOrder.Name.rawValue, ascending: true) - let descriptorID = NSSortDescriptor(key: SortOrder.ID.rawValue, ascending: false) - let descriptorURL = NSSortDescriptor(key: SortOrder.URL.rawValue, ascending: true) + let descriptorName = NSSortDescriptor(key: SortOrder.Name.rawValue, ascending: false) + let descriptorHost = NSSortDescriptor(key: SortOrder.Host.rawValue, ascending: false) + let descriptorSize = NSSortDescriptor(key: SortOrder.Size.rawValue, ascending: false) + let descriptorTime = NSSortDescriptor(key: SortOrder.Time.rawValue, ascending: false) + let descriptorURL = NSSortDescriptor(key: SortOrder.URL.rawValue, ascending: false) - databaseTableView.tableColumns[1].sortDescriptorPrototype = descriptorName - databaseTableView.tableColumns[2].sortDescriptorPrototype = descriptorID - databaseTableView.tableColumns[3].sortDescriptorPrototype = descriptorURL + tableView.tableColumns[1].sortDescriptorPrototype = descriptorName + tableView.tableColumns[2].sortDescriptorPrototype = descriptorHost + tableView.tableColumns[3].sortDescriptorPrototype = descriptorSize + tableView.tableColumns[4].sortDescriptorPrototype = descriptorTime + tableView.tableColumns[5].sortDescriptorPrototype = descriptorURL } func sortTableView() { @@ -82,14 +155,21 @@ class DatabaseViewController: NSViewController { switch sortOrder { case .Name: return sortAscending ? $0.fileName < $1.fileName : $0.fileName > $1.fileName - case .ID: - return sortAscending ? $0.identifier! < $1.identifier! : $0.identifier! > $1.identifier! + case .Host: + if let host0 = $0.host, let host1 = $1.host { + return sortAscending ? host0 < host1 : host0 > host1 + } + return false + case .Size: + return sortAscending ? $0.size < $1.size : $0.size > $1.size + case .Time: + return sortAscending ? $0.createdDate < $1.createdDate : $0.createdDate > $1.createdDate case .URL: return sortAscending ? $0.url < $1.url : $0.url > $1.url } } - databaseTableView.reloadData() + tableView.reloadData() } } @@ -114,10 +194,12 @@ extension DatabaseViewController: NSTableViewDelegate { cell?.textField?.stringValue = String(row + 1) case NSUserInterfaceItemIdentifier(rawValue: "name"): cell?.textField?.stringValue = item.fileName - case NSUserInterfaceItemIdentifier(rawValue: "id"): - cell?.textField?.stringValue = String(item.identifier ?? 0) - case NSUserInterfaceItemIdentifier(rawValue: "isImage"): - cell?.textField?.stringValue = item.isImage ? "Yes".localized : "No".localized + case NSUserInterfaceItemIdentifier(rawValue: "host"): + cell?.imageView?.image = Host.getIconByType(type: getHostById(item.host)?.type ?? .smms) + case NSUserInterfaceItemIdentifier(rawValue: "size"): + cell?.textField?.stringValue = "\(ByteCountFormatter.string(fromByteCount: Int64(item.size), countStyle: .decimal))" + case NSUserInterfaceItemIdentifier(rawValue: "time"): + cell?.textField?.stringValue = item.createdDate.format() case NSUserInterfaceItemIdentifier(rawValue: "url"): cell?.textField?.stringValue = item.url case NSUserInterfaceItemIdentifier(rawValue: "review"): @@ -129,20 +211,6 @@ extension DatabaseViewController: NSTableViewDelegate { return cell } - func tableView(_ tableView: NSTableView, shouldSelectRow row: Int) -> Bool { - if selectionDidChange { - selectedRow.removeAll() - } - - selectedRow.insert(row) - selectionDidChange = false - return true - } - - func tableViewSelectionDidChange(_ notification: Notification) { - selectionDidChange = true - } - func tableView(_ tableView: NSTableView, sortDescriptorsDidChange oldDescriptors: [NSSortDescriptor]) { guard let sortDescriptor = tableView.sortDescriptors.first else { return @@ -161,6 +229,8 @@ extension DatabaseViewController: NSTableViewDelegate { // MARK: - sort order enum SortOrder: String { case Name - case ID + case Host + case Size + case Time case URL } diff --git a/uPic/Views/DatabaseWindow/DatabaseWindowController.swift b/uPic/Views/DatabaseWindow/DatabaseWindowController.swift index 132e628a..209410f0 100644 --- a/uPic/Views/DatabaseWindow/DatabaseWindowController.swift +++ b/uPic/Views/DatabaseWindow/DatabaseWindowController.swift @@ -19,6 +19,7 @@ class DatabaseWindowController: NSWindowController { window?.title += " \(DBManager.shared.getHistoryList().count) " + "items".localized } } + } extension DatabaseWindowController: NSWindowDelegate { diff --git a/uPic/Views/DatabaseWindow/en.lproj/Database.strings b/uPic/Views/DatabaseWindow/en.lproj/Database.strings index 60dab65d..cbda214c 100644 --- a/uPic/Views/DatabaseWindow/en.lproj/Database.strings +++ b/uPic/Views/DatabaseWindow/en.lproj/Database.strings @@ -5,18 +5,33 @@ /* Class = "NSToolbarItem"; paletteLabel = "Delete All"; ObjectID = "1Wp-tE-KGb"; */ "1Wp-tE-KGb.paletteLabel" = "Delete All"; -/* Class = "NSTextFieldCell"; title = "Table View Cell"; ObjectID = "A25-IL-lsb"; */ -"A25-IL-lsb.title" = "Table View Cell"; +/* Class = "NSTextFieldCell"; title = "Name"; ObjectID = "A25-IL-lsb"; */ +"A25-IL-lsb.title" = "Name"; + +/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "Aux-L1-4gC"; */ +"Aux-L1-4gC.title" = "Text Cell"; + +/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "Bmb-UQ-bf6"; */ +"Bmb-UQ-bf6.title" = "Text Cell"; /* Class = "NSTableColumn"; headerCell.title = "URL"; ObjectID = "CeV-29-0Xb"; */ "CeV-29-0Xb.headerCell.title" = "URL"; -/* Class = "NSTextFieldCell"; title = "Table View Cell"; ObjectID = "Mwg-rj-Qgg"; */ -"Mwg-rj-Qgg.title" = "Table View Cell"; +/* Class = "NSTableColumn"; headerCell.title = "Size"; ObjectID = "DKQ-Ar-A7t"; */ +"DKQ-Ar-A7t.headerCell.title" = "Size"; + +/* Class = "NSTextFieldCell"; title = "URL"; ObjectID = "Mwg-rj-Qgg"; */ +"Mwg-rj-Qgg.title" = "URL"; + +/* Class = "NSTextFieldCell"; title = "Time"; ObjectID = "Oop-Sb-42w"; */ +"Oop-Sb-42w.title" = "Time"; /* Class = "NSTableColumn"; headerCell.title = "Review"; ObjectID = "PuM-Cu-8cO"; */ "PuM-Cu-8cO.headerCell.title" = "Review"; +/* Class = "NSTableColumn"; headerCell.title = "Host"; ObjectID = "Wbb-7n-akY"; */ +"Wbb-7n-akY.headerCell.title" = "Host"; + /* Class = "NSToolbarItem"; label = "Copy"; ObjectID = "Zhb-aV-Ibc"; */ "Zhb-aV-Ibc.label" = "Copy"; @@ -35,24 +50,24 @@ /* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "e0t-kU-Jo8"; */ "e0t-kU-Jo8.title" = "Text Cell"; -/* Class = "NSTextFieldCell"; title = "Table View Cell"; ObjectID = "gre-PU-B4n"; */ -"gre-PU-B4n.title" = "Table View Cell"; +/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "gff-B2-sFV"; */ +"gff-B2-sFV.title" = "Text Cell"; -/* Class = "NSTextFieldCell"; title = "Table View Cell"; ObjectID = "nOC-jD-wpP"; */ -"nOC-jD-wpP.title" = "Table View Cell"; +/* Class = "NSTextFieldCell"; title = "1"; ObjectID = "nOC-jD-wpP"; */ +"nOC-jD-wpP.title" = "1"; /* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "nzt-ZE-Al0"; */ "nzt-ZE-Al0.headerCell.title" = "Name"; -/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "tIy-g5-5yU"; */ -"tIy-g5-5yU.headerCell.title" = "ID"; - -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "v7g-KE-k2n"; */ -"v7g-KE-k2n.title" = "Text Cell"; +/* Class = "NSTableColumn"; headerCell.title = "Time"; ObjectID = "uKn-q2-bBe"; */ +"uKn-q2-bBe.headerCell.title" = "Time"; /* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "x8P-wG-KE1"; */ "x8P-wG-KE1.title" = "Text Cell"; +/* Class = "NSTextFieldCell"; title = "Size"; ObjectID = "xFO-bI-gPs"; */ +"xFO-bI-gPs.title" = "Size"; + /* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "xZb-4G-2d6"; */ "xZb-4G-2d6.title" = "Text Cell"; diff --git a/uPic/Views/DatabaseWindow/zh-Hans.lproj/Database.strings b/uPic/Views/DatabaseWindow/zh-Hans.lproj/Database.strings index d39a71af..4b9058a3 100644 --- a/uPic/Views/DatabaseWindow/zh-Hans.lproj/Database.strings +++ b/uPic/Views/DatabaseWindow/zh-Hans.lproj/Database.strings @@ -5,18 +5,33 @@ /* Class = "NSToolbarItem"; paletteLabel = "Delete All"; ObjectID = "1Wp-tE-KGb"; */ "1Wp-tE-KGb.paletteLabel" = "全部清除"; -/* Class = "NSTextFieldCell"; title = "Table View Cell"; ObjectID = "A25-IL-lsb"; */ -"A25-IL-lsb.title" = "Table View Cell"; +/* Class = "NSTextFieldCell"; title = "Name"; ObjectID = "A25-IL-lsb"; */ +"A25-IL-lsb.title" = "名称"; + +/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "Aux-L1-4gC"; */ +"Aux-L1-4gC.title" = "Text Cell"; + +/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "Bmb-UQ-bf6"; */ +"Bmb-UQ-bf6.title" = "Text Cell"; /* Class = "NSTableColumn"; headerCell.title = "URL"; ObjectID = "CeV-29-0Xb"; */ "CeV-29-0Xb.headerCell.title" = "URL"; -/* Class = "NSTextFieldCell"; title = "Table View Cell"; ObjectID = "Mwg-rj-Qgg"; */ -"Mwg-rj-Qgg.title" = "Table View Cell"; +/* Class = "NSTableColumn"; headerCell.title = "Size"; ObjectID = "DKQ-Ar-A7t"; */ +"DKQ-Ar-A7t.headerCell.title" = "大小"; + +/* Class = "NSTextFieldCell"; title = "URL"; ObjectID = "Mwg-rj-Qgg"; */ +"Mwg-rj-Qgg.title" = "URL"; + +/* Class = "NSTextFieldCell"; title = "Time"; ObjectID = "Oop-Sb-42w"; */ +"Oop-Sb-42w.title" = "时间"; /* Class = "NSTableColumn"; headerCell.title = "Review"; ObjectID = "PuM-Cu-8cO"; */ "PuM-Cu-8cO.headerCell.title" = "预览"; +/* Class = "NSTableColumn"; headerCell.title = "Host"; ObjectID = "Wbb-7n-akY"; */ +"Wbb-7n-akY.headerCell.title" = "图床"; + /* Class = "NSToolbarItem"; label = "Copy"; ObjectID = "Zhb-aV-Ibc"; */ "Zhb-aV-Ibc.label" = "复制"; @@ -35,24 +50,24 @@ /* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "e0t-kU-Jo8"; */ "e0t-kU-Jo8.title" = "Text Cell"; -/* Class = "NSTextFieldCell"; title = "Table View Cell"; ObjectID = "gre-PU-B4n"; */ -"gre-PU-B4n.title" = "Table View Cell"; +/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "gff-B2-sFV"; */ +"gff-B2-sFV.title" = "Text Cell"; -/* Class = "NSTextFieldCell"; title = "Table View Cell"; ObjectID = "nOC-jD-wpP"; */ -"nOC-jD-wpP.title" = "Table View Cell"; +/* Class = "NSTextFieldCell"; title = "1"; ObjectID = "nOC-jD-wpP"; */ +"nOC-jD-wpP.title" = "1"; /* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "nzt-ZE-Al0"; */ "nzt-ZE-Al0.headerCell.title" = "名称"; -/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "tIy-g5-5yU"; */ -"tIy-g5-5yU.headerCell.title" = "ID"; - -/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "v7g-KE-k2n"; */ -"v7g-KE-k2n.title" = "Text Cell"; +/* Class = "NSTableColumn"; headerCell.title = "Time"; ObjectID = "uKn-q2-bBe"; */ +"uKn-q2-bBe.headerCell.title" = "时间"; /* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "x8P-wG-KE1"; */ "x8P-wG-KE1.title" = "Text Cell"; +/* Class = "NSTextFieldCell"; title = "Size"; ObjectID = "xFO-bI-gPs"; */ +"xFO-bI-gPs.title" = "大小"; + /* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "xZb-4G-2d6"; */ "xZb-4G-2d6.title" = "Text Cell"; diff --git a/uPic/Views/DatabaseWindow/zh-Hant.lproj/Database.strings b/uPic/Views/DatabaseWindow/zh-Hant.lproj/Database.strings index 60dab65d..2c8e7b92 100644 --- a/uPic/Views/DatabaseWindow/zh-Hant.lproj/Database.strings +++ b/uPic/Views/DatabaseWindow/zh-Hant.lproj/Database.strings @@ -36,7 +36,7 @@ "e0t-kU-Jo8.title" = "Text Cell"; /* Class = "NSTextFieldCell"; title = "Table View Cell"; ObjectID = "gre-PU-B4n"; */ -"gre-PU-B4n.title" = "Table View Cell"; +//"gre-PU-B4n.title" = "Table View Cell"; /* Class = "NSTextFieldCell"; title = "Table View Cell"; ObjectID = "nOC-jD-wpP"; */ "nOC-jD-wpP.title" = "Table View Cell"; @@ -45,10 +45,10 @@ "nzt-ZE-Al0.headerCell.title" = "Name"; /* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "tIy-g5-5yU"; */ -"tIy-g5-5yU.headerCell.title" = "ID"; +//"tIy-g5-5yU.headerCell.title" = "ID"; /* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "v7g-KE-k2n"; */ -"v7g-KE-k2n.title" = "Text Cell"; +//"v7g-KE-k2n.title" = "Text Cell"; /* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "x8P-wG-KE1"; */ "x8P-wG-KE1.title" = "Text Cell"; @@ -58,3 +58,31 @@ /* Class = "NSWindow"; title = "uPic Database"; ObjectID = "zqs-gy-XY6"; */ "zqs-gy-XY6.title" = "uPic Database"; + +//################################################################################## +//# AutoGenStrings 2021-02-02 20:52:14 +//################################################################################## + +/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "Bmb-UQ-bf6"; */ +"Bmb-UQ-bf6.title" = "Text Cell"; + +/* Class = "NSTableColumn"; headerCell.title = "Size"; ObjectID = "DKQ-Ar-A7t"; */ +"DKQ-Ar-A7t.headerCell.title" = "Size"; + +/* Class = "NSTableColumn"; headerCell.title = "Host"; ObjectID = "Wbb-7n-akY"; */ +"Wbb-7n-akY.headerCell.title" = "Host"; + +/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "Aux-L1-4gC"; */ +"Aux-L1-4gC.title" = "Text Cell"; + +/* Class = "NSTextFieldCell"; title = "Size"; ObjectID = "xFO-bI-gPs"; */ +"xFO-bI-gPs.title" = "Size"; + +/* Class = "NSTableColumn"; headerCell.title = "Time"; ObjectID = "uKn-q2-bBe"; */ +"uKn-q2-bBe.headerCell.title" = "Time"; + +/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "gff-B2-sFV"; */ +"gff-B2-sFV.title" = "Text Cell"; + +/* Class = "NSTextFieldCell"; title = "Time"; ObjectID = "Oop-Sb-42w"; */ +"Oop-Sb-42w.title" = "Time"; diff --git a/uPic/Views/HistoryRecord/HistoryThumbnailModel.swift b/uPic/Views/HistoryRecord/HistoryThumbnailModel.swift index cbad9074..22da7b87 100644 --- a/uPic/Views/HistoryRecord/HistoryThumbnailModel.swift +++ b/uPic/Views/HistoryRecord/HistoryThumbnailModel.swift @@ -16,6 +16,9 @@ class HistoryThumbnailModel: TableCodable { var previewWidth: Double = 0 var previewHeight: Double = 0 var thumbnailData: Data? + var createdDate: Date = Date() + var size: Int = 0 + var host: String? var isImage: Bool = false var isAutoIncrement: Bool { return true } @@ -25,6 +28,10 @@ class HistoryThumbnailModel: TableCodable { return url.lastPathComponent } + var ext: String? { + return url.lastPathComponent.pathExtension + } + var thumbnailSize: NSSize { return NSSize(width: thumbnailWidth, height: thumbnailHeight) } @@ -49,6 +56,9 @@ class HistoryThumbnailModel: TableCodable { case previewWidth case previewHeight case thumbnailData + case createdDate + case size + case host case isImage static var columnConstraintBindings: [CodingKeys: ColumnConstraintBinding]? { @@ -64,6 +74,13 @@ class HistoryThumbnailModel: TableCodable { model.previewWidth = keyValue["previewWidth"] as! Double model.previewHeight = keyValue["previewHeight"] as! Double model.thumbnailData = keyValue["thumbnailData"] as? Data + if let createDateStr = keyValue["createdDate"] as? String, !createDateStr.isEmpty { + model.createdDate = Date.dateFromISOString(string: createDateStr)! + } else { + model.createdDate = Date() + } + model.size = keyValue["size"] as? Int ?? 0 + model.host = keyValue["host"] as? String model.isImage = keyValue["isImage"] as! Bool return model } @@ -76,6 +93,10 @@ class HistoryThumbnailModel: TableCodable { if let thumbnailData = thumbnailData { historyKeyValue["thumbnailData"] = thumbnailData } + + historyKeyValue["createdDate"] = createdDate.toISOString() + historyKeyValue["size"] = size + historyKeyValue["host"] = host historyKeyValue["isImage"] = isImage return historyKeyValue } diff --git a/uPic/Views/PreferencesWindow/AboutPreferencesViewController.swift b/uPic/Views/PreferencesWindow/AboutPreferencesViewController.swift index 4c92e786..e7953111 100644 --- a/uPic/Views/PreferencesWindow/AboutPreferencesViewController.swift +++ b/uPic/Views/PreferencesWindow/AboutPreferencesViewController.swift @@ -15,8 +15,9 @@ class AboutPreferencesViewController: PreferencesViewController { override func viewDidLoad() { super.viewDidLoad() - let versionObject = Bundle.main.infoDictionary?["CFBundleShortVersionString"] - versionLabel.stringValue = versionObject as? String ?? "" + let versionNum = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String + let buildNum = Bundle.main.infoDictionary?["CFBundleVersion"] as! String + versionLabel.stringValue = "v\(versionNum) (\(buildNum))" } @IBAction func githubButtonClicked(_ sender: NSButton) { @@ -54,18 +55,9 @@ class AboutPreferencesViewController: PreferencesViewController { NSWorkspace.shared.open(url) } - @IBAction func paypalButtonClicked(_ sender: NSButton) { - (NSApplication.shared.delegate as? AppDelegate)?.sponsorByPaypal() + @IBAction func didClickShowWelcomePageButton(_ sender: NSButton) { + _ = WindowManager.shared.showWindow(storyboard: "Welcome", withIdentifier: "welcomeWindowController") } - - @IBAction func alipayButtonClicked(_ sender: NSButton) { - (NSApplication.shared.delegate as? AppDelegate)?.sponsorByAlipay() - } - - @IBAction func weChatPayButtonClicked(_ sender: NSButton) { - (NSApplication.shared.delegate as? AppDelegate)?.sponsorByWechatPay() - } - } class LinkButton: NSButton { diff --git a/uPic/Views/PreferencesWindow/AdvancedPreferencesViewController.swift b/uPic/Views/PreferencesWindow/AdvancedPreferencesViewController.swift index 6ddeba49..bb9c3c52 100644 --- a/uPic/Views/PreferencesWindow/AdvancedPreferencesViewController.swift +++ b/uPic/Views/PreferencesWindow/AdvancedPreferencesViewController.swift @@ -21,6 +21,8 @@ class AdvancedPreferencesViewController: PreferencesViewController { @IBOutlet weak var historyRecordFileNameScrollSpeed: NSTextField! @IBOutlet weak var historyRecordFileNameScrollWaitTime: NSTextField! @IBOutlet weak var finderExtensionIcon: NSPopUpButton! + @IBOutlet weak var fullDiskAuthorizationImage: NSImageView! + @IBOutlet weak var fullDiskAuthorizationButton: NSButton! @IBOutlet weak var resetPreferencesButton: NSButton! // MARK: Lifecycle @@ -29,6 +31,7 @@ class AdvancedPreferencesViewController: PreferencesViewController { super.viewDidLoad() resetAllValues() + checkFullDiskAuthorizationStatus() } func resetAllValues() { @@ -57,6 +60,17 @@ class AdvancedPreferencesViewController: PreferencesViewController { } } + func checkFullDiskAuthorizationStatus() { + let isAuthorized = DiskPermissionManager.shared.checkFullDiskAuthorizationStatus() + if isAuthorized { + fullDiskAuthorizationImage.image = NSImage(named: NSImage.statusAvailableName) + fullDiskAuthorizationButton.title = "Authorized".localized + } else { + fullDiskAuthorizationImage.image = NSImage(named: NSImage.statusPartiallyAvailableName) + fullDiskAuthorizationButton.title = "Not Authorized".localized + } + } + @IBAction func didClickHistoryRecordConfigurationResetButton(_ sender: NSButton) { Defaults.removeObject(forKey: Keys.historyRecordWidth) @@ -88,10 +102,22 @@ class AdvancedPreferencesViewController: PreferencesViewController { FinderUtil.setIcon(sender.indexOfSelectedItem) } - @IBAction func didClickRestartFinder(_ sender: NSButton) { - let killFinderScript = #"do shell script "killall Finder""# - let script = NSAppleScript(source: killFinderScript) - script!.executeAndReturnError(nil) + @IBAction func didClickOpenOutputFormatCustomizationPanelButton(_ sender: NSButton) { + let outputFormatCustomizationViewController = storyboard!.instantiateController(withIdentifier: "OutputFormatCustomization") as! OutputFormatCustomization + + presentAsSheet(outputFormatCustomizationViewController) + } + + @IBAction func didClickfullDiskAuthorizationButton(_ sender: NSButton) { + let isAuthorized = DiskPermissionManager.shared.checkFullDiskAuthorizationStatus() + if isAuthorized { + // 取消 + DiskPermissionManager.shared.cancelFullDiskPermissions() + } else { + // 设置页授权根目录 + DiskPermissionManager.shared.requestFullDiskPermissions() + } + checkFullDiskAuthorizationStatus() } @IBAction func resetPreferencesButtonClicked(_ sender: NSButton) { diff --git a/uPic/Views/PreferencesWindow/Base.lproj/Preferences.storyboard b/uPic/Views/PreferencesWindow/Base.lproj/Preferences.storyboard index ee56875f..d3a9e421 100644 --- a/uPic/Views/PreferencesWindow/Base.lproj/Preferences.storyboard +++ b/uPic/Views/PreferencesWindow/Base.lproj/Preferences.storyboard @@ -1,8 +1,8 @@ - + - + @@ -13,7 +13,8 @@ - + + @@ -34,7 +35,7 @@ - + @@ -98,7 +99,7 @@ - + @@ -181,14 +182,14 @@ - + - + - + @@ -196,10 +197,10 @@ - + - + @@ -207,12 +208,15 @@ - + + + + @@ -223,10 +227,10 @@ - + - + @@ -234,12 +238,15 @@ - + + + + @@ -250,10 +257,10 @@ - + - + @@ -261,12 +268,15 @@ - + + + + @@ -277,7 +287,7 @@ - + @@ -285,7 +295,7 @@ - + @@ -354,6 +364,10 @@ + + + + @@ -364,7 +378,7 @@ - + @@ -390,6 +404,9 @@ + + + @@ -433,6 +450,9 @@ + + + @@ -443,7 +463,7 @@ - + @@ -466,6 +486,9 @@ + + + @@ -476,7 +499,7 @@ - + @@ -499,6 +522,9 @@ + + + @@ -509,10 +535,10 @@ - + + + + @@ -545,7 +606,7 @@ - + @@ -553,7 +614,7 @@ - + @@ -564,7 +625,7 @@ - + @@ -580,35 +641,61 @@ + + + + + + + + + + + + + - - + + + + + + + + + + - - - - - - - - - @@ -650,11 +737,14 @@ + - + + + @@ -687,6 +777,8 @@ + + @@ -705,17 +797,22 @@ + + + + + @@ -730,24 +827,251 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + @@ -755,7 +1079,7 @@ - + @@ -773,7 +1097,7 @@ - + @@ -805,7 +1129,7 @@ - + @@ -837,7 +1161,7 @@ - + @@ -869,7 +1193,7 @@ - + @@ -900,84 +1224,57 @@ - - + + - - - + + + - - - - - - - - - + + - - - - + + + + - @@ -1024,7 +1321,7 @@ - + @@ -1171,7 +1468,7 @@ Gw - + @@ -1480,14 +1777,16 @@ Gw + + - + + - diff --git a/uPic/Views/PreferencesWindow/ConfigView/CustomConfigSheetController.swift b/uPic/Views/PreferencesWindow/ConfigView/CustomConfigSheetController.swift index f13c3dd8..dab7650d 100644 --- a/uPic/Views/PreferencesWindow/ConfigView/CustomConfigSheetController.swift +++ b/uPic/Views/PreferencesWindow/ConfigView/CustomConfigSheetController.swift @@ -10,34 +10,32 @@ import Cocoa import SwiftyJSON class CustomConfigSheetController: NSViewController { - - @IBOutlet weak var cancelButton: NSButton! - @IBOutlet weak var okButton: NSButton! + @IBOutlet var cancelButton: NSButton! + @IBOutlet var okButton: NSButton! - @IBOutlet weak var addHeaderButton: NSButton! - @IBOutlet weak var addBodyButton: NSButton! - @IBOutlet weak var scrollView: NSScrollView! + @IBOutlet var addHeaderButton: NSButton! + @IBOutlet var addBodyButton: NSButton! + @IBOutlet var scrollView: NSScrollView! - var headers:Array> = []; - var bodys:Array> = []; + var headers: [[String: String]] = [] + var bodys: [[String: String]] = [] override func viewDidLoad() { super.viewDidLoad() // Do view setup here. - - okButton.highlight(true) - scrollView.hasVerticalScroller = true - scrollView.hasHorizontalScroller = true + + self.okButton.highlight(true) + self.scrollView.hasVerticalScroller = true + self.scrollView.hasHorizontalScroller = true } - - + @IBAction func addHeaderBtnClicked(_ sender: Any) { - headers.append(["key": "", "value": ""]) + self.headers.append(["key": "", "value": ""]) self.refreshScroolView() } - + @IBAction func addBodyBtnClicked(_ sender: Any) { - bodys.append(["key": "", "value": ""]) + self.bodys.append(["key": "", "value": ""]) self.refreshScroolView() } @@ -82,13 +80,13 @@ class CustomConfigSheetController: NSViewController { contentView.addSubview(valueField) nextKeyViews.append(valueField) - let removeBtn = NSButton(frame: NSRect(x: gapLeft * 2 + paddingLeft + keyWidth + valueWidth, y: y, width: height, height: height)) + let removeBtn = NSButton(frame: NSRect(x: gapLeft * 2 + paddingLeft + keyWidth + valueWidth, y: y, width: height, height: height)) removeBtn.bezelStyle = .texturedRounded removeBtn.identifier = NSUserInterfaceItemIdentifier(rawValue: "header-\(index)-remove_btn") removeBtn.image = NSImage(named: NSImage.removeTemplateName) removeBtn.imagePosition = .imageOnly removeBtn.target = self - removeBtn.action = #selector(onRemoveItem(_:)) + removeBtn.action = #selector(self.onRemoveItem(_:)) contentView.addSubview(removeBtn) } @@ -122,21 +120,21 @@ class CustomConfigSheetController: NSViewController { contentView.addSubview(valueField) nextKeyViews.append(valueField) - let removeBtn = NSButton(frame: NSRect(x: gapLeft * 2 + paddingLeft + keyWidth + valueWidth, y: y, width: height, height: height)) + let removeBtn = NSButton(frame: NSRect(x: gapLeft * 2 + paddingLeft + keyWidth + valueWidth, y: y, width: height, height: height)) removeBtn.bezelStyle = .texturedRounded removeBtn.identifier = NSUserInterfaceItemIdentifier(rawValue: "body-\(index)-remove_btn") removeBtn.image = NSImage(named: NSImage.removeTemplateName) removeBtn.imagePosition = .imageOnly removeBtn.target = self - removeBtn.action = #selector(onRemoveItem(_:)) + removeBtn.action = #selector(self.onRemoveItem(_:)) contentView.addSubview(removeBtn) } } self.setNextKeyViews(nextKeyViews) - contentView.frame = NSRect(x: 0, y: 0, width: Int(scrollView.frame.width), height: y + height + paddingTop) - scrollView.documentView = contentView + contentView.frame = NSRect(x: 0, y: 0, width: Int(self.scrollView.frame.width), height: y + height + paddingTop) + self.scrollView.documentView = contentView if let documentView = scrollView.documentView { if documentView.isFlipped { documentView.scroll(.zero) @@ -157,7 +155,6 @@ class CustomConfigSheetController: NSViewController { let nextView = nextKeyViews[index + 1] currentView.nextKeyView = nextView - } } } @@ -172,18 +169,17 @@ class CustomConfigSheetController: NSViewController { return } - if (type == "header") { - if (index >= 0 || index < self.headers.count) { + if type == "header" { + if index >= 0 || index < self.headers.count { self.headers.remove(at: index) self.refreshScroolView() } - } else if (type == "body") { - if (index >= 0 || index < self.headers.count) { + } else if type == "body" { + if index >= 0 || index < self.headers.count { self.bodys.remove(at: index) self.refreshScroolView() } } - } } @@ -206,23 +202,21 @@ extension CustomConfigSheetController: NSTextFieldDelegate { let index = Int(args[1])! let field = String(args[2]) - if (index < 0) { + if index < 0 { return } - let value = textField.stringValue let trimValue = value.trim() - if (type == "header" && index < self.headers.count) { + if type == "header", index < self.headers.count { self.headers[index][field] = trimValue - } else if (type == "body" && index < self.bodys.count) { + } else if type == "body", index < self.bodys.count { self.bodys[index][field] = trimValue } } } - func controlTextDidEndEditing(_ obj: Notification) { if let textField = obj.object as? NSTextField, let identifier = textField.identifier?.rawValue { let args = identifier.split(separator: Character("-")) @@ -230,14 +224,13 @@ extension CustomConfigSheetController: NSTextFieldDelegate { let index = Int(args[1])! let field = String(args[2]) - if (index < 0) { + if index < 0 { return } - - if (type == "header" && index < self.headers.count) { + if type == "header", index < self.headers.count { textField.stringValue = self.headers[index][field] ?? textField.stringValue - } else if (type == "body" && index < self.bodys.count) { + } else if type == "body", index < self.bodys.count { textField.stringValue = self.bodys[index][field] ?? textField.stringValue } } diff --git a/uPic/Views/PreferencesWindow/ConfigView/Views/CustomConfigView.swift b/uPic/Views/PreferencesWindow/ConfigView/Views/CustomConfigView.swift index 92b61f10..1cfd25c4 100644 --- a/uPic/Views/PreferencesWindow/ConfigView/Views/CustomConfigView.swift +++ b/uPic/Views/PreferencesWindow/ConfigView/Views/CustomConfigView.swift @@ -10,7 +10,7 @@ import Cocoa class CustomConfigView: ConfigView { - var postConfigSheetController: CustomConfigSheetController?; + var postConfigSheetController: CustomConfigSheetController? override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) diff --git a/uPic/Views/PreferencesWindow/ConfigView/Views/S3ConfigView.swift b/uPic/Views/PreferencesWindow/ConfigView/Views/S3ConfigView.swift index 100887ef..7122d78a 100644 --- a/uPic/Views/PreferencesWindow/ConfigView/Views/S3ConfigView.swift +++ b/uPic/Views/PreferencesWindow/ConfigView/Views/S3ConfigView.swift @@ -84,7 +84,7 @@ class S3ConfigView: ConfigView { if selectRegion != nil { regionButtonPopUp.select(selectRegion) // 初次设置,手动处罚一下事件,将数据写入data - if data.region.isEmpty { + if data.region == nil || data.region!.isEmpty { self.regionChange(regionButtonPopUp) } } @@ -204,6 +204,10 @@ class S3ConfigView: ConfigView { endpointLabel.isHidden = !customize endpointField.isHidden = !customize + if (customize) { + self.data?.setValue(nil, forKey: "region") + } + if (!customize && !endpointField.stringValue.isEmpty) { endpointField.stringValue = "" self.data?.setValue(nil, forKey: "endpoint") diff --git a/uPic/Views/PreferencesWindow/OutputFormatCustomization.swift b/uPic/Views/PreferencesWindow/OutputFormatCustomization.swift new file mode 100644 index 00000000..ce0d25ce --- /dev/null +++ b/uPic/Views/PreferencesWindow/OutputFormatCustomization.swift @@ -0,0 +1,136 @@ +// +// OutputFormatCustomization.swift +// uPic +// +// Created by Licardo on 2021/1/17. +// Copyright © 2021 Svend Jin. All rights reserved. +// + +import Cocoa + +class OutputFormatCustomization: NSViewController { + @IBOutlet var tableView: NSTableView! + + var nameTextField: NSTextField! + var customStyleTextField: NSTextField! + var deleteButton: NSButton! + + var items: [OutputFormatModel] = [] + + override func viewDidLoad() { + super.viewDidLoad() + + items = DBManager.shared.getOutputFormatList() + + tableView.dataSource = self + tableView.delegate = self + } + + @IBAction func didClickAddButton(_ sender: NSButton) { + items.append(OutputFormatModel(name: "Custom", value: "{url}")) + tableView.reloadData() + } + + @IBAction func didClickCancelButton(_ sender: NSButton) { + dismiss(sender) + } + + @IBAction func didClickSaveButton(_ sender: NSButton) { + blurEditingTextField() + DBManager.shared.saveOutputFormats(items) + dismiss(sender) + } + + // MARK: 将正在编辑的输入框执行 endEdit + func blurEditingTextField() { + for view in self.tableView.subviews { + if !(view is NSTableRowView) { + continue + } + for subView in view.subviews { + if subView is NSTextField { + let subTextField = subView as! NSTextField + if let editor = subTextField.currentEditor() { + subTextField.endEditing(editor) + } + } + } + } + } +} + +// MARK: - DataSource + +extension OutputFormatCustomization: NSTableViewDataSource { + func numberOfRows(in tableView: NSTableView) -> Int { + items.count + } +} + +// MARK: - Delegate + +extension OutputFormatCustomization: NSTableViewDelegate { + + fileprivate enum CellIdentifiers { + static let NameCell = "name" + static let ValueCell = "value" + } + + func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { + + + switch tableColumn?.identifier { + case NSUserInterfaceItemIdentifier(rawValue: "name"): // 自定义格式的名称 + nameTextField = NSTextField() + nameTextField.bezelStyle = .roundedBezel + nameTextField.stringValue = items[row].name + nameTextField.identifier = NSUserInterfaceItemIdentifier(rawValue: "name") + nameTextField.tag = row + nameTextField.delegate = self + return nameTextField + case NSUserInterfaceItemIdentifier(rawValue: "value"): // 自定义格式的内容 + customStyleTextField = NSTextField() + customStyleTextField.bezelStyle = .roundedBezel + customStyleTextField.stringValue = items[row].value + customStyleTextField.identifier = NSUserInterfaceItemIdentifier(rawValue: "value") + customStyleTextField.tag = row + customStyleTextField.delegate = self + return customStyleTextField + case NSUserInterfaceItemIdentifier(rawValue: "delete"): // 删除按钮 + deleteButton = NSButton() + deleteButton.bezelStyle = .rounded + deleteButton.image = NSImage(named: NSImage.removeTemplateName) + deleteButton.imagePosition = .imageOnly + deleteButton.addTarget { _ in + self.items.remove(at: row) + self.tableView.reloadData() + } + return deleteButton + default: + return nil + } + } +} +extension OutputFormatCustomization: NSTextFieldDelegate { + // 监听表格单元格(图床名称)修改完成 + func controlTextDidEndEditing(_ notification: Notification) { + let textField = notification.object as! NSTextField + + guard let identifier = textField.identifier?.rawValue else { + return + } + + let item = self.items[textField.tag] + + switch identifier { + case "name": + item.name = textField.stringValue + break + case "value": + item.value = textField.stringValue + break + default: + break + } + } +} diff --git a/uPic/Views/PreferencesWindow/PreferencesViewController.swift b/uPic/Views/PreferencesWindow/PreferencesViewController.swift index 0b71a5f6..a8786082 100644 --- a/uPic/Views/PreferencesWindow/PreferencesViewController.swift +++ b/uPic/Views/PreferencesWindow/PreferencesViewController.swift @@ -25,10 +25,6 @@ class PreferencesViewController: NSViewController { if NSApp.activationPolicy() == .accessory { NSApp.setActivationPolicy(.regular) } - - let userInfo: [AnyHashable: Any] = ["path": "121"] - DistributedNotificationCenter.default() - .postNotificationName(NSNotification.Name(rawValue: "uploadByFinder"), object: nil, userInfo: userInfo, deliverImmediately: true) // MARK: 偏好设置tab切换动画 self.setWindowFrame() diff --git a/uPic/Views/PreferencesWindow/en.lproj/Preferences.strings b/uPic/Views/PreferencesWindow/en.lproj/Preferences.strings index 3f2a1d1a..de262d44 100644 --- a/uPic/Views/PreferencesWindow/en.lproj/Preferences.strings +++ b/uPic/Views/PreferencesWindow/en.lproj/Preferences.strings @@ -2,11 +2,8 @@ /* Class = "NSButtonCell"; title = "svend.cc"; ObjectID = "0dV-As-mmQ"; */ "0dV-As-mmQ.title" = "svend.cc"; -/* Class = "NSTextFieldCell"; title = "may require a"; ObjectID = "2Rg-te-FPU"; */ -"2Rg-te-FPU.title" = "may require a"; - -/* Class = "NSButtonCell"; title = "Paypal"; ObjectID = "59m-hG-lVw"; */ -"59m-hG-lVw.title" = "Paypal"; +/* Class = "NSTextFieldCell"; title = "need a Finder Restart"; ObjectID = "2Rg-te-FPU"; */ +"2Rg-te-FPU.title" = "need a Finder Restart"; /* Class = "NSViewController"; title = "Host"; ObjectID = "5Ln-jV-uxk"; */ "5Ln-jV-uxk.title" = "Host"; @@ -14,6 +11,9 @@ /* Class = "NSWindow"; title = "Preferences"; ObjectID = "5f3-UK-Rft"; */ "5f3-UK-Rft.title" = "Preferences"; +/* Class = "NSButtonCell"; title = "Show"; ObjectID = "7Gg-u8-8Yt"; */ +"7Gg-u8-8Yt.title" = "Show"; + /* Class = "NSButtonCell"; title = "Reset"; ObjectID = "8gb-uy-oRd"; */ "8gb-uy-oRd.title" = "Reset"; @@ -29,6 +29,9 @@ /* Class = "NSTextFieldCell"; title = "File name scroll speed:"; ObjectID = "BBZ-i9-B2g"; */ "BBZ-i9-B2g.title" = "File name scroll speed:"; +/* Class = "NSButtonCell"; title = "iSvend"; ObjectID = "BoF-vP-aWK"; */ +"BoF-vP-aWK.title" = "iSvend"; + /* Class = "NSButtonCell"; title = "Add Header Field"; ObjectID = "Ckh-A7-mxC"; */ "Ckh-A7-mxC.title" = "Add Header Field"; @@ -41,9 +44,18 @@ /* Class = "NSViewController"; title = "General"; ObjectID = "Gn1-zC-bzB"; */ "Gn1-zC-bzB.title" = "General"; +/* Class = "NSTextFieldCell"; title = "Full Disk Access"; ObjectID = "Gu0-HV-q4H"; */ +"Gu0-HV-q4H.title" = "Full Disk Access"; + /* Class = "NSMenuItem"; title = "Non"; ObjectID = "GwK-5k-ATM"; */ "GwK-5k-ATM.title" = "Non"; +/* Class = "NSTextFieldCell"; title = "Note: Please use {url} {filename} as placeholder for your url"; ObjectID = "Gws-yz-JWw"; */ +"Gws-yz-JWw.title" = "Note: Please use {url} {filename} as placeholder for your url"; + +/* Class = "NSTextFieldCell"; title = "Output Format Customization"; ObjectID = "GzP-4S-ioU"; */ +"GzP-4S-ioU.title" = "Output Format Customization"; + /* Class = "NSViewController"; title = "Advanced"; ObjectID = "H3q-JS-Bu4"; */ "H3q-JS-Bu4.title" = "Advanced"; @@ -53,6 +65,9 @@ /* Class = "NSButtonCell"; title = "svend.jin@gmail.com"; ObjectID = "IPL-yO-Vkp"; */ "IPL-yO-Vkp.title" = "svend.jin@gmail.com"; +/* Class = "NSButtonCell"; title = "Config"; ObjectID = "Jbz-2F-L08"; */ +"Jbz-2F-L08.title" = "Config"; + /* Class = "NSTextFieldCell"; title = "0.1.0"; ObjectID = "Jnf-AX-bIr"; */ "Jnf-AX-bIr.title" = "0.1.0"; @@ -62,6 +77,9 @@ /* Class = "NSTextFieldCell"; title = "Columns:"; ObjectID = "N1b-Cf-tno"; */ "N1b-Cf-tno.title" = "Columns:"; +/* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "NLj-vQ-ghD"; */ +"NLj-vQ-ghD.headerCell.title" = "Name"; + /* Class = "NSTextFieldCell"; title = "🐦 Twitter:"; ObjectID = "OKr-1C-5jV"; */ "OKr-1C-5jV.title" = "🐦 Twitter:"; @@ -80,15 +98,18 @@ /* Class = "NSTextFieldCell"; title = "Supports {year} {month} {day} {hour} {minute} {second} {since_second} {since_millisecond} {random} {filename} {.suffix} {suffix} {mimetype} {saveKey} and etc."; ObjectID = "R0i-0c-6TZ"; */ "R0i-0c-6TZ.title" = "Supports {year} {month} {day} {hour} {minute} {second} {since_second} {since_millisecond} {random} {filename} {.suffix} {suffix} {mimetype} {saveKey} and etc."; +/* Class = "NSTableColumn"; headerCell.title = "Custom Style"; ObjectID = "RAq-Oy-he8"; */ +"RAq-Oy-he8.headerCell.title" = "Custom Style"; + +/* Class = "NSButtonCell"; title = "Cancel"; ObjectID = "SfQ-Lo-Xpr"; */ +"SfQ-Lo-Xpr.title" = "Cancel"; + /* Class = "NSButtonCell"; title = "⚠️ Reset"; ObjectID = "TD4-LI-X9U"; */ "TD4-LI-X9U.title" = "⚠️ Reset"; /* Class = "NSTextFieldCell"; title = "History record"; ObjectID = "UN0-Iq-Cop"; */ "UN0-Iq-Cop.title" = "History record"; -/* Class = "NSTextFieldCell"; title = "💸 Donate:"; ObjectID = "Vjv-pA-ffP"; */ -"Vjv-pA-ffP.title" = "💸 Donate:"; - /* Class = "NSTextFieldCell"; title = "✉️ Contact:"; ObjectID = "Vu4-Wz-Agk"; */ "Vu4-Wz-Agk.title" = "✉️ Contact:"; @@ -119,17 +140,14 @@ /* Class = "NSMenuItem"; title = "More"; ObjectID = "dZy-kW-0lH"; */ "dZy-kW-0lH.title" = "More"; -/* Class = "NSButtonCell"; title = "Alipay"; ObjectID = "eWy-BH-pJy"; */ -"eWy-BH-pJy.title" = "Alipay"; - /* Class = "NSTextFieldCell"; title = "uPic for iOS is now available on App Store!"; ObjectID = "f1C-OB-3jS"; */ "f1C-OB-3jS.title" = "uPic for iOS is now available on App Store!"; /* Class = "NSButtonCell"; title = "https://github.com/gee1k/uPic"; ObjectID = "f2V-P5-pQI"; */ "f2V-P5-pQI.title" = "https://github.com/gee1k/uPic"; -/* Class = "NSButtonCell"; title = "WeChat"; ObjectID = "fJL-Ts-QPI"; */ -"fJL-Ts-QPI.title" = "WeChat"; +/* Class = "NSButtonCell"; title = "Save"; ObjectID = "gUg-yZ-cS0"; */ +"gUg-yZ-cS0.title" = "Save"; /* Class = "NSButtonCell"; title = "@realSvend"; ObjectID = "i90-se-6z8"; */ "i90-se-6z8.title" = "@realSvend"; @@ -137,9 +155,6 @@ /* Class = "NSTextFieldCell"; title = "Width:"; ObjectID = "iRI-j6-BHQ"; */ "iRI-j6-BHQ.title" = "Width:"; -/* Class = "NSButtonCell"; title = "Finder Restart"; ObjectID = "jA2-Zt-kWu"; */ -"jA2-Zt-kWu.title" = "Finder Restart"; - /* Class = "NSTextFieldCell"; title = "Reset"; ObjectID = "jcs-Ou-OZ2"; */ "jcs-Ou-OZ2.title" = "Reset"; @@ -152,9 +167,18 @@ /* Class = "NSViewController"; title = "About"; ObjectID = "k6X-N1-mVu"; */ "k6X-N1-mVu.title" = "About"; +/* Class = "NSButtonCell"; title = "Not Authorized"; ObjectID = "l8U-fu-WXc"; */ +"l8U-fu-WXc.title" = "Not Authorized"; + +/* Class = "NSTextFieldCell"; title = "Hold option and right click on finder, then select Relaunch."; ObjectID = "mDT-aa-auv"; */ +"mDT-aa-auv.title" = "Hold option and right click on finder, then select Relaunch."; + /* Class = "NSTextFieldCell"; title = "uPic"; ObjectID = "mOB-su-ZM1"; */ "mOB-su-ZM1.title" = "uPic"; +/* Class = "NSTableColumn"; headerCell.title = "Delete"; ObjectID = "nB3-hC-RSM"; */ +"nB3-hC-RSM.headerCell.title" = "Delete"; + /* Class = "NSTextFieldCell"; title = "uPic will automatically launch at login."; ObjectID = "ngT-lX-vFA"; */ "ngT-lX-vFA.title" = "uPic will automatically launch at login."; @@ -172,3 +196,19 @@ /* Class = "NSTextFieldCell"; title = "Icon:"; ObjectID = "ugx-B2-gPe"; */ "ugx-B2-gPe.title" = "Icon:"; + +/* Class = "NSTextFieldCell"; title = "✋Welcome Page:"; ObjectID = "ul8-3a-sB4"; */ +"ul8-3a-sB4.title" = "✋Welcome Page:"; + +/* Class = "NSTextFieldCell"; title = "Output Format Customization"; ObjectID = "w0T-ah-0NT"; */ +"w0T-ah-0NT.title" = "Output Format Customization"; + +/* Class = "NSTextFieldCell"; title = "💬 Telegram:"; ObjectID = "yO0-9g-BJK"; */ +"yO0-9g-BJK.title" = "💬 Telegram:"; + +//################################################################################## +//# AutoGenStrings 2021-02-02 20:52:14 +//################################################################################## + +/* Class = "NSViewController"; title = "Restart Finder prompt"; ObjectID = "gNK-aF-Cmm"; */ +"gNK-aF-Cmm.title" = "Restart Finder prompt"; diff --git a/uPic/Views/PreferencesWindow/zh-Hans.lproj/Preferences.strings b/uPic/Views/PreferencesWindow/zh-Hans.lproj/Preferences.strings index d339ab3f..88a83268 100644 --- a/uPic/Views/PreferencesWindow/zh-Hans.lproj/Preferences.strings +++ b/uPic/Views/PreferencesWindow/zh-Hans.lproj/Preferences.strings @@ -2,11 +2,8 @@ /* Class = "NSButtonCell"; title = "svend.cc"; ObjectID = "0dV-As-mmQ"; */ "0dV-As-mmQ.title" = "svend.cc"; -/* Class = "NSTextFieldCell"; title = "may require a"; ObjectID = "2Rg-te-FPU"; */ -"2Rg-te-FPU.title" = "可能需要"; - -/* Class = "NSButtonCell"; title = "Paypal"; ObjectID = "59m-hG-lVw"; */ -"59m-hG-lVw.title" = "Paypal"; +/* Class = "NSTextFieldCell"; title = "need a Finder Restart"; ObjectID = "2Rg-te-FPU"; */ +"2Rg-te-FPU.title" = "需要重启访达"; /* Class = "NSViewController"; title = "Host"; ObjectID = "5Ln-jV-uxk"; */ "5Ln-jV-uxk.title" = "图床"; @@ -14,6 +11,9 @@ /* Class = "NSWindow"; title = "Preferences"; ObjectID = "5f3-UK-Rft"; */ "5f3-UK-Rft.title" = "偏好设置"; +/* Class = "NSButtonCell"; title = "Show"; ObjectID = "7Gg-u8-8Yt"; */ +"7Gg-u8-8Yt.title" = "显示"; + /* Class = "NSButtonCell"; title = "Reset"; ObjectID = "8gb-uy-oRd"; */ "8gb-uy-oRd.title" = "重置"; @@ -29,6 +29,9 @@ /* Class = "NSTextFieldCell"; title = "File name scroll speed:"; ObjectID = "BBZ-i9-B2g"; */ "BBZ-i9-B2g.title" = "文件名滚动速度(ms):"; +/* Class = "NSButtonCell"; title = "iSvend"; ObjectID = "BoF-vP-aWK"; */ +"BoF-vP-aWK.title" = "iSvend"; + /* Class = "NSButtonCell"; title = "Add Header Field"; ObjectID = "Ckh-A7-mxC"; */ "Ckh-A7-mxC.title" = "增加 Header 字段"; @@ -41,9 +44,18 @@ /* Class = "NSViewController"; title = "General"; ObjectID = "Gn1-zC-bzB"; */ "Gn1-zC-bzB.title" = "通用"; +/* Class = "NSTextFieldCell"; title = "Full Disk Access"; ObjectID = "Gu0-HV-q4H"; */ +"Gu0-HV-q4H.title" = "完全磁盘访问"; + /* Class = "NSMenuItem"; title = "Non"; ObjectID = "GwK-5k-ATM"; */ "GwK-5k-ATM.title" = "无图标"; +/* Class = "NSTextFieldCell"; title = "Note: Please use {url} {filename} as placeholder for your url"; ObjectID = "Gws-yz-JWw"; */ +"Gws-yz-JWw.title" = "注意: 请使用 {url} {filename} 作为您 URL 的占位符"; + +/* Class = "NSTextFieldCell"; title = "Output Format Customization"; ObjectID = "GzP-4S-ioU"; */ +"GzP-4S-ioU.title" = "输出格式自定义"; + /* Class = "NSViewController"; title = "Advanced"; ObjectID = "H3q-JS-Bu4"; */ "H3q-JS-Bu4.title" = "高级"; @@ -53,6 +65,9 @@ /* Class = "NSButtonCell"; title = "svend.jin@gmail.com"; ObjectID = "IPL-yO-Vkp"; */ "IPL-yO-Vkp.title" = "svend.jin@gmail.com"; +/* Class = "NSButtonCell"; title = "Config"; ObjectID = "Jbz-2F-L08"; */ +"Jbz-2F-L08.title" = "配置"; + /* Class = "NSTextFieldCell"; title = "0.1.0"; ObjectID = "Jnf-AX-bIr"; */ "Jnf-AX-bIr.title" = "0.1.0"; @@ -62,6 +77,9 @@ /* Class = "NSTextFieldCell"; title = "Columns:"; ObjectID = "N1b-Cf-tno"; */ "N1b-Cf-tno.title" = "列数:"; +/* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "NLj-vQ-ghD"; */ +"NLj-vQ-ghD.headerCell.title" = "名称"; + /* Class = "NSTextFieldCell"; title = "🐦 Twitter:"; ObjectID = "OKr-1C-5jV"; */ "OKr-1C-5jV.title" = "🐦 Twitter:"; @@ -80,15 +98,18 @@ /* Class = "NSTextFieldCell"; title = "Supports {year} {month} {day} {hour} {minute} {second} {since_second} {since_millisecond} {random} {filename} {.suffix} {suffix} {mimetype} {saveKey} and etc."; ObjectID = "R0i-0c-6TZ"; */ "R0i-0c-6TZ.title" = "支持 {year} {month} {day} {hour} {minute} {second} {since_second} {since_millisecond} {random} {filename} {.suffix} {suffix} {mimetype} {saveKey} 等变量。"; +/* Class = "NSTableColumn"; headerCell.title = "Custom Style"; ObjectID = "RAq-Oy-he8"; */ +"RAq-Oy-he8.headerCell.title" = "自定义格式"; + +/* Class = "NSButtonCell"; title = "Cancel"; ObjectID = "SfQ-Lo-Xpr"; */ +"SfQ-Lo-Xpr.title" = "取消"; + /* Class = "NSButtonCell"; title = "⚠️ Reset"; ObjectID = "TD4-LI-X9U"; */ "TD4-LI-X9U.title" = "⚠️ 撤销"; /* Class = "NSTextFieldCell"; title = "History record"; ObjectID = "UN0-Iq-Cop"; */ "UN0-Iq-Cop.title" = "历史记录"; -/* Class = "NSTextFieldCell"; title = "💸 Donate:"; ObjectID = "Vjv-pA-ffP"; */ -"Vjv-pA-ffP.title" = "💸 赞助:"; - /* Class = "NSTextFieldCell"; title = "✉️ Contact:"; ObjectID = "Vu4-Wz-Agk"; */ "Vu4-Wz-Agk.title" = "✉️ 联系:"; @@ -119,17 +140,14 @@ /* Class = "NSMenuItem"; title = "More"; ObjectID = "dZy-kW-0lH"; */ "dZy-kW-0lH.title" = "更多"; -/* Class = "NSButtonCell"; title = "Alipay"; ObjectID = "eWy-BH-pJy"; */ -"eWy-BH-pJy.title" = "支付宝"; - /* Class = "NSTextFieldCell"; title = "uPic for iOS is now available on App Store!"; ObjectID = "f1C-OB-3jS"; */ "f1C-OB-3jS.title" = "uPic for iOS 现可在 App Store 上下载!"; /* Class = "NSButtonCell"; title = "https://github.com/gee1k/uPic"; ObjectID = "f2V-P5-pQI"; */ "f2V-P5-pQI.title" = "https://github.com/gee1k/uPic"; -/* Class = "NSButtonCell"; title = "WeChat"; ObjectID = "fJL-Ts-QPI"; */ -"fJL-Ts-QPI.title" = "微信"; +/* Class = "NSButtonCell"; title = "Save"; ObjectID = "gUg-yZ-cS0"; */ +"gUg-yZ-cS0.title" = "保存"; /* Class = "NSButtonCell"; title = "@realSvend"; ObjectID = "i90-se-6z8"; */ "i90-se-6z8.title" = "@realSvend"; @@ -137,9 +155,6 @@ /* Class = "NSTextFieldCell"; title = "Width:"; ObjectID = "iRI-j6-BHQ"; */ "iRI-j6-BHQ.title" = "宽度:"; -/* Class = "NSButtonCell"; title = "Finder Restart"; ObjectID = "jA2-Zt-kWu"; */ -"jA2-Zt-kWu.title" = "重启访达"; - /* Class = "NSTextFieldCell"; title = "Reset"; ObjectID = "jcs-Ou-OZ2"; */ "jcs-Ou-OZ2.title" = "重置"; @@ -152,9 +167,18 @@ /* Class = "NSViewController"; title = "About"; ObjectID = "k6X-N1-mVu"; */ "k6X-N1-mVu.title" = "关于"; +/* Class = "NSButtonCell"; title = "Not Authorized"; ObjectID = "l8U-fu-WXc"; */ +"l8U-fu-WXc.title" = "未授权"; + +/* Class = "NSTextFieldCell"; title = "Hold option and right click on finder, then select Relaunch."; ObjectID = "mDT-aa-auv"; */ +"mDT-aa-auv.title" = "按住 option 并在访达上右击, 然后选择重新开启."; + /* Class = "NSTextFieldCell"; title = "uPic"; ObjectID = "mOB-su-ZM1"; */ "mOB-su-ZM1.title" = "uPic"; +/* Class = "NSTableColumn"; headerCell.title = "Delete"; ObjectID = "nB3-hC-RSM"; */ +"nB3-hC-RSM.headerCell.title" = "删除"; + /* Class = "NSTextFieldCell"; title = "uPic will automatically launch at login."; ObjectID = "ngT-lX-vFA"; */ "ngT-lX-vFA.title" = "uPic 将在系统登录时自动启动。"; @@ -173,3 +197,18 @@ /* Class = "NSTextFieldCell"; title = "Icon:"; ObjectID = "ugx-B2-gPe"; */ "ugx-B2-gPe.title" = "图标:"; +/* Class = "NSTextFieldCell"; title = "✋Welcome Page:"; ObjectID = "ul8-3a-sB4"; */ +"ul8-3a-sB4.title" = "✋欢迎页:"; + +/* Class = "NSTextFieldCell"; title = "Output Format Customization"; ObjectID = "w0T-ah-0NT"; */ +"w0T-ah-0NT.title" = "输出格式自定义"; + +/* Class = "NSTextFieldCell"; title = "💬 Telegram:"; ObjectID = "yO0-9g-BJK"; */ +"yO0-9g-BJK.title" = "💬 Telegram:"; + +//################################################################################## +//# AutoGenStrings 2021-02-02 20:52:14 +//################################################################################## + +/* Class = "NSViewController"; title = "Restart Finder prompt"; ObjectID = "gNK-aF-Cmm"; */ +"gNK-aF-Cmm.title" = "Restart Finder prompt"; diff --git a/uPic/Views/PreferencesWindow/zh-Hant.lproj/Preferences.strings b/uPic/Views/PreferencesWindow/zh-Hant.lproj/Preferences.strings index 6c510c3f..6b93b6f9 100644 --- a/uPic/Views/PreferencesWindow/zh-Hant.lproj/Preferences.strings +++ b/uPic/Views/PreferencesWindow/zh-Hant.lproj/Preferences.strings @@ -2,11 +2,8 @@ /* Class = "NSButtonCell"; title = "svend.cc"; ObjectID = "0dV-As-mmQ"; */ "0dV-As-mmQ.title" = "svend.cc"; -/* Class = "NSTextFieldCell"; title = "may require a"; ObjectID = "2Rg-te-FPU"; */ -"2Rg-te-FPU.title" = "可能需要"; - -/* Class = "NSButtonCell"; title = "Paypal"; ObjectID = "59m-hG-lVw"; */ -"59m-hG-lVw.title" = "PayPal"; +/* Class = "NSTextFieldCell"; title = "need a Finder Restart"; ObjectID = "2Rg-te-FPU"; */ +"2Rg-te-FPU.title" = "需要重启访达"; /* Class = "NSViewController"; title = "Host"; ObjectID = "5Ln-jV-uxk"; */ "5Ln-jV-uxk.title" = "圖床"; @@ -14,6 +11,9 @@ /* Class = "NSWindow"; title = "Preferences"; ObjectID = "5f3-UK-Rft"; */ "5f3-UK-Rft.title" = "偏好設定"; +/* Class = "NSButtonCell"; title = "Show"; ObjectID = "7Gg-u8-8Yt"; */ +"7Gg-u8-8Yt.title" = "显示"; + /* Class = "NSButtonCell"; title = "Reset"; ObjectID = "8gb-uy-oRd"; */ "8gb-uy-oRd.title" = "重設"; @@ -29,6 +29,9 @@ /* Class = "NSTextFieldCell"; title = "File name scroll speed:"; ObjectID = "BBZ-i9-B2g"; */ "BBZ-i9-B2g.title" = "文件名滾動速度(ms):"; +/* Class = "NSButtonCell"; title = "iSvend"; ObjectID = "BoF-vP-aWK"; */ +"BoF-vP-aWK.title" = "iSvend"; + /* Class = "NSButtonCell"; title = "Add Header Field"; ObjectID = "Ckh-A7-mxC"; */ "Ckh-A7-mxC.title" = "增加 Header 字段"; @@ -41,9 +44,18 @@ /* Class = "NSViewController"; title = "General"; ObjectID = "Gn1-zC-bzB"; */ "Gn1-zC-bzB.title" = "通用"; +/* Class = "NSTextFieldCell"; title = "Full Disk Access"; ObjectID = "Gu0-HV-q4H"; */ +"Gu0-HV-q4H.title" = "完全磁片訪問"; + /* Class = "NSMenuItem"; title = "Non"; ObjectID = "GwK-5k-ATM"; */ "GwK-5k-ATM.title" = "無圖標"; +/* Class = "NSTextFieldCell"; title = "Note: Please use {url} {filename} as placeholder for your url"; ObjectID = "Gws-yz-JWw"; */ +"Gws-yz-JWw.title" = "注意:請使用 {url} {filename} 作為您URL的預留位置"; + +/* Class = "NSTextFieldCell"; title = "Output Format Customization"; ObjectID = "GzP-4S-ioU"; */ +"GzP-4S-ioU.title" = "輸出格式自定義"; + /* Class = "NSViewController"; title = "Advanced"; ObjectID = "H3q-JS-Bu4"; */ "H3q-JS-Bu4.title" = "進階"; @@ -53,6 +65,9 @@ /* Class = "NSButtonCell"; title = "svend.jin@gmail.com"; ObjectID = "IPL-yO-Vkp"; */ "IPL-yO-Vkp.title" = "svend.jin@gmail.com"; +/* Class = "NSButtonCell"; title = "Config"; ObjectID = "Jbz-2F-L08"; */ +"Jbz-2F-L08.title" = "配置"; + /* Class = "NSTextFieldCell"; title = "0.1.0"; ObjectID = "Jnf-AX-bIr"; */ "Jnf-AX-bIr.title" = "0.1.0"; @@ -62,6 +77,9 @@ /* Class = "NSTextFieldCell"; title = "Columns:"; ObjectID = "N1b-Cf-tno"; */ "N1b-Cf-tno.title" = "列數:"; +/* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "NLj-vQ-ghD"; */ +"NLj-vQ-ghD.headerCell.title" = "名称"; + /* Class = "NSTextFieldCell"; title = "🐦 Twitter:"; ObjectID = "OKr-1C-5jV"; */ "OKr-1C-5jV.title" = "🐦 Twitter:"; @@ -80,15 +98,18 @@ /* Class = "NSTextFieldCell"; title = "Supports {year} {month} {day} {hour} {minute} {second} {since_second} {since_millisecond} {random} {filename} {.suffix} {suffix} {mimetype} {saveKey} and etc."; ObjectID = "R0i-0c-6TZ"; */ "R0i-0c-6TZ.title" = "支持 {year} {month} {day} {hour} {minute} {second} {since_second} {since_millisecond} {random} {filename} {.suffix} {suffix} {mimetype} {saveKey} 等變數。"; +/* Class = "NSTableColumn"; headerCell.title = "Custom Style"; ObjectID = "RAq-Oy-he8"; */ +"RAq-Oy-he8.headerCell.title" = "自定义格式"; + +/* Class = "NSButtonCell"; title = "Cancel"; ObjectID = "SfQ-Lo-Xpr"; */ +"SfQ-Lo-Xpr.title" = "取消"; + /* Class = "NSButtonCell"; title = "⚠️ Reset"; ObjectID = "TD4-LI-X9U"; */ "TD4-LI-X9U.title" = "⚠️ 撤回"; /* Class = "NSTextFieldCell"; title = "History record"; ObjectID = "UN0-Iq-Cop"; */ "UN0-Iq-Cop.title" = "歷史記錄"; -/* Class = "NSTextFieldCell"; title = "💸 Donate:"; ObjectID = "Vjv-pA-ffP"; */ -"Vjv-pA-ffP.title" = "💸 贊助:"; - /* Class = "NSTextFieldCell"; title = "✉️ Contact:"; ObjectID = "Vu4-Wz-Agk"; */ "Vu4-Wz-Agk.title" = "✉️ 聯繫:"; @@ -119,18 +140,14 @@ /* Class = "NSMenuItem"; title = "More"; ObjectID = "dZy-kW-0lH"; */ "dZy-kW-0lH.title" = "更多"; -/* Class = "NSButtonCell"; title = "Alipay"; ObjectID = "eWy-BH-pJy"; */ -"eWy-BH-pJy.title" = "支付寶"; - /* Class = "NSTextFieldCell"; title = "uPic for iOS is now available on App Store!"; ObjectID = "f1C-OB-3jS"; */ "f1C-OB-3jS.title" = "uPic for iOS 現可在 App Store 上下載!"; - /* Class = "NSButtonCell"; title = "https://github.com/gee1k/uPic"; ObjectID = "f2V-P5-pQI"; */ "f2V-P5-pQI.title" = "https://github.com/gee1k/uPic"; -/* Class = "NSButtonCell"; title = "WeChat"; ObjectID = "fJL-Ts-QPI"; */ -"fJL-Ts-QPI.title" = "WeChat"; +/* Class = "NSButtonCell"; title = "Save"; ObjectID = "gUg-yZ-cS0"; */ +"gUg-yZ-cS0.title" = "保存"; /* Class = "NSButtonCell"; title = "@realSvend"; ObjectID = "i90-se-6z8"; */ "i90-se-6z8.title" = "@realSvend"; @@ -138,9 +155,6 @@ /* Class = "NSTextFieldCell"; title = "Width:"; ObjectID = "iRI-j6-BHQ"; */ "iRI-j6-BHQ.title" = "寬度:"; -/* Class = "NSButtonCell"; title = "Finder Restart"; ObjectID = "jA2-Zt-kWu"; */ -"jA2-Zt-kWu.title" = "重啟訪達"; - /* Class = "NSTextFieldCell"; title = "Reset"; ObjectID = "jcs-Ou-OZ2"; */ "jcs-Ou-OZ2.title" = "重置"; @@ -153,9 +167,18 @@ /* Class = "NSViewController"; title = "About"; ObjectID = "k6X-N1-mVu"; */ "k6X-N1-mVu.title" = "關於"; +/* Class = "NSButtonCell"; title = "Not Authorized"; ObjectID = "l8U-fu-WXc"; */ +"l8U-fu-WXc.title" = "未授权"; + +/* Class = "NSTextFieldCell"; title = "Hold option and right click on finder, then select Relaunch."; ObjectID = "mDT-aa-auv"; */ +"mDT-aa-auv.title" = "按住 option 并在访达上右击, 然后选择重新开启."; + /* Class = "NSTextFieldCell"; title = "uPic"; ObjectID = "mOB-su-ZM1"; */ "mOB-su-ZM1.title" = "uPic"; +/* Class = "NSTableColumn"; headerCell.title = "Delete"; ObjectID = "nB3-hC-RSM"; */ +"nB3-hC-RSM.headerCell.title" = "删除"; + /* Class = "NSTextFieldCell"; title = "uPic will automatically launch at login."; ObjectID = "ngT-lX-vFA"; */ "ngT-lX-vFA.title" = "uPic 將在系統啟動時時自動啟動。"; @@ -173,3 +196,19 @@ /* Class = "NSTextFieldCell"; title = "Icon:"; ObjectID = "ugx-B2-gPe"; */ "ugx-B2-gPe.title" = "圖標:"; + +/* Class = "NSTextFieldCell"; title = "✋Welcome Page:"; ObjectID = "ul8-3a-sB4"; */ +"ul8-3a-sB4.title" = "✋歡迎頁:"; + +/* Class = "NSTextFieldCell"; title = "Output Format Customization"; ObjectID = "w0T-ah-0NT"; */ +"w0T-ah-0NT.title" = "輸出格式自定義"; + +/* Class = "NSTextFieldCell"; title = "💬 Telegram:"; ObjectID = "yO0-9g-BJK"; */ +"yO0-9g-BJK.title" = "💬 Telegram:"; + +//################################################################################## +//# AutoGenStrings 2021-02-02 20:52:14 +//################################################################################## + +/* Class = "NSViewController"; title = "Restart Finder prompt"; ObjectID = "gNK-aF-Cmm"; */ +"gNK-aF-Cmm.title" = "Restart Finder prompt"; diff --git a/uPic/Views/ScreenshotAuthorizationHelpWindow/Base.lproj/ScreenshotAuthorizationHelp.storyboard b/uPic/Views/ScreenshotAuthorizationHelpWindow/Base.lproj/ScreenshotAuthorizationHelp.storyboard new file mode 100644 index 00000000..0c88d672 --- /dev/null +++ b/uPic/Views/ScreenshotAuthorizationHelpWindow/Base.lproj/ScreenshotAuthorizationHelp.storyboard @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/uPic/Views/ScreenshotAuthorizationHelpWindow/ScreenshotAuthorizationHelpViewController.swift b/uPic/Views/ScreenshotAuthorizationHelpWindow/ScreenshotAuthorizationHelpViewController.swift new file mode 100644 index 00000000..000c897f --- /dev/null +++ b/uPic/Views/ScreenshotAuthorizationHelpWindow/ScreenshotAuthorizationHelpViewController.swift @@ -0,0 +1,18 @@ +// +// ScreenshotAuthorizationHelpViewController.swift +// uPic +// +// Created by Svend Jin on 2021/1/24. +// Copyright © 2021 Svend Jin. All rights reserved. +// + +import Cocoa + +class ScreenshotAuthorizationHelpViewController: NSViewController { + + @IBOutlet weak var openPreferencesButton: NSButton! + + @IBAction func didClickopenPreferencesButton(_ sender: NSButton) { + ScreenUtil.openPrivacyScreenCapture() + } +} diff --git a/uPic/Views/ScreenshotAuthorizationHelpWindow/en.lproj/ScreenshotAuthorizationHelp.strings b/uPic/Views/ScreenshotAuthorizationHelpWindow/en.lproj/ScreenshotAuthorizationHelp.strings new file mode 100644 index 00000000..943f9d01 --- /dev/null +++ b/uPic/Views/ScreenshotAuthorizationHelpWindow/en.lproj/ScreenshotAuthorizationHelp.strings @@ -0,0 +1,11 @@ +/* Class = "NSWindow"; title = "Window"; ObjectID = "IIp-aX-hKg"; */ +"IIp-aX-hKg.title" = "Get Screenshot Permission Tutorial"; + +/* Class = "NSTextFieldCell"; title = "请打开系统偏好设置,“点击安全性与隐私”"; ObjectID = "8OE-MZ-BV3"; Note = "step1"; */ +"8OE-MZ-BV3.title" = "Please open System Preferences and click `Security and Privacy`"; + +/* Class = "NSTextFieldCell"; title = "授予 uPic “屏幕录制”权限"; ObjectID = "qqL-jK-k4X"; */ +"qqL-jK-k4X.title" = "Grant uPic `screen recording` permission"; + +/* Class = "NSButton"; title = "Open Security & Privacy"; ObjectID = "MZV-nV-okO"; */ +"MZV-nV-okO.title" = "Open Security & Privacy"; diff --git a/uPic/Views/ScreenshotAuthorizationHelpWindow/zh-Hans.lproj/ScreenshotAuthorizationHelp.strings b/uPic/Views/ScreenshotAuthorizationHelpWindow/zh-Hans.lproj/ScreenshotAuthorizationHelp.strings new file mode 100644 index 00000000..f7d8784e --- /dev/null +++ b/uPic/Views/ScreenshotAuthorizationHelpWindow/zh-Hans.lproj/ScreenshotAuthorizationHelp.strings @@ -0,0 +1,11 @@ +/* Class = "NSWindow"; title = "Window"; ObjectID = "IIp-aX-hKg"; */ +"IIp-aX-hKg.title" = "获取截图权限教程"; + +/* Class = "NSTextFieldCell"; title = "请打开系统偏好设置,“点击安全性与隐私”"; ObjectID = "8OE-MZ-BV3"; Note = "step1"; */ +"8OE-MZ-BV3.title" = "请打开系统偏好设置,“点击安全性与隐私”"; + +/* Class = "NSTextFieldCell"; title = "授予 uPic “屏幕录制”权限"; ObjectID = "qqL-jK-k4X"; */ +"qqL-jK-k4X.title" = "授予 uPic “屏幕录制”权限"; + +/* Class = "NSButton"; title = "Open Security & Privacy"; ObjectID = "MZV-nV-okO"; */ +"MZV-nV-okO.title" = "打开安全性与隐私"; diff --git a/uPic/Views/ScreenshotAuthorizationHelpWindow/zh-Hant.lproj/ScreenshotAuthorizationHelp.strings b/uPic/Views/ScreenshotAuthorizationHelpWindow/zh-Hant.lproj/ScreenshotAuthorizationHelp.strings new file mode 100644 index 00000000..913ac8f3 --- /dev/null +++ b/uPic/Views/ScreenshotAuthorizationHelpWindow/zh-Hant.lproj/ScreenshotAuthorizationHelp.strings @@ -0,0 +1,11 @@ +/* Class = "NSWindow"; title = "Window"; ObjectID = "IIp-aX-hKg"; */ +"IIp-aX-hKg.title" = "獲取截圖許可權教程"; + +/* Class = "NSTextFieldCell"; title = "请打开系统偏好设置,“点击安全性与隐私”"; ObjectID = "8OE-MZ-BV3"; Note = "step1"; */ +"8OE-MZ-BV3.title" = "請打開系統偏好設定,“點擊安全性與隱私”"; + +/* Class = "NSTextFieldCell"; title = "授予 uPic “屏幕录制”权限"; ObjectID = "qqL-jK-k4X"; */ +"qqL-jK-k4X.title" = "授予 uPic “荧幕錄製”許可權"; + +/* Class = "NSButton"; title = "Open Security & Privacy"; ObjectID = "MZV-nV-okO"; */ +"MZV-nV-okO.title" = "打開安全性與隱私"; diff --git a/uPic/Views/WelcomeView/Base.lproj/Welcome.storyboard b/uPic/Views/WelcomeView/Base.lproj/Welcome.storyboard new file mode 100644 index 00000000..3be10fce --- /dev/null +++ b/uPic/Views/WelcomeView/Base.lproj/Welcome.storyboard @@ -0,0 +1,653 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A powerful and simple file uploader tool. +Upload any files to any services you like. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Just drag the file to uPic icon on the status menu bar and then release your mouse. +It is just this simple. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + You can take a screenshot and upload. +Please enable Setting -> Security & Privacy -> Privacy -> Screen Recording -> uPic + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Limited by macOS, uPic can not access files outside of sandbox. +If not granted permission, uPic may not be able to upload some files. +Please be aware that uPic DO NOT collect any of your informations. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/uPic/Views/WelcomeView/WelcomeViewController.swift b/uPic/Views/WelcomeView/WelcomeViewController.swift new file mode 100644 index 00000000..42a3895c --- /dev/null +++ b/uPic/Views/WelcomeView/WelcomeViewController.swift @@ -0,0 +1,108 @@ +// +// WelcomViewController.swift +// uPic +// +// Created by Licardo on 2021/1/19. +// Copyright © 2021 Svend Jin. All rights reserved. +// + +import Cocoa + +class WelcomViewController: NSViewController { + + @IBOutlet weak var closeButton: NSButton! + @IBOutlet weak var containerView: NSView! + @IBOutlet weak var previousButton: NSButton! + @IBOutlet weak var previousButtonLabel: NSTextField! + @IBOutlet weak var nextButton: NSButton! + @IBOutlet weak var nextButtonLabel: NSTextField! + + // 子界面 + var currentViewIndex = 0 + let viewList = [ + WindowManager.shared.instantiateControllerFromStoryboard(storyboard: "Welcome", withIdentifier: "welcomeViewController0") as NSViewController, + WindowManager.shared.instantiateControllerFromStoryboard(storyboard: "Welcome", withIdentifier: "welcomeViewController1") as NSViewController, + WindowManager.shared.instantiateControllerFromStoryboard(storyboard: "Welcome", withIdentifier: "welcomeViewController2") as NSViewController, + WindowManager.shared.instantiateControllerFromStoryboard(storyboard: "Welcome", withIdentifier: "welcomeViewController3") as NSViewController, + WindowManager.shared.instantiateControllerFromStoryboard(storyboard: "Welcome", withIdentifier: "welcomeViewController4") as NSViewController, + WindowManager.shared.instantiateControllerFromStoryboard(storyboard: "Welcome", withIdentifier: "welcomeViewController5") as NSViewController, + WindowManager.shared.instantiateControllerFromStoryboard(storyboard: "Welcome", withIdentifier: "welcomeViewController6") as NSViewController + ] + + override func viewDidLoad() { + super.viewDidLoad() + // Do view setup here. + + closeButton.alphaValue = 0.5 + + for viewController in viewList { + addChild(viewController) + } + containerView.addSubview(children[0].view) + } + + @IBAction func didClickCloseButton(_ sender: NSButton) { + closeWindow(sender) + } + @IBAction func didClickPreviousButton(_ sender: NSButton) { + switchToPage(to: currentViewIndex - 1) + } + + @IBAction func didClickNextButton(_ sender: NSButton) { + if currentViewIndex == viewList.count - 1 { // 最后一个页面 + debugPrintOnly("开始授权") + // 欢迎页授权用户主目录 + DiskPermissionManager.shared.requestHomeDirectoryPermissions() + closeWindow(sender) + } else { + switchToPage(to: currentViewIndex + 1) + } + } + + func closeWindow(_ sender: Any) { + view.window?.close() + } + +} + +// MARK: - 界面切换 +extension WelcomViewController { + // 翻页 + func switchToPage(to targetViewIndex: Int) { + if targetViewIndex>=0 && targetViewIndex < viewList.count { + // 切换按钮可见性 + if targetViewIndex == 0 { + previousButton.isHidden = true + previousButtonLabel.isHidden = true + nextButton.isHidden = false + nextButtonLabel.isHidden = false + } else if targetViewIndex == viewList.count { + previousButton.isHidden = false + previousButtonLabel.isHidden = false + nextButton.isHidden = true + nextButtonLabel.isHidden = true + } else { + previousButton.isHidden = false + previousButtonLabel.isHidden = false + nextButton.isHidden = false + nextButtonLabel.isHidden = false + } + // 切换页面 + let currentViewController = viewList[currentViewIndex] + let targetViewController = viewList[targetViewIndex] + if targetViewIndex < currentViewIndex { + transition(from: currentViewController, to: targetViewController, options: .slideRight, completionHandler: nil) + } else { + transition(from: currentViewController, to: targetViewController, options: .slideLeft, completionHandler: nil) + } + // 更新文本 + if targetViewIndex == viewList.count - 1 { // 最后一个页面 + nextButtonLabel.stringValue = "Authorize".localized + } else { + nextButtonLabel.stringValue = "Next".localized + } + // 更新引用 + currentViewIndex = targetViewIndex + } + } +} diff --git a/uPic/Views/WelcomeView/WelcomeWindowController.swift b/uPic/Views/WelcomeView/WelcomeWindowController.swift new file mode 100644 index 00000000..745b7f4e --- /dev/null +++ b/uPic/Views/WelcomeView/WelcomeWindowController.swift @@ -0,0 +1,19 @@ +// +// WelcomeWindowController.swift +// uPic +// +// Created by Licardo on 2021/1/19. +// Copyright © 2021 Svend Jin. All rights reserved. +// + +import Cocoa + +class WelcomeWindowController: NSWindowController { + + override func windowDidLoad() { + super.windowDidLoad() + + // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. + } + +} diff --git a/uPic/Views/WelcomeView/en.lproj/Welcome.strings b/uPic/Views/WelcomeView/en.lproj/Welcome.strings new file mode 100644 index 00000000..e407f36f --- /dev/null +++ b/uPic/Views/WelcomeView/en.lproj/Welcome.strings @@ -0,0 +1,57 @@ + +/* Class = "NSTextFieldCell"; title = "Share Extension"; ObjectID = "5PO-nX-1ts"; */ +"5PO-nX-1ts.title" = "Share Extension"; + +/* Class = "NSTextFieldCell"; title = "Next"; ObjectID = "EN9-1Z-Sqq"; */ +"EN9-1Z-Sqq.title" = "Next"; + +/* Class = "NSTextFieldCell"; title = "A powerful and simple file uploader tool.\nUpload any files to any services you like."; ObjectID = "J8p-JL-LaG"; */ +"J8p-JL-LaG.title" = "A powerful and simple file uploader tool.\nUpload any files to any services you like."; + +/* Class = "NSTextFieldCell"; title = "Due to system security restrictions, uPic cannot access files outside the sandbox. \nYou will not be able to use right click upload, share upload, command line upload, etc. without authorization. \nNote: uPic does not collect any information from you."; ObjectID = "KKR-Bg-AzW"; */ +"KKR-Bg-AzW.title" = "Due to system security restrictions, uPic cannot access files outside the sandbox. \nYou will not be able to use right click upload, share upload, command line upload, etc. without authorization. \nNote: uPic does not collect any information from you."; + +/* Class = "NSTextFieldCell"; title = "Authorization"; ObjectID = "RwC-HL-AhF"; */ +"RwC-HL-AhF.title" = "Authorization"; + +/* Class = "NSTextFieldCell"; title = "Just drag the file to uPic icon on the status menu bar and then release your mouse.\nIt is just this simple. "; ObjectID = "U8F-dC-vKZ"; */ +"U8F-dC-vKZ.title" = "Just drag the file to uPic icon on the status menu bar and then release your mouse.\nIt is just this simple. "; + +/* Class = "NSTextFieldCell"; title = "Multiple Services"; ObjectID = "X47-xi-iV3"; */ +"X47-xi-iV3.title" = "Multiple Services"; + +/* Class = "NSTextFieldCell"; title = "We need"; ObjectID = "a6A-gm-fbk"; */ +"a6A-gm-fbk.title" = "We need"; + +/* Class = "NSWindow"; title = "Window"; ObjectID = "aw5-Tv-dJb"; */ +"aw5-Tv-dJb.title" = "Window"; + +/* Class = "NSTextFieldCell"; title = "Drag to Upload"; ObjectID = "dfW-Tj-Gog"; */ +"dfW-Tj-Gog.title" = "Drag to Upload"; + +/* Class = "NSTextFieldCell"; title = "You can take a screenshot and upload.\nPlease enable Setting -> Security & Privacy -> Privacy -> Screen Recording -> uPic"; ObjectID = "isq-Ch-gao"; */ +"isq-Ch-gao.title" = "You can take a screenshot and upload.\nPlease enable Setting -> Security & Privacy -> Privacy -> Screen Recording -> uPic"; + +/* Class = "NSTextFieldCell"; title = "Previous"; ObjectID = "lZV-cL-KsE"; */ +"lZV-cL-KsE.title" = "Previous"; + +/* Class = "NSTextFieldCell"; title = "uPic"; ObjectID = "mld-Ub-NIp"; */ +"mld-Ub-NIp.title" = "uPic"; + +/* Class = "NSTextFieldCell"; title = "Upload Screenshot"; ObjectID = "n2q-3P-rmS"; */ +"n2q-3P-rmS.title" = "Upload Screenshot"; + +/* Class = "NSTextFieldCell"; title = "Welcome to"; ObjectID = "pk7-xU-bny"; */ +"pk7-xU-bny.title" = "Welcome to"; + +/* Class = "NSTextFieldCell"; title = "Finder Extension"; ObjectID = "vGP-mK-Tjk"; */ +"vGP-mK-Tjk.title" = "Finder Extension"; + +/* Class = "NSTextFieldCell"; title = "GitHub, Imgur, SM.MS, Qiniu KODO, Upyun USS, Aliyun OSS, Tencent Cloud COS, Gitee, Amazon S3, Baidu Cloud BOS, Lsky Pro"; ObjectID = "ve2-Sd-1j7"; */ +"ve2-Sd-1j7.title" = "GitHub, Imgur, SM.MS, Qiniu KODO, Upyun USS, Aliyun OSS, Tencent Cloud COS, Gitee, Amazon S3, Baidu Cloud BOS, Lsky Pro"; + +/* Class = "NSTextFieldCell"; title = "Click share button and select \"Upload via uPic\"."; ObjectID = "xlO-Fz-Nxq"; */ +"xlO-Fz-Nxq.title" = "Click share button and select \"Upload via uPic\"."; + +/* Class = "NSTextFieldCell"; title = "Right click on the file and select \"Upload via uPic\"."; ObjectID = "xz2-3l-Jef"; */ +"xz2-3l-Jef.title" = "Right click on the file and select \"Upload via uPic\"."; diff --git a/uPic/Views/WelcomeView/zh-Hans.lproj/Welcome.strings b/uPic/Views/WelcomeView/zh-Hans.lproj/Welcome.strings new file mode 100644 index 00000000..5c7b458f --- /dev/null +++ b/uPic/Views/WelcomeView/zh-Hans.lproj/Welcome.strings @@ -0,0 +1,57 @@ + +/* Class = "NSTextFieldCell"; title = "Share Extension"; ObjectID = "5PO-nX-1ts"; */ +"5PO-nX-1ts.title" = "共享菜单"; + +/* Class = "NSTextFieldCell"; title = "Next"; ObjectID = "EN9-1Z-Sqq"; */ +"EN9-1Z-Sqq.title" = "下一步"; + +/* Class = "NSTextFieldCell"; title = "A powerful and simple file uploader tool.\nUpload any files to any services you like."; ObjectID = "J8p-JL-LaG"; */ +"J8p-JL-LaG.title" = "一个强大且简单的上传工具\n将任何文件上传至任何服务"; + +/* Class = "NSTextFieldCell"; title = "Due to system security restrictions, uPic cannot access files outside the sandbox. \nYou will not be able to use right click upload, share upload, command line upload, etc. without authorization. \nNote: uPic does not collect any information from you."; ObjectID = "KKR-Bg-AzW"; */ +"KKR-Bg-AzW.title" = "由于系统的安全限制,uPic 无法访问沙盒之外的文件。\n若不授权将无法使用右键上传、分享上传、命令行上传等功能。\n注:uPic 不会收集您的任何信息。"; + +/* Class = "NSTextFieldCell"; title = "Authorization"; ObjectID = "RwC-HL-AhF"; */ +"RwC-HL-AhF.title" = "授权"; + +/* Class = "NSTextFieldCell"; title = "Just drag the file to uPic icon on the status menu bar and then release your mouse.\nIt is just this simple. "; ObjectID = "U8F-dC-vKZ"; */ +"U8F-dC-vKZ.title" = "将文件拖拽至 uPic 菜单栏图标然后松开鼠标\n就是这么简单"; + +/* Class = "NSTextFieldCell"; title = "Multiple Services"; ObjectID = "X47-xi-iV3"; */ +"X47-xi-iV3.title" = "多个服务"; + +/* Class = "NSTextFieldCell"; title = "We need"; ObjectID = "a6A-gm-fbk"; */ +"a6A-gm-fbk.title" = "我们需要"; + +/* Class = "NSWindow"; title = "Window"; ObjectID = "aw5-Tv-dJb"; */ +"aw5-Tv-dJb.title" = "Window"; + +/* Class = "NSTextFieldCell"; title = "Drag to Upload"; ObjectID = "dfW-Tj-Gog"; */ +"dfW-Tj-Gog.title" = "拖拽上传"; + +/* Class = "NSTextFieldCell"; title = "You can take a screenshot and upload.\nPlease enable Setting -> Security & Privacy -> Privacy -> Screen Recording -> uPic"; ObjectID = "isq-Ch-gao"; */ +"isq-Ch-gao.title" = "您可以截图上传\n请开启 系统偏好设置 -> 安全性与隐私 -> 隐私 -> 屏幕录制 -> uPic"; + +/* Class = "NSTextFieldCell"; title = "Previous"; ObjectID = "lZV-cL-KsE"; */ +"lZV-cL-KsE.title" = "上一步"; + +/* Class = "NSTextFieldCell"; title = "uPic"; ObjectID = "mld-Ub-NIp"; */ +"mld-Ub-NIp.title" = "uPic"; + +/* Class = "NSTextFieldCell"; title = "Upload Screenshot"; ObjectID = "n2q-3P-rmS"; */ +"n2q-3P-rmS.title" = "截图上传"; + +/* Class = "NSTextFieldCell"; title = "Welcome to"; ObjectID = "pk7-xU-bny"; */ +"pk7-xU-bny.title" = "欢迎使用"; + +/* Class = "NSTextFieldCell"; title = "Finder Extension"; ObjectID = "vGP-mK-Tjk"; */ +"vGP-mK-Tjk.title" = "访达扩展"; + +/* Class = "NSTextFieldCell"; title = "GitHub, Imgur, SM.MS, Qiniu KODO, Upyun USS, Aliyun OSS, Tencent Cloud COS, Gitee, Amazon S3, Baidu Cloud BOS, Lsky Pro"; ObjectID = "ve2-Sd-1j7"; */ +"ve2-Sd-1j7.title" = "GitHub, Imgur, SM.MS, 七牛 KODO, 又拍云 USS, 阿里云 OSS, 腾讯云 COS, Gitee, Amazon S3, 百度云 BOS, Lsky Pro"; + +/* Class = "NSTextFieldCell"; title = "Click share button and select \"Upload via uPic\"."; ObjectID = "xlO-Fz-Nxq"; */ +"xlO-Fz-Nxq.title" = "点击分享按钮并选择 \"使用 uPic 上传\""; + +/* Class = "NSTextFieldCell"; title = "Right click on the file and select \"Upload via uPic\"."; ObjectID = "xz2-3l-Jef"; */ +"xz2-3l-Jef.title" = "在文件上右键并选择 \"使用 uPic 上传\""; diff --git a/uPic/Views/WelcomeView/zh-Hant.lproj/Welcome.strings b/uPic/Views/WelcomeView/zh-Hant.lproj/Welcome.strings new file mode 100644 index 00000000..4fcf1d7e --- /dev/null +++ b/uPic/Views/WelcomeView/zh-Hant.lproj/Welcome.strings @@ -0,0 +1,57 @@ + +/* Class = "NSTextFieldCell"; title = "Share Extension"; ObjectID = "5PO-nX-1ts"; */ +"5PO-nX-1ts.title" = "共亯選單"; + +/* Class = "NSTextFieldCell"; title = "Next"; ObjectID = "EN9-1Z-Sqq"; */ +"EN9-1Z-Sqq.title" = "下一步"; + +/* Class = "NSTextFieldCell"; title = "A powerful and simple file uploader tool.\nUpload any files to any services you like."; ObjectID = "J8p-JL-LaG"; */ +"J8p-JL-LaG.title" = "一個强大且簡單的上傳工具\n將任何文件上傳至任何服務"; + +/* Class = "NSTextFieldCell"; title = "Due to system security restrictions, uPic cannot access files outside the sandbox. \nYou will not be able to use right click upload, share upload, command line upload, etc. without authorization. \nNote: uPic does not collect any information from you."; ObjectID = "KKR-Bg-AzW"; */ +"KKR-Bg-AzW.title" = "由於系統的安全限制,uPic 無法訪問沙箱之外的檔案。\n若不授權將無法使用右鍵上傳、分享上傳、命令列上傳等功能。\n注:uPic不會收集您的任何資訊。"; + +/* Class = "NSTextFieldCell"; title = "Authorization"; ObjectID = "RwC-HL-AhF"; */ +"RwC-HL-AhF.title" = "授權"; + +/* Class = "NSTextFieldCell"; title = "Just drag the file to uPic icon on the status menu bar and then release your mouse.\nIt is just this simple. "; ObjectID = "U8F-dC-vKZ"; */ +"U8F-dC-vKZ.title" = "將檔案拖拽至uPic功能表列圖標然後鬆開滑鼠\n就是這麼簡單"; + +/* Class = "NSTextFieldCell"; title = "Multiple Services"; ObjectID = "X47-xi-iV3"; */ +"X47-xi-iV3.title" = "多個服務"; + +/* Class = "NSTextFieldCell"; title = "We need"; ObjectID = "a6A-gm-fbk"; */ +"a6A-gm-fbk.title" = "我們需要"; + +/* Class = "NSWindow"; title = "Window"; ObjectID = "aw5-Tv-dJb"; */ +"aw5-Tv-dJb.title" = "Window"; + +/* Class = "NSTextFieldCell"; title = "Drag to Upload"; ObjectID = "dfW-Tj-Gog"; */ +"dfW-Tj-Gog.title" = "拖拽上傳"; + +/* Class = "NSTextFieldCell"; title = "You can take a screenshot and upload.\nPlease enable Setting -> Security & Privacy -> Privacy -> Screen Recording -> uPic"; ObjectID = "isq-Ch-gao"; */ +"isq-Ch-gao.title" = "您可以截圖上傳\n請開啟系統偏好設定 -> 安全性與隱私 -> 隱私 -> 荧幕錄製 -> uPic"; + +/* Class = "NSTextFieldCell"; title = "Previous"; ObjectID = "lZV-cL-KsE"; */ +"lZV-cL-KsE.title" = "上一步"; + +/* Class = "NSTextFieldCell"; title = "uPic"; ObjectID = "mld-Ub-NIp"; */ +"mld-Ub-NIp.title" = "uPic"; + +/* Class = "NSTextFieldCell"; title = "Upload Screenshot"; ObjectID = "n2q-3P-rmS"; */ +"n2q-3P-rmS.title" = "截圖上傳"; + +/* Class = "NSTextFieldCell"; title = "Welcome to"; ObjectID = "pk7-xU-bny"; */ +"pk7-xU-bny.title" = "歡迎使用"; + +/* Class = "NSTextFieldCell"; title = "Finder Extension"; ObjectID = "vGP-mK-Tjk"; */ +"vGP-mK-Tjk.title" = "訪達擴展"; + +/* Class = "NSTextFieldCell"; title = "GitHub, Imgur, SM.MS, Qiniu KODO, Upyun USS, Aliyun OSS, Tencent Cloud COS, Gitee, Amazon S3, Baidu Cloud BOS, Lsky Pro"; ObjectID = "ve2-Sd-1j7"; */ +"ve2-Sd-1j7.title" = "GitHub, Imgur, SM.MS, 七牛 KODO, 又拍云 USS, 阿里云 OSS, 腾讯云 COS, Gitee, Amazon S3, 百度云 BOS, Lsky Pro"; + +/* Class = "NSTextFieldCell"; title = "Click share button and select \"Upload via uPic\"."; ObjectID = "xlO-Fz-Nxq"; */ +"xlO-Fz-Nxq.title" = "點擊分享按鈕並選擇 \"使用uPic上傳\""; + +/* Class = "NSTextFieldCell"; title = "Right click on the file and select \"Upload via uPic\"."; ObjectID = "xz2-3l-Jef"; */ +"xz2-3l-Jef.title" = "在檔案上右鍵並選擇 \"使用uPic上傳\""; diff --git a/uPic/en.lproj/Localizable.strings b/uPic/en.lproj/Localizable.strings index 4778079a..c4210d3e 100644 --- a/uPic/en.lproj/Localizable.strings +++ b/uPic/en.lproj/Localizable.strings @@ -15,7 +15,19 @@ "Example:" = "Example:"; "On" = "On"; "Off" = "Off"; +"Later" = "Later"; "APP Name" = "APP Name"; +"Copy" = "Copy"; + +// 欢迎界面 +"Next" = "Next"; +"Authorize" = "Authorize"; +"Not Authorized" = "Not Authorized"; +"Authorized" = "Authorized"; + +// 全盘权限授权 Alert 提示 +"Full Disk Access" = "Full Disk Access"; +"Full Disk Access Message" = "Due to system security restrictions, App Store downloads do not have the right to read files outside of the app directly. So we need your authorization, but we won't collect any information from you!\nNote: Without authorization, you will not be able to use right click upload, share upload, command line upload and other functions"; /* 成功通知标题 */ "Successfully" = "Successfully"; @@ -44,6 +56,8 @@ /* 文件不存在或已被删除 */ "The file does not exist or has been deleted!" = "The file does not exist or has been deleted!"; +/* 无权访问该文件 */ +"No access to file!" = "Do not have permission to access this file, please go to preferences to authorize disk access!"; /* 文件格式不支持 */ "File format not supported!" = "File format not supported!"; /* 文件大小超过限制 */ diff --git a/uPic/en.lproj/Main.strings b/uPic/en.lproj/Main.strings index 5ebe233a..6f712f34 100644 --- a/uPic/en.lproj/Main.strings +++ b/uPic/en.lproj/Main.strings @@ -27,7 +27,7 @@ "6dh-zS-Vam.title" = "Redo"; /* Class = "NSMenuItem"; title = "Paypal"; ObjectID = "70g-zL-O4p"; */ -"70g-zL-O4p.title" = "Paypal"; +//"70g-zL-O4p.title" = "Paypal"; /* Class = "NSMenu"; title = "Main Menu"; ObjectID = "AYu-sK-qS6"; */ "AYu-sK-qS6.title" = "Main Menu"; @@ -63,7 +63,7 @@ "Opc-aA-hUg.title" = "Markdown"; /* Class = "NSMenuItem"; title = "WeChat"; ObjectID = "Qky-3r-Bgs"; */ -"Qky-3r-Bgs.title" = "WeChat"; +//"Qky-3r-Bgs.title" = "WeChat"; /* Class = "NSMenuItem"; title = "Select All"; ObjectID = "Ruw-6m-B2m"; */ "Ruw-6m-B2m.title" = "Select All"; @@ -90,7 +90,7 @@ "Z6H-TN-83r.title" = "More"; /* Class = "NSMenuItem"; title = "Alipay"; ObjectID = "aHw-Zc-eD7"; */ -"aHw-Zc-eD7.title" = "Alipay"; +//"aHw-Zc-eD7.title" = "Alipay"; /* Class = "NSMenu"; title = "File"; ObjectID = "bib-Uj-vzu"; */ "bib-Uj-vzu.title" = "File"; @@ -111,7 +111,7 @@ "gVA-U4-sdL.title" = "Paste"; /* Class = "NSMenu"; title = "Donate"; ObjectID = "iGe-NR-YFa"; */ -"iGe-NR-YFa.title" = "Donate"; +//"iGe-NR-YFa.title" = "Donate"; /* Class = "NSMenu"; title = "Output format encode"; ObjectID = "jbA-xM-vl3"; */ "jbA-xM-vl3.title" = "Output format encode"; @@ -141,13 +141,20 @@ "x3v-GG-iWU.title" = "Copy"; /* Class = "NSMenuItem"; title = "Donate"; ObjectID = "yCF-Ec-Lgz"; */ -"yCF-Ec-Lgz.title" = "Donate"; +//"yCF-Ec-Lgz.title" = "Donate"; /* Class = "NSMenuItem"; title = "Off"; ObjectID = "yW4-Cl-nF5"; */ "yW4-Cl-nF5.title" = "Off"; /* Class = "NSMenuItem"; title = "Check for updates..."; ObjectID = "yai-4F-Btp"; */ -"yai-4F-Btp.title" = "Check for updates..."; +//"yai-4F-Btp.title" = "Check for updates..."; /* Class = "NSMenuItem"; title = "On"; ObjectID = "ynd-0y-yEv"; */ "ynd-0y-yEv.title" = "On"; + +//################################################################################## +//# AutoGenStrings 2021-02-02 20:52:14 +//################################################################################## + +/* Class = "NSMenuItem"; title = "Custom"; ObjectID = "F4P-SL-bu2"; */ +"F4P-SL-bu2.title" = "Custom"; diff --git a/uPic/zh-Hans.lproj/Localizable.strings b/uPic/zh-Hans.lproj/Localizable.strings index 779cd2ee..408d5170 100644 --- a/uPic/zh-Hans.lproj/Localizable.strings +++ b/uPic/zh-Hans.lproj/Localizable.strings @@ -15,7 +15,20 @@ "Example:" = "示例:"; "On" = "开启"; "Off" = "关闭"; +"Later" = "稍后"; "APP Name" = "APP 名称"; +"Copy" = "复制"; + +// 欢迎界面 +"Next" = "下一步"; +"Authorize" = "授权"; +"Not Authorized" = "未授权"; +"Authorized" = "已授权"; + +// 全盘权限授权 Alert 提示 +"Full Disk Access" = "完全磁盘访问"; +"Full Disk Access Message" = "由于系统的安全限制,App Store 下载的软件无权直接读取应用外的文件。所以我们需要您的授权,但我们不会收集你的任何信息! +\n注:若不授权,将无法使用右键上传、分享上传、命令行上传等功能"; /* 成功通知标题 */ "Successfully" = "成功"; @@ -44,6 +57,8 @@ /* 复制的文件不存在 */ "The file does not exist or has been deleted!" = "复制的文件不存在或已被删除!"; +/* 无权访问该文件 */ +"No access to file!" = "无权访问该文件,请前往偏好设置授权磁盘访问!"; /* 文件格式不支持 */ "File format not supported!" = "文件格式不支持!"; /* 文件大小超过限制 */ diff --git a/uPic/zh-Hans.lproj/Main.strings b/uPic/zh-Hans.lproj/Main.strings index 4562f1da..63826c3a 100644 --- a/uPic/zh-Hans.lproj/Main.strings +++ b/uPic/zh-Hans.lproj/Main.strings @@ -27,7 +27,7 @@ "6dh-zS-Vam.title" = "重做"; /* Class = "NSMenuItem"; title = "Paypal"; ObjectID = "70g-zL-O4p"; */ -"70g-zL-O4p.title" = "Paypal"; +//"70g-zL-O4p.title" = "Paypal"; /* Class = "NSMenu"; title = "Main Menu"; ObjectID = "AYu-sK-qS6"; */ "AYu-sK-qS6.title" = "Main Menu"; @@ -63,7 +63,7 @@ "Opc-aA-hUg.title" = "Markdown"; /* Class = "NSMenuItem"; title = "WeChat"; ObjectID = "Qky-3r-Bgs"; */ -"Qky-3r-Bgs.title" = "微信"; +//"Qky-3r-Bgs.title" = "微信"; /* Class = "NSMenuItem"; title = "Select All"; ObjectID = "Ruw-6m-B2m"; */ "Ruw-6m-B2m.title" = "全选"; @@ -90,7 +90,7 @@ "Z6H-TN-83r.title" = "更多"; /* Class = "NSMenuItem"; title = "Alipay"; ObjectID = "aHw-Zc-eD7"; */ -"aHw-Zc-eD7.title" = "支付宝"; +//"aHw-Zc-eD7.title" = "支付宝"; /* Class = "NSMenu"; title = "File"; ObjectID = "bib-Uj-vzu"; */ "bib-Uj-vzu.title" = "文件"; @@ -111,7 +111,7 @@ "gVA-U4-sdL.title" = "粘贴"; /* Class = "NSMenu"; title = "Donate"; ObjectID = "iGe-NR-YFa"; */ -"iGe-NR-YFa.title" = "捐赠"; +//"iGe-NR-YFa.title" = "捐赠"; /* Class = "NSMenu"; title = "Output format encode"; ObjectID = "jbA-xM-vl3"; */ "jbA-xM-vl3.title" = "输出格式编码"; @@ -141,13 +141,20 @@ "x3v-GG-iWU.title" = "拷贝"; /* Class = "NSMenuItem"; title = "Donate"; ObjectID = "yCF-Ec-Lgz"; */ -"yCF-Ec-Lgz.title" = "捐赠"; +//"yCF-Ec-Lgz.title" = "捐赠"; /* Class = "NSMenuItem"; title = "Off"; ObjectID = "yW4-Cl-nF5"; */ "yW4-Cl-nF5.title" = "关闭"; /* Class = "NSMenuItem"; title = "Check for updates..."; ObjectID = "yai-4F-Btp"; */ -"yai-4F-Btp.title" = "检查更新..."; +//"yai-4F-Btp.title" = "检查更新..."; /* Class = "NSMenuItem"; title = "On"; ObjectID = "ynd-0y-yEv"; */ "ynd-0y-yEv.title" = "开启"; + +//################################################################################## +//# AutoGenStrings 2021-02-02 20:52:14 +//################################################################################## + +/* Class = "NSMenuItem"; title = "Custom"; ObjectID = "F4P-SL-bu2"; */ +"F4P-SL-bu2.title" = "Custom"; diff --git a/uPic/zh-Hant.lproj/Localizable.strings b/uPic/zh-Hant.lproj/Localizable.strings index ecc0d117..88c83ec0 100644 --- a/uPic/zh-Hant.lproj/Localizable.strings +++ b/uPic/zh-Hant.lproj/Localizable.strings @@ -16,7 +16,20 @@ "Example:" = "範例:"; "On" = "開啟"; "Off" = "關閉"; +"Later" = "稍後"; "APP Name" = "APP 名稱"; +"Copy" = "复制"; + +// 欢迎界面 +"Next" = "下一步"; +"Authorize" = "授权"; +"Not Authorized" = "未授权"; +"Authorized" = "已授权"; + +// 全盘权限授权 Alert 提示 +"Full Disk Access" = "完全磁片訪問"; +"Full Disk Access Message" = "由於系統的安全限制,App Store下載的軟件無權直接讀取應用外的檔案。所以我們需要您的授權,但我們不會收集你的任何資訊! +\n注:若不授權,將無法使用右鍵上傳、分享上傳、命令列上傳等功能"; /* 成功通知標題 */ "Successfully" = "成功"; @@ -45,8 +58,10 @@ /* 複製的文件不存在 */ "The file does not exist or has been deleted!" = "複製的文件不存在或已被刪除!"; +/* 无权访问该文件 */ +"No access to file!" = "無權訪問該檔案,請前往偏好設定授權磁片訪問!"; /* 文件格式不支持 */ -"File format not supported!" = "文件格式不支持!"; +"File format not supported!" = "檔案格式不支持!"; /* 文件大小超過限制 */ "File is over the size limit! Limit:" = "文件大小超過限制!限制:"; /* 圖床配置存在問題, 請檢查 */ diff --git a/uPic/zh-Hant.lproj/Main.strings b/uPic/zh-Hant.lproj/Main.strings index 32599b70..86fc670c 100644 --- a/uPic/zh-Hant.lproj/Main.strings +++ b/uPic/zh-Hant.lproj/Main.strings @@ -27,7 +27,7 @@ "6dh-zS-Vam.title" = "復原"; /* Class = "NSMenuItem"; title = "Paypal"; ObjectID = "70g-zL-O4p"; */ -"70g-zL-O4p.title" = "Paypal"; +//"70g-zL-O4p.title" = "Paypal"; /* Class = "NSMenu"; title = "Main Menu"; ObjectID = "AYu-sK-qS6"; */ "AYu-sK-qS6.title" = "Main Menu"; @@ -63,7 +63,7 @@ "Opc-aA-hUg.title" = "Markdown"; /* Class = "NSMenuItem"; title = "WeChat"; ObjectID = "Qky-3r-Bgs"; */ -"Qky-3r-Bgs.title" = "Wechat"; +//"Qky-3r-Bgs.title" = "Wechat"; /* Class = "NSMenuItem"; title = "Select All"; ObjectID = "Ruw-6m-B2m"; */ "Ruw-6m-B2m.title" = "全選"; @@ -90,7 +90,7 @@ "Z6H-TN-83r.title" = "更多"; /* Class = "NSMenuItem"; title = "Alipay"; ObjectID = "aHw-Zc-eD7"; */ -"aHw-Zc-eD7.title" = "支付寶"; +//"aHw-Zc-eD7.title" = "支付寶"; /* Class = "NSMenu"; title = "File"; ObjectID = "bib-Uj-vzu"; */ "bib-Uj-vzu.title" = "文件"; @@ -111,7 +111,7 @@ "gVA-U4-sdL.title" = "貼上"; /* Class = "NSMenu"; title = "Donate"; ObjectID = "iGe-NR-YFa"; */ -"iGe-NR-YFa.title" = "贊助"; +//"iGe-NR-YFa.title" = "贊助"; /* Class = "NSMenu"; title = "Output format encode"; ObjectID = "jbA-xM-vl3"; */ "jbA-xM-vl3.title" = "輸出格式編碼"; @@ -141,13 +141,20 @@ "x3v-GG-iWU.title" = "複製"; /* Class = "NSMenuItem"; title = "Donate"; ObjectID = "yCF-Ec-Lgz"; */ -"yCF-Ec-Lgz.title" = "贊助"; +//"yCF-Ec-Lgz.title" = "贊助"; /* Class = "NSMenuItem"; title = "Off"; ObjectID = "yW4-Cl-nF5"; */ "yW4-Cl-nF5.title" = "關閉"; /* Class = "NSMenuItem"; title = "Check for updates..."; ObjectID = "yai-4F-Btp"; */ -"yai-4F-Btp.title" = "檢查更新..."; +//"yai-4F-Btp.title" = "檢查更新..."; /* Class = "NSMenuItem"; title = "On"; ObjectID = "ynd-0y-yEv"; */ "ynd-0y-yEv.title" = "開啟"; + +//################################################################################## +//# AutoGenStrings 2021-02-02 20:52:14 +//################################################################################## + +/* Class = "NSMenuItem"; title = "Custom"; ObjectID = "F4P-SL-bu2"; */ +"F4P-SL-bu2.title" = "Custom"; diff --git a/uPicFinderExtension/FinderSync.swift b/uPicFinderExtension/FinderSync.swift index b08e1881..465f965b 100644 --- a/uPicFinderExtension/FinderSync.swift +++ b/uPicFinderExtension/FinderSync.swift @@ -13,6 +13,8 @@ class FinderSync: FIFinderSync { override init() { super.init() + NSLog("FinderSync() launched from %@", Bundle.main.bundlePath as NSString) + // Set up the directory we are syncing. let finderSync = FIFinderSyncController.default() if let mountedVolumes = FileManager.default.mountedVolumeURLs(includingResourceValuesForKeys: nil, options: [.skipHiddenVolumes]) { @@ -27,79 +29,53 @@ class FinderSync: FIFinderSync { } } - // MARK: - Menu and toolbar item support - - override var toolbarItemName: String { - return "uPic" - } - - override var toolbarItemToolTip: String { - return "Upload selected files via uPic".localized - } - - override var toolbarItemImage: NSImage { - var image: NSImage? = nil + override func menu(for menuKind: FIMenuKind) -> NSMenu? { + // Produce a menu for the extension. + + let menu = NSMenu(title: "") + let uploadMenuItem = NSMenuItem(title: "Upload via uPic".localized, action: #selector(uploadFile(_:)), keyEquivalent: "") + switch FinderUtil.getIcon() { + case 0: + uploadMenuItem.image = nil case 2: - image = NSImage(named: "color") + uploadMenuItem.image = NSImage(named: "color") default: if #available(macOS 11, *) { - image = NSImage(named: "single_new") + uploadMenuItem.image = NSImage(named: "single_new") } else { - image = NSImage(named: "single") + uploadMenuItem.image = NSImage(named: "single") } } - image?.isTemplate = true - return image! + uploadMenuItem.image?.isTemplate = true + menu.addItem(uploadMenuItem) + + return menu } - override func menu(for menuKind: FIMenuKind) -> NSMenu? { - // Produce a menu for the extension. + @IBAction func uploadFile(_ sender: AnyObject?) { + let paths = getSelectedPathsFromFinder() + let pathString = paths.joined(separator: "\n") - switch menuKind { - case .contextualMenuForItems, .toolbarItemMenu: - let menu = NSMenu(title: "") - let uploadMenuItem = NSMenuItem(title: "Upload via uPic".localized, action: #selector(uploadFile(_:)), keyEquivalent: "") - - switch FinderUtil.getIcon() { - case 0: - uploadMenuItem.image = nil - case 2: - uploadMenuItem.image = NSImage(named: "color") - default: - if #available(macOS 11, *) { - uploadMenuItem.image = NSImage(named: "single_new") - } else { - uploadMenuItem.image = NSImage(named: "single") - } - } - - uploadMenuItem.image?.isTemplate = true - menu.addItem(uploadMenuItem) - - return menu - default: - break - } + let encodeUrl = "uPic://files?\(pathString)".urlEncoded() - return nil + if let url = URL(string: encodeUrl) { + NSWorkspace.shared.open(url) + } else { + UploadNotifier.postNotification(.uploadFiles, object: pathString) + } } - @IBAction func uploadFile(_ sender: AnyObject?) { - if let items = FIFinderSyncController.default().selectedItemURLs() { - var paths = "" - for item in items { - let filePath = item.path - paths = "\(paths)\(filePath)\n" - } - let encodeUrl = "uPic://files?\(paths)".urlEncoded() - - if let url = URL(string: encodeUrl) { - NSWorkspace.shared.open(url) - } else { - UploadNotifier.postNotification(.uploadFiles, object: paths) + func getSelectedPathsFromFinder() -> [String] { + var paths = [String]() + if let items = FIFinderSyncController.default().selectedItemURLs(), items.count > 0 { + items.forEach { (url) in + paths.append(url.path) } + } else if let url = FIFinderSyncController.default().targetedURL() { + paths.append(url.path) } + return paths } } diff --git a/uPicFinderExtension/Info.plist b/uPicFinderExtension/Info.plist index 3c4b8dc0..63a962c9 100644 --- a/uPicFinderExtension/Info.plist +++ b/uPicFinderExtension/Info.plist @@ -34,7 +34,7 @@ $(PRODUCT_MODULE_NAME).FinderSync NSHumanReadableCopyright - Copyright © 2020 Svend Jin. All rights reserved. + Copyright © 2021 Svend Jin. All rights reserved. NSPrincipalClass NSApplication TeamIdentifierPrefix diff --git a/uPicFinderExtension/uPicFinderExtension.entitlements b/uPicFinderExtension/uPicFinderExtension.entitlements index c847c113..3a64222f 100644 --- a/uPicFinderExtension/uPicFinderExtension.entitlements +++ b/uPicFinderExtension/uPicFinderExtension.entitlements @@ -8,7 +8,9 @@ $(TeamIdentifierPrefix)com.svend.uPic - com.apple.security.files.user-selected.read-only + com.apple.security.files.user-selected.read-write + + com.apple.security.network.client diff --git a/uPicFinderExtension/uPicFinderExtensionDebug.entitlements b/uPicFinderExtension/uPicFinderExtensionDebug.entitlements new file mode 100644 index 00000000..3a64222f --- /dev/null +++ b/uPicFinderExtension/uPicFinderExtensionDebug.entitlements @@ -0,0 +1,16 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.application-groups + + $(TeamIdentifierPrefix)com.svend.uPic + + com.apple.security.files.user-selected.read-write + + com.apple.security.network.client + + + diff --git a/uPicShareExtension/Info.plist b/uPicShareExtension/Info.plist index ce8b33cd..bffc625c 100644 --- a/uPicShareExtension/Info.plist +++ b/uPicShareExtension/Info.plist @@ -29,7 +29,18 @@ NSExtensionAttributes NSExtensionActivationRule - TRUEPREDICATE + + NSExtensionActivationSupportsAttachmentsWithMaxCount + 9 + NSExtensionActivationSupportsFileWithMaxCount + 9 + NSExtensionActivationSupportsImageWithMaxCount + 9 + NSExtensionActivationSupportsMovieWithMaxCount + 9 + NSExtensionActivationSupportsText + + NSExtensionPointIdentifier com.apple.share-services diff --git a/uPicShareExtension/uPicShareExtension.entitlements b/uPicShareExtension/uPicShareExtension.entitlements index f2ef3ae0..3a64222f 100644 --- a/uPicShareExtension/uPicShareExtension.entitlements +++ b/uPicShareExtension/uPicShareExtension.entitlements @@ -2,9 +2,15 @@ - com.apple.security.app-sandbox - - com.apple.security.files.user-selected.read-only - + com.apple.security.app-sandbox + + com.apple.security.application-groups + + $(TeamIdentifierPrefix)com.svend.uPic + + com.apple.security.files.user-selected.read-write + + com.apple.security.network.client + diff --git a/uPicShareExtension/uPicShareExtensionDebug.entitlements b/uPicShareExtension/uPicShareExtensionDebug.entitlements new file mode 100644 index 00000000..3a64222f --- /dev/null +++ b/uPicShareExtension/uPicShareExtensionDebug.entitlements @@ -0,0 +1,16 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.application-groups + + $(TeamIdentifierPrefix)com.svend.uPic + + com.apple.security.files.user-selected.read-write + + com.apple.security.network.client + + +