123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435 |
- //
- // SceneDelegate.swift
- // Nextcloud
- //
- // Created by Marino Faggiana on 25/03/24.
- // Copyright © 2024 Marino Faggiana. All rights reserved.
- //
- // Author Marino Faggiana <marino.faggiana@nextcloud.com>
- //
- // This program is free software: you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License
- // along with this program. If not, see <http://www.gnu.org/licenses/>.
- //
- import UIKit
- import NextcloudKit
- import WidgetKit
- import SwiftEntryKit
- import TOPasscodeViewController
- class SceneDelegate: UIResponder, UIWindowSceneDelegate {
- var window: UIWindow?
- private let appDelegate = UIApplication.shared.delegate as? AppDelegate
- private var privacyProtectionWindow: UIWindow?
- func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
- guard let windowScene = (scene as? UIWindowScene),
- let appDelegate else { return }
- self.window = UIWindow(windowScene: windowScene)
- #if os(visionOS)
- // TEST
- // window?.overrideUserInterfaceStyle = .dark
- #endif
- if NCManageDatabase.shared.getActiveAccount() != nil {
- if let mainTabBarController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() as? NCMainTabBarController {
- SceneManager.shared.register(scene: scene, withRootViewController: mainTabBarController)
- window?.rootViewController = mainTabBarController
- window?.makeKeyAndVisible()
- }
- } else {
- if NCBrandOptions.shared.disable_intro {
- appDelegate.openLogin(selector: NCGlobal.shared.introLogin, openLoginWeb: false, windowForRootViewController: window)
- } else {
- if let viewController = UIStoryboard(name: "NCIntro", bundle: nil).instantiateInitialViewController() as? NCIntroViewController {
- let navigationController = NCLoginNavigationController(rootViewController: viewController)
- window?.rootViewController = navigationController
- window?.makeKeyAndVisible()
- }
- }
- }
- appDelegate.startTimerErrorNetworking(scene: scene)
- }
- func sceneDidDisconnect(_ scene: UIScene) {
- print("[DEBUG] Scene did disconnect")
- }
- func sceneWillEnterForeground(_ scene: UIScene) {
- NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Scene will enter in foreground")
- guard let appDelegate else { return }
- // In Login mode is possible ONLY 1 window
- if (UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene }).count > 1,
- (appDelegate.activeLogin?.view.window != nil || appDelegate.activeLoginWeb?.view.window != nil) || (UIApplication.shared.firstWindow?.rootViewController is NCLoginNavigationController) {
- UIApplication.shared.allSceneSessionDestructionExceptFirst()
- return
- }
- guard !appDelegate.account.isEmpty else { return }
- hidePrivacyProtectionWindow()
- if let window = SceneManager.shared.getWindow(scene: scene), let mainTabBarController = SceneManager.shared.getMainTabBarController(scene: scene) {
- window.rootViewController = mainTabBarController
- if NCKeychain().presentPasscode {
- NCPasscode.shared.presentPasscode(viewController: mainTabBarController, delegate: self) {
- NCPasscode.shared.enableTouchFaceID()
- }
- } else if NCKeychain().accountRequest {
- requestedAccount(viewController: mainTabBarController)
- }
- }
- NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterRichdocumentGrabFocus)
- NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSourceNetwork, second: 2)
- }
- func sceneDidBecomeActive(_ scene: UIScene) {
- NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Scene did become active")
- NCSettingsBundleHelper.setVersionAndBuildNumber()
- NCSettingsBundleHelper.checkAndExecuteSettings(delay: 0.5)
- // START TIMER UPLOAD PROCESS
- NCNetworkingProcess.shared.startTimer(scene: scene)
- hidePrivacyProtectionWindow()
- NCService().startRequestServicesServer()
- NCAutoUpload.shared.initAutoUpload(viewController: nil) { items in
- NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Initialize Auto upload with \(items) uploads")
- }
- }
- func sceneWillResignActive(_ scene: UIScene) {
- NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Scene will resign active")
- guard let appDelegate,
- !appDelegate.account.isEmpty else { return }
- // STOP TIMER UPLOAD PROCESS
- NCNetworkingProcess.shared.stopTimer()
- if NCKeychain().privacyScreenEnabled {
- if SwiftEntryKit.isCurrentlyDisplaying {
- SwiftEntryKit.dismiss {
- self.showPrivacyProtectionWindow()
- }
- } else {
- showPrivacyProtectionWindow()
- }
- }
- // Reload Widget
- WidgetCenter.shared.reloadAllTimelines()
- // Clear older files
- let days = NCKeychain().cleanUpDay
- let utilityFileSystem = NCUtilityFileSystem()
- utilityFileSystem.cleanUp(directory: utilityFileSystem.directoryProviderStorage, days: TimeInterval(days))
- }
- func sceneDidEnterBackground(_ scene: UIScene) {
- NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Scene did enter in background")
- guard let appDelegate,
- !appDelegate.account.isEmpty else { return }
- if let autoUpload = NCManageDatabase.shared.getActiveAccount()?.autoUpload, autoUpload {
- NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Auto upload: true")
- if UIApplication.shared.backgroundRefreshStatus == .available {
- NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Auto upload in background: true")
- } else {
- NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Auto upload in background: false")
- }
- } else {
- NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Auto upload: false")
- }
- if let error = appDelegate.updateShareAccounts() {
- NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Create share accounts \(error.localizedDescription)")
- }
- appDelegate.scheduleAppRefresh()
- appDelegate.scheduleAppProcessing()
- NCNetworking.shared.cancelAllQueue()
- NCNetworking.shared.cancelDataTask()
- NCNetworking.shared.cancelDownloadTasks()
- NCNetworking.shared.cancelUploadTasks()
- if NCKeychain().presentPasscode {
- showPrivacyProtectionWindow()
- }
- }
- func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
- guard let mainTabBarController = SceneManager.shared.getMainTabBarController(scene: scene) as? NCMainTabBarController,
- let url = URLContexts.first?.url,
- let appDelegate else { return }
- let sceneIdentifier = mainTabBarController.sceneIdentifier
- let account = appDelegate.account
- let scheme = url.scheme
- let action = url.host
- func getMatchedAccount(userId: String, url: String) -> tableAccount? {
- if let activeAccount = NCManageDatabase.shared.getActiveAccount() {
- let urlBase = URL(string: activeAccount.urlBase)
- if url.contains(urlBase?.host ?? "") && userId == activeAccount.userId {
- return activeAccount
- } else {
- let accounts = NCManageDatabase.shared.getAllAccount()
- for account in accounts {
- let urlBase = URL(string: account.urlBase)
- if url.contains(urlBase?.host ?? "") && userId == account.userId {
- appDelegate.changeAccount(account.account, userProfile: nil)
- return account
- }
- }
- }
- }
- return nil
- }
- /*
- Example: nextcloud://open-action?action=create-voice-memo&&user=marinofaggiana&url=https://cloud.nextcloud.com
- */
- if !account.isEmpty && scheme == NCGlobal.shared.appScheme && action == "open-action" {
- if let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false) {
- let queryItems = urlComponents.queryItems
- guard let actionScheme = queryItems?.filter({ $0.name == "action" }).first?.value,
- let userScheme = queryItems?.filter({ $0.name == "user" }).first?.value,
- let urlScheme = queryItems?.filter({ $0.name == "url" }).first?.value else { return }
- if getMatchedAccount(userId: userScheme, url: urlScheme) == nil {
- let message = NSLocalizedString("_the_account_", comment: "") + " " + userScheme + NSLocalizedString("_of_", comment: "") + " " + urlScheme + " " + NSLocalizedString("_does_not_exist_", comment: "")
- let alertController = UIAlertController(title: NSLocalizedString("_info_", comment: ""), message: message, preferredStyle: .alert)
- alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in }))
- mainTabBarController.present(alertController, animated: true, completion: { })
- return
- }
- switch actionScheme {
- case NCGlobal.shared.actionUploadAsset:
- NCAskAuthorization().askAuthorizationPhotoLibrary(viewController: mainTabBarController) { hasPermission in
- if hasPermission {
- NCPhotosPickerViewController(mainTabBarController: mainTabBarController, maxSelectedAssets: 0, singleSelectedMode: false)
- }
- }
- case NCGlobal.shared.actionScanDocument:
- NCDocumentCamera.shared.openScannerDocument(viewController: mainTabBarController)
- case NCGlobal.shared.actionTextDocument:
- let directEditingCreators = NCManageDatabase.shared.getDirectEditingCreators(account: appDelegate.account)
- let directEditingCreator = directEditingCreators!.first(where: { $0.editor == NCGlobal.shared.editorText})!
- let serverUrl = mainTabBarController.currentServerUrl()
- Task {
- let fileName = await NCNetworking.shared.createFileName(fileNameBase: NSLocalizedString("_untitled_", comment: "") + ".md", account: appDelegate.account, serverUrl: serverUrl)
- let fileNamePath = NCUtilityFileSystem().getFileNamePath(String(describing: fileName), serverUrl: serverUrl, urlBase: appDelegate.urlBase, userId: appDelegate.userId)
- self.appDelegate?.createTextDocument(mainTabBarController: mainTabBarController, fileNamePath: fileNamePath, fileName: String(describing: fileName), creatorId: directEditingCreator.identifier)
- }
- case NCGlobal.shared.actionVoiceMemo:
- NCAskAuthorization().askAuthorizationAudioRecord(viewController: mainTabBarController) { hasPermission in
- if hasPermission {
- if let viewController = UIStoryboard(name: "NCAudioRecorderViewController", bundle: nil).instantiateInitialViewController() as? NCAudioRecorderViewController {
- viewController.serverUrl = mainTabBarController.currentServerUrl()
- viewController.modalTransitionStyle = .crossDissolve
- viewController.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
- mainTabBarController.present(viewController, animated: true, completion: nil)
- }
- }
- }
- default:
- print("No action")
- }
- }
- return
- }
- /*
- Example: nextcloud://open-file?path=Talk/IMG_0000123.jpg&user=marinofaggiana&link=https://cloud.nextcloud.com/f/123
- */
- else if !account.isEmpty && scheme == NCGlobal.shared.appScheme && action == "open-file" {
- if let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false) {
- var serverUrl: String = ""
- var fileName: String = ""
- let queryItems = urlComponents.queryItems
- guard let userScheme = queryItems?.filter({ $0.name == "user" }).first?.value,
- let pathScheme = queryItems?.filter({ $0.name == "path" }).first?.value,
- let linkScheme = queryItems?.filter({ $0.name == "link" }).first?.value else { return}
- guard let matchedAccount = getMatchedAccount(userId: userScheme, url: linkScheme) else {
- guard let domain = URL(string: linkScheme)?.host else { return }
- fileName = (pathScheme as NSString).lastPathComponent
- let message = String(format: NSLocalizedString("_account_not_available_", comment: ""), userScheme, domain, fileName)
- let alertController = UIAlertController(title: NSLocalizedString("_info_", comment: ""), message: message, preferredStyle: .alert)
- alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in }))
- mainTabBarController.present(alertController, animated: true, completion: { })
- return
- }
- let davFiles = NextcloudKit.shared.nkCommonInstance.dav + "/files/" + appDelegate.userId
- if pathScheme.contains("/") {
- fileName = (pathScheme as NSString).lastPathComponent
- serverUrl = matchedAccount.urlBase + "/" + davFiles + "/" + (pathScheme as NSString).deletingLastPathComponent
- } else {
- fileName = pathScheme
- serverUrl = matchedAccount.urlBase + "/" + davFiles
- }
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
- NCActionCenter.shared.openFileViewInFolder(serverUrl: serverUrl, fileNameBlink: nil, fileNameOpen: fileName, sceneIdentifier: sceneIdentifier)
- }
- }
- return
- /*
- Example: nextcloud://open-and-switch-account?user=marinofaggiana&url=https://cloud.nextcloud.com
- */
- } else if !account.isEmpty && scheme == NCGlobal.shared.appScheme && action == "open-and-switch-account" {
- guard let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false) else { return }
- let queryItems = urlComponents.queryItems
- guard let userScheme = queryItems?.filter({ $0.name == "user" }).first?.value,
- let urlScheme = queryItems?.filter({ $0.name == "url" }).first?.value else { return }
- // If the account doesn't exist, return false which will open the app without switching
- if getMatchedAccount(userId: userScheme, url: urlScheme) == nil {
- return
- }
- // Otherwise open the app and switch accounts
- return
- } else {
- let applicationHandle = NCApplicationHandle()
- let isHandled = applicationHandle.applicationOpenURL(url)
- if isHandled {
- return
- } else {
- scene.open(url, options: nil)
- }
- }
- }
- private func showPrivacyProtectionWindow() {
- guard let windowScene = self.window?.windowScene else {
- return
- }
- privacyProtectionWindow = UIWindow(windowScene: windowScene)
- privacyProtectionWindow?.rootViewController = UIStoryboard(name: "LaunchScreen", bundle: nil).instantiateInitialViewController()
- privacyProtectionWindow?.windowLevel = .alert + 1
- privacyProtectionWindow?.makeKeyAndVisible()
- }
- private func hidePrivacyProtectionWindow() {
- privacyProtectionWindow?.isHidden = true
- privacyProtectionWindow = nil
- }
- }
- // MARK: - Extension
- extension SceneDelegate: NCPasscodeDelegate {
- func requestedAccount(viewController: UIViewController?) {
- let accounts = NCManageDatabase.shared.getAllAccount()
- if accounts.count > 1, let accountRequestVC = UIStoryboard(name: "NCAccountRequest", bundle: nil).instantiateInitialViewController() as? NCAccountRequest {
- accountRequestVC.activeAccount = NCManageDatabase.shared.getActiveAccount()
- accountRequestVC.accounts = accounts
- accountRequestVC.enableTimerProgress = true
- accountRequestVC.enableAddAccount = false
- accountRequestVC.dismissDidEnterBackground = false
- accountRequestVC.delegate = self
- accountRequestVC.startTimer()
- let screenHeighMax = UIScreen.main.bounds.height - (UIScreen.main.bounds.height / 5)
- let numberCell = accounts.count
- let height = min(CGFloat(numberCell * Int(accountRequestVC.heightCell) + 45), screenHeighMax)
- let popup = NCPopupViewController(contentController: accountRequestVC, popupWidth: 300, popupHeight: height + 20)
- popup.backgroundAlpha = 0.8
- viewController?.present(popup, animated: true)
- }
- }
- func passcodeReset(_ passcodeViewController: TOPasscodeViewController) {
- appDelegate?.resetApplication()
- }
- }
- extension SceneDelegate: NCAccountRequestDelegate {
- func accountRequestAddAccount() { }
- func accountRequestChangeAccount(account: String) {
- appDelegate?.changeAccount(account, userProfile: nil)
- }
- }
- // MARK: - Scene Manager
- class SceneManager {
- static let shared = SceneManager()
- private var sceneMainTabBarController: [NCMainTabBarController: UIScene] = [:]
- func register(scene: UIScene, withRootViewController rootViewController: NCMainTabBarController) {
- sceneMainTabBarController[rootViewController] = scene
- }
- func getMainTabBarController(scene: UIScene?) -> UIViewController? {
- for mainTabBarController in sceneMainTabBarController.keys {
- if sceneMainTabBarController[mainTabBarController] == scene {
- return mainTabBarController
- }
- }
- return nil
- }
- func getMainTabBarController(sceneIdentifier: String) -> NCMainTabBarController? {
- for mainTabBarController in sceneMainTabBarController.keys {
- if sceneIdentifier == mainTabBarController.sceneIdentifier {
- return mainTabBarController
- }
- }
- return nil
- }
- func getWindow(scene: UIScene?) -> UIWindow? {
- return (scene as? UIWindowScene)?.keyWindow
- }
- func getSceneIdentifier() -> [String] {
- var results: [String] = []
- for mainTabBarController in sceneMainTabBarController.keys {
- results.append(mainTabBarController.sceneIdentifier)
- }
- return results
- }
- func getAllMainTabBarController() -> [NCMainTabBarController] {
- return Array(sceneMainTabBarController.keys)
- }
- }
|