From 4dc64bb75fa42447b1a778e36105dd5874253f83 Mon Sep 17 00:00:00 2001 From: Azuma Kasumi Date: Mon, 10 Apr 2023 12:08:53 +0900 Subject: [PATCH 01/12] =?UTF-8?q?iPad=E3=81=AEactivityView=E8=A1=A8?= =?UTF-8?q?=E7=A4=BA=E3=83=BBsubWebView=E3=81=AE=E5=8B=95=E4=BD=9C?= =?UTF-8?q?=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WebView/View/WebViewController.swift | 48 ++++++++++++++----- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/AgileWorks/AgileWorks/WebView/View/WebViewController.swift b/AgileWorks/AgileWorks/WebView/View/WebViewController.swift index 4cdd571..4a17a82 100644 --- a/AgileWorks/AgileWorks/WebView/View/WebViewController.swift +++ b/AgileWorks/AgileWorks/WebView/View/WebViewController.swift @@ -18,9 +18,10 @@ class WebViewController: UIViewController { @IBOutlet private var closeButton: UIBarButtonItem! @IBOutlet private var menuButton: UIBarButtonItem! var mainWebView: WKWebView! - var subWebView: WKWebView! // 別ウインドウで開いたときの子ウインドウスタック var subViewStack = SubViewStack() + //subWebView読み込みフラグ + var subWebViewLoadingFlg = false var loadURL: String! var reloadTab = false var showNotification = false @@ -464,17 +465,18 @@ extension WebViewController: WKUIDelegate { func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? { if navigationAction.targetFrame?.isMainFrame != true { - subWebView = WKWebView(frame: self.formView.bounds, configuration: configuration) - subWebView.navigationDelegate = self - subWebView.uiDelegate = self - subViewStack.push(subWebView, superView: mainWebView) - subWebView.load(navigationAction.request) - - //キャンセルボタンの表示 - self.closeButton.title = getDisplayString(key: "Close", comment: "") - self.closeButton.isEnabled = true - - return subWebView + if !subWebViewLoadingFlg { + subWebViewLoadingFlg = true + let subWebView = WKWebView(frame: self.formView.bounds, configuration: configuration) + //読み込むが非表示 + subWebView.isHidden = true + subWebView.navigationDelegate = self + subWebView.uiDelegate = self + subViewStack.push(subWebView, superView: mainWebView) + subWebView.load(navigationAction.request) + + return subWebView + } } return nil } @@ -497,6 +499,15 @@ extension WebViewController: WKNavigationDelegate { download(url: url, saveAs: attachmentFileName) decisionHandler(.cancel) } else { + //subWebViewの場合 + if !subViewStack.isEmpty { + //subWebViewの表示 + webView.isHidden = false + //キャンセルボタンの表示 + self.closeButton.title = getDisplayString(key: "Close", comment: "") + self.closeButton.isEnabled = true + subWebViewLoadingFlg = false + } decisionHandler(.allow) } } @@ -614,9 +625,20 @@ extension WebViewController: WKNavigationDelegate { } DispatchQueue.main.async {[self] in let activityViewController = UIActivityViewController(activityItems: [tempPath], applicationActivities: nil) + //iPadのみ + if UIDevice.current.userInterfaceIdiom == .pad { + let deviceSize = UIScreen.main.bounds + if let popPC = activityViewController.popoverPresentationController { + popPC.sourceRect = CGRect(x: UIScreen.main.bounds.width / 2, y: UIScreen.main.bounds.height / 2, width: 0, height: 0) + popPC.sourceView = self.view + popPC.permittedArrowDirections = UIPopoverArrowDirection(rawValue: 0) + } + } activityViewController.completionWithItemsHandler = { (activityType: UIActivity.ActivityType?, completed: Bool, returnedItems: [Any]?, activityError: Error?) in + //subWebViewを消す self.closeTapped() - + subWebViewLoadingFlg = false + guard completed else { return } -- GitLab From 727f1aec0b3cf5e63eb359564c3bf79a905a8a17 Mon Sep 17 00:00:00 2001 From: Azuma Kasumi Date: Fri, 14 Apr 2023 11:14:03 +0900 Subject: [PATCH 02/12] =?UTF-8?q?=E3=82=A2=E3=83=97=E3=83=AA=E3=83=90?= =?UTF-8?q?=E3=83=BC=E3=82=B8=E3=83=A7=E3=83=B3=E3=82=A2=E3=83=83=E3=83=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AgileWorks/AgileWorks.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AgileWorks/AgileWorks.xcodeproj/project.pbxproj b/AgileWorks/AgileWorks.xcodeproj/project.pbxproj index 10691b2..2c0de42 100644 --- a/AgileWorks/AgileWorks.xcodeproj/project.pbxproj +++ b/AgileWorks/AgileWorks.xcodeproj/project.pbxproj @@ -1822,7 +1822,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.0; + MARKETING_VERSION = 1.0.1; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", @@ -1996,7 +1996,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.0; + MARKETING_VERSION = 1.0.1; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", -- GitLab From 04e787156b6c93ae74d2227f30dc172138745e74 Mon Sep 17 00:00:00 2001 From: Azuma Kasumi Date: Mon, 8 May 2023 15:50:19 +0900 Subject: [PATCH 03/12] =?UTF-8?q?=E3=83=A2=E3=83=BC=E3=83=80=E3=83=AB?= =?UTF-8?q?=E3=81=AE=E8=A1=A8=E7=A4=BA=E3=83=BB=E3=83=AD=E3=82=B0=E3=82=A4?= =?UTF-8?q?=E3=83=B3=E7=94=BB=E9=9D=A2=E3=81=B8=E3=81=AE=E9=81=B7=E7=A7=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AgileWorks.xcodeproj/project.pbxproj | 4 + .../AgileWorks/App/RootViewController.swift | 1 + .../Login/Builder/LoginBuilder.swift | 4 + .../Login/View/LoginViewController.swift | 2 + .../View/MordalViewController.swift | 18 ++- .../ServerSwitchingTableViewController.swift | 80 +++++++++++ .../serverSwitchingViewController.storyboard | 132 ++++++++++++++++-- .../Strings/Chinese-Simplified.strings | 1 + .../Strings/Chinese-Traditional.strings | 1 + AgileWorks/AgileWorks/Strings/English.strings | 1 + .../AgileWorks/Strings/Japanese.strings | 1 + .../Strings/en.lproj/Localizable.strings | 1 + .../Strings/ja.lproj/Localizable.strings | 1 + .../Strings/zh-Hans.lproj/Localizable.strings | 1 + .../Strings/zh-Hant.lproj/Localizable.strings | 1 + .../WebView/View/MenuViewController.swift | 1 + .../WebView/View/WebViewController.swift | 1 + .../Common/DataStore/KeychainDataStore.swift | 16 +++ 18 files changed, 256 insertions(+), 11 deletions(-) create mode 100644 AgileWorks/AgileWorks/ServerSwitching/View/ServerSwitchingTableViewController.swift diff --git a/AgileWorks/AgileWorks.xcodeproj/project.pbxproj b/AgileWorks/AgileWorks.xcodeproj/project.pbxproj index 5c044bc..64104ad 100644 --- a/AgileWorks/AgileWorks.xcodeproj/project.pbxproj +++ b/AgileWorks/AgileWorks.xcodeproj/project.pbxproj @@ -47,6 +47,7 @@ 75BC052F29ECE8AC00E21941 /* ServerSwitchingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75BC052E29ECE8AC00E21941 /* ServerSwitchingViewController.swift */; }; 75BC053229ED087000E21941 /* ServerSwitchingViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 75BC053129ED087000E21941 /* ServerSwitchingViewController.storyboard */; }; 75BC053429EDA23700E21941 /* MordalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75BC053329EDA23700E21941 /* MordalViewController.swift */; }; + 75BC053629F8DFCC00E21941 /* ServerSwitchingTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75BC053529F8DFCC00E21941 /* ServerSwitchingTableViewController.swift */; }; 75EDD2272806618A0068B4BC /* WidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EDD2262806618A0068B4BC /* WidgetView.swift */; }; 75EDD2282806618A0068B4BC /* WidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EDD2262806618A0068B4BC /* WidgetView.swift */; }; 75EDD2292806618A0068B4BC /* WidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EDD2262806618A0068B4BC /* WidgetView.swift */; }; @@ -252,6 +253,7 @@ 75BC052E29ECE8AC00E21941 /* ServerSwitchingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSwitchingViewController.swift; sourceTree = ""; }; 75BC053129ED087000E21941 /* ServerSwitchingViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = ServerSwitchingViewController.storyboard; sourceTree = ""; }; 75BC053329EDA23700E21941 /* MordalViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MordalViewController.swift; sourceTree = ""; }; + 75BC053529F8DFCC00E21941 /* ServerSwitchingTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSwitchingTableViewController.swift; sourceTree = ""; }; 75EDD2262806618A0068B4BC /* WidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetView.swift; sourceTree = ""; }; 75EF9CAC27E9E983003178A3 /* WidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = WidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 75EF9CAD27E9E983003178A3 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; @@ -512,6 +514,7 @@ 75BC052E29ECE8AC00E21941 /* ServerSwitchingViewController.swift */, 75BC053129ED087000E21941 /* ServerSwitchingViewController.storyboard */, 75BC053329EDA23700E21941 /* MordalViewController.swift */, + 75BC053529F8DFCC00E21941 /* ServerSwitchingTableViewController.swift */, ); path = View; sourceTree = ""; @@ -1441,6 +1444,7 @@ 76AE530725D3652400AFA45A /* LicenseViewBuilder.swift in Sources */, 3127EE1B241A2B4D00535CC7 /* TodayViewController.swift in Sources */, BDAABA1B24A361E90077EC69 /* PostDeviceEndpoint.swift in Sources */, + 75BC053629F8DFCC00E21941 /* ServerSwitchingTableViewController.swift in Sources */, 31AA002F24347BBD000177B4 /* ApprovalResponse.swift in Sources */, BD7A8008241A16B90040B418 /* LinkManager.swift in Sources */, C535772E2754D5C500EAA660 /* WebViewController.swift in Sources */, diff --git a/AgileWorks/AgileWorks/App/RootViewController.swift b/AgileWorks/AgileWorks/App/RootViewController.swift index 6e82fe6..3ca5135 100644 --- a/AgileWorks/AgileWorks/App/RootViewController.swift +++ b/AgileWorks/AgileWorks/App/RootViewController.swift @@ -67,6 +67,7 @@ extension RootViewController { KeychainDataStore().removeOAuthState() KeychainDataStore().removeAccessToken() KeychainDataStore().removeSessionID() + KeychainDataStore().removeServerName() KeychainDataStore().removeLanguage() KeychainDataStore().removeDeviceID() diff --git a/AgileWorks/AgileWorks/Login/Builder/LoginBuilder.swift b/AgileWorks/AgileWorks/Login/Builder/LoginBuilder.swift index 13926ad..1921dde 100644 --- a/AgileWorks/AgileWorks/Login/Builder/LoginBuilder.swift +++ b/AgileWorks/AgileWorks/Login/Builder/LoginBuilder.swift @@ -26,6 +26,10 @@ struct LoginBuilderImpl: LoginBuilder { ) return viewController } + + func loginStoryboard() -> LoginViewController { + return storyboard() + } } extension LoginBuilderImpl { diff --git a/AgileWorks/AgileWorks/Login/View/LoginViewController.swift b/AgileWorks/AgileWorks/Login/View/LoginViewController.swift index d12e5f1..4e9c58b 100644 --- a/AgileWorks/AgileWorks/Login/View/LoginViewController.swift +++ b/AgileWorks/AgileWorks/Login/View/LoginViewController.swift @@ -74,6 +74,7 @@ class LoginViewController: UIViewController { KeychainDataStore().removeOAuthState() KeychainDataStore().removeAccessToken() KeychainDataStore().removeSessionID() + KeychainDataStore().removeServerName() KeychainDataStore().removeLanguage() KeychainDataStore().removeDeviceID() @@ -209,6 +210,7 @@ class LoginViewController: UIViewController { case .success(let response): setStringsName(language: response.user.displayLanguage) KeychainDataStore().writeSessionID(sessionID: response.sessionId) + KeychainDataStore().writeServerName(serverName: "サーバー識別名") //TODO response.server.name DispatchQueue.main.async { //メイン画面表示 AppDelegate.shared.rootViewController.switchToMainScreen() diff --git a/AgileWorks/AgileWorks/ServerSwitching/View/MordalViewController.swift b/AgileWorks/AgileWorks/ServerSwitching/View/MordalViewController.swift index 8474044..6327480 100644 --- a/AgileWorks/AgileWorks/ServerSwitching/View/MordalViewController.swift +++ b/AgileWorks/AgileWorks/ServerSwitching/View/MordalViewController.swift @@ -10,9 +10,18 @@ import UIKit import FloatingPanel class MordalViewController: UIViewController { + @IBOutlet private var accessPoint: UILabel! + @IBOutlet private var addServer: UIButton! + + let navVC = UINavigationController(rootViewController: LoginBuilderImpl().loginStoryboard()) + + @objc func cancelTapped(_ sender: UIBarButtonItem) { + navVC.dismiss(animated: true) + } + override func viewDidLoad() { super.viewDidLoad() - + accessPoint.text = getDisplayString(key: "ServerTitle", comment: "") // Do any additional setup after loading the view. } @@ -20,4 +29,11 @@ class MordalViewController: UIViewController { let controller = storyboard.instantiateViewController(withIdentifier: "MordalViewController") as! MordalViewController return controller } + @IBAction private func addServerTapped(_ sender: Any) { + //モーダルの表示 + navVC.modalPresentationStyle = .fullScreen + let leftButton = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelTapped(_:))) + navVC.navigationBar.topItem!.leftBarButtonItem = leftButton + self.present(navVC, animated: true) + } } diff --git a/AgileWorks/AgileWorks/ServerSwitching/View/ServerSwitchingTableViewController.swift b/AgileWorks/AgileWorks/ServerSwitching/View/ServerSwitchingTableViewController.swift new file mode 100644 index 0000000..54764d3 --- /dev/null +++ b/AgileWorks/AgileWorks/ServerSwitching/View/ServerSwitchingTableViewController.swift @@ -0,0 +1,80 @@ +// +// ServerSwitchingTableTableViewController.swift +// AgileWorks +// +// Created by Azuma Kasumi on 2023/04/26. +// Copyright © 2023 ATLED CORP. All rights reserved. +// + +import UIKit + +class ServerSwitchingTableTableViewController: UITableViewController { + @IBOutlet var table: UITableView! + + override func viewDidLoad() { + super.viewDidLoad() + table.tableFooterView = UIView() + } + + // MARK: - Table view data source + + override func numberOfSections(in tableView: UITableView) -> Int { + // #warning Incomplete implementation, return the number of sections + return 1 + } + //セルの数 + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + // #warning Incomplete implementation, return the number of rows + return 1 + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "ServerSwitchingTableViewCell", for: indexPath) + + let serverName = cell.viewWithTag(1) as! UILabel + serverName.text = KeychainDataStore().readServerName() + + let badgeIcon = cell.viewWithTag(2) as! UIImageView + badgeIcon.image = UIImage(systemName: "circle.fill", withConfiguration: UIImage.SymbolConfiguration(font: .systemFont(ofSize: 25))) + let approvalCount = cell.viewWithTag(3) as! UILabel + + //ログイン中のサーバー + if indexPath.row == 0 { + //チェックマーク + badgeIcon.image = UIImage(systemName: "checkmark.circle.fill", withConfiguration: UIImage.SymbolConfiguration(font: .systemFont(ofSize: 25))) + badgeIcon.tintColor = UIColor(named: getDisplayString(key: "MainColor", comment: "")) + //承認待ち件数は取得しないため非表示 + approvalCount.isHidden = true + } else {//その他サーバー + setApprovalsCount(label: approvalCount) + } + + return cell + } + + override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return 50 + } + + //承認待ち件数取得 + private func setApprovalsCount(label: UILabel){ + let approvalsEndpoint = GetApprovalsEndpoint() + + Session.send(approvalsEndpoint) { result in + var reqApprovalCount: Int = 0 + switch result { + case .success(let response): + let requestApproval = "REQUEST_APPROVAL" + for item in response.items where item.code == requestApproval { + reqApprovalCount = item.count + DispatchQueue.main.async { + label.text = String(reqApprovalCount) + } + } + case .failure(let error): + log.e(error) + label.text = "0" + } + } + } +} diff --git a/AgileWorks/AgileWorks/ServerSwitching/View/serverSwitchingViewController.storyboard b/AgileWorks/AgileWorks/ServerSwitching/View/serverSwitchingViewController.storyboard index 7f04f14..6cdbd82 100644 --- a/AgileWorks/AgileWorks/ServerSwitching/View/serverSwitchingViewController.storyboard +++ b/AgileWorks/AgileWorks/ServerSwitching/View/serverSwitchingViewController.storyboard @@ -4,6 +4,8 @@ + + @@ -22,7 +24,7 @@ - + @@ -32,25 +34,135 @@ - + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AgileWorks/AgileWorks/Strings/Chinese-Simplified.strings b/AgileWorks/AgileWorks/Strings/Chinese-Simplified.strings index 7d800c1..dca6489 100644 --- a/AgileWorks/AgileWorks/Strings/Chinese-Simplified.strings +++ b/AgileWorks/AgileWorks/Strings/Chinese-Simplified.strings @@ -58,6 +58,7 @@ //server "ServerTitle" = "接続先サーバー"; +"accessPoint" = "接続先"; // Notification "DocOverrideConfirm" = "由通知点选的文件已经显示了。\n你想放弃当前的编辑并显示一个新的文件吗?"; diff --git a/AgileWorks/AgileWorks/Strings/Chinese-Traditional.strings b/AgileWorks/AgileWorks/Strings/Chinese-Traditional.strings index 4168400..6cc1879 100644 --- a/AgileWorks/AgileWorks/Strings/Chinese-Traditional.strings +++ b/AgileWorks/AgileWorks/Strings/Chinese-Traditional.strings @@ -58,6 +58,7 @@ //server "ServerTitle" = "接続先サーバー"; +"accessPoint" = "接続先"; // Notification "DocOverrideConfirm" = "由通知點選的文件已經顯示了。 \n你想放棄當前的編輯並顯示一個新的文件嗎?"; diff --git a/AgileWorks/AgileWorks/Strings/English.strings b/AgileWorks/AgileWorks/Strings/English.strings index 527ffdb..66bb9ee 100644 --- a/AgileWorks/AgileWorks/Strings/English.strings +++ b/AgileWorks/AgileWorks/Strings/English.strings @@ -58,6 +58,7 @@ //server "ServerTitle" = "接続先サーバー"; +"accessPoint" = "接続先"; // Notification "DocOverrideConfirm" = "A document by a notification tap is already displayed.\nDo you want to discard the current edits and display a new document?"; diff --git a/AgileWorks/AgileWorks/Strings/Japanese.strings b/AgileWorks/AgileWorks/Strings/Japanese.strings index 471ddc0..ff87ef0 100644 --- a/AgileWorks/AgileWorks/Strings/Japanese.strings +++ b/AgileWorks/AgileWorks/Strings/Japanese.strings @@ -58,6 +58,7 @@ //server "ServerTitle" = "接続先サーバー"; +"accessPoint" = "接続先"; // Notification "DocOverrideConfirm" = "既に通知タップによる書類が表示されています。\n現在の編集内容を破棄し、新たな書類を表示しますか?"; diff --git a/AgileWorks/AgileWorks/Strings/en.lproj/Localizable.strings b/AgileWorks/AgileWorks/Strings/en.lproj/Localizable.strings index 7f2918a..55a7d34 100644 --- a/AgileWorks/AgileWorks/Strings/en.lproj/Localizable.strings +++ b/AgileWorks/AgileWorks/Strings/en.lproj/Localizable.strings @@ -58,6 +58,7 @@ //server "ServerTitle" = "接続先サーバー"; +"accessPoint" = "接続先"; // Notification "DocOverrideConfirm" = "A document by a notification tap is already displayed.\nDo you want to discard the current edits and display a new document?"; diff --git a/AgileWorks/AgileWorks/Strings/ja.lproj/Localizable.strings b/AgileWorks/AgileWorks/Strings/ja.lproj/Localizable.strings index 529cfff..4f6fbc8 100644 --- a/AgileWorks/AgileWorks/Strings/ja.lproj/Localizable.strings +++ b/AgileWorks/AgileWorks/Strings/ja.lproj/Localizable.strings @@ -58,6 +58,7 @@ //server "ServerTitle" = "接続先サーバー"; +"accessPoint" = "接続先"; // Notification "DocOverrideConfirm" = "既に通知タップによる書類が表示されています。\n現在の編集内容を破棄し、新たな書類を表示しますか?"; diff --git a/AgileWorks/AgileWorks/Strings/zh-Hans.lproj/Localizable.strings b/AgileWorks/AgileWorks/Strings/zh-Hans.lproj/Localizable.strings index 19b2444..9495f6d 100644 --- a/AgileWorks/AgileWorks/Strings/zh-Hans.lproj/Localizable.strings +++ b/AgileWorks/AgileWorks/Strings/zh-Hans.lproj/Localizable.strings @@ -58,6 +58,7 @@ //server "ServerTitle" = "接続先サーバー"; +"accessPoint" = "接続先"; // Notification "DocOverrideConfirm" = "由通知点选的文件已经显示了。\n你想放弃当前的编辑并显示一个新的文件吗?"; diff --git a/AgileWorks/AgileWorks/Strings/zh-Hant.lproj/Localizable.strings b/AgileWorks/AgileWorks/Strings/zh-Hant.lproj/Localizable.strings index a4898c3..e01613e 100644 --- a/AgileWorks/AgileWorks/Strings/zh-Hant.lproj/Localizable.strings +++ b/AgileWorks/AgileWorks/Strings/zh-Hant.lproj/Localizable.strings @@ -58,6 +58,7 @@ //server "ServerTitle" = "接続先サーバー"; +"accessPoint" = "接続先"; // Notification "DocOverrideConfirm" = "由通知點選的文件已經顯示了。 \n你想放棄當前的編輯並顯示一個新的文件嗎?"; diff --git a/AgileWorks/AgileWorks/WebView/View/MenuViewController.swift b/AgileWorks/AgileWorks/WebView/View/MenuViewController.swift index 07e6ba3..20add4e 100644 --- a/AgileWorks/AgileWorks/WebView/View/MenuViewController.swift +++ b/AgileWorks/AgileWorks/WebView/View/MenuViewController.swift @@ -73,6 +73,7 @@ class MenuViewController: UIViewController { self.nameLabel.text = userName self.serverLabel.text = serverName KeychainDataStore().writeSessionID(sessionID: sessionId) + KeychainDataStore().writeServerName(serverName: serverName) } case .failure: DispatchQueue.main.async { diff --git a/AgileWorks/AgileWorks/WebView/View/WebViewController.swift b/AgileWorks/AgileWorks/WebView/View/WebViewController.swift index 4cdd571..fe9d431 100644 --- a/AgileWorks/AgileWorks/WebView/View/WebViewController.swift +++ b/AgileWorks/AgileWorks/WebView/View/WebViewController.swift @@ -218,6 +218,7 @@ class WebViewController: UIViewController { // セッション情報取得成功 case .success(let response): KeychainDataStore().writeSessionID(sessionID: response.sessionId) + KeychainDataStore().writeServerName(serverName: "サーバー識別名") //TODO response.server.name setStringsName(language: response.user.displayLanguage) if isInit { // 画面ロード diff --git a/AgileWorks/Common/DataStore/KeychainDataStore.swift b/AgileWorks/Common/DataStore/KeychainDataStore.swift index 681a27c..3529ac1 100644 --- a/AgileWorks/Common/DataStore/KeychainDataStore.swift +++ b/AgileWorks/Common/DataStore/KeychainDataStore.swift @@ -20,6 +20,7 @@ final class KeychainDataStore: DataStoreProtocol { private let kContextPath: String = "ContextPath" private let kDeviceID: String = "DeviceID" private let kSessionID: String = "SessionID" + private let kServerName: String = "ServerName" // アクセストークンの書き込み func writeAccessToken(accessToken: String) { @@ -143,6 +144,21 @@ final class KeychainDataStore: DataStoreProtocol { removeKeychainValue(key: kSessionID) } + // サーバー識別名の書き込み + func writeServerName(serverName: String) { + setKeychainValue(key: kServerName, value: serverName) + } + + // サーバー識別名の読み込み + func readServerName() -> String? { + return getKeychainValue(key: kServerName) + } + + // サーバー識別名の削除 + func removeServerName() { + removeKeychainValue(key: kServerName) + } + // KeyChain へ指定の値をセット private func setKeychainValue(key: String, value: String) { let keychain = Keychain(service: service, accessGroup: groupId) -- GitLab From 91d1a6025cadbd1eaf8d9fd6bb7fba80b40964d8 Mon Sep 17 00:00:00 2001 From: Azuma Kasumi Date: Fri, 19 May 2023 11:58:43 +0900 Subject: [PATCH 04/12] =?UTF-8?q?=E3=82=B5=E3=83=BC=E3=83=90=E3=83=BC?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0=E3=81=8B=E3=82=89=E3=83=AD=E3=82=B0=E3=82=A4?= =?UTF-8?q?=E3=83=B3=E5=88=87=E3=82=8A=E6=9B=BF=E3=81=88=EF=BC=88=E3=82=AD?= =?UTF-8?q?=E3=83=BC=E3=83=81=E3=82=A7=E3=83=B3=E5=88=87=E3=82=8A=E6=9B=BF?= =?UTF-8?q?=E3=81=88=E4=B8=8D=E5=8F=AF=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AgileWorks/App/RootViewController.swift | 26 ++++++- .../Login/Builder/LoginBuilder.swift | 15 ++-- .../Login/View/LoginViewController.swift | 74 ++++++++++++------- .../View/MordalViewController.swift | 3 +- .../Common/DataStore/KeychainDataStore.swift | 8 +- .../DataStore/UserDefaultsDataStore.swift | 61 ++++++++++++++- 6 files changed, 146 insertions(+), 41 deletions(-) diff --git a/AgileWorks/AgileWorks/App/RootViewController.swift b/AgileWorks/AgileWorks/App/RootViewController.swift index 3ca5135..0ce909d 100644 --- a/AgileWorks/AgileWorks/App/RootViewController.swift +++ b/AgileWorks/AgileWorks/App/RootViewController.swift @@ -40,7 +40,7 @@ class RootViewController: UIViewController { extension RootViewController { func showLoginScreen() { - let new = LoginBuilderImpl().build() + let new = LoginBuilderImpl().build(addServerloginFlg: false) addChild(new) new.view.frame = view.bounds @@ -78,6 +78,28 @@ extension RootViewController { WidgetCenter.shared.reloadAllTimelines() } } + /* + UserDefaultsDataStore().removeServer() + let serverList = UserDefaultsDataStore().readServerList() + if serverList.isEmpty { + DispatchQueue.main.async { + self.switchToLogout() + //ウィジェットの更新 + if #available(iOS 14.0, *) { + WidgetCenter.shared.reloadAllTimelines() + } + } + } else { + KeychainDataStore().setGroupId(serverNumber: serverList.first!) + DispatchQueue.main.async { + self.switchToMainScreen() + //ウィジェットの更新 + if #available(iOS 14.0, *) { + WidgetCenter.shared.reloadAllTimelines() + } + } + } + */ } } @@ -104,7 +126,7 @@ extension RootViewController { } func switchToLogout() { - let new = LoginBuilderImpl().build() + let new = LoginBuilderImpl().build(addServerloginFlg: false) animateDismissTransition(to: new) } diff --git a/AgileWorks/AgileWorks/Login/Builder/LoginBuilder.swift b/AgileWorks/AgileWorks/Login/Builder/LoginBuilder.swift index 1921dde..42d56a5 100644 --- a/AgileWorks/AgileWorks/Login/Builder/LoginBuilder.swift +++ b/AgileWorks/AgileWorks/Login/Builder/LoginBuilder.swift @@ -9,14 +9,14 @@ import UIKit protocol LoginBuilder { - func build() -> UIViewController + func build(addServerloginFlg: Bool) -> UIViewController } struct LoginBuilderImpl: LoginBuilder { let identifier = "LoginViewController" - func build() -> UIViewController { - let viewController = storyboard() + func build(addServerloginFlg: Bool) -> UIViewController { + let viewController = storyboard(addServerloginFlg: addServerloginFlg) viewController.inject( presenter: LoginPresenterImpl( view: viewController, @@ -27,15 +27,14 @@ struct LoginBuilderImpl: LoginBuilder { return viewController } - func loginStoryboard() -> LoginViewController { - return storyboard() - } } extension LoginBuilderImpl { - private func storyboard() -> LoginViewController { + private func storyboard(addServerloginFlg: Bool) -> LoginViewController { let storyboard = mainStoryboard() - let viewController = storyboard.instantiateViewController(withIdentifier: identifier) as! LoginViewController + let viewController = storyboard.instantiateViewController(identifier: identifier){ coder in + LoginViewController(coder: coder, addServerloginFlg: addServerloginFlg) + } return viewController } diff --git a/AgileWorks/AgileWorks/Login/View/LoginViewController.swift b/AgileWorks/AgileWorks/Login/View/LoginViewController.swift index 4e9c58b..37e45d7 100644 --- a/AgileWorks/AgileWorks/Login/View/LoginViewController.swift +++ b/AgileWorks/AgileWorks/Login/View/LoginViewController.swift @@ -35,11 +35,22 @@ class LoginViewController: UIViewController { @IBOutlet private var qrCodeReadView: UIView! @IBOutlet private var qrCodeStartupButton: UIButton! @IBOutlet private var scrollViewBottomConstraint: NSLayoutConstraint! + //サーバー追加画面フラグ + public var addServerloginFlg: Bool private let activityIndicator = UIActivityIndicatorView(style: .whiteLarge) private var presenter: LoginPresenter! + init?(coder: NSCoder, addServerloginFlg: Bool){ + self.addServerloginFlg = addServerloginFlg + super.init(coder: coder) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + private var serverHost: String? { guard let server = serverTextField.text else { return nil } return server @@ -58,29 +69,30 @@ class LoginViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - - //ログイン画面が表示されると通知を取得しない - - self.devcie { result in - switch result { - case .success: - break - case .failure(let error): - log.e(error) + //サーバー追加画面の場合は認証情報を削除しない + if !addServerloginFlg { + //ログイン画面が表示されると通知を取得しない + self.devcie { result in + switch result { + case .success: + break + case .failure(let error): + log.e(error) + } } - } - //認証情報削除 - KeychainDataStore().removeOAuthState() - KeychainDataStore().removeAccessToken() - KeychainDataStore().removeSessionID() - KeychainDataStore().removeServerName() - KeychainDataStore().removeLanguage() - KeychainDataStore().removeDeviceID() - - //ウィジェットの更新 - if #available(iOS 14.0, *) { - WidgetCenter.shared.reloadAllTimelines() + //認証情報削除 + KeychainDataStore().removeOAuthState() + KeychainDataStore().removeAccessToken() + KeychainDataStore().removeSessionID() + KeychainDataStore().removeServerName() + KeychainDataStore().removeLanguage() + KeychainDataStore().removeDeviceID() + + //ウィジェットの更新 + if #available(iOS 14.0, *) { + WidgetCenter.shared.reloadAllTimelines() + } } clientCertificateSettingView.isHidden = (CertificateDataStore().readClientCertificate() == nil) @@ -88,10 +100,12 @@ class LoginViewController: UIViewController { setupFixedWording() //保存されたサーバー名・コンテキストパスの取得 - let server = Configuration.shared.awServer - let context = Configuration.shared.awContextPath - serverTextField.text = server - contextTextField.text = context + if !addServerloginFlg { + let server = Configuration.shared.awServer + let context = Configuration.shared.awContextPath + serverTextField.text = server + contextTextField.text = context + } loginButton.isEnabled = isTextFieldValue() view.addSubview(activityIndicator) @@ -169,6 +183,15 @@ class LoginViewController: UIViewController { guard let context = context else { return } disableLogin() +/* + //サーバー切り替え + if let serverId = UserDefaultsDataStore().serchEmptyServerData() { + KeychainDataStore().setGroupId(serverNumber: serverId) + } else { + //TODO: サーバー追加できない場合 + } + */ + //サーバー名コンテキストパスの保存 KeychainDataStore().writeServerURL(serverURL: serverHost) KeychainDataStore().writeContextPath(contextPath: context) @@ -212,6 +235,7 @@ class LoginViewController: UIViewController { KeychainDataStore().writeSessionID(sessionID: response.sessionId) KeychainDataStore().writeServerName(serverName: "サーバー識別名") //TODO response.server.name DispatchQueue.main.async { + //UserDefaultsDataStore().addServerList() //メイン画面表示 AppDelegate.shared.rootViewController.switchToMainScreen() } diff --git a/AgileWorks/AgileWorks/ServerSwitching/View/MordalViewController.swift b/AgileWorks/AgileWorks/ServerSwitching/View/MordalViewController.swift index 6327480..495d92e 100644 --- a/AgileWorks/AgileWorks/ServerSwitching/View/MordalViewController.swift +++ b/AgileWorks/AgileWorks/ServerSwitching/View/MordalViewController.swift @@ -13,7 +13,7 @@ class MordalViewController: UIViewController { @IBOutlet private var accessPoint: UILabel! @IBOutlet private var addServer: UIButton! - let navVC = UINavigationController(rootViewController: LoginBuilderImpl().loginStoryboard()) + let navVC = UINavigationController(rootViewController: LoginBuilderImpl().build(addServerloginFlg: true)) @objc func cancelTapped(_ sender: UIBarButtonItem) { navVC.dismiss(animated: true) @@ -22,7 +22,6 @@ class MordalViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() accessPoint.text = getDisplayString(key: "ServerTitle", comment: "") - // Do any additional setup after loading the view. } static func fromStoryboard(_ storyboard: UIStoryboard = UIStoryboard(name: "ServerSwitchingViewController", bundle: nil)) -> MordalViewController { diff --git a/AgileWorks/Common/DataStore/KeychainDataStore.swift b/AgileWorks/Common/DataStore/KeychainDataStore.swift index 3529ac1..e6fdd1c 100644 --- a/AgileWorks/Common/DataStore/KeychainDataStore.swift +++ b/AgileWorks/Common/DataStore/KeychainDataStore.swift @@ -12,7 +12,9 @@ import UIKit final class KeychainDataStore: DataStoreProtocol { private let service = "AgileWorks" - private let groupId = Bundle.main.object(forInfoDictionaryKey: "AppIdentifierPrefix") as! String + Configuration.shared.awShareBundleIdentifier + private let baseGroupId = Bundle.main.object(forInfoDictionaryKey: "AppIdentifierPrefix") as! String + Configuration.shared.awShareBundleIdentifier + //private var groupId: String = "" + private var groupId: String = Bundle.main.object(forInfoDictionaryKey: "AppIdentifierPrefix") as! String + Configuration.shared.awShareBundleIdentifier private let kAccessToken: String = "AccessToken" private let kOAuthState: String = "OAuthState" private let kLanguage: String = "Localizable" @@ -22,6 +24,10 @@ final class KeychainDataStore: DataStoreProtocol { private let kSessionID: String = "SessionID" private let kServerName: String = "ServerName" + func setGroupId(serverNumber: Int) { + groupId = baseGroupId + String(serverNumber) + } + // アクセストークンの書き込み func writeAccessToken(accessToken: String) { setKeychainValue(key: kAccessToken, value: accessToken) diff --git a/AgileWorks/Common/DataStore/UserDefaultsDataStore.swift b/AgileWorks/Common/DataStore/UserDefaultsDataStore.swift index 1e39b58..4c53b66 100644 --- a/AgileWorks/Common/DataStore/UserDefaultsDataStore.swift +++ b/AgileWorks/Common/DataStore/UserDefaultsDataStore.swift @@ -17,6 +17,9 @@ final class UserDefaultsDataStore: DataStoreProtocol { private let kFirebaseRemovalKey: String = "FirebaseRemoval" private let kLastAcceptedLicenseVersionKey: String = "LastAppceptedLicenseVersion" private let kUpdateWidgetFlgKey : String = "UpdateWidgetFlg" + private let kServerListkey: String = "ServerList" + + private let severCount = 5 init() { sharedDefaults = UserDefaults() @@ -41,17 +44,69 @@ final class UserDefaultsDataStore: DataStoreProtocol { func readLastAcceptedLicenseVersion() -> Int? { return sharedDefaults.integer(forKey: kLastAcceptedLicenseVersionKey) } - + //ウィジェット更新フラグ func writeUpdateWidgetFlg(update: Bool) { sharedDefaults.set(update, forKey: kUpdateWidgetFlgKey) } - + func readUpdateWidgetFlg() -> Bool? { return sharedDefaults.bool(forKey: kUpdateWidgetFlgKey) } - + func removeUpdateWidgetFlg(update: Bool) { sharedDefaults.removeObject(forKey: kUpdateWidgetFlgKey) } + + //接続先サーバー管理 + func writeServerList(list: [Int]) { + sharedDefaults.set(list, forKey: kServerListkey) + } + + func readServerList() -> [Int] { + if let serverList = sharedDefaults.array(forKey: kServerListkey) as? [Int] { + return serverList + } + return [] + } + + func removeServer() { + var serverList = readServerList() + if !serverList.isEmpty { + //先頭(ログアウト処理を行ったサーバー)をリストから削除 + serverList.removeFirst() + writeServerList(list: serverList) + } + } + + //サーバー接続先を保存できる識別番号を探す + func serchEmptyServerData() -> Int? { + var serverList = readServerList() + for num in 0 ..< severCount { + if serverList.contains(num) { + return num + } + } + return nil + } + + //サーバー追加 + func addServerList() { + var serverList = readServerList() + if let serverNumber = serchEmptyServerData() { + serverList.insert(serverNumber, at: 0) + writeServerList(list: serverList) + } + } + + //サーバー並び替え + func changeServerList(firstServer: Int) { + var serverList = readServerList() + if serverList.contains(firstServer) { + //要素を削除してから先頭に追加する + serverList.removeAll(where: { $0 == firstServer }) + serverList.insert(firstServer, at: 0) + writeServerList(list: serverList) + } + } } -- GitLab From b98cbbeabdfd0bf2dd5572c16280af50db87e498 Mon Sep 17 00:00:00 2001 From: Azuma Kasumi Date: Wed, 24 May 2023 16:06:41 +0900 Subject: [PATCH 05/12] =?UTF-8?q?=E3=82=AD=E3=83=BC=E3=83=81=E3=82=A7?= =?UTF-8?q?=E3=83=BC=E3=83=B3=E3=81=AE=E5=88=87=E3=82=8A=E6=9B=BF=E3=81=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AgileWorks-Production.entitlements | 6 ++- .../AgileWorks/App/RootViewController.swift | 16 +++----- .../Login/View/LoginViewController.swift | 9 ++--- .../View/MordalViewController.swift | 3 ++ .../ServerSwitchingTableViewController.swift | 39 ++++++++++++++----- .../View/MenuTableViewController.swift | 2 +- .../WebView/View/WebViewController.swift | 2 +- .../Common/DataStore/KeychainDataStore.swift | 21 +++++----- .../DataStore/UserDefaultsDataStore.swift | 22 ++++++++++- 9 files changed, 78 insertions(+), 42 deletions(-) diff --git a/AgileWorks/AgileWorks/AgileWorks-Production.entitlements b/AgileWorks/AgileWorks/AgileWorks-Production.entitlements index 6f5ee78..4db9e2b 100644 --- a/AgileWorks/AgileWorks/AgileWorks-Production.entitlements +++ b/AgileWorks/AgileWorks/AgileWorks-Production.entitlements @@ -6,7 +6,11 @@ development keychain-access-groups - $(AppIdentifierPrefix)jp.atled.AgileWorks + $(AppIdentifierPrefix)jp.atled.agileworks0 + $(AppIdentifierPrefix)jp.atled.agileworks1 + $(AppIdentifierPrefix)jp.atled.agileworks2 + $(AppIdentifierPrefix)jp.atled.agileworks3 + $(AppIdentifierPrefix)jp.atled.agileworks4 diff --git a/AgileWorks/AgileWorks/App/RootViewController.swift b/AgileWorks/AgileWorks/App/RootViewController.swift index 0ce909d..a26249a 100644 --- a/AgileWorks/AgileWorks/App/RootViewController.swift +++ b/AgileWorks/AgileWorks/App/RootViewController.swift @@ -55,7 +55,7 @@ extension RootViewController { } // ログアウトアラート デフォルトボタンアクション生成 - func logoutDefaultAction(title: String) -> UIAlertAction { + func logoutDefaultAction(serverRemove: Bool, title: String) -> UIAlertAction { let defaultAction = UIAlertAction(title: title, style: .default) { _ in self.logout { result in switch result { @@ -71,15 +71,10 @@ extension RootViewController { KeychainDataStore().removeLanguage() KeychainDataStore().removeDeviceID() - DispatchQueue.main.async { - self.switchToLogout() - //ウィジェットの更新 - if #available(iOS 14.0, *) { - WidgetCenter.shared.reloadAllTimelines() - } + if serverRemove { + UserDefaultsDataStore().removeServer() } - /* - UserDefaultsDataStore().removeServer() + let serverList = UserDefaultsDataStore().readServerList() if serverList.isEmpty { DispatchQueue.main.async { @@ -90,7 +85,7 @@ extension RootViewController { } } } else { - KeychainDataStore().setGroupId(serverNumber: serverList.first!) + UserDefaultsDataStore().setGroupId(serverNumber: serverList.first!) DispatchQueue.main.async { self.switchToMainScreen() //ウィジェットの更新 @@ -99,7 +94,6 @@ extension RootViewController { } } } - */ } } diff --git a/AgileWorks/AgileWorks/Login/View/LoginViewController.swift b/AgileWorks/AgileWorks/Login/View/LoginViewController.swift index 37e45d7..07e9acd 100644 --- a/AgileWorks/AgileWorks/Login/View/LoginViewController.swift +++ b/AgileWorks/AgileWorks/Login/View/LoginViewController.swift @@ -183,14 +183,13 @@ class LoginViewController: UIViewController { guard let context = context else { return } disableLogin() -/* + //サーバー切り替え if let serverId = UserDefaultsDataStore().serchEmptyServerData() { - KeychainDataStore().setGroupId(serverNumber: serverId) + UserDefaultsDataStore().setGroupId(serverNumber: serverId) } else { //TODO: サーバー追加できない場合 } - */ //サーバー名コンテキストパスの保存 KeychainDataStore().writeServerURL(serverURL: serverHost) @@ -235,7 +234,7 @@ class LoginViewController: UIViewController { KeychainDataStore().writeSessionID(sessionID: response.sessionId) KeychainDataStore().writeServerName(serverName: "サーバー識別名") //TODO response.server.name DispatchQueue.main.async { - //UserDefaultsDataStore().addServerList() + UserDefaultsDataStore().addServerList() //メイン画面表示 AppDelegate.shared.rootViewController.switchToMainScreen() } @@ -326,7 +325,7 @@ class LoginViewController: UIViewController { let message = getLocalizableStrings(key: "LoginErrorMessage", comment: "") let defaultAction: UIAlertAction if isLogout { - defaultAction = AppDelegate.shared.rootViewController.logoutDefaultAction(title: getLocalizableStrings(key: "OK", comment: "")) + defaultAction = AppDelegate.shared.rootViewController.logoutDefaultAction(serverRemove: false, title: getLocalizableStrings(key: "OK", comment: "")) } else { defaultAction = UIAlertAction(title: getLocalizableStrings(key: "OK", comment: ""), style: .default, handler: nil) } diff --git a/AgileWorks/AgileWorks/ServerSwitching/View/MordalViewController.swift b/AgileWorks/AgileWorks/ServerSwitching/View/MordalViewController.swift index 495d92e..468fa9b 100644 --- a/AgileWorks/AgileWorks/ServerSwitching/View/MordalViewController.swift +++ b/AgileWorks/AgileWorks/ServerSwitching/View/MordalViewController.swift @@ -19,6 +19,9 @@ class MordalViewController: UIViewController { navVC.dismiss(animated: true) } + func cancel() { + navVC.dismiss(animated: true) + } override func viewDidLoad() { super.viewDidLoad() accessPoint.text = getDisplayString(key: "ServerTitle", comment: "") diff --git a/AgileWorks/AgileWorks/ServerSwitching/View/ServerSwitchingTableViewController.swift b/AgileWorks/AgileWorks/ServerSwitching/View/ServerSwitchingTableViewController.swift index 54764d3..f7a35d5 100644 --- a/AgileWorks/AgileWorks/ServerSwitching/View/ServerSwitchingTableViewController.swift +++ b/AgileWorks/AgileWorks/ServerSwitching/View/ServerSwitchingTableViewController.swift @@ -10,14 +10,32 @@ import UIKit class ServerSwitchingTableTableViewController: UITableViewController { @IBOutlet var table: UITableView! - + var serverList: [Int] = [] + override func viewDidLoad() { super.viewDidLoad() + serverList = UserDefaultsDataStore().readServerList() table.tableFooterView = UIView() } - + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + //承認待ち件数の表示 + Task{ + for row in 1.. Int { // #warning Incomplete implementation, return the number of sections return 1 @@ -25,14 +43,15 @@ class ServerSwitchingTableTableViewController: UITableViewController { //セルの数 override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // #warning Incomplete implementation, return the number of rows - return 1 + return serverList.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "ServerSwitchingTableViewCell", for: indexPath) let serverName = cell.viewWithTag(1) as! UILabel - serverName.text = KeychainDataStore().readServerName() + let serverNumber = serverList[indexPath.row] + serverName.text = KeychainDataStore().readServerName(serverNumber: serverNumber) let badgeIcon = cell.viewWithTag(2) as! UIImageView badgeIcon.image = UIImage(systemName: "circle.fill", withConfiguration: UIImage.SymbolConfiguration(font: .systemFont(ofSize: 25))) @@ -45,19 +64,19 @@ class ServerSwitchingTableTableViewController: UITableViewController { badgeIcon.tintColor = UIColor(named: getDisplayString(key: "MainColor", comment: "")) //承認待ち件数は取得しないため非表示 approvalCount.isHidden = true - } else {//その他サーバー - setApprovalsCount(label: approvalCount) } return cell } - + override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 50 } - + private func callApprovalCount(label: UILabel) async{ + await setApprovalsCount(label: label) + } //承認待ち件数取得 - private func setApprovalsCount(label: UILabel){ + private func setApprovalsCount(label: UILabel) async { let approvalsEndpoint = GetApprovalsEndpoint() Session.send(approvalsEndpoint) { result in diff --git a/AgileWorks/AgileWorks/WebView/View/MenuTableViewController.swift b/AgileWorks/AgileWorks/WebView/View/MenuTableViewController.swift index 368a19e..c487fbf 100644 --- a/AgileWorks/AgileWorks/WebView/View/MenuTableViewController.swift +++ b/AgileWorks/AgileWorks/WebView/View/MenuTableViewController.swift @@ -79,7 +79,7 @@ class MenuTableViewController: UITableViewController { private func logout() { // ログアウトタップ時処理 let message = getDisplayString(key: "LogoutConfirm", comment: "") - let defaultAction = AppDelegate.shared.rootViewController.logoutDefaultAction(title: getDisplayString(key: "YES", comment: "")) + let defaultAction = AppDelegate.shared.rootViewController.logoutDefaultAction(serverRemove: true, title: getDisplayString(key: "YES", comment: "")) let cancelAction = UIAlertAction(title: getDisplayString(key: "NO", comment: ""), style: .cancel) { _ in if let indexPath = self.tableView.indexPath(for: self.logoutCell) { self.tableView.deselectRow(at: indexPath, animated: true) diff --git a/AgileWorks/AgileWorks/WebView/View/WebViewController.swift b/AgileWorks/AgileWorks/WebView/View/WebViewController.swift index fe9d431..eabd361 100644 --- a/AgileWorks/AgileWorks/WebView/View/WebViewController.swift +++ b/AgileWorks/AgileWorks/WebView/View/WebViewController.swift @@ -262,7 +262,7 @@ class WebViewController: UIViewController { DispatchQueue.main.async { let title = getDisplayString(key: "RefreshTokenUpdateErrorTitle", comment: "") let message = getDisplayString(key: "RefreshTokenUpdateError", comment: "") - let defaultAction = AppDelegate.shared.rootViewController.logoutDefaultAction(title: getDisplayString(key: "OK", comment: "")) + let defaultAction = AppDelegate.shared.rootViewController.logoutDefaultAction(serverRemove: true, title: getDisplayString(key: "OK", comment: "")) AppDelegate.shared.rootViewController.showAlertScreen(view: self, title: title, message: message, defaultAction: defaultAction, cancelAction: nil) } // その他エラーの場合 diff --git a/AgileWorks/Common/DataStore/KeychainDataStore.swift b/AgileWorks/Common/DataStore/KeychainDataStore.swift index e6fdd1c..0e2a3b1 100644 --- a/AgileWorks/Common/DataStore/KeychainDataStore.swift +++ b/AgileWorks/Common/DataStore/KeychainDataStore.swift @@ -12,9 +12,6 @@ import UIKit final class KeychainDataStore: DataStoreProtocol { private let service = "AgileWorks" - private let baseGroupId = Bundle.main.object(forInfoDictionaryKey: "AppIdentifierPrefix") as! String + Configuration.shared.awShareBundleIdentifier - //private var groupId: String = "" - private var groupId: String = Bundle.main.object(forInfoDictionaryKey: "AppIdentifierPrefix") as! String + Configuration.shared.awShareBundleIdentifier private let kAccessToken: String = "AccessToken" private let kOAuthState: String = "OAuthState" private let kLanguage: String = "Localizable" @@ -24,10 +21,6 @@ final class KeychainDataStore: DataStoreProtocol { private let kSessionID: String = "SessionID" private let kServerName: String = "ServerName" - func setGroupId(serverNumber: Int) { - groupId = baseGroupId + String(serverNumber) - } - // アクセストークンの書き込み func writeAccessToken(accessToken: String) { setKeychainValue(key: kAccessToken, value: accessToken) @@ -45,7 +38,7 @@ final class KeychainDataStore: DataStoreProtocol { // 認可ステータスの書き込み func writeOAuthState(authState: OIDAuthState) { - let keychain = Keychain(service: service, accessGroup: groupId) + let keychain = Keychain(service: service, accessGroup: UserDefaultsDataStore().readGroupId()!) guard let object = try? NSKeyedArchiver.archivedData(withRootObject: authState, requiringSecureCoding: true) else { return } @@ -54,7 +47,7 @@ final class KeychainDataStore: DataStoreProtocol { // 認可ステータスの読み込み func readOAuthState() -> OIDAuthState? { - let keychain = Keychain(service: service, accessGroup: groupId) + let keychain = Keychain(service: service, accessGroup: UserDefaultsDataStore().readGroupId()!) if let object = keychain[data: kOAuthState] { guard let authState = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(object) as? OIDAuthState else { return nil @@ -159,6 +152,10 @@ final class KeychainDataStore: DataStoreProtocol { func readServerName() -> String? { return getKeychainValue(key: kServerName) } + func readServerName(serverNumber: Int) -> String? { + let keychain = Keychain(service: service, accessGroup: UserDefaultsDataStore().readBaseGroupId() + String(serverNumber)) + return keychain[kServerName] + } // サーバー識別名の削除 func removeServerName() { @@ -167,17 +164,17 @@ final class KeychainDataStore: DataStoreProtocol { // KeyChain へ指定の値をセット private func setKeychainValue(key: String, value: String) { - let keychain = Keychain(service: service, accessGroup: groupId) + let keychain = Keychain(service: service, accessGroup: UserDefaultsDataStore().readGroupId()!) keychain[key] = value } // KeyChain から指定の値を取得 private func getKeychainValue(key: String) -> String? { - let keychain = Keychain(service: service, accessGroup: groupId) + let keychain = Keychain(service: service, accessGroup: UserDefaultsDataStore().readGroupId()!) return keychain[key] } // KeyChain から指定の値を削除 private func removeKeychainValue(key: String) { - let keychain = Keychain(service: service, accessGroup: groupId) + let keychain = Keychain(service: service, accessGroup: UserDefaultsDataStore().readGroupId()!) do { try keychain.remove(key) } catch { diff --git a/AgileWorks/Common/DataStore/UserDefaultsDataStore.swift b/AgileWorks/Common/DataStore/UserDefaultsDataStore.swift index 4c53b66..7c62120 100644 --- a/AgileWorks/Common/DataStore/UserDefaultsDataStore.swift +++ b/AgileWorks/Common/DataStore/UserDefaultsDataStore.swift @@ -18,6 +18,8 @@ final class UserDefaultsDataStore: DataStoreProtocol { private let kLastAcceptedLicenseVersionKey: String = "LastAppceptedLicenseVersion" private let kUpdateWidgetFlgKey : String = "UpdateWidgetFlg" private let kServerListkey: String = "ServerList" + private let kGroupIdkey: String = "GroupId" + private let baseGroupId = Bundle.main.object(forInfoDictionaryKey: "AppIdentifierPrefix") as! String + Configuration.shared.awShareBundleIdentifier private let severCount = 5 @@ -82,8 +84,11 @@ final class UserDefaultsDataStore: DataStoreProtocol { //サーバー接続先を保存できる識別番号を探す func serchEmptyServerData() -> Int? { var serverList = readServerList() + if serverList.isEmpty { + return serverList.count + } for num in 0 ..< severCount { - if serverList.contains(num) { + if !serverList.contains(num) { return num } } @@ -109,4 +114,19 @@ final class UserDefaultsDataStore: DataStoreProtocol { writeServerList(list: serverList) } } + + func setGroupId(serverNumber: Int) { + sharedDefaults.set(baseGroupId + String(serverNumber), forKey: kGroupIdkey) + } + func readGroupId() -> String? { + if let groupId = sharedDefaults.string(forKey: kGroupIdkey) as? String{ + return groupId + }else { + setGroupId(serverNumber: 0) + return sharedDefaults.string(forKey: kGroupIdkey) + } + } + func readBaseGroupId() -> String { + return baseGroupId + } } -- GitLab From 72bc947e097a1bf0cbd06096e82739a776d78edb Mon Sep 17 00:00:00 2001 From: Azuma Kasumi Date: Mon, 29 May 2023 16:42:47 +0900 Subject: [PATCH 06/12] =?UTF-8?q?=E3=82=B5=E3=83=BC=E3=83=90=E3=83=BC?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0=E3=83=BB=E3=83=AD=E3=82=B0=E3=82=A2=E3=82=A6?= =?UTF-8?q?=E3=83=88=20=E6=AD=A3=E5=B8=B8=E7=B3=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AgileWorks/AgileWorks/Login/View/LoginViewController.swift | 2 ++ .../ServerSwitching/View/MordalViewController.swift | 2 ++ .../View/ServerSwitchingTableViewController.swift | 4 ++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/AgileWorks/AgileWorks/Login/View/LoginViewController.swift b/AgileWorks/AgileWorks/Login/View/LoginViewController.swift index 07e9acd..7b82f00 100644 --- a/AgileWorks/AgileWorks/Login/View/LoginViewController.swift +++ b/AgileWorks/AgileWorks/Login/View/LoginViewController.swift @@ -235,6 +235,8 @@ class LoginViewController: UIViewController { KeychainDataStore().writeServerName(serverName: "サーバー識別名") //TODO response.server.name DispatchQueue.main.async { UserDefaultsDataStore().addServerList() + let serverList = UserDefaultsDataStore().readServerList() + UserDefaultsDataStore().setGroupId(serverNumber: serverList.first!) //メイン画面表示 AppDelegate.shared.rootViewController.switchToMainScreen() } diff --git a/AgileWorks/AgileWorks/ServerSwitching/View/MordalViewController.swift b/AgileWorks/AgileWorks/ServerSwitching/View/MordalViewController.swift index 468fa9b..bc7b78a 100644 --- a/AgileWorks/AgileWorks/ServerSwitching/View/MordalViewController.swift +++ b/AgileWorks/AgileWorks/ServerSwitching/View/MordalViewController.swift @@ -16,6 +16,8 @@ class MordalViewController: UIViewController { let navVC = UINavigationController(rootViewController: LoginBuilderImpl().build(addServerloginFlg: true)) @objc func cancelTapped(_ sender: UIBarButtonItem) { + var serverList = UserDefaultsDataStore().readServerList() + UserDefaultsDataStore().setGroupId(serverNumber: serverList.first!) navVC.dismiss(animated: true) } diff --git a/AgileWorks/AgileWorks/ServerSwitching/View/ServerSwitchingTableViewController.swift b/AgileWorks/AgileWorks/ServerSwitching/View/ServerSwitchingTableViewController.swift index f7a35d5..265e158 100644 --- a/AgileWorks/AgileWorks/ServerSwitching/View/ServerSwitchingTableViewController.swift +++ b/AgileWorks/AgileWorks/ServerSwitching/View/ServerSwitchingTableViewController.swift @@ -23,14 +23,14 @@ class ServerSwitchingTableTableViewController: UITableViewController { //承認待ち件数の表示 Task{ for row in 1.. Date: Tue, 30 May 2023 20:27:50 +0900 Subject: [PATCH 07/12] =?UTF-8?q?navigationViewController=E3=81=AE?= =?UTF-8?q?=E8=A6=8B=E7=9B=B4=E3=81=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AgileWorks/App/RootViewController.swift | 4 +-- .../Login/Builder/LoginBuilder.swift | 18 +++++++------ .../Login/View/LoginViewController.swift | 25 +++++++++++-------- .../View/MordalViewController.swift | 15 +---------- .../ServerSwitchingTableViewController.swift | 9 ++++++- 5 files changed, 37 insertions(+), 34 deletions(-) diff --git a/AgileWorks/AgileWorks/App/RootViewController.swift b/AgileWorks/AgileWorks/App/RootViewController.swift index a26249a..ace6f96 100644 --- a/AgileWorks/AgileWorks/App/RootViewController.swift +++ b/AgileWorks/AgileWorks/App/RootViewController.swift @@ -40,7 +40,7 @@ class RootViewController: UIViewController { extension RootViewController { func showLoginScreen() { - let new = LoginBuilderImpl().build(addServerloginFlg: false) + let new = LoginBuilderImpl().build() addChild(new) new.view.frame = view.bounds @@ -120,7 +120,7 @@ extension RootViewController { } func switchToLogout() { - let new = LoginBuilderImpl().build(addServerloginFlg: false) + let new = LoginBuilderImpl().build() animateDismissTransition(to: new) } diff --git a/AgileWorks/AgileWorks/Login/Builder/LoginBuilder.swift b/AgileWorks/AgileWorks/Login/Builder/LoginBuilder.swift index 42d56a5..54a3c59 100644 --- a/AgileWorks/AgileWorks/Login/Builder/LoginBuilder.swift +++ b/AgileWorks/AgileWorks/Login/Builder/LoginBuilder.swift @@ -9,14 +9,15 @@ import UIKit protocol LoginBuilder { - func build(addServerloginFlg: Bool) -> UIViewController + func build() -> UIViewController } struct LoginBuilderImpl: LoginBuilder { let identifier = "LoginViewController" + var navVC: UINavigationController? = nil - func build(addServerloginFlg: Bool) -> UIViewController { - let viewController = storyboard(addServerloginFlg: addServerloginFlg) + func build() -> UIViewController { + let viewController = storyboard() viewController.inject( presenter: LoginPresenterImpl( view: viewController, @@ -27,14 +28,17 @@ struct LoginBuilderImpl: LoginBuilder { return viewController } + func naviBuild() -> UINavigationController { + let navVC = UINavigationController(rootViewController: build()) + navVC.modalPresentationStyle = .fullScreen + return navVC + } } extension LoginBuilderImpl { - private func storyboard(addServerloginFlg: Bool) -> LoginViewController { + private func storyboard() -> LoginViewController { let storyboard = mainStoryboard() - let viewController = storyboard.instantiateViewController(identifier: identifier){ coder in - LoginViewController(coder: coder, addServerloginFlg: addServerloginFlg) - } + let viewController = storyboard.instantiateViewController(withIdentifier: identifier) as! LoginViewController return viewController } diff --git a/AgileWorks/AgileWorks/Login/View/LoginViewController.swift b/AgileWorks/AgileWorks/Login/View/LoginViewController.swift index 7b82f00..3b23efb 100644 --- a/AgileWorks/AgileWorks/Login/View/LoginViewController.swift +++ b/AgileWorks/AgileWorks/Login/View/LoginViewController.swift @@ -36,21 +36,12 @@ class LoginViewController: UIViewController { @IBOutlet private var qrCodeStartupButton: UIButton! @IBOutlet private var scrollViewBottomConstraint: NSLayoutConstraint! //サーバー追加画面フラグ - public var addServerloginFlg: Bool + private var addServerloginFlg = false private let activityIndicator = UIActivityIndicatorView(style: .whiteLarge) private var presenter: LoginPresenter! - init?(coder: NSCoder, addServerloginFlg: Bool){ - self.addServerloginFlg = addServerloginFlg - super.init(coder: coder) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - private var serverHost: String? { guard let server = serverTextField.text else { return nil } return server @@ -69,6 +60,11 @@ class LoginViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() + if let navVC = self.parent as? UINavigationController { + addServerloginFlg = true + let leftButton = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelTapped(_:))) + navVC.navigationBar.topItem!.leftBarButtonItem = leftButton + } //サーバー追加画面の場合は認証情報を削除しない if !addServerloginFlg { //ログイン画面が表示されると通知を取得しない @@ -129,6 +125,12 @@ class LoginViewController: UIViewController { func dismissKeyboard() { self.view.endEditing(true) } + + @objc private func cancelTapped(_ sender: UIBarButtonItem) { + var serverList = UserDefaultsDataStore().readServerList() + UserDefaultsDataStore().setGroupId(serverNumber: serverList.first!) + self.parent!.dismiss(animated: true) + } //ログイン画面の固定文言表示 private func setupFixedWording() { @@ -239,6 +241,9 @@ class LoginViewController: UIViewController { UserDefaultsDataStore().setGroupId(serverNumber: serverList.first!) //メイン画面表示 AppDelegate.shared.rootViewController.switchToMainScreen() + if let nc = self.parent as? UINavigationController { + nc.dismiss(animated: true) + } } // セッション情報取得失敗 case .failure(let error): diff --git a/AgileWorks/AgileWorks/ServerSwitching/View/MordalViewController.swift b/AgileWorks/AgileWorks/ServerSwitching/View/MordalViewController.swift index bc7b78a..a67e42a 100644 --- a/AgileWorks/AgileWorks/ServerSwitching/View/MordalViewController.swift +++ b/AgileWorks/AgileWorks/ServerSwitching/View/MordalViewController.swift @@ -13,17 +13,6 @@ class MordalViewController: UIViewController { @IBOutlet private var accessPoint: UILabel! @IBOutlet private var addServer: UIButton! - let navVC = UINavigationController(rootViewController: LoginBuilderImpl().build(addServerloginFlg: true)) - - @objc func cancelTapped(_ sender: UIBarButtonItem) { - var serverList = UserDefaultsDataStore().readServerList() - UserDefaultsDataStore().setGroupId(serverNumber: serverList.first!) - navVC.dismiss(animated: true) - } - - func cancel() { - navVC.dismiss(animated: true) - } override func viewDidLoad() { super.viewDidLoad() accessPoint.text = getDisplayString(key: "ServerTitle", comment: "") @@ -35,9 +24,7 @@ class MordalViewController: UIViewController { } @IBAction private func addServerTapped(_ sender: Any) { //モーダルの表示 - navVC.modalPresentationStyle = .fullScreen - let leftButton = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelTapped(_:))) - navVC.navigationBar.topItem!.leftBarButtonItem = leftButton + let navVC = LoginBuilderImpl().naviBuild() self.present(navVC, animated: true) } } diff --git a/AgileWorks/AgileWorks/ServerSwitching/View/ServerSwitchingTableViewController.swift b/AgileWorks/AgileWorks/ServerSwitching/View/ServerSwitchingTableViewController.swift index 265e158..b390be1 100644 --- a/AgileWorks/AgileWorks/ServerSwitching/View/ServerSwitchingTableViewController.swift +++ b/AgileWorks/AgileWorks/ServerSwitching/View/ServerSwitchingTableViewController.swift @@ -72,6 +72,11 @@ class ServerSwitchingTableTableViewController: UITableViewController { override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 50 } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + UserDefaultsDataStore().setGroupId(serverNumber: serverList[indexPath.row]) + AppDelegate.shared.rootViewController.switchToMainScreen() + } private func callApprovalCount(label: UILabel) async{ await setApprovalsCount(label: label) } @@ -92,7 +97,9 @@ class ServerSwitchingTableTableViewController: UITableViewController { } case .failure(let error): log.e(error) - label.text = "0" + DispatchQueue.main.async { + label.text = "0" + } } } } -- GitLab From 7c362b1d067fac3f6d1bf441d81f89934021f083 Mon Sep 17 00:00:00 2001 From: Azuma Kasumi Date: Fri, 2 Jun 2023 13:12:49 +0900 Subject: [PATCH 08/12] =?UTF-8?q?=E3=83=A2=E3=83=BC=E3=83=80=E3=83=AB?= =?UTF-8?q?=E3=82=92=E9=96=89=E3=81=98=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Login/View/LoginViewController.swift | 4 +-- .../ServerSwitchingTableViewController.swift | 29 ++++++++++++------- .../View/ServerSwitchingViewController.swift | 4 +-- .../WebView/View/MenuViewController.swift | 2 +- .../Common/DataStore/KeychainDataStore.swift | 3 +- 5 files changed, 26 insertions(+), 16 deletions(-) diff --git a/AgileWorks/AgileWorks/Login/View/LoginViewController.swift b/AgileWorks/AgileWorks/Login/View/LoginViewController.swift index 3b23efb..58e6da2 100644 --- a/AgileWorks/AgileWorks/Login/View/LoginViewController.swift +++ b/AgileWorks/AgileWorks/Login/View/LoginViewController.swift @@ -129,7 +129,7 @@ class LoginViewController: UIViewController { @objc private func cancelTapped(_ sender: UIBarButtonItem) { var serverList = UserDefaultsDataStore().readServerList() UserDefaultsDataStore().setGroupId(serverNumber: serverList.first!) - self.parent!.dismiss(animated: true) + self.presentingViewController?.presentingViewController?.dismiss(animated: true, completion: nil) } //ログイン画面の固定文言表示 @@ -242,7 +242,7 @@ class LoginViewController: UIViewController { //メイン画面表示 AppDelegate.shared.rootViewController.switchToMainScreen() if let nc = self.parent as? UINavigationController { - nc.dismiss(animated: true) + self.presentingViewController?.presentingViewController?.dismiss(animated: true, completion: nil) } } // セッション情報取得失敗 diff --git a/AgileWorks/AgileWorks/ServerSwitching/View/ServerSwitchingTableViewController.swift b/AgileWorks/AgileWorks/ServerSwitching/View/ServerSwitchingTableViewController.swift index b390be1..f540c2b 100644 --- a/AgileWorks/AgileWorks/ServerSwitching/View/ServerSwitchingTableViewController.swift +++ b/AgileWorks/AgileWorks/ServerSwitching/View/ServerSwitchingTableViewController.swift @@ -10,11 +10,9 @@ import UIKit class ServerSwitchingTableTableViewController: UITableViewController { @IBOutlet var table: UITableView! - var serverList: [Int] = [] override func viewDidLoad() { super.viewDidLoad() - serverList = UserDefaultsDataStore().readServerList() table.tableFooterView = UIView() } @@ -22,14 +20,15 @@ class ServerSwitchingTableTableViewController: UITableViewController { super.viewWillAppear(animated) //承認待ち件数の表示 Task{ - for row in 1.. Int { - // #warning Incomplete implementation, return the number of sections return 1 } //セルの数 override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - // #warning Incomplete implementation, return the number of rows - return serverList.count + let serverCount = UserDefaultsDataStore().readServerList().count + return serverCount } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "ServerSwitchingTableViewCell", for: indexPath) + let serverList = UserDefaultsDataStore().readServerList() let serverName = cell.viewWithTag(1) as! UILabel let serverNumber = serverList[indexPath.row] serverName.text = KeychainDataStore().readServerName(serverNumber: serverNumber) @@ -72,18 +71,28 @@ class ServerSwitchingTableTableViewController: UITableViewController { override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return 50 } - + + //セル選択時の処理 override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - UserDefaultsDataStore().setGroupId(serverNumber: serverList[indexPath.row]) + if indexPath.row == 0 { + self.dismiss(animated: true, completion: nil) + return + } + let serverList = UserDefaultsDataStore().readServerList() + let server = serverList[indexPath.row] + UserDefaultsDataStore().setGroupId(serverNumber: server) + UserDefaultsDataStore().changeServerList(firstServer: server) AppDelegate.shared.rootViewController.switchToMainScreen() + self.parent!.dismiss(animated: true) } + private func callApprovalCount(label: UILabel) async{ await setApprovalsCount(label: label) } + //承認待ち件数取得 private func setApprovalsCount(label: UILabel) async { let approvalsEndpoint = GetApprovalsEndpoint() - Session.send(approvalsEndpoint) { result in var reqApprovalCount: Int = 0 switch result { diff --git a/AgileWorks/AgileWorks/ServerSwitching/View/ServerSwitchingViewController.swift b/AgileWorks/AgileWorks/ServerSwitching/View/ServerSwitchingViewController.swift index 3ebe6b9..652e871 100644 --- a/AgileWorks/AgileWorks/ServerSwitching/View/ServerSwitchingViewController.swift +++ b/AgileWorks/AgileWorks/ServerSwitching/View/ServerSwitchingViewController.swift @@ -29,9 +29,9 @@ class ServerSwitchingViewController: UIViewController, UIGestureRecognizerDelega fpc.surfaceView.cornerRadius = 24.0 //下スワイプで閉じる fpc.isRemovalInteractionEnabled = true - let mordalVC = MordalViewController.fromStoryboard() + let modalVC = MordalViewController.fromStoryboard() self.view.addSubview(fpc.view) - fpc.set(contentViewController: mordalVC) + fpc.set(contentViewController: modalVC) fpc.addPanel(toParent: self) } diff --git a/AgileWorks/AgileWorks/WebView/View/MenuViewController.swift b/AgileWorks/AgileWorks/WebView/View/MenuViewController.swift index 20add4e..0129ea3 100644 --- a/AgileWorks/AgileWorks/WebView/View/MenuViewController.swift +++ b/AgileWorks/AgileWorks/WebView/View/MenuViewController.swift @@ -67,7 +67,7 @@ class MenuViewController: UIViewController { switch result { case .success(let response): let userName = response.user.name - let serverName = "サーバー識別名" //TODO response.server.name + let serverName = KeychainDataStore().readServerURL()! //TODO response.server.name let sessionId = response.sessionId DispatchQueue.main.async { self.nameLabel.text = userName diff --git a/AgileWorks/Common/DataStore/KeychainDataStore.swift b/AgileWorks/Common/DataStore/KeychainDataStore.swift index 0e2a3b1..b3e7a6c 100644 --- a/AgileWorks/Common/DataStore/KeychainDataStore.swift +++ b/AgileWorks/Common/DataStore/KeychainDataStore.swift @@ -154,7 +154,8 @@ final class KeychainDataStore: DataStoreProtocol { } func readServerName(serverNumber: Int) -> String? { let keychain = Keychain(service: service, accessGroup: UserDefaultsDataStore().readBaseGroupId() + String(serverNumber)) - return keychain[kServerName] + //return keychain[kServerName] //TODO: サーバー識別名 + return keychain[kServerURL] } // サーバー識別名の削除 -- GitLab From ab2a6183ea494156161f76004a26278ba2b374e2 Mon Sep 17 00:00:00 2001 From: Azuma Kasumi Date: Mon, 5 Jun 2023 16:06:37 +0900 Subject: [PATCH 09/12] =?UTF-8?q?UI=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AgileWorks/Common/WidgetView.swift | 49 +++++++++++-------- .../TodayExtension-Production.entitlements | 6 ++- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/AgileWorks/Common/WidgetView.swift b/AgileWorks/Common/WidgetView.swift index 49e429b..a22fdd3 100644 --- a/AgileWorks/Common/WidgetView.swift +++ b/AgileWorks/Common/WidgetView.swift @@ -108,6 +108,7 @@ struct ApprovalWidgetView: View { //書類状況を表示するための各BOXビュー struct StatusBoxView: View { var entry: EntryData + @State private var selection = 0 //書類状態の種類をカウント func rowCnt() -> Int { @@ -152,29 +153,37 @@ struct StatusBoxView: View { } var body: some View { - GeometryReader { geometry in - //ios13・14~状態確認ウィジェット - if geometry.size.height > kCellDefaultHight { - VStack(spacing: 5) { - ForEach(0.. kCellDefaultHight { + VStack(spacing: 5) { + ForEach(0.. keychain-access-groups - $(AppIdentifierPrefix)jp.atled.agileworks + $(AppIdentifierPrefix)jp.atled.agileworks0 + $(AppIdentifierPrefix)jp.atled.agileworks1 + $(AppIdentifierPrefix)jp.atled.agileworks2 + $(AppIdentifierPrefix)jp.atled.agileworks3 + $(AppIdentifierPrefix)jp.atled.agileworks4 -- GitLab From b5b2b1b5c95edaa5d2219d269ab60aafa474cb4a Mon Sep 17 00:00:00 2001 From: Azuma Kasumi Date: Tue, 13 Jun 2023 11:37:51 +0900 Subject: [PATCH 10/12] =?UTF-8?q?=E3=82=A6=E3=82=A3=E3=82=B8=E3=82=A7?= =?UTF-8?q?=E3=83=83=E3=83=88=E8=A4=87=E6=95=B0=E3=82=B5=E3=83=BC=E3=83=90?= =?UTF-8?q?=E3=83=BC=E5=88=87=E3=82=8A=E6=9B=BF=E3=81=88=20widget=20Extens?= =?UTF-8?q?ion=E3=80=80UI=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AgileWorks.xcodeproj/project.pbxproj | 12 +- .../AgileWorks-Production.entitlements | 4 + .../AgileWorksRelease-Production.entitlements | 20 +++ AgileWorks/AgileWorks/App/AppDelegate.swift | 9 ++ .../DataStore/UserDefaultsDataStore.swift | 11 +- AgileWorks/Common/WidgetView.swift | 136 ++++++++++++++---- .../TodayExtension-Production.entitlements | 4 + ...ayExtensionRelease-Production.entitlements | 18 +++ .../View/TodayViewController.swift | 98 +++++-------- .../WidgetExtension.entitlements | 10 +- .../WidgetExtension/WidgetExtension.swift | 54 ------- ...etExtensionRelease-Production.entitlements | 18 +++ 12 files changed, 250 insertions(+), 144 deletions(-) create mode 100644 AgileWorks/AgileWorks/AgileWorksRelease-Production.entitlements create mode 100644 AgileWorks/TodayExtension/TodayExtensionRelease-Production.entitlements create mode 100644 AgileWorks/WidgetExtension/WidgetExtensionRelease-Production.entitlements diff --git a/AgileWorks/AgileWorks.xcodeproj/project.pbxproj b/AgileWorks/AgileWorks.xcodeproj/project.pbxproj index 0ff8792..1e9166c 100644 --- a/AgileWorks/AgileWorks.xcodeproj/project.pbxproj +++ b/AgileWorks/AgileWorks.xcodeproj/project.pbxproj @@ -11,7 +11,6 @@ 3127EE0F241A2A9500535CC7 /* TodayViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3127EE0E241A2A9500535CC7 /* TodayViewController.swift */; }; 3127EE12241A2A9500535CC7 /* TodayViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3127EE10241A2A9500535CC7 /* TodayViewController.storyboard */; }; 3127EE16241A2A9500535CC7 /* TodayExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 3127EE0A241A2A9500535CC7 /* TodayExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - 3127EE1B241A2B4D00535CC7 /* TodayViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3127EE0E241A2A9500535CC7 /* TodayViewController.swift */; }; 31AA002F24347BBD000177B4 /* ApprovalResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31AA002E24347BBD000177B4 /* ApprovalResponse.swift */; }; 31AA003024347BD1000177B4 /* ApprovalResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31AA002E24347BBD000177B4 /* ApprovalResponse.swift */; }; 3AF4A84524A06A73006C0C0A /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3AF4A84724A06A73006C0C0A /* Localizable.strings */; }; @@ -242,6 +241,9 @@ 3AF4A84824A06AD0006C0C0A /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; 7503F77D27EAF7E00074A76E /* WidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = WidgetExtension.entitlements; sourceTree = ""; }; 756C7E7A282B6A5700C24F4D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 7576916A2A2EFEEC00EAFCBC /* AgileWorksRelease-Production.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "AgileWorksRelease-Production.entitlements"; sourceTree = ""; }; + 7576916B2A2F003400EAFCBC /* TodayExtensionRelease-Production.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "TodayExtensionRelease-Production.entitlements"; sourceTree = ""; }; + 757691732A32E5F100EAFCBC /* WidgetExtensionRelease-Production.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "WidgetExtensionRelease-Production.entitlements"; sourceTree = ""; }; 75917F9227BD315A0051E201 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; 75917F9627BD317E0051E201 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = ""; }; 75917F9B27BDF0F10051E201 /* Japanese.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = Japanese.strings; sourceTree = ""; }; @@ -453,6 +455,7 @@ 3127EE0D241A2A9500535CC7 /* TodayExtension */ = { isa = PBXGroup; children = ( + 7576916B2A2F003400EAFCBC /* TodayExtensionRelease-Production.entitlements */, BD285CAF24D2ACA300DC712E /* View */, 3127EE13241A2A9500535CC7 /* Info.plist */, BD10D30624E38C2F00A0DFDC /* TodayExtension-Production.entitlements */, @@ -522,6 +525,7 @@ 75EF9CB127E9E983003178A3 /* WidgetExtension */ = { isa = PBXGroup; children = ( + 757691732A32E5F100EAFCBC /* WidgetExtensionRelease-Production.entitlements */, 7503F77D27EAF7E00074A76E /* WidgetExtension.entitlements */, 75EF9CB227E9E983003178A3 /* WidgetExtension.swift */, 75EF9CB427E9E984003178A3 /* Assets.xcassets */, @@ -812,6 +816,7 @@ BDA1831123F3FD7F00C9A6DD /* AgileWorks */ = { isa = PBXGroup; children = ( + 7576916A2A2EFEEC00EAFCBC /* AgileWorksRelease-Production.entitlements */, BD5061B2242865BC0014F3FA /* Configurations */, BDA6D6A42411FFAA00FA9C33 /* Settings.bundle */, BDA1831B23F3FD8000C9A6DD /* Assets.xcassets */, @@ -1442,7 +1447,6 @@ C599740B27D992E9006F5AAC /* OpenLicenseTableViewCell.swift in Sources */, 76AE533325D37B0200AFA45A /* LicenseViewPresenter.swift in Sources */, 76AE530725D3652400AFA45A /* LicenseViewBuilder.swift in Sources */, - 3127EE1B241A2B4D00535CC7 /* TodayViewController.swift in Sources */, BDAABA1B24A361E90077EC69 /* PostDeviceEndpoint.swift in Sources */, 75BC053629F8DFCC00E21941 /* ServerSwitchingTableViewController.swift in Sources */, 31AA002F24347BBD000177B4 /* ApprovalResponse.swift in Sources */, @@ -1540,6 +1544,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = BD5061AF242848560014F3FA /* Release-Production-Today.xcconfig */; buildSettings = { + CODE_SIGN_ENTITLEMENTS = "TodayExtension/TodayExtensionRelease-Production.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; @@ -1600,7 +1605,7 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_ENTITLEMENTS = WidgetExtension/WidgetExtension.entitlements; + CODE_SIGN_ENTITLEMENTS = "WidgetExtension/WidgetExtensionRelease-Production.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; @@ -2028,6 +2033,7 @@ baseConfigurationReference = BD5061A9242846A50014F3FA /* Release-Production.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + CODE_SIGN_ENTITLEMENTS = "AgileWorks/AgileWorksRelease-Production.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; diff --git a/AgileWorks/AgileWorks/AgileWorks-Production.entitlements b/AgileWorks/AgileWorks/AgileWorks-Production.entitlements index 4db9e2b..002355e 100644 --- a/AgileWorks/AgileWorks/AgileWorks-Production.entitlements +++ b/AgileWorks/AgileWorks/AgileWorks-Production.entitlements @@ -4,6 +4,10 @@ aps-environment development + com.apple.security.application-groups + + group.jp.atled.agileworks + keychain-access-groups $(AppIdentifierPrefix)jp.atled.agileworks0 diff --git a/AgileWorks/AgileWorks/AgileWorksRelease-Production.entitlements b/AgileWorks/AgileWorks/AgileWorksRelease-Production.entitlements new file mode 100644 index 0000000..002355e --- /dev/null +++ b/AgileWorks/AgileWorks/AgileWorksRelease-Production.entitlements @@ -0,0 +1,20 @@ + + + + + aps-environment + development + com.apple.security.application-groups + + group.jp.atled.agileworks + + keychain-access-groups + + $(AppIdentifierPrefix)jp.atled.agileworks0 + $(AppIdentifierPrefix)jp.atled.agileworks1 + $(AppIdentifierPrefix)jp.atled.agileworks2 + $(AppIdentifierPrefix)jp.atled.agileworks3 + $(AppIdentifierPrefix)jp.atled.agileworks4 + + + diff --git a/AgileWorks/AgileWorks/App/AppDelegate.swift b/AgileWorks/AgileWorks/App/AppDelegate.swift index 84ff5cb..70723b2 100644 --- a/AgileWorks/AgileWorks/App/AppDelegate.swift +++ b/AgileWorks/AgileWorks/App/AppDelegate.swift @@ -72,6 +72,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate { OAuthService.currentAuthorizationFlow = nil } + //タップされたサーバーに切り替える + let serverList = UserDefaultsDataStore().readServerList() + if !serverList.isEmpty { + let tapServer = UserDefaultsDataStore().readTapServer() + UserDefaultsDataStore().changeServerList(firstServer: tapServer!) + UserDefaultsDataStore().setGroupId(serverNumber: tapServer!) + } + + //ios13の場合 if url.scheme == urlSchemeName { var strUrl = url.absoluteString diff --git a/AgileWorks/Common/DataStore/UserDefaultsDataStore.swift b/AgileWorks/Common/DataStore/UserDefaultsDataStore.swift index 7c62120..31c9173 100644 --- a/AgileWorks/Common/DataStore/UserDefaultsDataStore.swift +++ b/AgileWorks/Common/DataStore/UserDefaultsDataStore.swift @@ -19,12 +19,13 @@ final class UserDefaultsDataStore: DataStoreProtocol { private let kUpdateWidgetFlgKey : String = "UpdateWidgetFlg" private let kServerListkey: String = "ServerList" private let kGroupIdkey: String = "GroupId" + private let kTapServer: String = "TapServer" private let baseGroupId = Bundle.main.object(forInfoDictionaryKey: "AppIdentifierPrefix") as! String + Configuration.shared.awShareBundleIdentifier private let severCount = 5 init() { - sharedDefaults = UserDefaults() + sharedDefaults = UserDefaults(suiteName: "group.jp.atled.agileworks")! } func writeFirebaseRemoval(flag: Bool) { @@ -115,6 +116,14 @@ final class UserDefaultsDataStore: DataStoreProtocol { } } + func setTapServer(serverNumber: Int) { + sharedDefaults.set(serverNumber, forKey: kTapServer) + } + + func readTapServer() -> Int? { + return sharedDefaults.integer(forKey: kTapServer) + } + func setGroupId(serverNumber: Int) { sharedDefaults.set(baseGroupId + String(serverNumber), forKey: kGroupIdkey) } diff --git a/AgileWorks/Common/WidgetView.swift b/AgileWorks/Common/WidgetView.swift index a22fdd3..3bca8f6 100644 --- a/AgileWorks/Common/WidgetView.swift +++ b/AgileWorks/Common/WidgetView.swift @@ -44,6 +44,31 @@ struct EntryData { var viewController: UIViewController? } +struct TodayWidgetView: View { + var entrys: [EntryData] + @State private var selection = 0 + var serverList = UserDefaultsDataStore().readServerList() + + var body: some View { + VStack (spacing: 0) { + //未ログインの場合はサーバー切り替えボタンを表示しない + if !UserDefaultsDataStore().readServerList().isEmpty { + Picker(selection: $selection, label: Text("")) { + ForEach(0.. Int { var row = entry.approvalItems.count / 2 @@ -154,12 +179,11 @@ struct StatusBoxView: View { var body: some View { VStack (spacing: 0) { - Picker("", selection: self.$selection) { - Text("apple").tag(0) - Text("banana").tag(1) - Text("orange").tag(2) + if #available(iOS 14.0, *) { + if !serverList.isEmpty { + Text(KeychainDataStore().readServerName(serverNumber: serverList[0])!) + } } - .pickerStyle(SegmentedPickerStyle()) GeometryReader { geometry in //ios13・14~状態確認ウィジェット if geometry.size.height > kCellDefaultHight { @@ -175,7 +199,6 @@ struct StatusBoxView: View { } } .position(x: geometry.size.width / 2, y: geometry.size.height / 2) - .background(backColor()) } else { //ios13 承認待ちウィジェット if let num = findApproval() { RowView(entry: entry, boxSize: boxSize(viewSize: geometry.size), itemNum: num, oneBox: true) @@ -187,6 +210,7 @@ struct StatusBoxView: View { } } } + .background(backColor()) } } //ウィジェット1行分のビュー @@ -242,7 +266,7 @@ struct LinkView: View { var body: some View { if #available(iOS 14.0, *) { Link(destination: URL(string: getURL())!, label: { - ApprovalItemView(approvalItem: approvalItem, message: message) + ApprovalItemView(approvalItem: approvalItem, message: message, serverNameFlag: false) }) } else { ApprovalItemView(approvalItem: approvalItem, message: message) @@ -259,30 +283,41 @@ struct LinkView: View { struct ApprovalItemView: View { let approvalItem: ApprovalItem let message: String? + let serverList = UserDefaultsDataStore().readServerList() + var serverNameFlag = true var body: some View { - GeometryReader { geometry in - HStack(spacing: 0) { - Image(systemName: "folder") - .frame(width: geometry.size.width * 0.3, height: geometry.size.height) - .foregroundColor(Color.textColor) - if message == nil { - VStack(alignment: .leading) { - Text(approvalItem.name) - .frame(alignment: .leading) - .foregroundColor(Color.textColor) - Text("\(approvalItem.count)").font(.subheadline) - .frame(alignment: .leading) - .foregroundColor(Color.textColor) + VStack (spacing: 0) { + if #available(iOS 14.0, *) { + if serverNameFlag { + if !serverList.isEmpty { + Text(KeychainDataStore().readServerName(serverNumber: serverList[0])!) + } + } + } + GeometryReader { geometry in + HStack(spacing: 0) { + Image(systemName: "folder") + .frame(width: geometry.size.width * 0.3, height: geometry.size.height) + .foregroundColor(Color.textColor) + if message == nil { + VStack(alignment: .leading) { + Text(approvalItem.name) + .frame(alignment: .leading) + .foregroundColor(Color.textColor) + Text("\(approvalItem.count)").font(.subheadline) + .frame(alignment: .leading) + .foregroundColor(Color.textColor) + } + } else { //APIサーバーエラーの場合の表示 + Text(message ?? "-") } - } else { //APIサーバーエラーの場合の表示 - Text(message ?? "-") } + Spacer() } - Spacer() + .background(Color.widgetBoxColor) + .cornerRadius(20) } - .background(Color.widgetBoxColor) - .cornerRadius(20) } } @@ -305,6 +340,55 @@ func checkApprovalItems(approvalItems: [ApprovalItem]) -> [ApprovalItem] { return result } +enum WidgetAPIResult { + case success(T) + case nodate(String) + case failure(String) +} + +func fetch(completion: @escaping (WidgetAPIResult) -> Void) { + var serverList = UserDefaultsDataStore().readServerList() + if serverList.isEmpty { + completion(.failure(getDisplayString(key: "NotLogedin", comment: ""))) + return + } + + let approvalsEndpoint = GetApprovalsEndpoint() + + Session.send(approvalsEndpoint) { result in + switch result { + case .success(let response): + if !response.items.isEmpty { + completion(.success(response)) + } else { + completion(.nodate(getDisplayString(key: "NoData", comment: ""))) + } + case .failure(let error): + var errorMessage = "-" + switch error { + case .connectionError(let error): + if let message = errorMessageNSError(error: error) { + errorMessage = message + } + default: + break + } + completion(.failure(errorMessage)) + } + } +} + +func errorMessageNSError(error: Error) -> String? { + switch URLError.Code(rawValue: (error as NSError).code) { + case .notConnectedToInternet: // -1009 + return getDisplayString(key: "NotConnectNetworkError", comment: "") + case .timedOut: // -1001 + return getDisplayString(key: "TimedOutNetworkError", comment: "") + default: + return nil + } +} + //URLの末尾に設定するステータスを返す func getStatus(code: String) -> String? { var status: String? diff --git a/AgileWorks/TodayExtension/TodayExtension-Production.entitlements b/AgileWorks/TodayExtension/TodayExtension-Production.entitlements index 87bf715..df7a8b6 100644 --- a/AgileWorks/TodayExtension/TodayExtension-Production.entitlements +++ b/AgileWorks/TodayExtension/TodayExtension-Production.entitlements @@ -2,6 +2,10 @@ + com.apple.security.application-groups + + group.jp.atled.agileworks + keychain-access-groups $(AppIdentifierPrefix)jp.atled.agileworks0 diff --git a/AgileWorks/TodayExtension/TodayExtensionRelease-Production.entitlements b/AgileWorks/TodayExtension/TodayExtensionRelease-Production.entitlements new file mode 100644 index 0000000..df7a8b6 --- /dev/null +++ b/AgileWorks/TodayExtension/TodayExtensionRelease-Production.entitlements @@ -0,0 +1,18 @@ + + + + + com.apple.security.application-groups + + group.jp.atled.agileworks + + keychain-access-groups + + $(AppIdentifierPrefix)jp.atled.agileworks0 + $(AppIdentifierPrefix)jp.atled.agileworks1 + $(AppIdentifierPrefix)jp.atled.agileworks2 + $(AppIdentifierPrefix)jp.atled.agileworks3 + $(AppIdentifierPrefix)jp.atled.agileworks4 + + + diff --git a/AgileWorks/TodayExtension/View/TodayViewController.swift b/AgileWorks/TodayExtension/View/TodayViewController.swift index 304cc9d..e912c5c 100644 --- a/AgileWorks/TodayExtension/View/TodayViewController.swift +++ b/AgileWorks/TodayExtension/View/TodayViewController.swift @@ -25,24 +25,48 @@ class TodayViewController: UIViewController, NCWidgetProviding { } func widgetPerformUpdate(completionHandler: (@escaping (NCUpdateResult) -> Void)) { + let serverList = UserDefaultsDataStore().readServerList() + var entrys: [EntryData] = [] + var entry: EntryData = EntryData(approvalItems: previewItems(), message: getDisplayString(key: "NotLogedin", comment: ""), viewController: self) + + if serverList.isEmpty { + entrys.append(entry) + } + + //ログイン中の書類件数を全て取得する + for server in serverList { + UserDefaultsDataStore().setGroupId(serverNumber: server) + entry = resultEntry() + entrys.append(entry) + + } + UserDefaultsDataStore().setGroupId(serverNumber: serverList.first!) + + //描画 + var rootView = TodayWidgetView(entrys: entrys) + self.callWidgetView(vc: UIHostingController(rootView: rootView)) + completionHandler(NCUpdateResult.newData) + } + + func resultEntry() -> EntryData{ + var fetchFlag = true + var entry = EntryData(approvalItems: previewItems(), message: getDisplayString(key: "NotLogedin", comment: ""), viewController: self) fetch { result in - DispatchQueue.main.async { - var rootView: StatusCheckWidgetView - switch result { - case .success(let response): - self.approvalItems = checkApprovalItems(approvalItems: response.items) - rootView = StatusCheckWidgetView(entry: EntryData(approvalItems: self.approvalItems, message: nil, viewController: self)) - completionHandler(.newData) - case .nodate(let message): - rootView = StatusCheckWidgetView(entry: EntryData(approvalItems: [ApprovalItem](), message: message, viewController: self)) - completionHandler(.noData) - case .failure(let message): - rootView = StatusCheckWidgetView(entry: EntryData(approvalItems: previewItems(), message: message, viewController: self)) - completionHandler(.failed) - } - self.callWidgetView(vc: UIHostingController(rootView: rootView)) + switch result { + case .success(let response): + self.approvalItems = checkApprovalItems(approvalItems: response.items) + entry = EntryData(approvalItems: self.approvalItems, message: nil, viewController: self) + case .nodate(let message): + entry = EntryData(approvalItems: [ApprovalItem](), message: message, viewController: self) + case .failure(let message): + entry = EntryData(approvalItems: previewItems(), message: message, viewController: self) } + fetchFlag = false + } + while fetchFlag{ + Thread.sleep(forTimeInterval: 0.5) } + return entry } func callWidgetView(vc: UIViewController) { @@ -84,47 +108,3 @@ extension TodayViewController: UITableViewDelegate { } } */ - -extension TodayViewController { - func fetch(completion: @escaping (APIResult) -> Void) { - guard KeychainDataStore().readAccessToken() != nil else { - completion(.failure(getDisplayString(key: "NotLogedin", comment: ""))) - return - } - - let approvalsEndpoint = GetApprovalsEndpoint() - - Session.send(approvalsEndpoint) { result in - switch result { - case .success(let response): - if !response.items.isEmpty { - completion(.success(response)) - } else { - completion(.nodate(getDisplayString(key: "NoData", comment: ""))) - } - case .failure(let error): - var errorMessage = "-" - switch error { - case .connectionError(let error): - if let message = self.errorMessageNSError(error: error) { - errorMessage = message - } - default: - break - } - completion(.failure(errorMessage)) - } - } - } - - func errorMessageNSError(error: Error) -> String? { - switch URLError.Code(rawValue: (error as NSError).code) { - case .notConnectedToInternet: // -1009 - return getDisplayString(key: "NotConnectNetworkError", comment: "") - case .timedOut: // -1001 - return getDisplayString(key: "TimedOutNetworkError", comment: "") - default: - return nil - } - } -} diff --git a/AgileWorks/WidgetExtension/WidgetExtension.entitlements b/AgileWorks/WidgetExtension/WidgetExtension.entitlements index 71e202e..df7a8b6 100644 --- a/AgileWorks/WidgetExtension/WidgetExtension.entitlements +++ b/AgileWorks/WidgetExtension/WidgetExtension.entitlements @@ -2,9 +2,17 @@ + com.apple.security.application-groups + + group.jp.atled.agileworks + keychain-access-groups - $(AppIdentifierPrefix)jp.atled.agileworks + $(AppIdentifierPrefix)jp.atled.agileworks0 + $(AppIdentifierPrefix)jp.atled.agileworks1 + $(AppIdentifierPrefix)jp.atled.agileworks2 + $(AppIdentifierPrefix)jp.atled.agileworks3 + $(AppIdentifierPrefix)jp.atled.agileworks4 diff --git a/AgileWorks/WidgetExtension/WidgetExtension.swift b/AgileWorks/WidgetExtension/WidgetExtension.swift index cf99640..132712b 100644 --- a/AgileWorks/WidgetExtension/WidgetExtension.swift +++ b/AgileWorks/WidgetExtension/WidgetExtension.swift @@ -93,57 +93,3 @@ struct WidgetExtension_Previews: PreviewProvider { .previewContext(WidgetPreviewContext(family: .systemSmall)) } } - -enum widgetAPIResult { - case success(T) - case nodate(String) - case failure(String) -} - -func fetch(completion: @escaping (widgetAPIResult) -> Void) { - guard KeychainDataStore().readAccessToken() != nil else { - completion(.failure(getDisplayString(key: "NotLogedin", comment: ""))) - return - } - - let approvalsEndpoint = GetApprovalsEndpoint() - - while UserDefaultsDataStore().readUpdateWidgetFlg() ?? false { - //別のウィジェットが更新中の場合は待つ - } - UserDefaultsDataStore().writeUpdateWidgetFlg(update: true) - Session.send(approvalsEndpoint) { result in - UserDefaultsDataStore().writeUpdateWidgetFlg(update: false) - switch result { - case .success(let response): - if !response.items.isEmpty { - completion(.success(response)) - } else { - completion(.nodate(getDisplayString(key: "NoData", comment: ""))) - } - case .failure(let error): - var errorMessage = "-" - switch error { - case .connectionError(let error): - if let message = errorMessageNSError(error: error) { - errorMessage = message - } - default: - break - } - completion(.failure(errorMessage)) - } - } -} - -func errorMessageNSError(error: Error) -> String? { - switch URLError.Code(rawValue: (error as NSError).code) { - case .notConnectedToInternet: // -1009 - return getDisplayString(key: "NotConnectNetworkError", comment: "") - case .timedOut: // -1001 - return getDisplayString(key: "TimedOutNetworkError", comment: "") - default: - return nil - } -} - diff --git a/AgileWorks/WidgetExtension/WidgetExtensionRelease-Production.entitlements b/AgileWorks/WidgetExtension/WidgetExtensionRelease-Production.entitlements new file mode 100644 index 0000000..df7a8b6 --- /dev/null +++ b/AgileWorks/WidgetExtension/WidgetExtensionRelease-Production.entitlements @@ -0,0 +1,18 @@ + + + + + com.apple.security.application-groups + + group.jp.atled.agileworks + + keychain-access-groups + + $(AppIdentifierPrefix)jp.atled.agileworks0 + $(AppIdentifierPrefix)jp.atled.agileworks1 + $(AppIdentifierPrefix)jp.atled.agileworks2 + $(AppIdentifierPrefix)jp.atled.agileworks3 + $(AppIdentifierPrefix)jp.atled.agileworks4 + + + -- GitLab From 1e3e038a5e6ea97c4230967403ff538242ecd2ab Mon Sep 17 00:00:00 2001 From: Azuma Kasumi Date: Fri, 16 Jun 2023 13:24:38 +0900 Subject: [PATCH 11/12] =?UTF-8?q?=E3=82=A6=E3=82=A3=E3=82=B8=E3=82=A7?= =?UTF-8?q?=E3=83=83=E3=83=88=E3=81=AE=E7=B7=A8=E9=9B=86=EF=BC=88=E6=9C=AA?= =?UTF-8?q?=E8=A8=AD=E5=AE=9A=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AgileWorks.xcodeproj/project.pbxproj | 254 +++++++++++++++++- .../xcschemes/IntentsExtension.xcscheme | 96 +++++++ AgileWorks/AgileWorks/Info.plist | 4 + AgileWorks/IntentsExtension/Info.plist | 27 ++ .../IntentsExtension/IntentHandler.swift | 137 ++++++++++ .../WidgetConfiguration.intentdefinition | 152 +++++++++++ .../WidgetExtension/WidgetExtension.swift | 11 +- 7 files changed, 675 insertions(+), 6 deletions(-) create mode 100644 AgileWorks/AgileWorks.xcodeproj/xcshareddata/xcschemes/IntentsExtension.xcscheme create mode 100644 AgileWorks/IntentsExtension/Info.plist create mode 100644 AgileWorks/IntentsExtension/IntentHandler.swift create mode 100644 AgileWorks/WidgetExtension/WidgetConfiguration.intentdefinition diff --git a/AgileWorks/AgileWorks.xcodeproj/project.pbxproj b/AgileWorks/AgileWorks.xcodeproj/project.pbxproj index 1e9166c..b1f8bcc 100644 --- a/AgileWorks/AgileWorks.xcodeproj/project.pbxproj +++ b/AgileWorks/AgileWorks.xcodeproj/project.pbxproj @@ -47,6 +47,13 @@ 75BC053229ED087000E21941 /* ServerSwitchingViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 75BC053129ED087000E21941 /* ServerSwitchingViewController.storyboard */; }; 75BC053429EDA23700E21941 /* MordalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75BC053329EDA23700E21941 /* MordalViewController.swift */; }; 75BC053629F8DFCC00E21941 /* ServerSwitchingTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75BC053529F8DFCC00E21941 /* ServerSwitchingTableViewController.swift */; }; + 75D4EC652A3C00B00096F9D2 /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 75D4EC642A3C00B00096F9D2 /* Intents.framework */; }; + 75D4EC682A3C00B00096F9D2 /* IntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75D4EC672A3C00B00096F9D2 /* IntentHandler.swift */; }; + 75D4EC6C2A3C00B00096F9D2 /* IntentsExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 75D4EC632A3C00B00096F9D2 /* IntentsExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 75D4EC712A3C01D90096F9D2 /* WidgetConfiguration.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 75D4EC702A3C01D90096F9D2 /* WidgetConfiguration.intentdefinition */; }; + 75D4EC722A3C01D90096F9D2 /* WidgetConfiguration.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 75D4EC702A3C01D90096F9D2 /* WidgetConfiguration.intentdefinition */; }; + 75D4EC732A3C12730096F9D2 /* WidgetConfiguration.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 75D4EC702A3C01D90096F9D2 /* WidgetConfiguration.intentdefinition */; }; + 75D4EC742A3C168C0096F9D2 /* IntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75D4EC672A3C00B00096F9D2 /* IntentHandler.swift */; }; 75EDD2272806618A0068B4BC /* WidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EDD2262806618A0068B4BC /* WidgetView.swift */; }; 75EDD2282806618A0068B4BC /* WidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EDD2262806618A0068B4BC /* WidgetView.swift */; }; 75EDD2292806618A0068B4BC /* WidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EDD2262806618A0068B4BC /* WidgetView.swift */; }; @@ -198,6 +205,13 @@ remoteGlobalIDString = 3127EE09241A2A9500535CC7; remoteInfo = TodayExtension; }; + 75D4EC6A2A3C00B00096F9D2 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BDA1830723F3FD7F00C9A6DD /* Project object */; + proxyType = 1; + remoteGlobalIDString = 75D4EC622A3C00B00096F9D2; + remoteInfo = IntentsExtension; + }; 75EF9CB727E9E984003178A3 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BDA1830723F3FD7F00C9A6DD /* Project object */; @@ -221,6 +235,7 @@ dstPath = ""; dstSubfolderSpec = 13; files = ( + 75D4EC6C2A3C00B00096F9D2 /* IntentsExtension.appex in Embed App Extensions */, 7672AD73257EFF500063884A /* ShareExtension.appex in Embed App Extensions */, 3127EE16241A2A9500535CC7 /* TodayExtension.appex in Embed App Extensions */, 75EF9CB927E9E985003178A3 /* WidgetExtension.appex in Embed App Extensions */, @@ -256,6 +271,11 @@ 75BC053129ED087000E21941 /* ServerSwitchingViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = ServerSwitchingViewController.storyboard; sourceTree = ""; }; 75BC053329EDA23700E21941 /* MordalViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MordalViewController.swift; sourceTree = ""; }; 75BC053529F8DFCC00E21941 /* ServerSwitchingTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSwitchingTableViewController.swift; sourceTree = ""; }; + 75D4EC632A3C00B00096F9D2 /* IntentsExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = IntentsExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 75D4EC642A3C00B00096F9D2 /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; }; + 75D4EC672A3C00B00096F9D2 /* IntentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentHandler.swift; sourceTree = ""; }; + 75D4EC692A3C00B00096F9D2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 75D4EC702A3C01D90096F9D2 /* WidgetConfiguration.intentdefinition */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; path = WidgetConfiguration.intentdefinition; sourceTree = ""; }; 75EDD2262806618A0068B4BC /* WidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetView.swift; sourceTree = ""; }; 75EF9CAC27E9E983003178A3 /* WidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = WidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 75EF9CAD27E9E983003178A3 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; @@ -392,6 +412,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 75D4EC602A3C00B00096F9D2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 75D4EC652A3C00B00096F9D2 /* Intents.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 75EF9CA927E9E983003178A3 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -429,6 +457,7 @@ CF516C40B9AA44C977664C98 /* Pods_All_AgileWorks.framework */, 75EF9CAD27E9E983003178A3 /* WidgetKit.framework */, 75EF9CAF27E9E983003178A3 /* SwiftUI.framework */, + 75D4EC642A3C00B00096F9D2 /* Intents.framework */, ); name = Frameworks; sourceTree = ""; @@ -522,6 +551,15 @@ path = View; sourceTree = ""; }; + 75D4EC662A3C00B00096F9D2 /* IntentsExtension */ = { + isa = PBXGroup; + children = ( + 75D4EC672A3C00B00096F9D2 /* IntentHandler.swift */, + 75D4EC692A3C00B00096F9D2 /* Info.plist */, + ); + path = IntentsExtension; + sourceTree = ""; + }; 75EF9CB127E9E983003178A3 /* WidgetExtension */ = { isa = PBXGroup; children = ( @@ -530,6 +568,7 @@ 75EF9CB227E9E983003178A3 /* WidgetExtension.swift */, 75EF9CB427E9E984003178A3 /* Assets.xcassets */, 75EF9CB627E9E984003178A3 /* Info.plist */, + 75D4EC702A3C01D90096F9D2 /* WidgetConfiguration.intentdefinition */, ); path = WidgetExtension; sourceTree = ""; @@ -796,6 +835,7 @@ 3127EE0D241A2A9500535CC7 /* TodayExtension */, 7672AD6A257EFF500063884A /* ShareExtension */, 75EF9CB127E9E983003178A3 /* WidgetExtension */, + 75D4EC662A3C00B00096F9D2 /* IntentsExtension */, BDA1831023F3FD7F00C9A6DD /* Products */, 833C64FFE6F6CB735DE07EB7 /* Pods */, 07A802C56A3436654CD69C43 /* Frameworks */, @@ -809,6 +849,7 @@ 3127EE0A241A2A9500535CC7 /* TodayExtension.appex */, 7672AD69257EFF500063884A /* ShareExtension.appex */, 75EF9CAC27E9E983003178A3 /* WidgetExtension.appex */, + 75D4EC632A3C00B00096F9D2 /* IntentsExtension.appex */, ); name = Products; sourceTree = ""; @@ -1057,6 +1098,23 @@ productReference = 3127EE0A241A2A9500535CC7 /* TodayExtension.appex */; productType = "com.apple.product-type.app-extension"; }; + 75D4EC622A3C00B00096F9D2 /* IntentsExtension */ = { + isa = PBXNativeTarget; + buildConfigurationList = 75D4EC6F2A3C00B00096F9D2 /* Build configuration list for PBXNativeTarget "IntentsExtension" */; + buildPhases = ( + 75D4EC5F2A3C00B00096F9D2 /* Sources */, + 75D4EC602A3C00B00096F9D2 /* Frameworks */, + 75D4EC612A3C00B00096F9D2 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = IntentsExtension; + productName = IntentsExtension; + productReference = 75D4EC632A3C00B00096F9D2 /* IntentsExtension.appex */; + productType = "com.apple.product-type.app-extension"; + }; 75EF9CAB27E9E983003178A3 /* WidgetExtension */ = { isa = PBXNativeTarget; buildConfigurationList = 75EF9CBC27E9E985003178A3 /* Build configuration list for PBXNativeTarget "WidgetExtension" */; @@ -1110,6 +1168,7 @@ 3127EE15241A2A9500535CC7 /* PBXTargetDependency */, 7672AD72257EFF500063884A /* PBXTargetDependency */, 75EF9CB827E9E984003178A3 /* PBXTargetDependency */, + 75D4EC6B2A3C00B00096F9D2 /* PBXTargetDependency */, ); name = AgileWorks; packageProductDependencies = ( @@ -1125,13 +1184,16 @@ BDA1830723F3FD7F00C9A6DD /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 1320; + LastSwiftUpdateCheck = 1410; LastUpgradeCheck = 1140; ORGANIZATIONNAME = "ATLED CORP"; TargetAttributes = { 3127EE09241A2A9500535CC7 = { CreatedOnToolsVersion = 11.3.1; }; + 75D4EC622A3C00B00096F9D2 = { + CreatedOnToolsVersion = 14.1; + }; 75EF9CAB27E9E983003178A3 = { CreatedOnToolsVersion = 13.2.1; }; @@ -1167,6 +1229,7 @@ 3127EE09241A2A9500535CC7 /* TodayExtension */, 7672AD68257EFF500063884A /* ShareExtension */, 75EF9CAB27E9E983003178A3 /* WidgetExtension */, + 75D4EC622A3C00B00096F9D2 /* IntentsExtension */, ); }; /* End PBXProject section */ @@ -1186,6 +1249,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 75D4EC612A3C00B00096F9D2 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 75EF9CAA27E9E983003178A3 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -1354,6 +1424,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 75D4EC5F2A3C00B00096F9D2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 75D4EC682A3C00B00096F9D2 /* IntentHandler.swift in Sources */, + 75D4EC732A3C12730096F9D2 /* WidgetConfiguration.intentdefinition in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 75EF9CA827E9E983003178A3 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1362,6 +1441,7 @@ 75EF9CD127E9ED82003178A3 /* XCGLoggerExtensions.swift in Sources */, 75EF9CD027E9ED7B003178A3 /* StringsUtility.swift in Sources */, 75EF9CCF27E9ED6D003178A3 /* ErrorResponse.swift in Sources */, + 75D4EC742A3C168C0096F9D2 /* IntentHandler.swift in Sources */, 75EF9CCE27E9ED5F003178A3 /* Log.swift in Sources */, 75EF9CCD27E9ED53003178A3 /* GetApprovalsEndpoint.swift in Sources */, 75EF9CCC27E9ED3B003178A3 /* ApprovalResponse.swift in Sources */, @@ -1373,6 +1453,7 @@ 75EF9CC727E9ECF9003178A3 /* APIEndpoint.swift in Sources */, 75EF9CC527E9ECEF003178A3 /* SessionInfo.swift in Sources */, 75EF9CC627E9ECEF003178A3 /* Session.swift in Sources */, + 75D4EC722A3C01D90096F9D2 /* WidgetConfiguration.intentdefinition in Sources */, 75EF9CC427E9ECE5003178A3 /* URLAuthenticationUtility.swift in Sources */, 75EF9CC327E9ECDB003178A3 /* KeychainDataStore.swift in Sources */, 75EF9CC227E9ECD2003178A3 /* GetSessionEndpoint.swift in Sources */, @@ -1464,6 +1545,7 @@ BD969631240C9CD400521925 /* SessionInfo.swift in Sources */, BD928CCE2407500400ED04C2 /* UserDefaultsDataStore.swift in Sources */, BD5061B4242866780014F3FA /* Configuration.swift in Sources */, + 75D4EC712A3C01D90096F9D2 /* WidgetConfiguration.intentdefinition in Sources */, 76AE52DD25D35CDC00AFA45A /* LicenseUtility.swift in Sources */, BDAB1F6F240D0D1400EA15FD /* APIEndpoint.swift in Sources */, C50CF79227D8708B0042C210 /* OpenLicenseViewController.swift in Sources */, @@ -1489,6 +1571,11 @@ target = 3127EE09241A2A9500535CC7 /* TodayExtension */; targetProxy = 3127EE14241A2A9500535CC7 /* PBXContainerItemProxy */; }; + 75D4EC6B2A3C00B00096F9D2 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 75D4EC622A3C00B00096F9D2 /* IntentsExtension */; + targetProxy = 75D4EC6A2A3C00B00096F9D2 /* PBXContainerItemProxy */; + }; 75EF9CB827E9E984003178A3 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 75EF9CAB27E9E983003178A3 /* WidgetExtension */; @@ -1569,6 +1656,162 @@ }; name = "Release-Production"; }; + 75D4EC6D2A3C00B00096F9D2 /* Release-Production */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "Apple Development"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = 4TWZNUHVN6; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = IntentsExtension/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = IntentsExtension; + INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 ATLED CORP. All rights reserved."; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = jp.atled.agileworks.IntentsExtension; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = "Release-Production"; + }; + 75D4EC6E2A3C00B00096F9D2 /* Debug-Production */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "Apple Development"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = 4TWZNUHVN6; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = IntentsExtension/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = IntentsExtension; + INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 ATLED CORP. All rights reserved."; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = jp.atled.agileworks.IntentsExtension; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Debug-Production"; + }; 75EF9CBA27E9E985003178A3 /* Release-Production */ = { isa = XCBuildConfiguration; baseConfigurationReference = 75EF9CBF27E9EBB3003178A3 /* Release-Production-Widget.xcconfig */; @@ -2129,6 +2372,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = "Release-Production"; }; + 75D4EC6F2A3C00B00096F9D2 /* Build configuration list for PBXNativeTarget "IntentsExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 75D4EC6D2A3C00B00096F9D2 /* Release-Production */, + 75D4EC6E2A3C00B00096F9D2 /* Debug-Production */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = "Release-Production"; + }; 75EF9CBC27E9E985003178A3 /* Build configuration list for PBXNativeTarget "WidgetExtension" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/AgileWorks/AgileWorks.xcodeproj/xcshareddata/xcschemes/IntentsExtension.xcscheme b/AgileWorks/AgileWorks.xcodeproj/xcshareddata/xcschemes/IntentsExtension.xcscheme new file mode 100644 index 0000000..d3f03e1 --- /dev/null +++ b/AgileWorks/AgileWorks.xcodeproj/xcshareddata/xcschemes/IntentsExtension.xcscheme @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AgileWorks/AgileWorks/Info.plist b/AgileWorks/AgileWorks/Info.plist index a511440..395e718 100644 --- a/AgileWorks/AgileWorks/Info.plist +++ b/AgileWorks/AgileWorks/Info.plist @@ -62,6 +62,10 @@ ${PRODUCT_NAME} NSPhotoLibraryUsageDescription ${PRODUCT_NAME} + NSUserActivityTypes + + WidgetConfigurationIntent + UIBackgroundModes remote-notification diff --git a/AgileWorks/IntentsExtension/Info.plist b/AgileWorks/IntentsExtension/Info.plist new file mode 100644 index 0000000..22a1714 --- /dev/null +++ b/AgileWorks/IntentsExtension/Info.plist @@ -0,0 +1,27 @@ + + + + + NSExtension + + NSExtensionAttributes + + IntentsRestrictedWhileLocked + + IntentsRestrictedWhileProtectedDataUnavailable + + IntentsSupported + + INSearchForMessagesIntent + INSendMessageIntent + INSetMessageAttributeIntent + WidgetConfigurationIntent + + + NSExtensionPointIdentifier + com.apple.intents-service + NSExtensionPrincipalClass + $(PRODUCT_MODULE_NAME).IntentHandler + + + diff --git a/AgileWorks/IntentsExtension/IntentHandler.swift b/AgileWorks/IntentsExtension/IntentHandler.swift new file mode 100644 index 0000000..819de9b --- /dev/null +++ b/AgileWorks/IntentsExtension/IntentHandler.swift @@ -0,0 +1,137 @@ +// +// IntentHandler.swift +// IntentsExtension +// +// Created by Azuma Kasumi on 2023/06/16. +// Copyright © 2023 ATLED CORP. All rights reserved. +// + +import Intents + +// As an example, this class is set up to handle Message intents. +// You will want to replace this or add other intents as appropriate. +// The intents you wish to handle must be declared in the extension's Info.plist. + +// You can test your example integration by saying things to Siri like: +// "Send a message using " +// " John saying hello" +// "Search for messages in " + +class IntentHandler: INExtension, WidgetConfigurationIntentHandling{ + func provideParameterOptionsCollection(for intent: WidgetConfigurationIntent, searchTerm: String?, with completion: @escaping (INObjectCollection?, Error?) -> Void) { + var widgetTypeIdentifiers: [ServerType] = [] + //let serverList = UserDefaultsDataStore().readServerList() + for i in 0..<4 {//serverList.count { + //let serverName = KeychainDataStore().readServerName(serverNumber: serverList[i]) + let item = ServerType(identifier: String(i), display: "type" + String(i))//serverName!) + widgetTypeIdentifiers.append(item) + } + let allWidgetTypeIdentifiers = INObjectCollection(items: widgetTypeIdentifiers) + completion(allWidgetTypeIdentifiers, nil) + } + + + override func handler(for intent: INIntent) -> Any { + // This is the default implementation. If you want different objects to handle different intents, + // you can override this and return the handler you want for that particular intent. + + return self + } + + // MARK: - INSendMessageIntentHandling + + // Implement resolution methods to provide additional information about your intent (optional). + func resolveRecipients(for intent: INSendMessageIntent, with completion: @escaping ([INSendMessageRecipientResolutionResult]) -> Void) { + if let recipients = intent.recipients { + + // If no recipients were provided we'll need to prompt for a value. + if recipients.count == 0 { + completion([INSendMessageRecipientResolutionResult.needsValue()]) + return + } + + var resolutionResults = [INSendMessageRecipientResolutionResult]() + for recipient in recipients { + let matchingContacts = [recipient] // Implement your contact matching logic here to create an array of matching contacts + switch matchingContacts.count { + case 2 ... Int.max: + // We need Siri's help to ask user to pick one from the matches. + resolutionResults += [INSendMessageRecipientResolutionResult.disambiguation(with: matchingContacts)] + + case 1: + // We have exactly one matching contact + resolutionResults += [INSendMessageRecipientResolutionResult.success(with: recipient)] + + case 0: + // We have no contacts matching the description provided + resolutionResults += [INSendMessageRecipientResolutionResult.unsupported()] + + default: + break + + } + } + completion(resolutionResults) + } else { + completion([INSendMessageRecipientResolutionResult.needsValue()]) + } + } + + func resolveContent(for intent: INSendMessageIntent, with completion: @escaping (INStringResolutionResult) -> Void) { + if let text = intent.content, !text.isEmpty { + completion(INStringResolutionResult.success(with: text)) + } else { + completion(INStringResolutionResult.needsValue()) + } + } + + // Once resolution is completed, perform validation on the intent and provide confirmation (optional). + + func confirm(intent: INSendMessageIntent, completion: @escaping (INSendMessageIntentResponse) -> Void) { + // Verify user is authenticated and your app is ready to send a message. + + let userActivity = NSUserActivity(activityType: NSStringFromClass(INSendMessageIntent.self)) + let response = INSendMessageIntentResponse(code: .ready, userActivity: userActivity) + completion(response) + } + + // Handle the completed intent (required). + + func handle(intent: INSendMessageIntent, completion: @escaping (INSendMessageIntentResponse) -> Void) { + // Implement your application logic to send a message here. + + let userActivity = NSUserActivity(activityType: NSStringFromClass(INSendMessageIntent.self)) + let response = INSendMessageIntentResponse(code: .success, userActivity: userActivity) + completion(response) + } + + // Implement handlers for each intent you wish to handle. As an example for messages, you may wish to also handle searchForMessages and setMessageAttributes. + + // MARK: - INSearchForMessagesIntentHandling + + func handle(intent: INSearchForMessagesIntent, completion: @escaping (INSearchForMessagesIntentResponse) -> Void) { + // Implement your application logic to find a message that matches the information in the intent. + + let userActivity = NSUserActivity(activityType: NSStringFromClass(INSearchForMessagesIntent.self)) + let response = INSearchForMessagesIntentResponse(code: .success, userActivity: userActivity) + // Initialize with found message's attributes + response.messages = [INMessage( + identifier: "identifier", + content: "I am so excited about SiriKit!", + dateSent: Date(), + sender: INPerson(personHandle: INPersonHandle(value: "sarah@example.com", type: .emailAddress), nameComponents: nil, displayName: "Sarah", image: nil, contactIdentifier: nil, customIdentifier: nil), + recipients: [INPerson(personHandle: INPersonHandle(value: "+1-415-555-5555", type: .phoneNumber), nameComponents: nil, displayName: "John", image: nil, contactIdentifier: nil, customIdentifier: nil)] + )] + completion(response) + } + + // MARK: - INSetMessageAttributeIntentHandling + + func handle(intent: INSetMessageAttributeIntent, completion: @escaping (INSetMessageAttributeIntentResponse) -> Void) { + // Implement your application logic to set the message attribute here. + + let userActivity = NSUserActivity(activityType: NSStringFromClass(INSetMessageAttributeIntent.self)) + let response = INSetMessageAttributeIntentResponse(code: .success, userActivity: userActivity) + completion(response) + } +} diff --git a/AgileWorks/WidgetExtension/WidgetConfiguration.intentdefinition b/AgileWorks/WidgetExtension/WidgetConfiguration.intentdefinition new file mode 100644 index 0000000..595709d --- /dev/null +++ b/AgileWorks/WidgetExtension/WidgetConfiguration.intentdefinition @@ -0,0 +1,152 @@ + + + + + INEnums + + INIntentDefinitionModelVersion + 1.2 + INIntentDefinitionNamespace + APtLEj + INIntentDefinitionSystemVersion + 21G217 + INIntentDefinitionToolsBuildVersion + 14B47b + INIntentDefinitionToolsVersion + 14.1 + INIntents + + + INIntentCategory + information + INIntentDescriptionID + AJiNw5 + INIntentEligibleForWidgets + + INIntentIneligibleForSuggestions + + INIntentLastParameterTag + 2 + INIntentName + WidgetConfiguration + INIntentParameters + + + INIntentParameterConfigurable + + INIntentParameterDisplayName + サーバー名 + INIntentParameterDisplayNameID + dpfWQr + INIntentParameterDisplayPriority + 1 + INIntentParameterName + parameter + INIntentParameterObjectType + ServerType + INIntentParameterObjectTypeNamespace + APtLEj + INIntentParameterSupportsDynamicEnumeration + + INIntentParameterSupportsSearch + + INIntentParameterTag + 2 + INIntentParameterType + Object + + + INIntentResponse + + INIntentResponseCodes + + + INIntentResponseCodeName + success + INIntentResponseCodeSuccess + + + + INIntentResponseCodeName + failure + + + + INIntentTitle + Widget Configuration + INIntentTitleID + 4UDv2R + INIntentType + Custom + INIntentVerb + View + + + INTypes + + + INTypeDisplayName + ServerType + INTypeDisplayNameID + zid8zR + INTypeLastPropertyTag + 101 + INTypeName + ServerType + INTypeProperties + + + INTypePropertyDefault + + INTypePropertyDisplayPriority + 1 + INTypePropertyName + identifier + INTypePropertyTag + 1 + INTypePropertyType + String + + + INTypePropertyDefault + + INTypePropertyDisplayPriority + 2 + INTypePropertyName + displayString + INTypePropertyTag + 2 + INTypePropertyType + String + + + INTypePropertyDefault + + INTypePropertyDisplayPriority + 3 + INTypePropertyName + pronunciationHint + INTypePropertyTag + 3 + INTypePropertyType + String + + + INTypePropertyDefault + + INTypePropertyDisplayPriority + 4 + INTypePropertyName + alternativeSpeakableMatches + INTypePropertySupportsMultipleValues + + INTypePropertyTag + 4 + INTypePropertyType + SpeakableString + + + + + + diff --git a/AgileWorks/WidgetExtension/WidgetExtension.swift b/AgileWorks/WidgetExtension/WidgetExtension.swift index 132712b..fb649c8 100644 --- a/AgileWorks/WidgetExtension/WidgetExtension.swift +++ b/AgileWorks/WidgetExtension/WidgetExtension.swift @@ -9,17 +9,17 @@ import WidgetKit import SwiftUI -struct Provider: TimelineProvider { +struct Provider: IntentTimelineProvider { func placeholder(in context: Context) -> SimpleEntry { SimpleEntry(date: Date(), approvalItems: previewItems(), message: nil) } - func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) { + func getSnapshot(for configuration: WidgetConfigurationIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) { let entry = SimpleEntry(date: Date(), approvalItems: previewItems(), message: nil) completion(entry) } - func getTimeline(in context: Context, completion: @escaping (Timeline) -> ()) { + func getTimeline(for configuration: WidgetConfigurationIntent, in context: Context, completion: @escaping (Timeline) -> ()) { var entries: [SimpleEntry] = [] // Generate a timeline consisting of five entries an hour apart, starting from the current date. @@ -53,7 +53,7 @@ struct StatusCheckWidget: Widget { let kind: String = "StatusCheck" var body: some WidgetConfiguration { - StaticConfiguration(kind: kind, provider: Provider()) { entry in + IntentConfiguration(kind: kind, intent: WidgetConfigurationIntent.self, provider: Provider()) { entry in StatusCheckWidgetView(entry: EntryData(approvalItems: entry.approvalItems, message: entry.message, viewController: nil)) } @@ -68,7 +68,7 @@ struct ApprovalWidget: Widget { let kind: String = "Approval" var body: some WidgetConfiguration { - StaticConfiguration(kind: kind, provider: Provider()) { entry in + IntentConfiguration(kind: kind, intent: WidgetConfigurationIntent.self, provider: Provider()) { entry in ApprovalWidgetView(entry: EntryData(approvalItems: entry.approvalItems, message: entry.message, viewController: nil)) } .configurationDisplayName(getDisplayString(key: "ApprovalWidgetName", comment: "")) @@ -93,3 +93,4 @@ struct WidgetExtension_Previews: PreviewProvider { .previewContext(WidgetPreviewContext(family: .systemSmall)) } } + -- GitLab From d82015804a9bc8e55fff3ff0e824516d3773860c Mon Sep 17 00:00:00 2001 From: Azuma Kasumi Date: Tue, 27 Jun 2023 10:52:43 +0900 Subject: [PATCH 12/12] =?UTF-8?q?IntenstExtesion=E3=81=AE=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0=20=E3=83=AD=E3=82=B0=E3=82=A4=E3=83=B3=E9=87=8D?= =?UTF-8?q?=E8=A4=87=E7=A2=BA=E8=AA=8D=20=E3=83=87=E3=83=90=E3=82=A4?= =?UTF-8?q?=E3=82=B9=E7=99=BB=E9=8C=B2API=E3=82=B5=E3=83=BC=E3=83=90?= =?UTF-8?q?=E3=83=BC=E6=8C=87=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AgileWorks.xcodeproj/project.pbxproj | 61 ++++++++- AgileWorks/AgileWorks/App/AppDelegate.swift | 45 +++++-- .../AgileWorks/App/RootViewController.swift | 29 +++- .../Common/Service/DeviceService.swift | 6 +- .../Login/View/LoginViewController.swift | 52 ++++--- .../Strings/Chinese-Simplified.strings | 1 + .../Strings/Chinese-Traditional.strings | 1 + AgileWorks/AgileWorks/Strings/English.strings | 1 + .../AgileWorks/Strings/Japanese.strings | 1 + .../Strings/en.lproj/Localizable.strings | 1 + .../Strings/ja.lproj/Localizable.strings | 1 + .../Strings/zh-Hans.lproj/Localizable.strings | 1 + .../Strings/zh-Hant.lproj/Localizable.strings | 1 + .../WebView/View/WebViewController.swift | 1 + .../Common/DataStore/KeychainDataStore.swift | 73 +++++++--- .../DataStore/UserDefaultsDataStore.swift | 4 + AgileWorks/Common/OAuthService.swift | 5 +- .../WebClient/DeleteDeviceEndpoint.swift | 22 +-- AgileWorks/Common/WidgetView.swift | 127 ++++++++++++------ .../Debug-Production-Intents.xcconfig | 13 ++ .../Flavor/Production-Intents.xcconfig | 17 +++ .../Release-Production-Intents.xcconfig | 13 ++ AgileWorks/IntentsExtension/Info.plist | 9 ++ .../IntentsExtension/IntentHandler.swift | 8 +- ...entsExtensionDebug-Production.entitlements | 18 +++ ...tsExtensionRelease-Production.entitlements | 18 +++ .../View/TodayViewController.swift | 7 +- .../WidgetConfiguration.intentdefinition | 2 +- .../WidgetExtension/WidgetExtension.swift | 58 ++++++-- 29 files changed, 466 insertions(+), 130 deletions(-) create mode 100644 AgileWorks/Configurations/Debug-Production-Intents.xcconfig create mode 100644 AgileWorks/Configurations/Flavor/Production-Intents.xcconfig create mode 100644 AgileWorks/Configurations/Release-Production-Intents.xcconfig create mode 100644 AgileWorks/IntentsExtension/IntentsExtensionDebug-Production.entitlements create mode 100644 AgileWorks/IntentsExtension/IntentsExtensionRelease-Production.entitlements diff --git a/AgileWorks/AgileWorks.xcodeproj/project.pbxproj b/AgileWorks/AgileWorks.xcodeproj/project.pbxproj index b1f8bcc..ce4ac23 100644 --- a/AgileWorks/AgileWorks.xcodeproj/project.pbxproj +++ b/AgileWorks/AgileWorks.xcodeproj/project.pbxproj @@ -54,6 +54,15 @@ 75D4EC722A3C01D90096F9D2 /* WidgetConfiguration.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 75D4EC702A3C01D90096F9D2 /* WidgetConfiguration.intentdefinition */; }; 75D4EC732A3C12730096F9D2 /* WidgetConfiguration.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 75D4EC702A3C01D90096F9D2 /* WidgetConfiguration.intentdefinition */; }; 75D4EC742A3C168C0096F9D2 /* IntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75D4EC672A3C00B00096F9D2 /* IntentHandler.swift */; }; + 75D4EC782A3C29830096F9D2 /* UserDefaultsDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD928CCD2407500400ED04C2 /* UserDefaultsDataStore.swift */; }; + 75D4EC802A3C2CAD0096F9D2 /* Pods_All_AgileWorks.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 75D4EC7F2A3C2CAD0096F9D2 /* Pods_All_AgileWorks.framework */; }; + 75D4EC812A3C2CAD0096F9D2 /* Pods_All_AgileWorks.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 75D4EC7F2A3C2CAD0096F9D2 /* Pods_All_AgileWorks.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 75D4EC872A3C32F10096F9D2 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD5061B3242866780014F3FA /* Configuration.swift */; }; + 75D4EC882A3C33310096F9D2 /* KeychainDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDEA2CD4246CDAEF00D3E15F /* KeychainDataStore.swift */; }; + 75D4EC892A3C33490096F9D2 /* UserDefaultsExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDAB1F6C240D0D0000EA15FD /* UserDefaultsExtensions.swift */; }; + 75D4EC8A2A3C33720096F9D2 /* XCGLoggerExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD8D55D82420609000A667B0 /* XCGLoggerExtensions.swift */; }; + 75D4EC8B2A3C33E70096F9D2 /* Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDA74C5524501917000D4351 /* Log.swift */; }; + 75D4EC8C2A413E300096F9D2 /* WidgetConfiguration.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 75D4EC702A3C01D90096F9D2 /* WidgetConfiguration.intentdefinition */; }; 75EDD2272806618A0068B4BC /* WidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EDD2262806618A0068B4BC /* WidgetView.swift */; }; 75EDD2282806618A0068B4BC /* WidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EDD2262806618A0068B4BC /* WidgetView.swift */; }; 75EDD2292806618A0068B4BC /* WidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75EDD2262806618A0068B4BC /* WidgetView.swift */; }; @@ -243,6 +252,17 @@ name = "Embed App Extensions"; runOnlyForDeploymentPostprocessing = 0; }; + 75D4EC822A3C2CAD0096F9D2 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 75D4EC812A3C2CAD0096F9D2 /* Pods_All_AgileWorks.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ @@ -276,6 +296,13 @@ 75D4EC672A3C00B00096F9D2 /* IntentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentHandler.swift; sourceTree = ""; }; 75D4EC692A3C00B00096F9D2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 75D4EC702A3C01D90096F9D2 /* WidgetConfiguration.intentdefinition */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; path = WidgetConfiguration.intentdefinition; sourceTree = ""; }; + 75D4EC772A3C295F0096F9D2 /* IntentsExtensionDebug-Production.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "IntentsExtensionDebug-Production.entitlements"; sourceTree = ""; }; + 75D4EC792A3C29CB0096F9D2 /* IntentsExtensionRelease-Production.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "IntentsExtensionRelease-Production.entitlements"; sourceTree = ""; }; + 75D4EC7B2A3C2C760096F9D2 /* AppAuth.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AppAuth.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 75D4EC7F2A3C2CAD0096F9D2 /* Pods_All_AgileWorks.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Pods_All_AgileWorks.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 75D4EC832A3C2EE40096F9D2 /* Production-Intents.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Production-Intents.xcconfig"; sourceTree = ""; }; + 75D4EC852A3C308D0096F9D2 /* Debug-Production-Intents.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Debug-Production-Intents.xcconfig"; sourceTree = ""; }; + 75D4EC862A3C30B90096F9D2 /* Release-Production-Intents.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Release-Production-Intents.xcconfig"; sourceTree = ""; }; 75EDD2262806618A0068B4BC /* WidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetView.swift; sourceTree = ""; }; 75EF9CAC27E9E983003178A3 /* WidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = WidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 75EF9CAD27E9E983003178A3 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; @@ -416,6 +443,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 75D4EC802A3C2CAD0096F9D2 /* Pods_All_AgileWorks.framework in Frameworks */, 75D4EC652A3C00B00096F9D2 /* Intents.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -451,6 +479,8 @@ 07A802C56A3436654CD69C43 /* Frameworks */ = { isa = PBXGroup; children = ( + 75D4EC7F2A3C2CAD0096F9D2 /* Pods_All_AgileWorks.framework */, + 75D4EC7B2A3C2C760096F9D2 /* AppAuth.framework */, BDA74C5824502255000D4351 /* AppAuth.framework */, BDEB7D8F23F530A400EFAF31 /* KeychainAccess.framework */, 3127EE0B241A2A9500535CC7 /* NotificationCenter.framework */, @@ -554,6 +584,8 @@ 75D4EC662A3C00B00096F9D2 /* IntentsExtension */ = { isa = PBXGroup; children = ( + 75D4EC792A3C29CB0096F9D2 /* IntentsExtensionRelease-Production.entitlements */, + 75D4EC772A3C295F0096F9D2 /* IntentsExtensionDebug-Production.entitlements */, 75D4EC672A3C00B00096F9D2 /* IntentHandler.swift */, 75D4EC692A3C00B00096F9D2 /* Info.plist */, ); @@ -741,6 +773,8 @@ 764D0E00257F603400AB6617 /* Release-Production-Share.xcconfig */, 75EF9CBE27E9EB93003178A3 /* Debug-Production-Widget.xcconfig */, 75EF9CBF27E9EBB3003178A3 /* Release-Production-Widget.xcconfig */, + 75D4EC852A3C308D0096F9D2 /* Debug-Production-Intents.xcconfig */, + 75D4EC862A3C30B90096F9D2 /* Release-Production-Intents.xcconfig */, ); path = Configurations; sourceTree = ""; @@ -753,6 +787,7 @@ BD5061A1242845750014F3FA /* Production-Today.xcconfig */, 764D0DF7257F589D00AB6617 /* Production-Share.xcconfig */, 75EF9CBD27E9EB6E003178A3 /* Production-Widget.xcconfig */, + 75D4EC832A3C2EE40096F9D2 /* Production-Intents.xcconfig */, ); path = Flavor; sourceTree = ""; @@ -1105,6 +1140,7 @@ 75D4EC5F2A3C00B00096F9D2 /* Sources */, 75D4EC602A3C00B00096F9D2 /* Frameworks */, 75D4EC612A3C00B00096F9D2 /* Resources */, + 75D4EC822A3C2CAD0096F9D2 /* Embed Frameworks */, ); buildRules = ( ); @@ -1415,6 +1451,7 @@ BDBBF83D243CAB3300EEB25D /* GetApprovalsEndpoint.swift in Sources */, BDBBF840243CAB6200EEB25D /* UserDefaultsExtensions.swift in Sources */, BDA74C5724501917000D4351 /* Log.swift in Sources */, + 75D4EC8C2A413E300096F9D2 /* WidgetConfiguration.intentdefinition in Sources */, BD7DC0F324C061EA00C3FBED /* ErrorResponse.swift in Sources */, 3127EE0F241A2A9500535CC7 /* TodayViewController.swift in Sources */, 75917FB427C371390051E201 /* StringsUtility.swift in Sources */, @@ -1429,7 +1466,13 @@ buildActionMask = 2147483647; files = ( 75D4EC682A3C00B00096F9D2 /* IntentHandler.swift in Sources */, + 75D4EC882A3C33310096F9D2 /* KeychainDataStore.swift in Sources */, + 75D4EC892A3C33490096F9D2 /* UserDefaultsExtensions.swift in Sources */, 75D4EC732A3C12730096F9D2 /* WidgetConfiguration.intentdefinition in Sources */, + 75D4EC8A2A3C33720096F9D2 /* XCGLoggerExtensions.swift in Sources */, + 75D4EC872A3C32F10096F9D2 /* Configuration.swift in Sources */, + 75D4EC8B2A3C33E70096F9D2 /* Log.swift in Sources */, + 75D4EC782A3C29830096F9D2 /* UserDefaultsDataStore.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1658,6 +1701,7 @@ }; 75D4EC6D2A3C00B00096F9D2 /* Release-Production */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 75D4EC862A3C30B90096F9D2 /* Release-Production-Intents.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -1688,13 +1732,15 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_ENTITLEMENTS = "IntentsExtension/IntentsExtensionRelease-Production.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 4TWZNUHVN6; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 4TWZNUHVN6; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -1715,11 +1761,13 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 1.0.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = jp.atled.agileworks.IntentsExtension; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "AgileWorks App Wildcard"; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_COMPILATION_MODE = wholemodule; @@ -1733,6 +1781,7 @@ }; 75D4EC6E2A3C00B00096F9D2 /* Debug-Production */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 75D4EC852A3C308D0096F9D2 /* Debug-Production-Intents.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -1763,13 +1812,15 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_ENTITLEMENTS = "IntentsExtension/IntentsExtensionDebug-Production.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 4TWZNUHVN6; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 4TWZNUHVN6; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -1796,12 +1847,14 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 1.0.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = jp.atled.agileworks.IntentsExtension; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "AgileWorks App Wildcard"; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; diff --git a/AgileWorks/AgileWorks/App/AppDelegate.swift b/AgileWorks/AgileWorks/App/AppDelegate.swift index 70723b2..468a5ca 100644 --- a/AgileWorks/AgileWorks/App/AppDelegate.swift +++ b/AgileWorks/AgileWorks/App/AppDelegate.swift @@ -63,6 +63,24 @@ class AppDelegate: UIResponder, UIApplicationDelegate { OIDURLSessionProvider.setSession(Session.shared) } + private func getTapLink(url: URL) -> String? { + var strUrl = url.absoluteString + if let index = strUrl.firstIndex(of: "?") { + strUrl = String(strUrl.prefix(upTo: index)) + return strUrl + } + return nil + } + + private func getTapServer(url: URL) -> Int? { + var strUrl = url.absoluteString + var serverNumber: Int? + if strUrl.contains("serverNumber") { + serverNumber = (Int(String(strUrl.last!))) ?? nil + } + return serverNumber + } + // MARK: DeepLinks @available(iOS 9.0, *) func application(_ application: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any]) @@ -75,18 +93,26 @@ class AppDelegate: UIResponder, UIApplicationDelegate { //タップされたサーバーに切り替える let serverList = UserDefaultsDataStore().readServerList() if !serverList.isEmpty { - let tapServer = UserDefaultsDataStore().readTapServer() - UserDefaultsDataStore().changeServerList(firstServer: tapServer!) - UserDefaultsDataStore().setGroupId(serverNumber: tapServer!) - } + var tapServer: Int? + if #available(iOS 14.0, *) { + tapServer = getTapServer(url: url) + } else { + tapServer = UserDefaultsDataStore().readTapServer() + } + if let serverNumber = tapServer { + UserDefaultsDataStore().changeServerList(firstServer: serverNumber) + UserDefaultsDataStore().setGroupId(serverNumber: serverNumber) + Thread.sleep(forTimeInterval: 1) + } + } //ios13の場合 + var resultURL = url if url.scheme == urlSchemeName { var strUrl = url.absoluteString //指定した書類状態の取得、アプリ起動のみの場合は飛ばす if strUrl.contains("/") { - let result: URL var scheme = urlScheme // 不要な"/"を取り除く let delIdx = scheme.index(scheme.endIndex, offsetBy: -1) @@ -94,11 +120,14 @@ class AppDelegate: UIResponder, UIApplicationDelegate { //scheme以降の取得 strUrl = strUrl.replacingOccurrences(of: scheme, with: "") //遷移URLの取得 - result = getStatusURL(status: strUrl) - return Linker.handleDeeplink(url: result) + resultURL = getStatusURL(status: strUrl) + } + }else { //iOS14~ + if let url = getTapLink(url: url) { + resultURL = URL(string: url)! } } - return Linker.handleDeeplink(url: url) + return Linker.handleDeeplink(url: resultURL) } func getStatusURL(status: String) -> URL { diff --git a/AgileWorks/AgileWorks/App/RootViewController.swift b/AgileWorks/AgileWorks/App/RootViewController.swift index ace6f96..bf268dc 100644 --- a/AgileWorks/AgileWorks/App/RootViewController.swift +++ b/AgileWorks/AgileWorks/App/RootViewController.swift @@ -64,18 +64,15 @@ extension RootViewController { case .failure(let error): log.e(error) } - KeychainDataStore().removeOAuthState() - KeychainDataStore().removeAccessToken() - KeychainDataStore().removeSessionID() - KeychainDataStore().removeServerName() - KeychainDataStore().removeLanguage() - KeychainDataStore().removeDeviceID() + var serverList = UserDefaultsDataStore().readServerList() + let removeServer = serverList.first + self.deleteServerInfo(serverNumber: removeServer) if serverRemove { UserDefaultsDataStore().removeServer() } - let serverList = UserDefaultsDataStore().readServerList() + serverList = UserDefaultsDataStore().readServerList() if serverList.isEmpty { DispatchQueue.main.async { self.switchToLogout() @@ -100,6 +97,24 @@ extension RootViewController { return defaultAction } + func deleteServerInfo(serverNumber: Int?) { + DeviceService().deleteDevice(serverNumber: serverNumber) { result in + switch result { + case .success: + break + case .failure(let error): + log.e(error) + } + KeychainDataStore().removeOAuthState(serverNumber: serverNumber) + KeychainDataStore().removeAccessToken(serverNumber: serverNumber) + KeychainDataStore().removeDeviceID(serverNumber: serverNumber) + KeychainDataStore().removeSessionID(serverNumber: serverNumber) + } + //認証情報削除 + KeychainDataStore().removeServerName() + KeychainDataStore().removeLanguage() + } + // アラート表示 func showAlertScreen(view: UIViewController, title: String, message: String, defaultAction: UIAlertAction?, cancelAction: UIAlertAction?) { let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) diff --git a/AgileWorks/AgileWorks/Common/Service/DeviceService.swift b/AgileWorks/AgileWorks/Common/Service/DeviceService.swift index 98efebb..d2ee712 100644 --- a/AgileWorks/AgileWorks/Common/Service/DeviceService.swift +++ b/AgileWorks/AgileWorks/Common/Service/DeviceService.swift @@ -65,15 +65,15 @@ public class DeviceService { } } - func deleteDevice(completion: @escaping (APIResult) -> Void) { + func deleteDevice(serverNumber: Int? = nil, completion: @escaping (APIResult) -> Void) { let request = DeviceRequest(deleteFlag: true) - let deleteDevice = DeleteDeviceEndpoint(request: request) + let deleteDevice = DeleteDeviceEndpoint(request: request, serverNumber: serverNumber) Session.send(deleteDevice) { result in let completionArg: APIResult switch result { case .success: - KeychainDataStore().removeDeviceID() + KeychainDataStore().removeDeviceID(serverNumber: serverNumber) completionArg = .success(true) case .failure(let error): log.e(error) diff --git a/AgileWorks/AgileWorks/Login/View/LoginViewController.swift b/AgileWorks/AgileWorks/Login/View/LoginViewController.swift index 58e6da2..7ea78a9 100644 --- a/AgileWorks/AgileWorks/Login/View/LoginViewController.swift +++ b/AgileWorks/AgileWorks/Login/View/LoginViewController.swift @@ -67,23 +67,17 @@ class LoginViewController: UIViewController { } //サーバー追加画面の場合は認証情報を削除しない if !addServerloginFlg { - //ログイン画面が表示されると通知を取得しない - self.devcie { result in - switch result { - case .success: - break - case .failure(let error): - log.e(error) - } + let serverList = UserDefaultsDataStore().readServerList() + + //キーチェーン情報削除 + for serverNumber in serverList { + UserDefaultsDataStore().setGroupId(serverNumber: serverNumber) + //ログイン画面が表示されると通知を取得しない + AppDelegate.shared.rootViewController.deleteServerInfo(serverNumber: serverNumber) } - //認証情報削除 - KeychainDataStore().removeOAuthState() - KeychainDataStore().removeAccessToken() - KeychainDataStore().removeSessionID() - KeychainDataStore().removeServerName() - KeychainDataStore().removeLanguage() - KeychainDataStore().removeDeviceID() + //サーバーリストの削除 + UserDefaultsDataStore().removeAllServer() //ウィジェットの更新 if #available(iOS 14.0, *) { @@ -184,6 +178,26 @@ class LoginViewController: UIViewController { guard let serverHost = serverHost else { return } guard let context = context else { return } + //サーバーの重複チェック + let serverList = UserDefaultsDataStore().readServerList() + var serverCheckFlg = false + for serverNumber in serverList { + let serverName = KeychainDataStore().readServerName(serverNumber: serverNumber)! + if serverName == serverHost { + serverCheckFlg = true + let alert = UIAlertController(title: "", message: getLocalizableStrings(key: "LoginServerAlert", comment: ""), preferredStyle: .alert) + let ok = UIAlertAction(title: "OK", style: .default) { (action) in + return + } + alert.addAction(ok) + present(alert, animated: true, completion: nil) + } + } + + if serverCheckFlg { + return + } + disableLogin() //サーバー切り替え @@ -239,6 +253,10 @@ class LoginViewController: UIViewController { UserDefaultsDataStore().addServerList() let serverList = UserDefaultsDataStore().readServerList() UserDefaultsDataStore().setGroupId(serverNumber: serverList.first!) + //ウィジェットの更新 + if #available(iOS 14.0, *) { + WidgetCenter.shared.reloadAllTimelines() + } //メイン画面表示 AppDelegate.shared.rootViewController.switchToMainScreen() if let nc = self.parent as? UINavigationController { @@ -353,8 +371,8 @@ class LoginViewController: UIViewController { present(alertController, animated: true, completion: nil) } - private func devcie(completion: @escaping (APIResult) -> Void) { - DeviceService().deleteDevice { result in + private func devcie(serverNumber: Int, completion: @escaping (APIResult) -> Void) { + DeviceService().deleteDevice(serverNumber: serverNumber) { result in switch result { case .success: completion(.success(true)) diff --git a/AgileWorks/AgileWorks/Strings/Chinese-Simplified.strings b/AgileWorks/AgileWorks/Strings/Chinese-Simplified.strings index dca6489..f522d3b 100644 --- a/AgileWorks/AgileWorks/Strings/Chinese-Simplified.strings +++ b/AgileWorks/AgileWorks/Strings/Chinese-Simplified.strings @@ -24,6 +24,7 @@ "ClientCertificateRemovalCancel" = "取消"; "LoginErrorMessage" = "登录失败。 请重新登录。"; "CameraStartupErrorMessage" = "未能激活摄像机。"; +"LoginServerAlert" = "ログイン済のサーバーです。ログアウトを行ってから再度お試しください。"; // WebView "HomeTitle" = "家"; diff --git a/AgileWorks/AgileWorks/Strings/Chinese-Traditional.strings b/AgileWorks/AgileWorks/Strings/Chinese-Traditional.strings index 6cc1879..32cafea 100644 --- a/AgileWorks/AgileWorks/Strings/Chinese-Traditional.strings +++ b/AgileWorks/AgileWorks/Strings/Chinese-Traditional.strings @@ -24,6 +24,7 @@ "ClientCertificateRemovalCancel" = "取消"; "LoginErrorMessage" = "登錄失敗。請重新登錄。"; "CameraStartupErrorMessage" = "未能激活攝像機。"; +"LoginServerAlert" = "ログイン済のサーバーです。ログアウトを行ってから再度お試しください。"; // WebView "HomeTitle" = "家"; diff --git a/AgileWorks/AgileWorks/Strings/English.strings b/AgileWorks/AgileWorks/Strings/English.strings index 66bb9ee..91107a4 100644 --- a/AgileWorks/AgileWorks/Strings/English.strings +++ b/AgileWorks/AgileWorks/Strings/English.strings @@ -24,6 +24,7 @@ "ClientCertificateRemovalCancel" = "cancel"; "LoginErrorMessage" = "Login failed. Please login again."; "CameraStartupErrorMessage" = "Camera failed to start."; +"LoginServerAlert" = "ログイン済のサーバーです。ログアウトを行ってから再度お試しください。"; // WebView "HomeTitle" = "HOME"; diff --git a/AgileWorks/AgileWorks/Strings/Japanese.strings b/AgileWorks/AgileWorks/Strings/Japanese.strings index ff87ef0..5219e3c 100644 --- a/AgileWorks/AgileWorks/Strings/Japanese.strings +++ b/AgileWorks/AgileWorks/Strings/Japanese.strings @@ -24,6 +24,7 @@ "ClientCertificateRemovalCancel" = "キャンセル"; "LoginErrorMessage" = "ログインに失敗しました。再度ログインしてください。"; "CameraStartupErrorMessage" = "カメラの起動に失敗しました。"; +"LoginServerAlert" = "ログイン済のサーバーです。ログアウトを行ってから再度お試しください。"; // WebView "HomeTitle" = "HOME"; diff --git a/AgileWorks/AgileWorks/Strings/en.lproj/Localizable.strings b/AgileWorks/AgileWorks/Strings/en.lproj/Localizable.strings index 55a7d34..c2874e3 100644 --- a/AgileWorks/AgileWorks/Strings/en.lproj/Localizable.strings +++ b/AgileWorks/AgileWorks/Strings/en.lproj/Localizable.strings @@ -24,6 +24,7 @@ "ClientCertificateRemovalCancel" = "cancel"; "LoginErrorMessage" = "Login failed. Please login again."; "CameraStartupErrorMessage" = "Camera failed to start."; +"LoginServerAlert" = "ログイン済のサーバーです。ログアウトを行ってから再度お試しください。"; // WebView "HomeTitle" = "HOME"; diff --git a/AgileWorks/AgileWorks/Strings/ja.lproj/Localizable.strings b/AgileWorks/AgileWorks/Strings/ja.lproj/Localizable.strings index 4f6fbc8..2d54811 100644 --- a/AgileWorks/AgileWorks/Strings/ja.lproj/Localizable.strings +++ b/AgileWorks/AgileWorks/Strings/ja.lproj/Localizable.strings @@ -24,6 +24,7 @@ "ClientCertificateRemovalCancel" = "キャンセル"; "LoginErrorMessage" = "ログインに失敗しました。再度ログインしてください。"; "CameraStartupErrorMessage" = "カメラの起動に失敗しました。"; +"LoginServerAlert" = "ログイン済のサーバーです。ログアウトを行ってから再度お試しください。"; // WebView "HomeTitle" = "HOME"; diff --git a/AgileWorks/AgileWorks/Strings/zh-Hans.lproj/Localizable.strings b/AgileWorks/AgileWorks/Strings/zh-Hans.lproj/Localizable.strings index 9495f6d..55c49a3 100644 --- a/AgileWorks/AgileWorks/Strings/zh-Hans.lproj/Localizable.strings +++ b/AgileWorks/AgileWorks/Strings/zh-Hans.lproj/Localizable.strings @@ -24,6 +24,7 @@ "ClientCertificateRemovalCancel" = "取消"; "LoginErrorMessage" = "登录失败。 请重新登录。"; "CameraStartupErrorMessage" = "未能激活摄像机。"; +"LoginServerAlert" = "ログイン済のサーバーです。ログアウトを行ってから再度お試しください。"; // WebView "HomeTitle" = "家"; diff --git a/AgileWorks/AgileWorks/Strings/zh-Hant.lproj/Localizable.strings b/AgileWorks/AgileWorks/Strings/zh-Hant.lproj/Localizable.strings index e01613e..a818da8 100644 --- a/AgileWorks/AgileWorks/Strings/zh-Hant.lproj/Localizable.strings +++ b/AgileWorks/AgileWorks/Strings/zh-Hant.lproj/Localizable.strings @@ -24,6 +24,7 @@ "ClientCertificateRemovalCancel" = "取消"; "LoginErrorMessage" = "登錄失敗。請重新登錄。"; "CameraStartupErrorMessage" = "未能激活攝像機。"; +"LoginServerAlert" = "ログイン済のサーバーです。ログアウトを行ってから再度お試しください。"; // WebView "HomeTitle" = "家"; diff --git a/AgileWorks/AgileWorks/WebView/View/WebViewController.swift b/AgileWorks/AgileWorks/WebView/View/WebViewController.swift index 92720eb..008af00 100644 --- a/AgileWorks/AgileWorks/WebView/View/WebViewController.swift +++ b/AgileWorks/AgileWorks/WebView/View/WebViewController.swift @@ -106,6 +106,7 @@ class WebViewController: UIViewController { // WebView セットアップ private func setWebView() { + print(KeychainDataStore().readServerURL()) let userContentController = WKUserContentController() let script = "document.cookie='JSESSIONID=\(KeychainDataStore().readSessionID() ?? "")'" let cookieScript = WKUserScript(source: script, injectionTime: .atDocumentStart, forMainFrameOnly: false) diff --git a/AgileWorks/Common/DataStore/KeychainDataStore.swift b/AgileWorks/Common/DataStore/KeychainDataStore.swift index b3e7a6c..cd7b89e 100644 --- a/AgileWorks/Common/DataStore/KeychainDataStore.swift +++ b/AgileWorks/Common/DataStore/KeychainDataStore.swift @@ -27,12 +27,18 @@ final class KeychainDataStore: DataStoreProtocol { } // アクセストークンの読み込み - func readAccessToken() -> String? { + func readAccessToken(serverNumber: Int? = nil) -> String? { + if let serverNumber = serverNumber { + return getKeychainValue(key: kAccessToken, serverNumber: serverNumber) + } return getKeychainValue(key: kAccessToken) } // アクセストークンの削除 - func removeAccessToken() { + func removeAccessToken(serverNumber: Int? = nil) { + if let serverNumber = serverNumber { + removeKeychainValue(key: kAccessToken, serverNumber: serverNumber) + } removeKeychainValue(key: kAccessToken) } @@ -58,7 +64,10 @@ final class KeychainDataStore: DataStoreProtocol { } // 認可ステータスの削除 - func removeOAuthState() { + func removeOAuthState(serverNumber: Int? = nil) { + if let serverNumber = serverNumber { + removeKeychainValue(key: kOAuthState, serverNumber: serverNumber) + } removeKeychainValue(key: kOAuthState) } @@ -98,7 +107,10 @@ final class KeychainDataStore: DataStoreProtocol { } // コンテキストパスの読み込み - func readContextPath() -> String? { + func readContextPath(serverNumber: Int? = nil) -> String? { + if let serverNumber = serverNumber { + return getKeychainValue(key: kContextPath, serverNumber: serverNumber) + } return getKeychainValue(key: kContextPath) } @@ -113,8 +125,15 @@ final class KeychainDataStore: DataStoreProtocol { } // デバイスIDの読み込み - func readDeviceID() -> Int? { - guard let deviceIDString = getKeychainValue(key: kDeviceID) else { + func readDeviceID(serverNumber: Int? = nil) -> Int? { + var deviceIDString: String? + if let serverNumber = serverNumber { + deviceIDString = getKeychainValue(key: kDeviceID, serverNumber: serverNumber) + } else { + deviceIDString = getKeychainValue(key: kDeviceID) + } + + guard let deviceIDString = deviceIDString else { return nil } guard let deviceID = Int(deviceIDString) else { @@ -124,7 +143,10 @@ final class KeychainDataStore: DataStoreProtocol { } // デバイスIDの削除 - func removeDeviceID() { + func removeDeviceID(serverNumber: Int? = nil) { + if let serverNumber = serverNumber { + removeKeychainValue(key: kDeviceID, serverNumber: serverNumber) + } removeKeychainValue(key: kDeviceID) } @@ -139,8 +161,11 @@ final class KeychainDataStore: DataStoreProtocol { } // セッションIDの削除 - func removeSessionID() { - removeKeychainValue(key: kSessionID) + func removeSessionID(serverNumber: Int? = nil) { + if let serverNumber = serverNumber { + return removeKeychainValue(key: kSessionID, serverNumber: serverNumber) + } + return removeKeychainValue(key: kSessionID) } // サーバー識別名の書き込み @@ -149,13 +174,11 @@ final class KeychainDataStore: DataStoreProtocol { } // サーバー識別名の読み込み - func readServerName() -> String? { - return getKeychainValue(key: kServerName) - } - func readServerName(serverNumber: Int) -> String? { - let keychain = Keychain(service: service, accessGroup: UserDefaultsDataStore().readBaseGroupId() + String(serverNumber)) - //return keychain[kServerName] //TODO: サーバー識別名 - return keychain[kServerURL] + func readServerName(serverNumber: Int? = nil) -> String? { + if let serverNumber = serverNumber { + return getKeychainValue(key: kServerURL, serverNumber: serverNumber) + } + return getKeychainValue(key: kServerURL) } // サーバー識別名の削除 @@ -168,11 +191,21 @@ final class KeychainDataStore: DataStoreProtocol { let keychain = Keychain(service: service, accessGroup: UserDefaultsDataStore().readGroupId()!) keychain[key] = value } + private func setKeychainValue(key: String, value: String, serverNumber: Int) { + let keychain = Keychain(service: service, accessGroup: UserDefaultsDataStore().readBaseGroupId() + String(serverNumber)) + keychain[key] = value + } + // KeyChain から指定の値を取得 private func getKeychainValue(key: String) -> String? { let keychain = Keychain(service: service, accessGroup: UserDefaultsDataStore().readGroupId()!) return keychain[key] } + private func getKeychainValue(key: String, serverNumber: Int) -> String? { + let keychain = Keychain(service: service, accessGroup: UserDefaultsDataStore().readBaseGroupId() + String(serverNumber)) + return keychain[key] + } + // KeyChain から指定の値を削除 private func removeKeychainValue(key: String) { let keychain = Keychain(service: service, accessGroup: UserDefaultsDataStore().readGroupId()!) @@ -182,4 +215,12 @@ final class KeychainDataStore: DataStoreProtocol { log.e(error) } } + private func removeKeychainValue(key: String, serverNumber: Int) { + let keychain = Keychain(service: service, accessGroup: UserDefaultsDataStore().readBaseGroupId() + String(serverNumber)) + do { + try keychain.remove(key) + } catch { + log.e(error) + } + } } diff --git a/AgileWorks/Common/DataStore/UserDefaultsDataStore.swift b/AgileWorks/Common/DataStore/UserDefaultsDataStore.swift index 31c9173..aaa5091 100644 --- a/AgileWorks/Common/DataStore/UserDefaultsDataStore.swift +++ b/AgileWorks/Common/DataStore/UserDefaultsDataStore.swift @@ -81,6 +81,10 @@ final class UserDefaultsDataStore: DataStoreProtocol { writeServerList(list: serverList) } } + + func removeAllServer() { + writeServerList(list: []) + } //サーバー接続先を保存できる識別番号を探す func serchEmptyServerData() -> Int? { diff --git a/AgileWorks/Common/OAuthService.swift b/AgileWorks/Common/OAuthService.swift index 0786799..1a62912 100644 --- a/AgileWorks/Common/OAuthService.swift +++ b/AgileWorks/Common/OAuthService.swift @@ -53,10 +53,7 @@ public class OAuthService: NSObject { } KeychainDataStore().writeAccessToken(accessToken: accessToken) - //ウィジェットの更新 - if #available(iOS 14.0, *) { - WidgetCenter.shared.reloadAllTimelines() - } + completion(.success(())) } else { self.setAuthState(nil) diff --git a/AgileWorks/Common/WebClient/DeleteDeviceEndpoint.swift b/AgileWorks/Common/WebClient/DeleteDeviceEndpoint.swift index 3dae7ca..d6433cc 100644 --- a/AgileWorks/Common/WebClient/DeleteDeviceEndpoint.swift +++ b/AgileWorks/Common/WebClient/DeleteDeviceEndpoint.swift @@ -12,21 +12,16 @@ struct DeleteDeviceEndpoint: APIEndpoint { typealias Response = DeviceResponse let method: HttpMethod = .POST - let path = "/" + (KeychainDataStore().readContextPath() ?? "") + "/Broker/MobileAppApi/Device" + + let path: String var requestBody: Data? - var headerFields: [String: String]? { - return ["Authorization": "Bearer \(KeychainDataStore().readAccessToken() ?? "")", - "X-ATLED-AW-Device-Id": KeychainDataStore().readDeviceID()?.description ?? "", - "Content-Type": "application/json"] - } + var headerFields: [String: String]? - var pathParameters: [String]? { - return [KeychainDataStore().readDeviceID()?.description ?? ""] - } + var pathParameters: [String]? - init(request: DeviceRequest) { + init(request: DeviceRequest, serverNumber: Int?) { let encoder = JSONEncoder() encoder.keyEncodingStrategy = .convertToSnakeCase @@ -35,6 +30,13 @@ struct DeleteDeviceEndpoint: APIEndpoint { } catch { log.e(error.localizedDescription) } + self.path = "/" + (KeychainDataStore().readContextPath(serverNumber: serverNumber) ?? "") + "/Broker/MobileAppApi/Device" + + self.headerFields = ["Authorization": "Bearer \(KeychainDataStore().readAccessToken(serverNumber: serverNumber) ?? "")", + "X-ATLED-AW-Device-Id": KeychainDataStore().readDeviceID(serverNumber: serverNumber)?.description ?? "", + "Content-Type": "application/json"] + + self.pathParameters = [KeychainDataStore().readDeviceID(serverNumber: serverNumber)?.description ?? ""] } } diff --git a/AgileWorks/Common/WidgetView.swift b/AgileWorks/Common/WidgetView.swift index 3bca8f6..90517e9 100644 --- a/AgileWorks/Common/WidgetView.swift +++ b/AgileWorks/Common/WidgetView.swift @@ -39,6 +39,7 @@ func previewItems() -> [ApprovalItem] { } struct EntryData { + var serverNumber: Int? var approvalItems: [ApprovalItem] var message: String? var viewController: UIViewController? @@ -82,8 +83,11 @@ struct StatusCheckWidgetView: View { StatusBoxView(entry: entry) } else { //ログイン・コネクションエラー if #available(iOS 14.0, *) { - FailureWidgetView(entry: entry) - }else { + let url = getWorkURL(serverNumber: entry.serverNumber) + Link(destination: URL(string: url)!, label: { + FailureWidgetView(entry: entry) + }) + } else { FailureWidgetView(entry: entry) .onTapGesture { if entry.viewController != nil { @@ -108,23 +112,35 @@ struct ApprovalWidgetView: View { return nil } + func errorEntry() -> EntryData { + var errorEntry = entry + errorEntry.message = "-" + return errorEntry + } + var body: some View { //API取得成功 if entry.message == nil { if let num = findApproval() { //「承認依頼」項目あり if #available(iOS 14.0, *) { - ApprovalItemView(approvalItem: entry.approvalItems[num], message: entry.message) - .widgetURL(URL(string: Configuration.shared.awURL + "/" + (KeychainDataStore().readContextPath() ?? "") + "/Broker/Mobile#docList_" + "RequestApproval")) + let url = getURL(approvalItem: entry.approvalItems[num], serverNumber: entry.serverNumber) + ApprovalItemView(itemNum: num, entry: entry) + .widgetURL(URL(string: url)) } } else { //「承認依頼」項目なし - ApprovalItemView(approvalItem: ApprovalItem(code: "", name: "", count: 0), message: "-") + ApprovalItemView(itemNum: 0, entry: errorEntry()) } } else { //APIサーバーエラー if entry.message == "-" { - ApprovalItemView(approvalItem: ApprovalItem(code: "", name: "", count: 0), message: "-") + ApprovalItemView(itemNum: 0, entry: errorEntry()) } else {//ログイン・コネクションエラー - FailureWidgetView(entry: entry) + if #available(iOS 14.0, *) { + let url = getWorkURL(serverNumber: entry.serverNumber) + Link(destination: URL(string: url)!, label: { + FailureWidgetView(entry: entry) + }) + } } } } @@ -180,8 +196,8 @@ struct StatusBoxView: View { var body: some View { VStack (spacing: 0) { if #available(iOS 14.0, *) { - if !serverList.isEmpty { - Text(KeychainDataStore().readServerName(serverNumber: serverList[0])!) + if let serverNumber = entry.serverNumber { + Text(KeychainDataStore().readServerName(serverNumber: serverNumber)!) } } GeometryReader { geometry in @@ -223,11 +239,11 @@ struct RowView: View { var body: some View { HStack(spacing: 10) { //BOX左側 - LinkView(approvalItem: entry.approvalItems[itemNum], message: entry.message, viewController: entry.viewController) + LinkView(itemNum: itemNum, entry: entry) .frame(width: boxSize.width, height: boxSize.height) //BOX右側 if !oneBox { - LinkView(approvalItem: entry.approvalItems[itemNum + 1], message: entry.message, viewController: entry.viewController) + LinkView(itemNum: itemNum + 1, entry: entry) .frame(width: boxSize.width, height: boxSize.height) } else { HStack { @@ -241,22 +257,17 @@ struct RowView: View { //ウィジェットからアプリへ遷移するためのリンクview struct LinkView: View { - let approvalItem: ApprovalItem - let message: String? - let viewController: UIViewController? + let itemNum: Int + let entry: EntryData - //遷移先URLの取得(iOS14以降) - func getURL() -> String { - if let status = getStatus(code: approvalItem.code) { - return Configuration.shared.awURL + "/" + (KeychainDataStore().readContextPath() ?? "") + "/Broker/Mobile#docList_" + status - } else { - return Configuration.shared.awURL + "/" + (KeychainDataStore().readContextPath() ?? "") + "/Broker/Mobile#work" - } + func getApprovalItem() -> ApprovalItem { + return entry.approvalItems[itemNum] } //遷移先URLはアプリ側で設定するためURL末尾のステータスのみ設定(iOS13) func getStatusURL() -> String { //スキーム+ステータスで設定 + let approvalItem = getApprovalItem() if let status = getStatus(code: approvalItem.code) { return urlScheme + status } @@ -265,33 +276,33 @@ struct LinkView: View { var body: some View { if #available(iOS 14.0, *) { - Link(destination: URL(string: getURL())!, label: { - ApprovalItemView(approvalItem: approvalItem, message: message, serverNameFlag: false) + let url = getURL(approvalItem: getApprovalItem(), serverNumber: entry.serverNumber) + Link(destination: URL(string: url)!, label: { + ApprovalItemView(itemNum: itemNum, entry: entry, serverNameFlag: false) }) } else { - ApprovalItemView(approvalItem: approvalItem, message: message) - .onTapGesture { - if viewController != nil { - viewController!.extensionContext?.open(NSURL(fileURLWithPath: getStatusURL())as URL, completionHandler: nil) - } - } + ApprovalItemView(itemNum: itemNum, entry: entry) } } } //書類状況の内容を表示するビュー struct ApprovalItemView: View { - let approvalItem: ApprovalItem - let message: String? + let itemNum: Int + let entry: EntryData let serverList = UserDefaultsDataStore().readServerList() var serverNameFlag = true + + func getApprovalItem() -> ApprovalItem { + return entry.approvalItems[itemNum] + } var body: some View { VStack (spacing: 0) { if #available(iOS 14.0, *) { if serverNameFlag { - if !serverList.isEmpty { - Text(KeychainDataStore().readServerName(serverNumber: serverList[0])!) + if let serverNumber = entry.serverNumber { + Text(KeychainDataStore().readServerName(serverNumber: serverNumber)!) } } } @@ -300,17 +311,17 @@ struct ApprovalItemView: View { Image(systemName: "folder") .frame(width: geometry.size.width * 0.3, height: geometry.size.height) .foregroundColor(Color.textColor) - if message == nil { + if entry.message == nil { VStack(alignment: .leading) { - Text(approvalItem.name) + Text(getApprovalItem().name) .frame(alignment: .leading) .foregroundColor(Color.textColor) - Text("\(approvalItem.count)").font(.subheadline) + Text("\(getApprovalItem().count)").font(.subheadline) .frame(alignment: .leading) .foregroundColor(Color.textColor) } } else { //APIサーバーエラーの場合の表示 - Text(message ?? "-") + Text(entry.message ?? "-") } } Spacer() @@ -323,13 +334,42 @@ struct ApprovalItemView: View { //エラー文言を表示するビュー struct FailureWidgetView: View { - var entry: EntryData + let entry: EntryData + let serverList = UserDefaultsDataStore().readServerList() var body: some View { - Text(entry.message ?? "") - .foregroundColor(Color.textColor) + if !serverList.isEmpty { + if let serverNumber = entry.serverNumber { + Text(KeychainDataStore().readServerName(serverNumber: serverNumber)!) + } + } + Text(entry.message ?? "") + .frame(maxWidth: .infinity, maxHeight: .infinity) + .foregroundColor(Color.textColor) + } +} + +func getWorkURL(serverNumber: Int?) -> String { + var url = Configuration.shared.awURL + "/" + (KeychainDataStore().readContextPath() ?? "") + "/Broker/Mobile#work" + if let serverNumber = serverNumber { + url += "?serverNumber=" + String(serverNumber) + } + return url +} + +//遷移先URLの取得(iOS14以降) +func getURL(approvalItem: ApprovalItem, serverNumber: Int?) -> String { + if let status = getStatus(code: approvalItem.code) { + var url = Configuration.shared.awURL + "/" + (KeychainDataStore().readContextPath() ?? "") + "/Broker/Mobile#docList_" + status + if let serverNumber = serverNumber { + return url + "?serverNumber=" + String(serverNumber) + } + return url + } else { + return getWorkURL(serverNumber: serverNumber) } } + func checkApprovalItems(approvalItems: [ApprovalItem]) -> [ApprovalItem] { var result = [ApprovalItem]() for item in approvalItems { @@ -355,7 +395,14 @@ func fetch(completion: @escaping (WidgetAPIResult let approvalsEndpoint = GetApprovalsEndpoint() + while UserDefaultsDataStore().readUpdateWidgetFlg() ?? false { + //別のウィジェットが更新中の場合は待つ + } + UserDefaultsDataStore().writeUpdateWidgetFlg(update: true) + Session.send(approvalsEndpoint) { result in + UserDefaultsDataStore().writeUpdateWidgetFlg(update: false) + switch result { case .success(let response): if !response.items.isEmpty { diff --git a/AgileWorks/Configurations/Debug-Production-Intents.xcconfig b/AgileWorks/Configurations/Debug-Production-Intents.xcconfig new file mode 100644 index 0000000..26d7762 --- /dev/null +++ b/AgileWorks/Configurations/Debug-Production-Intents.xcconfig @@ -0,0 +1,13 @@ +// +// Debug-Production-Intents.xcconfig +// AgileWorks +// +// Created by Azuma Kasumi on 2023/06/16. +// Copyright © 2023 ATLED CORP. All rights reserved. +// + +// Configuration settings file format documentation can be found at: +// https://help.apple.com/xcode/#/dev745c5c974 +#include "../Pods/Target Support Files/Pods-All-AgileWorks/Pods-All-AgileWorks.debug-production.xcconfig" +#include "Build/Debug.xcconfig" +#include "Flavor/Production-Intents.xcconfig" diff --git a/AgileWorks/Configurations/Flavor/Production-Intents.xcconfig b/AgileWorks/Configurations/Flavor/Production-Intents.xcconfig new file mode 100644 index 0000000..61a9968 --- /dev/null +++ b/AgileWorks/Configurations/Flavor/Production-Intents.xcconfig @@ -0,0 +1,17 @@ +// +// Production-Intents.xcconfig +// AgileWorks +// +// Created by Azuma Kasumi on 2023/06/16. +// Copyright © 2023 ATLED CORP. All rights reserved. +// + +// Configuration settings file format documentation can be found at: +// https://help.apple.com/xcode/#/dev745c5c974 +#include "Base-Production.xcconfig" + +DISPLAY_NAME = AgileWorks + +PRODUCT_BUNDLE_IDENTIFIER = $(AGILE_WORKS_SHARE_BUNDLE_IDENTIFIER).IntentsExtension + +CODE_SIGN_ENTITLEMENTS = IntentsExtension/IntentsExtension.entitlements diff --git a/AgileWorks/Configurations/Release-Production-Intents.xcconfig b/AgileWorks/Configurations/Release-Production-Intents.xcconfig new file mode 100644 index 0000000..22583ba --- /dev/null +++ b/AgileWorks/Configurations/Release-Production-Intents.xcconfig @@ -0,0 +1,13 @@ +// +// Release-Production-Intents.xcconfig +// AgileWorks +// +// Created by Azuma Kasumi on 2023/06/16. +// Copyright © 2023 ATLED CORP. All rights reserved. +// + +// Configuration settings file format documentation can be found at: +// https://help.apple.com/xcode/#/dev745c5c974 +#include "../Pods/Target Support Files/Pods-All-AgileWorks/Pods-All-AgileWorks.release-production.xcconfig" +#include "Build/Release.xcconfig" +#include "Flavor/Production-Intents.xcconfig" diff --git a/AgileWorks/IntentsExtension/Info.plist b/AgileWorks/IntentsExtension/Info.plist index 22a1714..5b98bb3 100644 --- a/AgileWorks/IntentsExtension/Info.plist +++ b/AgileWorks/IntentsExtension/Info.plist @@ -2,6 +2,15 @@ + AppConfig + + AGILE_WORKS_SHARE_BUNDLE_IDENTIFIER + $(AGILE_WORKS_SHARE_BUNDLE_IDENTIFIER) + OAUTH_CLIENTID + $(OAUTH_CLIENTID) + + AppIdentifierPrefix + $(AppIdentifierPrefix) NSExtension NSExtensionAttributes diff --git a/AgileWorks/IntentsExtension/IntentHandler.swift b/AgileWorks/IntentsExtension/IntentHandler.swift index 819de9b..5fbafd8 100644 --- a/AgileWorks/IntentsExtension/IntentHandler.swift +++ b/AgileWorks/IntentsExtension/IntentHandler.swift @@ -20,10 +20,10 @@ import Intents class IntentHandler: INExtension, WidgetConfigurationIntentHandling{ func provideParameterOptionsCollection(for intent: WidgetConfigurationIntent, searchTerm: String?, with completion: @escaping (INObjectCollection?, Error?) -> Void) { var widgetTypeIdentifiers: [ServerType] = [] - //let serverList = UserDefaultsDataStore().readServerList() - for i in 0..<4 {//serverList.count { - //let serverName = KeychainDataStore().readServerName(serverNumber: serverList[i]) - let item = ServerType(identifier: String(i), display: "type" + String(i))//serverName!) + let serverList = UserDefaultsDataStore().readServerList() + for i in 0.. + + + + com.apple.security.application-groups + + group.jp.atled.agileworks + + keychain-access-groups + + $(AppIdentifierPrefix)jp.atled.agileworks0 + $(AppIdentifierPrefix)jp.atled.agileworks1 + $(AppIdentifierPrefix)jp.atled.agileworks2 + $(AppIdentifierPrefix)jp.atled.agileworks3 + $(AppIdentifierPrefix)jp.atled.agileworks4 + + + diff --git a/AgileWorks/IntentsExtension/IntentsExtensionRelease-Production.entitlements b/AgileWorks/IntentsExtension/IntentsExtensionRelease-Production.entitlements new file mode 100644 index 0000000..df7a8b6 --- /dev/null +++ b/AgileWorks/IntentsExtension/IntentsExtensionRelease-Production.entitlements @@ -0,0 +1,18 @@ + + + + + com.apple.security.application-groups + + group.jp.atled.agileworks + + keychain-access-groups + + $(AppIdentifierPrefix)jp.atled.agileworks0 + $(AppIdentifierPrefix)jp.atled.agileworks1 + $(AppIdentifierPrefix)jp.atled.agileworks2 + $(AppIdentifierPrefix)jp.atled.agileworks3 + $(AppIdentifierPrefix)jp.atled.agileworks4 + + + diff --git a/AgileWorks/TodayExtension/View/TodayViewController.swift b/AgileWorks/TodayExtension/View/TodayViewController.swift index e912c5c..fd075a2 100644 --- a/AgileWorks/TodayExtension/View/TodayViewController.swift +++ b/AgileWorks/TodayExtension/View/TodayViewController.swift @@ -28,7 +28,7 @@ class TodayViewController: UIViewController, NCWidgetProviding { let serverList = UserDefaultsDataStore().readServerList() var entrys: [EntryData] = [] var entry: EntryData = EntryData(approvalItems: previewItems(), message: getDisplayString(key: "NotLogedin", comment: ""), viewController: self) - + if serverList.isEmpty { entrys.append(entry) } @@ -38,7 +38,7 @@ class TodayViewController: UIViewController, NCWidgetProviding { UserDefaultsDataStore().setGroupId(serverNumber: server) entry = resultEntry() entrys.append(entry) - + } UserDefaultsDataStore().setGroupId(serverNumber: serverList.first!) @@ -55,7 +55,8 @@ class TodayViewController: UIViewController, NCWidgetProviding { switch result { case .success(let response): self.approvalItems = checkApprovalItems(approvalItems: response.items) - entry = EntryData(approvalItems: self.approvalItems, message: nil, viewController: self) + + entry = EntryData(approvalItems: self.approvalItems, viewController: self) case .nodate(let message): entry = EntryData(approvalItems: [ApprovalItem](), message: message, viewController: self) case .failure(let message): diff --git a/AgileWorks/WidgetExtension/WidgetConfiguration.intentdefinition b/AgileWorks/WidgetExtension/WidgetConfiguration.intentdefinition index 595709d..459916a 100644 --- a/AgileWorks/WidgetExtension/WidgetConfiguration.intentdefinition +++ b/AgileWorks/WidgetExtension/WidgetConfiguration.intentdefinition @@ -90,7 +90,7 @@ INTypeDisplayNameID zid8zR INTypeLastPropertyTag - 101 + 103 INTypeName ServerType INTypeProperties diff --git a/AgileWorks/WidgetExtension/WidgetExtension.swift b/AgileWorks/WidgetExtension/WidgetExtension.swift index fb649c8..7f9b269 100644 --- a/AgileWorks/WidgetExtension/WidgetExtension.swift +++ b/AgileWorks/WidgetExtension/WidgetExtension.swift @@ -11,11 +11,13 @@ import SwiftUI struct Provider: IntentTimelineProvider { func placeholder(in context: Context) -> SimpleEntry { - SimpleEntry(date: Date(), approvalItems: previewItems(), message: nil) + let entryData = EntryData(approvalItems: previewItems()) + return SimpleEntry(date: Date(), entryData: entryData) } func getSnapshot(for configuration: WidgetConfigurationIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) { - let entry = SimpleEntry(date: Date(), approvalItems: previewItems(), message: nil) + let entryData = EntryData(approvalItems: previewItems()) + let entry = SimpleEntry(date: Date(), entryData: entryData) completion(entry) } @@ -23,29 +25,60 @@ struct Provider: IntentTimelineProvider { var entries: [SimpleEntry] = [] // Generate a timeline consisting of five entries an hour apart, starting from the current date. - let entryDate = Calendar.current.date(byAdding: .minute, value: 15, to: Date()) ?? Date() - + let updateTime = Calendar.current.date(byAdding: .minute, value: 15, to: Date()) ?? Date() + let serverNumber = getServerNumber(configuration: configuration) + if serverNumber != nil { + UserDefaultsDataStore().setGroupId(serverNumber: serverNumber!) + } + fetch { result in DispatchQueue.main.async { switch result { case .success(let response): - entries.append(SimpleEntry(date: entryDate, approvalItems: checkApprovalItems(approvalItems: response.items), message: nil)) + let approvalItems = checkApprovalItems(approvalItems: response.items) + let entryData = EntryData(serverNumber: getServerNumber(configuration: configuration), approvalItems: approvalItems) + entries.append(SimpleEntry(date: updateTime, entryData: entryData)) case .nodate(let message): - entries.append(SimpleEntry(date: entryDate, approvalItems: [ApprovalItem](), message: message)) + let entryData = EntryData(serverNumber: getServerNumber(configuration: configuration), approvalItems: [ApprovalItem](), message: message) + entries.append(SimpleEntry(date: updateTime, entryData: entryData)) case .failure(let message): - entries.append(SimpleEntry(date: entryDate, approvalItems: previewItems(), message: message)) + let entryData = EntryData(serverNumber: getServerNumber(configuration: configuration), approvalItems: previewItems(), message: message) + entries.append(SimpleEntry(date: updateTime, entryData: entryData)) } - let timeline = Timeline(entries: entries, policy: .after(entryDate)) + let timeline = Timeline(entries: entries, policy: .after(updateTime)) completion(timeline) } } + let serverList = UserDefaultsDataStore().readServerList() + if !serverList.isEmpty { + UserDefaultsDataStore().setGroupId(serverNumber: serverList.first!) + } + } + + func getServerNumber(configuration: WidgetConfigurationIntent) -> Int? { + var serverNumber: Int? + + let serverList = UserDefaultsDataStore().readServerList() + if serverList.isEmpty { + return nil + } + // ウィジェット構成 + if configuration.parameter == nil { + serverNumber = serverList.first! + } else { + serverNumber = Int((configuration.parameter?.identifier!)!)! + //ウィジェットの構成が古い(ログアウトされたサーバーが選択されている)場合 + if !serverList.contains(serverNumber!) { + serverNumber = serverList.first! + } + } + return serverNumber } } struct SimpleEntry: TimelineEntry { let date: Date - var approvalItems: [ApprovalItem] - var message: String? + var entryData: EntryData } //状況確認ウィジェット @@ -54,8 +87,7 @@ struct StatusCheckWidget: Widget { var body: some WidgetConfiguration { IntentConfiguration(kind: kind, intent: WidgetConfigurationIntent.self, provider: Provider()) { entry in - - StatusCheckWidgetView(entry: EntryData(approvalItems: entry.approvalItems, message: entry.message, viewController: nil)) + StatusCheckWidgetView(entry: entry.entryData) } .configurationDisplayName(getDisplayString(key: "StatusCheckWidgetName", comment: "")) .description(getDisplayString(key: "StatusCheckWidgetDescription", comment: "")) @@ -69,7 +101,7 @@ struct ApprovalWidget: Widget { var body: some WidgetConfiguration { IntentConfiguration(kind: kind, intent: WidgetConfigurationIntent.self, provider: Provider()) { entry in - ApprovalWidgetView(entry: EntryData(approvalItems: entry.approvalItems, message: entry.message, viewController: nil)) + ApprovalWidgetView(entry: entry.entryData) } .configurationDisplayName(getDisplayString(key: "ApprovalWidgetName", comment: "")) .description(getDisplayString(key: "ApprovalWidgetDescription", comment: "")) -- GitLab