From d3fb04c41802e247bab9a1fd605720384ff20151 Mon Sep 17 00:00:00 2001 From: iHTCboy Date: Sat, 9 Apr 2022 16:45:36 +0800 Subject: [PATCH] =?UTF-8?q?v2.0.3=201.=20=E5=A2=9E=E5=8A=A0=E6=98=AF?= =?UTF-8?q?=E5=90=A6=E8=AE=B0=E4=BD=8F=E5=AF=86=E7=A0=81=E3=80=81=E4=BF=A1?= =?UTF-8?q?=E4=BB=BB=E8=AE=BE=E5=A4=87=E7=9A=84=E5=8B=BE=E9=80=89=E9=A1=B9?= =?UTF-8?q?=202.=20=E5=88=87=E6=8D=A2=E8=B4=A6=E5=8F=B7=E4=BB=8E=E5=8F=8C?= =?UTF-8?q?=E7=82=B9=E7=A1=AE=E8=AE=A4=E6=94=B9=E4=B8=BA=E5=8D=95=E5=87=BB?= =?UTF-8?q?=E7=A1=AE=E8=AE=A4=E5=88=87=E6=8D=A2=203.=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=92=8C=E5=AE=8C=E5=96=84=E4=B8=80=E4=BA=9BBug=E5=92=8C?= =?UTF-8?q?=E4=BD=93=E9=AA=8C=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AppleParty.xcodeproj/project.pbxproj | 24 +- .../APInAppPurchseVC.storyboard | 1 + .../InAppPurchseView/APInAppPurchseVC.swift | 11 +- .../Models/IAPCharge.swift | 0 .../Models/IAPModel.swift | 0 .../Models}/TierStemParser.swift | 0 .../InAppPurchseView/Models}/XLSXParser.swift | 2 +- .../Models/XMLModel.swift | 0 .../APSettingVC.swift | 2 + .../APSettingVC.xib | 1 + AppleParty/LoginView/APLogin2FAVC.swift | 2 + AppleParty/LoginView/APLogin2FAVC.xib | 14 + AppleParty/LoginView/APLoginVC.swift | 31 +- AppleParty/LoginView/APLoginVC.xib | 48 +- AppleParty/RootView/APRootVC.swift | 6 +- .../RootView/APSwichAccountPopover.swift | 10 +- AppleParty/SettingView/SettingVC.swift | 576 ------------------ AppleParty/Shared/Info/UserCenter.swift | 4 +- AppleParty/Shared/Network/APClient.swift | 2 +- AppleParty/Shared/Utils/APHUD.swift | 6 +- AppleParty/Shared/Utils/ARLogs.swift | 2 +- .../SparkleUpdate/AppleParty-release.html | 8 + AppleParty/SparkleUpdate/update.xml | 14 +- 23 files changed, 129 insertions(+), 635 deletions(-) rename AppleParty/AppListView/{ => InAppPurchseView}/Models/IAPCharge.swift (100%) rename AppleParty/AppListView/{ => InAppPurchseView}/Models/IAPModel.swift (100%) rename AppleParty/{Vendors/ITMS => AppListView/InAppPurchseView/Models}/TierStemParser.swift (100%) rename AppleParty/{Vendors/ITMS => AppListView/InAppPurchseView/Models}/XLSXParser.swift (99%) rename AppleParty/AppListView/{ => InAppPurchseView}/Models/XMLModel.swift (100%) rename AppleParty/{SettingView => AppSettingView}/APSettingVC.swift (92%) rename AppleParty/{SettingView => AppSettingView}/APSettingVC.xib (98%) delete mode 100644 AppleParty/SettingView/SettingVC.swift diff --git a/AppleParty.xcodeproj/project.pbxproj b/AppleParty.xcodeproj/project.pbxproj index c3e094a..e6d4e4c 100644 --- a/AppleParty.xcodeproj/project.pbxproj +++ b/AppleParty.xcodeproj/project.pbxproj @@ -291,7 +291,7 @@ 6D8F182B27F07E97001A30BF /* AppListView */, 6D8F183027F07E97001A30BF /* EmailToolView */, 6D8F183427F07E97001A30BF /* QRcodeView */, - 6D8F183127F07E97001A30BF /* SettingView */, + 6D8F183127F07E97001A30BF /* AppSettingView */, 6D8F184227F07E97001A30BF /* Shared */, 6D8F187A27F0AC74001A30BF /* Vendors */, 6D8F183327F07E97001A30BF /* SparkleUpdate */, @@ -357,6 +357,8 @@ 6D3ECCE927F1D6C6005E4597 /* IAPCharge.swift */, 6D3ECCE727F1D6BB005E4597 /* IAPModel.swift */, 6D3ECCDD27F1D027005E4597 /* XMLModel.swift */, + 6D8F187D27F0AC83001A30BF /* TierStemParser.swift */, + 6D8F187E27F0AC83001A30BF /* XLSXParser.swift */, ); path = Models; sourceTree = ""; @@ -384,15 +386,14 @@ 6D8F182B27F07E97001A30BF /* AppListView */ = { isa = PBXGroup; children = ( - 6D3ECCDC27F1D00B005E4597 /* Models */, - 6D8F183227F07E97001A30BF /* InAppPurchseView */, - 6D3ECCD127F1CAC5005E4597 /* ScreenShotsView */, 6D8F182D27F07E97001A30BF /* APAppListVC.swift */, 6D8F185E27F08161001A30BF /* AppList.storyboard */, 6D8F186527F081ED001A30BF /* APAppListAdapter.swift */, 6D8F186127F081D3001A30BF /* APAppListCell.swift */, 6D8F186227F081D3001A30BF /* APAppListCell.xib */, 6D8F186727F08201001A30BF /* APAppListModel.swift */, + 6D8F183227F07E97001A30BF /* InAppPurchseView */, + 6D3ECCD127F1CAC5005E4597 /* ScreenShotsView */, ); path = AppListView; sourceTree = ""; @@ -409,13 +410,13 @@ path = EmailToolView; sourceTree = ""; }; - 6D8F183127F07E97001A30BF /* SettingView */ = { + 6D8F183127F07E97001A30BF /* AppSettingView */ = { isa = PBXGroup; children = ( 6D59A22D27F31E7000C7D8F5 /* APSettingVC.swift */, 6D59A22E27F31E7000C7D8F5 /* APSettingVC.xib */, ); - path = SettingView; + path = AppSettingView; sourceTree = ""; }; 6D8F183227F07E97001A30BF /* InAppPurchseView */ = { @@ -430,6 +431,7 @@ 6D584B5727F20A8000924BFE /* APInAppPurchseCell.swift */, 6D584B5527F20A4D00924BFE /* APInappPurchseCell.xib */, 6D59A21A27F2D49000C7D8F5 /* DragView.swift */, + 6D3ECCDC27F1D00B005E4597 /* Models */, ); path = InAppPurchseView; sourceTree = ""; @@ -537,8 +539,6 @@ children = ( 6D8F188627F0ACA5001A30BF /* GDataXMLNode.h */, 6D8F188727F0ACA5001A30BF /* GDataXMLNode.m */, - 6D8F187D27F0AC83001A30BF /* TierStemParser.swift */, - 6D8F187E27F0AC83001A30BF /* XLSXParser.swift */, 6D8F188027F0AC83001A30BF /* XMLManager.swift */, ); path = ITMS; @@ -1077,7 +1077,7 @@ CODE_SIGN_ENTITLEMENTS = AppleParty/AppleParty.entitlements; CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 2022.04.07; + CURRENT_PROJECT_VERSION = 2022.04.09; DEVELOPMENT_TEAM = ""; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = AppleParty/Info.plist; @@ -1090,7 +1090,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.13; - MARKETING_VERSION = 2.0.2; + MARKETING_VERSION = 2.0.3; PRODUCT_BUNDLE_IDENTIFIER = cn.com.37iOS.AppleParty; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1111,7 +1111,7 @@ CODE_SIGN_ENTITLEMENTS = AppleParty/AppleParty.entitlements; CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 2022.04.07; + CURRENT_PROJECT_VERSION = 2022.04.09; DEVELOPMENT_TEAM = ""; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = AppleParty/Info.plist; @@ -1124,7 +1124,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.13; - MARKETING_VERSION = 2.0.2; + MARKETING_VERSION = 2.0.3; PRODUCT_BUNDLE_IDENTIFIER = cn.com.37iOS.AppleParty; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/AppleParty/AppListView/InAppPurchseView/APInAppPurchseVC.storyboard b/AppleParty/AppListView/InAppPurchseView/APInAppPurchseVC.storyboard index 451f988..6b4d9fb 100644 --- a/AppleParty/AppListView/InAppPurchseView/APInAppPurchseVC.storyboard +++ b/AppleParty/AppListView/InAppPurchseView/APInAppPurchseVC.storyboard @@ -462,6 +462,7 @@ + diff --git a/AppleParty/AppListView/InAppPurchseView/APInAppPurchseVC.swift b/AppleParty/AppListView/InAppPurchseView/APInAppPurchseVC.swift index ab3c891..aaba0f8 100644 --- a/AppleParty/AppListView/InAppPurchseView/APInAppPurchseVC.swift +++ b/AppleParty/AppListView/InAppPurchseView/APInAppPurchseVC.swift @@ -19,6 +19,7 @@ class APInAppPurchseVC: NSViewController { var iapList: [IAPList.IAP] = [] + @IBOutlet weak var outputIAPListBtn: NSButton! @IBOutlet weak var appNameView: NSTextField! @IBOutlet weak var outlineView: NSOutlineView! @@ -81,7 +82,7 @@ class APInAppPurchseVC: NSViewController { data.append(contentsOf: iaps.data(using: .utf8) ?? Data()) try data.write(to: filePath!) } catch { - // failed to write file (bad permissions, bad filename etc.) + NSAlert.show("导出失败:\(error.localizedDescription)") } } } @@ -107,7 +108,8 @@ extension APInAppPurchseVC { func fetchIAPs() { APClient.iaps(appid: currentApp!.adamId).request(showLoading: true, inView: self.view) { [weak self] result, response, error in guard let err = error else { - let iapL = IAPList(body:result, app: (self?.currentApp!)!) + guard let app = self?.currentApp else { return } //请求过程关闭页面可能导致为空 + let iapL = IAPList(body:result, app: app) self?.iapList = iapL.iapList self?.outlineView.reloadData() self?.updateRowInfo() @@ -122,6 +124,7 @@ extension APInAppPurchseVC { return } + outputIAPListBtn.isEnabled = false let group = DispatchGroup() for i in 0..= 8 && xlsx[7].count > 0 ) ? xlsx[7] : [String](repeating: "zh-Hans", count: ids.count) + // 如果没有填写,默认用简中 + let langs = xlsx[7].count > 0 ? xlsx[7].map { $0.count > 0 ? $0 : "zh-Hans" } : [String](repeating: "zh-Hans", count: ids.count) // 检查行数 guard ids.count == names.count, pris.count == levs.count, dps.count == types.count, types.count == ids.count, names.count == langs.count else { diff --git a/AppleParty/AppListView/Models/IAPCharge.swift b/AppleParty/AppListView/InAppPurchseView/Models/IAPCharge.swift similarity index 100% rename from AppleParty/AppListView/Models/IAPCharge.swift rename to AppleParty/AppListView/InAppPurchseView/Models/IAPCharge.swift diff --git a/AppleParty/AppListView/Models/IAPModel.swift b/AppleParty/AppListView/InAppPurchseView/Models/IAPModel.swift similarity index 100% rename from AppleParty/AppListView/Models/IAPModel.swift rename to AppleParty/AppListView/InAppPurchseView/Models/IAPModel.swift diff --git a/AppleParty/Vendors/ITMS/TierStemParser.swift b/AppleParty/AppListView/InAppPurchseView/Models/TierStemParser.swift similarity index 100% rename from AppleParty/Vendors/ITMS/TierStemParser.swift rename to AppleParty/AppListView/InAppPurchseView/Models/TierStemParser.swift diff --git a/AppleParty/Vendors/ITMS/XLSXParser.swift b/AppleParty/AppListView/InAppPurchseView/Models/XLSXParser.swift similarity index 99% rename from AppleParty/Vendors/ITMS/XLSXParser.swift rename to AppleParty/AppListView/InAppPurchseView/Models/XLSXParser.swift index 1cebc2f..0f339c9 100644 --- a/AppleParty/Vendors/ITMS/XLSXParser.swift +++ b/AppleParty/AppListView/InAppPurchseView/Models/XLSXParser.swift @@ -83,7 +83,7 @@ struct XLSXParser { return column.filter { (value) -> Bool in value == "语言" }.isNotEmpty - }.first ?? [] + }.first ?? xlsx[7] return [pris.filter({ $0 != "金额" }), prods.filter({ $0 != "Product ID" }), diff --git a/AppleParty/AppListView/Models/XMLModel.swift b/AppleParty/AppListView/InAppPurchseView/Models/XMLModel.swift similarity index 100% rename from AppleParty/AppListView/Models/XMLModel.swift rename to AppleParty/AppListView/InAppPurchseView/Models/XMLModel.swift diff --git a/AppleParty/SettingView/APSettingVC.swift b/AppleParty/AppSettingView/APSettingVC.swift similarity index 92% rename from AppleParty/SettingView/APSettingVC.swift rename to AppleParty/AppSettingView/APSettingVC.swift index e3a8ddf..8b52c6d 100644 --- a/AppleParty/SettingView/APSettingVC.swift +++ b/AppleParty/AppSettingView/APSettingVC.swift @@ -18,6 +18,7 @@ class APSettingVC: NSViewController { } } + @IBOutlet weak var trusDeviceBtn: NSButton! @IBOutlet weak var sPasswordBtn: NSButton! @IBOutlet weak var clearCacheBtn: NSButton! @@ -46,6 +47,7 @@ class APSettingVC: NSViewController { override func viewDidLoad() { super.viewDidLoad() title = "App设置" + trusDeviceBtn.state = InfoCenter.shared.trusDevice ? .on : .off } } diff --git a/AppleParty/SettingView/APSettingVC.xib b/AppleParty/AppSettingView/APSettingVC.xib similarity index 98% rename from AppleParty/SettingView/APSettingVC.xib rename to AppleParty/AppSettingView/APSettingVC.xib index 0fd07b0..42c1be5 100644 --- a/AppleParty/SettingView/APSettingVC.xib +++ b/AppleParty/AppSettingView/APSettingVC.xib @@ -10,6 +10,7 @@ + diff --git a/AppleParty/LoginView/APLogin2FAVC.swift b/AppleParty/LoginView/APLogin2FAVC.swift index dbe1a0f..0a787c0 100644 --- a/AppleParty/LoginView/APLogin2FAVC.swift +++ b/AppleParty/LoginView/APLogin2FAVC.swift @@ -18,6 +18,7 @@ class APLogin2FAVC: NSViewController { @IBOutlet weak var voiceCodeBtn: NSButton! @IBOutlet weak var phoneCodeView: NSTextField! @IBOutlet weak var tipsWarningView: NSTextField! + @IBOutlet weak var trusDeviceBtn: NSButton! @IBOutlet weak var indicatorView: NSProgressIndicator! @IBOutlet weak var verifyBtn: NSButton! @@ -31,6 +32,7 @@ class APLogin2FAVC: NSViewController { super.viewDidLoad() phoneCodeView.delegate = self fetchPhoneList() + trusDeviceBtn.state = InfoCenter.shared.trusDevice ? .on : .off } @IBAction func clickedCancelBtn(_ sender: NSButton) { diff --git a/AppleParty/LoginView/APLogin2FAVC.xib b/AppleParty/LoginView/APLogin2FAVC.xib index f6e6714..d0104ec 100644 --- a/AppleParty/LoginView/APLogin2FAVC.xib +++ b/AppleParty/LoginView/APLogin2FAVC.xib @@ -13,6 +13,7 @@ + @@ -151,6 +152,17 @@ DQ + @@ -159,6 +171,8 @@ DQ + + diff --git a/AppleParty/LoginView/APLoginVC.swift b/AppleParty/LoginView/APLoginVC.swift index 2c252e4..b0c6267 100644 --- a/AppleParty/LoginView/APLoginVC.swift +++ b/AppleParty/LoginView/APLoginVC.swift @@ -20,6 +20,7 @@ class APLoginVC: NSViewController { @IBOutlet weak var tableView: NSTableView! @IBOutlet weak var tipsWarningView: NSTextField! + @IBOutlet weak var autoLoginBtn: NSButton! @IBOutlet weak var indicatorView: NSProgressIndicator! @IBOutlet weak var loginBtn: NSButton! @@ -29,12 +30,10 @@ class APLoginVC: NSViewController { passwordView.delegate = self tipsWarningView.maximumNumberOfLines = 5 - tableView.delegate = self - tableView.dataSource = self - // 最近登录的账号 - let name = UserCenter.shared.loginedUser.appleid - let pwd = UserCenter.shared.loginedUser.password + let user = UserCenter.shared.loginedUser + let name = user.appleid + let pwd = user.password guard name.count > 0, pwd.count > 0 else { return } accountView.stringValue = name passwordView.stringValue = pwd @@ -54,6 +53,11 @@ class APLoginVC: NSViewController { @IBAction func showAccountHistoryList(_ sender: Any) { + if historyBox.isHidden { + tableView.delegate = self + tableView.dataSource = self + tableView.reloadData() + } historyBox.isHidden = !historyBox.isHidden } @@ -88,8 +92,11 @@ extension APLoginVC { case .notAuthorized: self?.showTips("Apple ID 或密码不正确") case .twoStepOrFactor: - // 账号密码正确 - UserCenter.shared.loginedUser = User(appleid: account, password: pwd) + // 保存账号密码 + if self?.autoLoginBtn.state == .on { + UserCenter.shared.isAutoLogin = true + UserCenter.shared.loginedUser = User(appleid: account, password: pwd) + } // 双重认证 let vc = APLogin2FAVC() vc.cancelHandle = { [weak self] in @@ -111,8 +118,11 @@ extension APLoginVC { let code = response?.statusCode // 登陆态有效 if code == 200 { - // 账号密码正确 - UserCenter.shared.loginedUser = User(appleid: account, password: pwd) + // 保存账号密码 + if self?.autoLoginBtn.state == .on { + UserCenter.shared.isAutoLogin = true + UserCenter.shared.loginedUser = User(appleid: account, password: pwd) + } self?.validateSession() } else { self?.showTips("\(code ?? 0),\(error.debugDescription)") @@ -140,6 +150,8 @@ extension APLoginVC { } func trusDevice() { + guard InfoCenter.shared.trusDevice else { return} + APClient.trusDevice(isTrus: true).request { result, response, error in if response?.statusCode == 204 { debugPrint("信任设备成功~") @@ -166,6 +178,7 @@ extension APLoginVC { func viewEnabled(_ isEnabled: Bool) { showTips("") loginBtn.isEnabled = isEnabled + historyBox.isHidden = true isEnabled ? indicatorView.stopAnimation(nil) : indicatorView.startAnimation(nil) } diff --git a/AppleParty/LoginView/APLoginVC.xib b/AppleParty/LoginView/APLoginVC.xib index 8c14d4d..0fb725b 100644 --- a/AppleParty/LoginView/APLoginVC.xib +++ b/AppleParty/LoginView/APLoginVC.xib @@ -9,6 +9,7 @@ + @@ -20,12 +21,12 @@ - + - + @@ -36,7 +37,7 @@ - + @@ -47,7 +48,7 @@ - + @@ -75,7 +76,7 @@ + @@ -213,15 +228,16 @@ Gw - + + + - diff --git a/AppleParty/RootView/APRootVC.swift b/AppleParty/RootView/APRootVC.swift index 5271de9..7bf7aef 100644 --- a/AppleParty/RootView/APRootVC.swift +++ b/AppleParty/RootView/APRootVC.swift @@ -21,8 +21,10 @@ class APRootVC: NSViewController { override func viewDidAppear() { super.viewDidAppear() - let wc = self.view.window?.windowController as! APRootWC - wc.clickedAccountItem(nil) + if UserCenter.shared.isAutoLogin { + let wc = self.view.window?.windowController as! APRootWC + wc.clickedAccountItem(nil) + } } /// 配置显示的功能列表 diff --git a/AppleParty/RootView/APSwichAccountPopover.swift b/AppleParty/RootView/APSwichAccountPopover.swift index bf1d580..46bf429 100644 --- a/AppleParty/RootView/APSwichAccountPopover.swift +++ b/AppleParty/RootView/APSwichAccountPopover.swift @@ -19,7 +19,6 @@ class APSwichAccountPopover: NSViewController { super.viewDidLoad() tableView.delegate = self tableView.dataSource = self - tableView.doubleAction = #selector(handleDoubleClick) } @IBAction func cliedCancelBtn(_ sender: Any) { @@ -50,8 +49,13 @@ extension APSwichAccountPopover: NSTableViewDelegate, NSTableViewDataSource { return nil } - @objc func handleDoubleClick() { - let clickedRow = tableView.clickedRow + func tableViewSelectionDidChange(_ notification: Notification){ + let tableView = notification.object as! NSTableView + let clickedRow = tableView.selectedRow + guard clickedRow >= 0 else { + return + } + tableView.deselectRow(clickedRow) if let selectFunc = selectHandle { selectFunc(clickedRow) } diff --git a/AppleParty/SettingView/SettingVC.swift b/AppleParty/SettingView/SettingVC.swift deleted file mode 100644 index f388f9d..0000000 --- a/AppleParty/SettingView/SettingVC.swift +++ /dev/null @@ -1,576 +0,0 @@ -// -// SettingVC.swift -// AppleParty -// -// Created by HTC on 2021/9/25. -// Copyright © 2021 37 Mobile Games. All rights reserved. -// - -import Cocoa - -class APSettingVC: NSViewController { - - // 完成回调通知 - var finishBlock: (([String]) -> Void)? - // 处理结果 - var errorsList = [String]() - var results = [String:[String:[Any]]]() - var dataPath: String = "default" - var commonPath: URL { - var documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] - documentsURL.appendPathComponent("AppleParty") - return documentsURL - } - var logFilePath: URL { - get { - var documentsURL = commonPath - documentsURL.appendPathComponent("Notification") - documentsURL.appendPathComponent("\(dataPath)_log.txt") - createFileDirectory(url: documentsURL) - return documentsURL - } - } - - // 定时同步时间:小时 - var syncHourString: String { - get { string(from: UserDefaults.standard.object(forKey: "SettingVC_syncHourString")) } - set { UserDefaults.standard.setValue(newValue, forKey: "SettingVC_syncHourString") } - } - // 定时同步时间:分钟 - var syncMinuteString: String { - get { string(from: UserDefaults.standard.object(forKey: "SettingVC_syncMinuteString")) } - set { UserDefaults.standard.setValue(newValue, forKey: "SettingVC_syncMinuteString") } - } - // 邮件通知 - var isSendEmail: Bool { - get { bool(from: UserDefaults.standard.object(forKey: "SettingVC_isSendEmail")) } - set { UserDefaults.standard.setValue(newValue, forKey: "SettingVC_isSendEmail") } - } - // 邮件地址 - var syncEmailsString: String { - get { string(from: UserDefaults.standard.object(forKey: "SettingVC_syncEmailsString")) } - set { UserDefaults.standard.setValue(newValue, forKey: "SettingVC_syncEmailsString") } - } - // 消息 - var messagesDB: [String: [String:Any]] { - get { - if let data = UserDefaults.standard.object(forKey: "SettingVC_messagesDB") as? Data, let db = NSKeyedUnarchiver.unarchiveObject(with: data) as? [String: [String:Any]] { - return db - } - return [:] - } - set { - UserDefaults.standard.setValue(NSKeyedArchiver.archivedData(withRootObject: newValue), forKey: "SettingVC_messagesDB") - } - } - - var isLoginViewShow: Bool { - get { return false } - set { - sPasswordBtn.isHidden = newValue - AccontTitleLbl.isHidden = newValue - timingSyncBtn.isHidden = newValue - syncHoursTF.isHidden = newValue - syncMinutesTF.isHidden = newValue - emailSyncBtn.isHidden = newValue - notiEmailsTF.isHidden = newValue - manualSyncBtn.isHidden = newValue - clearCacheBtn.isHidden = !newValue - AccountLine.isHidden = newValue - clearCachePwBtnLeadingConstraint.priority = newValue == true ? .defaultLow : .defaultHigh - } - } - - @IBOutlet weak var trusDeviceBtn: NSButton! - @IBOutlet weak var sPasswordBtn: NSButton! - @IBOutlet weak var AccontTitleLbl: NSTextField! - @IBOutlet weak var timingSyncBtn: NSButton! - @IBOutlet weak var syncHoursTF: NSTextField! - @IBOutlet weak var syncMinutesTF: NSTextField! - @IBOutlet weak var emailSyncBtn: NSButton! - @IBOutlet weak var notiEmailsTF: NSTextField! - @IBOutlet weak var manualSyncBtn: NSButton! - @IBOutlet weak var clearCacheBtn: NSButton! - @IBOutlet var AccountLine: NSView! - - @IBOutlet weak var clearCachePwBtnLeadingConstraint: NSLayoutConstraint! - - - @IBAction func clickedSAccountBtn(_ sender: NSButton) { - InfoCenter.shared.trusDevice = sender.state == .on ? true : false - } - - @IBAction func clickedSPasswordBtn(_ sender: Any) { - let sb = NSStoryboard(name: "APPasswordVC", bundle: Bundle(for: self.classForCoder)) - let pwdVC = sb.instantiateController(withIdentifier: "APPasswordVC") as? APPasswordVC - pwdVC?.callBackFunc = { pwd in - UserCenter.shared.developerKey = pwd - } - presentAsSheet(pwdVC!) - } - - @IBAction func clickedClearCacheBtn(_ sender: NSButton) { - // 清掉缓存 - HTTPCookieStorage.shared.cookies?.forEach(HTTPCookieStorage.shared.deleteCookie) - InfoCenter.shared.cookies = [] - APHUD.hide(message: "清掉缓存成功", view: self.view) - } - - @IBAction func clickedSettingNotiBtn(_ sender: NSButton) { - // 取消定时任务 - if sender.state == .off { - TimerUtils.shard.invalidateNotificationTimer() - return - } - // 检查定时时间的格式 - let hours = syncHoursTF.stringValue - let minutes = syncMinutesTF.stringValue - guard hours.isNotEmpty, minutes.isNotEmpty else { - APHUD.hide(message: "间隔时间不能为空!", view: self.view) - sender.state = .off - return - } - guard let hour = Int(hours), let minute = Int(minutes) else { - APHUD.hide(message: "间隔时间只能是数字!", view: self.view) - sender.state = .off - return - } - - let time = hour * 60 * 60 + minute * 60 - guard time > 0 else { - APHUD.hide(message: "间隔时间必然大于0!", view: self.view) - sender.state = .off - return - } - - // 保存时间 - syncHourString = hours - syncMinuteString = minutes - // 执行间隔定时任务 - TimerUtils.shard.startNotificationTimer(interval: TimeInterval(time)) - } - - @IBAction func clickedEmailSyncBtn(_ sender: NSButton) { - if sender.state == .off { - isSendEmail = false - return - } - // 读取定时时间 - let emailsString = notiEmailsTF.stringValue - guard emailsString.isNotEmpty else { - APHUD.hide(message: "同步通知的邮箱地址不能为空!", view: self.view) - sender.state = .off - return - } - // 邮件格式是否正确 - let allEmails = emailsString.components(separatedBy: [";", ";", ","]).filter({!$0.isEmpty}) - let emails = allEmails.filter({ isEmailValid($0) }) - guard allEmails.count == emails.count, emails.count > 0 else { - APHUD.hide(message: "邮箱地址格式有误,请检查!", view: self.view) - sender.state = .off - return - } - - isSendEmail = true - syncEmailsString = emailsString - - } - - @IBAction func clickedManualSyncBtn(_ sender: NSButton) { - manualSyncBtn.tag = 2 - //handleAccountLogin(sender) - } - - -// func handleAccountLogin(_ sender: NSButton, _ retry: Int = 2) { -// errorsList = [] -// results = [:] -// sender.isEnabled = false -// let tips = "【提示】可能网络原因导致检查失败,所以,自动任务仍在运行。" -// -// // 测试,清cookie,模拟过期的场景 -//// ARNetSession.default.config.httpCookieStorage?.cookies?.forEach({ cookie in -//// print(cookie) -//// if cookie.name == "myacinfo" || cookie.name == "itctx" { -//// ARNetSession.default.config.httpCookieStorage?.deleteCookie(cookie) -//// } -//// }) -// -// // 保存 csv 文件的时间路径 -// let dateFormatter : DateFormatter = DateFormatter() -// dateFormatter.dateFormat = "yyyyMMdd_HHmmss" -// let currentDate = dateFormatter.string(from: Date()) -// dataPath = currentDate -// debugPrint(currentDate) -// -// // 先检查,当前 Session 是否还有效 -// ARNet.check_session.request(successedHandler: { [weak self] result, response in -// // 未过期,请求数据 -// self?.saveLogs("cookie 未过期,直接请求账号数据。") -// self?.startAccountNotification(sender: sender, currentDateString: currentDate, ephemeralSession: ARBackgroundSession()) -// }, failedHandler: { [weak self] error, response in -// debugPrint(error ?? "") -// let code = response?.statusCode -// switch code { -// case 401: -// debugPrint("session已经过期,重新登陆!") -// self?.saveLogs("session已经过期,重新登陆中...") -// // 如果静默登陆成功,则继续,否则邮件通知 -// let account = UserCenter.shared.loginedUser.appleid -// let password = UserCenter.shared.loginedUser.password -// guard account.count > 0, password.count > 0 else { -// return -// } -// // 重新登陆账号 -// ARNet.signin_setup(account: account, password: password).request(successedHandler: { [weak self] (body, response) in -// let code = response?.statusCode -// self?.saveLogs("重新登陆账号,code:\(string(from: code))") -// switch code { -// case 200: -// HUDHelper.shared().loading(currentView()) -// // 更新 Session -// ARNet.login_session.request { (body, response) in -// HUDHelper.shared().hideLoading() -// let code = response?.statusCode -// self?.saveLogs("静默登陆账号成功,code:\(string(from: code))") -// // 静默登陆账号成功,继续 -// switch code { -// case 200, 201: -// self?.startAccountNotification(sender: sender, currentDateString: currentDate, ephemeralSession: ARBackgroundSession()) -// default: -// if retry > 0 { -// self?.handleAccountLogin(sender, retry - 1) -// return -// } -// let errors = dictionaryArray(body["serviceErrors"]) -// let msg = string(from: errors.first?["message"]) -// HUDHelper.shared().hide(withMessage: msg, in: currentView()) -// self?.faileSessionHandle(sender: sender, subTitle: "静默登陆账号失败", logs: ["错误码:\(string(from: response?.statusCode))", "Session Error: \(msg)"], stop: true) -// } -// } failedHandler: { error, response in -// HUDHelper.shared().hideLoading() -// if let code = response?.statusCode, code != 401, retry > 0 { -// self?.handleAccountLogin(sender, retry - 1) -// return -// } -// self?.faileSessionHandle(sender: sender, subTitle: "静默登陆账号失败", logs: [tips, "错误码:\(string(from: response?.statusCode))", "Session Response Error: \(String(describing: error))"]) -// } -// default: -// // 409 需要双重验证 -// // 412 需要升级双重认证 -// // 401 Apple ID 或密码不正确 -// self?.faileSessionHandle(sender: sender, text: "账号登陆状态[失效],需要双重验证,请重新登陆账号!", title: "账号登陆状态[失效]", subTitle: "静默登陆账号失败", logs: ["错误码:\(string(from: response?.statusCode))", "参考错误码: 409表示需要双重验证。", "【操作建议】请在后台重启App并重新登陆苹果账号~"], stop: true) -// } -// }, failedHandler: { [weak self] error, response in -// if let code = response?.statusCode, code != 401, retry > 0 { -// self?.handleAccountLogin(sender, retry - 1) -// return -// } -// self?.faileSessionHandle(sender: sender, subTitle: "静默登陆账号失败", logs: [tips, "错误码:\(string(from: response?.statusCode))", "Error: \(String(describing: error))"]) -// }) -// default: -// if retry > 0 { -// self?.handleAccountLogin(sender, retry - 1) -// return -// } -// self?.faileSessionHandle(sender: sender, logs: [tips, "错误码:\(string(from: response?.statusCode))", "Error: \(String(describing: error))"]) -// } -// }) -// } - - - - override func viewDidLoad() { - super.viewDidLoad() - title = "App设置" - setupUI() - } - - func setupUI() { - trusDeviceBtn.state = InfoCenter.shared.trusDevice ? .on : .off - timingSyncBtn.state = TimerUtils.shard.isValidNotificationTimer() ? .on : .off - syncHoursTF.stringValue = syncHourString - syncMinutesTF.stringValue = syncMinuteString - emailSyncBtn.state = isSendEmail ? .on : .off - notiEmailsTF.stringValue = syncEmailsString - } -} - - -extension APSettingVC { - - func faileSessionHandle(sender: NSButton, text: String = "账号自动登陆状态[错误]", title: String = "账号自动登陆状态[错误]", subTitle: String = "检查账号状态失败", logs: [String], stop: Bool = false) { - // 失败处理 - sender.isEnabled = true - saveLogs("‼️ login error: \(text) \(logs.debugDescription)") - sendEmailSync(title: title, subTitle: subTitle, logs: logs, stop: stop) - } - -// func startAccountNotification(sender: NSButton, currentDateString: String, ephemeralSession: ARBackgroundSession) { -// // 串行队列,同步任务 -// let group = DispatchGroup() -// -// // 获取所有账号,然后在读取账号的消息 -// var accounts = [[String:String]]() -// if let providers = UserCenter.shared.account_session["availableProviders"] as? [[String: Any]] { -// providers.forEach { provider in -// let name = provider["name"] as! String -// let providerId = String(provider["providerId"] as! Int) -// accounts.append(["name": name, "id": providerId]) -// } -// } -// -// debugPrint(accounts) -// -// feacth_loop_data(ephemeralSession: ephemeralSession, providers: accounts, group: group) -// -// group.notify(queue: .main) { [weak self] in -// self?.saveLogs("✅ 完成所有账号消息检查~ 🎉") -// self?.successCheckHandle() -// sender.isEnabled = true -// } -// -// } -// -// func feacth_loop_data(ephemeralSession: ARBackgroundSession, providers: [[String:String]], group: DispatchGroup, index: Int = 0) { -// group.enter() -// let group2 = DispatchGroup() -// let providerId = providers[index]["id"]! -// let providername = providers[index]["name"]! -// featch_account_data(ephemeralSession: ephemeralSession, providerId: providerId, providername: providername, group: group2) -// group2.notify(queue: .main) { [weak self] in -// self?.saveLogs("完成账号【\(providername)】所有数据处理~") -// if providers.count <= (index + 1) { -// group.leave() -// return -// } -// self?.feacth_loop_data(ephemeralSession: ephemeralSession, providers: providers, group: group, index: index + 1) -// group.leave() -// } -// } -// -// func featch_account_data(ephemeralSession: ARBackgroundSession, providerId: String, providername: String, group: DispatchGroup) { -// group.enter() -// ARNet.switch_account(providerId: providerId).bgRequest(ephemeralSession: ephemeralSession, successedHandler: { [weak self] jsonData, response in -// let group2 = DispatchGroup() -// self?.saveLogs("开始读取账号【\(providername)】消息~") -// self?.feactch_message(ephemeralSession: ephemeralSession, providername: providername, group: group2) -// group2.notify(queue: .main) { -// group.leave() -// } -// }, failedHandler: { [weak self] error, response in -// self?.saveLogs("❌ 切换账号失败: error:\(String(describing: error)),response:\(response.debugDescription)") -// if let code = response?.statusCode, code != 401 { -// self?.saveLogs("❌ 切换账号: \(providername)(\(providerId)) 失败~ 无法读取账号的新消息。(code:\(code))", error: true) -// } else { -// self?.saveLogs("❌ 切换账号失败: \(providername)(\(providerId)) ,自动尝试重新登陆中~", error: true) -// } -// group.leave() -// }) -// -// } -// -// func feactch_message(ephemeralSession: ARBackgroundSession, providername: String, group: DispatchGroup) { -// group.enter() -// ARNet.provider_news.bgRequest(ephemeralSession: ephemeralSession) { [weak self] result, response in -// let data = result["data"]! as! [Any] -// if var dict = self?.results[providername] { -// dict["news"] = data -// self?.results[providername] = dict -// } else { -// self?.results[providername] = ["news": data] -// } -// self?.saveLogs("获取账号新闻消息数据:\(providername):\(data.unicodeDescription)") -// group.leave() -// } failedHandler: { [weak self] error, response in -// self?.saveLogs("❌ 获取账号新闻消息失败:\(providername)。status:\(string(from: response?.statusCode)), error:\(String(describing: error))", error: true) -// group.leave() -// } -// -// -// group.enter() -// ARNet.contract_message.bgRequest(ephemeralSession: ephemeralSession) { [weak self] result, response in -// let data = result["data"]! as! [Any] -// if var dict = self?.results[providername] { -// dict["message"] = data -// self?.results[providername] = dict -// } else { -// self?.results[providername] = ["message": data] -// } -// self?.saveLogs("获取账号协议消息数据:\(providername):\(data.unicodeDescription)") -// group.leave() -// } failedHandler: { [weak self] error, response in -// self?.saveLogs("❌ 获取账号协议消息失败:\(providername)。status:\(string(from: response?.statusCode)), error:\(String(describing: error))", error: true) -// group.leave() -// } -// } - - - func successCheckHandle() { - // 判断是否为“切换账号失败:”,如果是重新请求 - let retry = manualSyncBtn.tag - if errorsList.contains(where: { $0.contains("切换账号失败:") }), retry > 0 { - clickedManualSyncBtn(manualSyncBtn) - manualSyncBtn.tag = retry - 1 - return - } - - let overTime = 2592000 // 一个月 - let currentTime = Int(Date().timeIntervalSince1970) - var alls = [String]() - // 取消新数据 - results.forEach { account,value in - // 对比是否为新消息,并保存 - let news = value["news"]! //开发者新闻 - let messages = value["message"]! //协议消息 - // 如果新闻不为空,才读取 - alls += getNewMsg(title: "开发者新闻:", news: news, account: account, currentTime: currentTime, overTime: overTime) - alls += getNewMsg(title: "协议消息:", news: messages, account: account, currentTime: currentTime, overTime: overTime) - } - - var title = "苹果账号消息通知[新消息]" - if alls.count == 0 { - title = "苹果账号消息通知[错误]" - } - - // 错误时,发邮件 - if errorsList.count > 0 { - alls.append("【错误日志】") - alls += errorsList - } - - // 有新消息 - if alls.count > 0 { - sendEmailSync(title:title, logs:alls) - } else { - self.saveLogs("无新消息,不发送邮件~") - } - } - - - func getNewMsg(title: String, news: [Any], account: String, currentTime: Int, overTime: Int) -> [String] { - var newMsg = [String]() - newMsg.append("账号:\(account)") - if news.isNotEmpty { - newMsg.append(title) - news.forEach { newData in - if var new = newData as? [String:Any], let subject = new["subject"] as? String, let message = new["message"] as? String { - // 数据库中存在相当的条目,判断时间是否超过一个月,如果超过,再次提示 - if var oldData = messagesDB[account] as? [String: [String:Any]] { - //条目存在,但消息超过一个月,重新认定为新消息,并覆盖 - if let oldSub = oldData[subject], let oldMessage = oldSub["message"] as? String, let oldDate = oldSub["date"] as? Int { - if message != oldMessage || (message == oldMessage && (currentTime - oldDate) > overTime) { - //消息内容不相同,或者 消息超过一个月,更新时间并覆盖 - newMsg.append("《\(subject)》") - newMsg.append(message) - new["date"] = currentTime - oldData[subject] = new - messagesDB[account] = oldData - } - } else { - //条目不存在数据库中,新消息 - newMsg.append("《\(subject)》") - newMsg.append(message) - new["date"] = currentTime - oldData[subject] = new - messagesDB[account] = oldData - } - - } else { - // 数据库没有这个账号的消息,新消息直接加入 - newMsg.append("《\(subject)》") - newMsg.append(message) - new["date"] = currentTime - messagesDB[account] = [subject:new] - } - } - } - } - - newMsg.append("") - return newMsg.count > 3 ? newMsg : [] - } - - - - func sendEmailSync(title: String = "苹果账号消息通知[新消息]", subTitle: String = "苹果账号新消息", logs: [String], stop: Bool = false) { - guard isSendEmail else { - return - } - // 收件人 - let allEmails = syncEmailsString.components(separatedBy: [";", ";", ",", ","]).filter({!$0.isEmpty}) - let emails = allEmails.filter({ isEmailValid($0) }) - guard emails.count > 0 else { - saveLogs("同步通知的邮箱地址格式错误!") - return - } - // 邮件内容 - let path = commonPath.path - var lis = logs.map({ $0.isEmpty ? "
" : "
  • " + $0.replacingOccurrences(of: path, with: "") + "
  • " }) - lis = lis.map({ $0.replacingOccurrences(of: "ref=\"/", with: "href=\"https://appstoreconnect.apple.com/") }) - lis = lis.map({ $0.replacingOccurrences(of: "href='/", with: "href='https://appstoreconnect.apple.com/") }) - lis = lis.map({ $0.replacingOccurrences(of: "_self", with: "_blank") }) - lis = lis.map({ $0.replacingOccurrences(of: "" - let htmlFile = Bundle.main.path(forResource:"AutoSendEmailTemplate", ofType: "html") - let htmlString = try? String(contentsOfFile: htmlFile!, encoding: String.Encoding.utf8) - var html = htmlString?.replacingOccurrences(of: "{{report_title}}", with: subTitle) - html = html?.replacingOccurrences(of: "{{report_result}}", with: resultHTML) - //debugPrint(html) - - // 发送邮件 - EmailUtils.autoSend(subject: "AppleParty — \(title)", recipients: emails, htmlContent: html!, retry: 3) { [weak self] error in - debugPrint(error as Any) - if (error != nil) { - self?.saveLogs("同步通知邮箱发送审失败:\(String(describing: error))") - } else { - self?.saveLogs("同步通知邮箱发送成功~") - } - } - - if stop == true { - print("停止定时任务") - TimerUtils.shard.invalidateNotificationTimer() - - } - } - - - func createFileDirectory(url: URL) { - let fm = FileManager.default - let directory = url.deletingLastPathComponent() - var isDirectory: ObjCBool = false - // 保证目录存在,不存在就创建目录 - if !(fm.fileExists(atPath: directory.path, isDirectory: &isDirectory) && isDirectory.boolValue) { - do { - try fm.createDirectory(at: directory, withIntermediateDirectories: true, attributes: nil) - } catch { - saveLogs("‼️ create Directory file error:\(error)") - } - } - } - - func saveLogs(_ log: String, error: Bool = false, retry: Int = 3) { - let dateFormatter : DateFormatter = DateFormatter() - dateFormatter.dateFormat = "[MM-dd HH:mm:ss] " - let currentDateString = dateFormatter.string(from: Date()) - let out = currentDateString + log - - if error { - errorsList.append(out) - } - - debugPrint(out) - - let path = logFilePath - do { - try out.appendLine(to: path) - } catch { - if retry > 0 { - saveLogs("‼️ retry save logs file~ error:\(error)", retry: retry - 1) - saveLogs(log, retry: retry - 1) - } - } - } - -} diff --git a/AppleParty/Shared/Info/UserCenter.swift b/AppleParty/Shared/Info/UserCenter.swift index 8dda91e..858f4a3 100644 --- a/AppleParty/Shared/Info/UserCenter.swift +++ b/AppleParty/Shared/Info/UserCenter.swift @@ -39,7 +39,7 @@ struct UserCenter { // MARK: - 历史登录用户 - var historyUser: [User] = { + lazy var historyUser: [User] = { if let value = try? APUtil.keychain.getString(UserCenterKey_HistoryUser_Key) { let array = value.components(separatedBy: "|") var result = [User]() @@ -53,7 +53,7 @@ struct UserCenter { // MARK: - 登录用户 var loginedUser: User { - get { + mutating get { return historyUser.first ?? User(appleid: "", password: "") } set { diff --git a/AppleParty/Shared/Network/APClient.swift b/AppleParty/Shared/Network/APClient.swift index ba4213b..a735601 100644 --- a/AppleParty/Shared/Network/APClient.swift +++ b/AppleParty/Shared/Network/APClient.swift @@ -298,7 +298,7 @@ extension APClient { func request(showLoading: Bool = false, inView: NSView = currentView() , retry: Int = 3, completionHandler: CompletionHandler?) { if showLoading { - APHUD.showLoading(view: inView) + APHUD.showLoading(inView) } APClientSession.shared.session.request(getUrl(), diff --git a/AppleParty/Shared/Utils/APHUD.swift b/AppleParty/Shared/Utils/APHUD.swift index e30413f..1c3b0b3 100644 --- a/AppleParty/Shared/Utils/APHUD.swift +++ b/AppleParty/Shared/Utils/APHUD.swift @@ -19,7 +19,7 @@ class HUD: NSObject { private var loadHud: MBProgressHUD? private var textHud: MBProgressHUD? - func showLoading(view: NSView = currentView()) { + func showLoading(_ view: NSView = currentView()) { if loadHud != nil { loadHud?.hide(true) } @@ -53,12 +53,14 @@ class HUD: NSObject { } func hide(message: String, view: NSView = currentView(), delayTime: TimeInterval = 3) { - guard let hud = MBProgressHUD.showAdded(to: view, animated: true) else { + guard let hud = MBProgressHUD(view: view) else { return } hud.mode = MBProgressHUDModeText hud.labelText = message hud.removeFromSuperViewOnHide = true + view.addSubview(hud) + hud.show(true) hud.hide(true, afterDelay: delayTime) } } diff --git a/AppleParty/Shared/Utils/ARLogs.swift b/AppleParty/Shared/Utils/ARLogs.swift index 7bf0d42..f2ef46b 100644 --- a/AppleParty/Shared/Utils/ARLogs.swift +++ b/AppleParty/Shared/Utils/ARLogs.swift @@ -26,7 +26,7 @@ class APLogs { let dataPath = dateFormatter.string(from: Date()) var documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] - documentsURL.appendPathComponent("AppleParyty") + documentsURL.appendPathComponent("AppleParty") documentsURL.appendPathComponent("Logs") documentsURL.appendPathComponent("\(dataPath)_log.txt") createFileDirectory(url: documentsURL) diff --git a/AppleParty/SparkleUpdate/AppleParty-release.html b/AppleParty/SparkleUpdate/AppleParty-release.html index 3d0f64f..c429c6d 100644 --- a/AppleParty/SparkleUpdate/AppleParty-release.html +++ b/AppleParty/SparkleUpdate/AppleParty-release.html @@ -15,6 +15,14 @@ --> +
    +

    v2.0.32022-04-09

    +
      +
    • 增加是否记住密码、信任设备的勾选项
    • +
    • 切换账号从双点确认改为单击确认切换
    • +
    • 修复和完善一些Bug和体验的问题,欢迎大家反馈~
    • +
    +

    v2.0.22022-04-07

      diff --git a/AppleParty/SparkleUpdate/update.xml b/AppleParty/SparkleUpdate/update.xml index f9a48ce..a20575c 100644 --- a/AppleParty/SparkleUpdate/update.xml +++ b/AppleParty/SparkleUpdate/update.xml @@ -5,16 +5,16 @@ Most recent changes with links to updates. zh_CN - Version 2.0.2 + Version 2.0.3 https://37iOS.GitHub.io/Sparkle/AppleParty-release.html - 2022-04-02 + 2022-04-09 10.13