Skip to content

Commit

Permalink
Deep link support for screens navigation (#2963)
Browse files Browse the repository at this point in the history
* added DeepLink code by Amrut Waghmare

Signed-off-by: Marino Faggiana <[email protected]>

* fix

Signed-off-by: Marino Faggiana <[email protected]>

* fix

Signed-off-by: Marino Faggiana <[email protected]>

* fix

Signed-off-by: Marino Faggiana <[email protected]>

* cleaning

Signed-off-by: Marino Faggiana <[email protected]>

* fix

Signed-off-by: Marino Faggiana <[email protected]>

* fix

Signed-off-by: Marino Faggiana <[email protected]>

* change classname

Signed-off-by: Marino Faggiana <[email protected]>

* cleaning code

Signed-off-by: Marino Faggiana <[email protected]>

* cleaning

Signed-off-by: Marino Faggiana <[email protected]>

---------

Signed-off-by: Marino Faggiana <[email protected]>
  • Loading branch information
marinofaggiana authored Jun 28, 2024
1 parent 6849606 commit aae2a7d
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 5 deletions.
1 change: 1 addition & 0 deletions Brand/NCBrand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ let userAgent: String = {
var privacy: String = "https://nextcloud.com/privacy"
var sourceCode: String = "https://github.com/nextcloud/ios"
var mobileconfig: String = "/remote.php/dav/provisioning/apple-provisioning.mobileconfig"
var appStoreUrl: String = "https://apps.apple.com/in/app/nextcloud/id1125420102"

// Auto Upload default folder
var folderDefaultAutoUpload: String = "Photos"
Expand Down
12 changes: 12 additions & 0 deletions Nextcloud.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,7 @@
F7A60F87292D215000FCE1F2 /* NCShareAccounts.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7A60F85292D215000FCE1F2 /* NCShareAccounts.storyboard */; };
F7A76DC8256A71CD00119AB3 /* UIImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B7504A2397D38E004E13EC /* UIImage+Extension.swift */; };
F7A76DCD256A71CE00119AB3 /* UIImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B7504A2397D38E004E13EC /* UIImage+Extension.swift */; };
F7A7FDDD2C2DBD6200E9A93A /* NCDeepLinkHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A7FDDB2C2DBD6200E9A93A /* NCDeepLinkHandler.swift */; };
F7A846DE2BB01ACB0024816F /* NCTrashCellProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A846DD2BB01ACB0024816F /* NCTrashCellProtocol.swift */; };
F7A8D72428F1771B008BBE1C /* NextcloudKit in Frameworks */ = {isa = PBXBuildFile; productRef = F7A8D72328F1771B008BBE1C /* NextcloudKit */; };
F7A8D72828F17728008BBE1C /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = F7A8D72728F17728008BBE1C /* RealmSwift */; };
Expand Down Expand Up @@ -1484,6 +1485,7 @@
F7A560412AE1593700BE8FD6 /* NCOperationSaveLivePhoto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCOperationSaveLivePhoto.swift; sourceTree = "<group>"; };
F7A60F84292D215000FCE1F2 /* NCShareAccounts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCShareAccounts.swift; sourceTree = "<group>"; };
F7A60F85292D215000FCE1F2 /* NCShareAccounts.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NCShareAccounts.storyboard; sourceTree = "<group>"; };
F7A7FDDB2C2DBD6200E9A93A /* NCDeepLinkHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCDeepLinkHandler.swift; sourceTree = "<group>"; };
F7A846DD2BB01ACB0024816F /* NCTrashCellProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCTrashCellProtocol.swift; sourceTree = "<group>"; };
F7AA41B827C7CF4600494705 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/InfoPlist.strings; sourceTree = "<group>"; };
F7AA41B927C7CF4B00494705 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2601,6 +2603,14 @@
path = Activity;
sourceTree = "<group>";
};
F7A7FDD92C2DBD6200E9A93A /* DeepLink */ = {
isa = PBXGroup;
children = (
F7A7FDDB2C2DBD6200E9A93A /* NCDeepLinkHandler.swift */,
);
path = DeepLink;
sourceTree = "<group>";
};
F7AE00F6230E8191007ACF8A /* BrowserWeb */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -2908,6 +2918,7 @@
F7AE00F6230E8191007ACF8A /* BrowserWeb */,
F70B866A2642A21300ED5349 /* Color */,
F7BAAD951ED5A63D00B7EAD4 /* Data */,
F7A7FDD92C2DBD6200E9A93A /* DeepLink */,
F7A0D14E259229FA008F8A13 /* Extensions */,
F7A3214D1E9E2A070069AD1B /* Favorites */,
F7725A5D251F33BB00D125E0 /* Files */,
Expand Down Expand Up @@ -4285,6 +4296,7 @@
F76882222C0DD1E7001CF441 /* NCCapabilitiesView.swift in Sources */,
AF93471A27E2361E002537EE /* NCShareAdvancePermissionHeader.swift in Sources */,
F7F878AE1FB9E3B900599E4F /* NCEndToEndMetadata.swift in Sources */,
F7A7FDDD2C2DBD6200E9A93A /* NCDeepLinkHandler.swift in Sources */,
3781B9B023DB2B7E006B4B1D /* AppDelegate+Menu.swift in Sources */,
F710D1F52405770F00A6033D /* NCViewerPDF.swift in Sources */,
F7B6B70427C4E7FA00A7F6EB /* NCScan+CollectionView.swift in Sources */,
Expand Down
156 changes: 156 additions & 0 deletions iOSClient/DeepLink/NCDeepLinkHandler.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
//
// DeepLinkHandler.swift
// Nextcloud
//
// Created by Amrut Waghmare on 29/05/24.
// Copyright © 2024 Marino Faggiana. All rights reserved.
//
// 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 Foundation
import UIKit
import SwiftUI

enum DeepLink: String {
case openFiles // nextcloud://openFiles
case openFavorites // nextcloud://openFavorites
case openMedia // nextcloud://openMedia
case openShared // nextcloud://openShared
case openOffline // nextcloud://openOffline
case openNotifications // nextcloud://openNotifications
case openDeleted // nextcloud://openDeleted
case openSettings // nextcloud://openSettings
case openAutoUpload // nextcloud://openAutoUpload
case openUrl // nextcloud://openUrl?url=https://nextcloud.com
case createNew // nextcloud://createNew
case checkAppUpdate // nextcloud://checkAppUpdate
}

enum ControllerConstants {
static let filesIndex = 0
static let favouriteIndex = 1
static let mediaIndex = 3
static let moreIndex = 4
static let notification = "NCNotification"
static let shares = "segueShares"
static let offline = "segueOffline"
static let delete = "segueTrash"
}

class NCDeepLinkHandler {
func parseDeepLink(_ url: URL, controller: NCMainTabBarController) {
guard let action = url.host, let deepLink = DeepLink(rawValue: action) else { return }
let params = getQueryParamsFromUrl(url: url)
handleDeepLink(deepLink, controller: controller, params: params)
}

func getQueryParamsFromUrl(url: URL) -> [String: Any]? {
guard
let components = URLComponents(url: url, resolvingAgainstBaseURL: true),
let queryItems = components.queryItems else { return nil }
return queryItems.reduce(into: [String: Any]()) { result, item in
result[item.name] = item.value
}
}

func handleDeepLink(_ deepLink: DeepLink, controller: NCMainTabBarController, params: [String: Any]? = nil) {
switch deepLink {
case .openFiles:
navigateTo(index: ControllerConstants.filesIndex, controller: controller)
case .openFavorites:
navigateTo(index: ControllerConstants.favouriteIndex, controller: controller)
case .openMedia:
navigateTo(index: ControllerConstants.mediaIndex, controller: controller)
case .openShared:
navigateToMore(withSegue: ControllerConstants.shares, controller: controller)
case .openOffline:
navigateToMore(withSegue: ControllerConstants.offline, controller: controller)
case .openNotifications:
navigateToNotification(controller: controller)
case .openDeleted:
navigateToMore(withSegue: ControllerConstants.delete, controller: controller)
case .openSettings:
navigateToSettings(controller: controller)
case .openAutoUpload:
navigateToAutoUpload(controller: controller)
case .openUrl:
openUrl(params: params)
case .createNew:
navigateToCreateNew(controller: controller)
case .checkAppUpdate:
navigateAppUpdate()
}
}

private func navigateTo(index: Int, controller: NCMainTabBarController) {
controller.selectedIndex = index
}

private func navigateToNotification(controller: NCMainTabBarController) {
controller.selectedIndex = ControllerConstants.filesIndex
guard let navigationController = controller.viewControllers?[controller.selectedIndex] as? UINavigationController,
let viewController = UIStoryboard(name: ControllerConstants.notification, bundle: nil).instantiateInitialViewController() as? NCNotification else { return }
navigationController.pushViewController(viewController, animated: true)
}

private func navigateToCreateNew(controller: NCMainTabBarController) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
controller.selectedIndex = ControllerConstants.filesIndex
DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
appDelegate.toggleMenu(controller: controller)
}
}

private func navigateToMore(withSegue segue: String, controller: NCMainTabBarController) {
controller.selectedIndex = ControllerConstants.moreIndex
guard let navigationController = controller.viewControllers?[controller.selectedIndex] as? UINavigationController else { return }
navigationController.viewControllers = navigationController.viewControllers.filter({$0.isKind(of: NCMore.self)})
navigationController.performSegue(withIdentifier: segue, sender: self)
}

private func navigateToSettings(controller: NCMainTabBarController) {
controller.selectedIndex = ControllerConstants.moreIndex
guard let navigationController = controller.viewControllers?[controller.selectedIndex] as? UINavigationController else { return }

let settingsView = NCSettingsView(model: NCSettingsModel(controller: controller))
let settingsController = UIHostingController(rootView: settingsView)
navigationController.pushViewController(settingsController, animated: true)
}

private func navigateToAutoUpload(controller: NCMainTabBarController) {
controller.selectedIndex = ControllerConstants.moreIndex
guard let navigationController = controller.viewControllers?[controller.selectedIndex] as? UINavigationController else { return }

let autoUploadView = NCAutoUploadView(model: NCAutoUploadModel(controller: controller))
let autoUploadController = UIHostingController(rootView: autoUploadView)
navigationController.pushViewController(autoUploadController, animated: true)
}

private func navigateAppUpdate() {
guard let url = URL(string: NCBrandOptions.shared.appStoreUrl) else { return }
handleUrl(url: url)
}

private func openUrl(params: [String: Any]?) {
guard let urlString = params?["url"] as? String, let url = URL(string: urlString) else { return }
handleUrl(url: url)
}

private func handleUrl(url: URL) {
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
}
}
4 changes: 1 addition & 3 deletions iOSClient/Main/NCActionCenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -250,12 +250,10 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec
// MARK: - Upload

@objc func uploadedFile(_ notification: NSNotification) {

guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
guard let userInfo = notification.userInfo as NSDictionary?,
let error = userInfo["error"] as? NKError,
let account = userInfo["account"] as? String,
account == appDelegate.account
account == self.appDelegate?.account
else { return }

if error != .success, error.errorCode != NSURLErrorCancelled, error.errorCode != NCGlobal.shared.errorRequestExplicityCancelled {
Expand Down
4 changes: 2 additions & 2 deletions iOSClient/NCGlobal.swift
Original file line number Diff line number Diff line change
Expand Up @@ -451,8 +451,8 @@ class NCGlobal: NSObject {
// MORE NEXTCLOUD APPS
let talkSchemeUrl = "nextcloudtalk://"
let notesSchemeUrl = "nextcloudnotes://"
let talkAppStoreUrl = "https://apps.apple.com/de/app/nextcloud-talk/id1296825574"
let notesAppStoreUrl = "https://apps.apple.com/de/app/nextcloud-notes/id813973264"
let talkAppStoreUrl = "https://apps.apple.com/in/app/nextcloud-talk/id1296825574"
let notesAppStoreUrl = "https://apps.apple.com/in/app/nextcloud-notes/id813973264"
let moreAppsUrl = "itms-apps://search.itunes.apple.com/WebObjects/MZSearch.woa/wa/search?media=software&term=nextcloud"

// SNAPSHOT PREVIEW
Expand Down
5 changes: 5 additions & 0 deletions iOSClient/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,11 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
}
// Otherwise open the app and switch accounts
return
} else if !account.isEmpty, let action {
if DeepLink(rawValue: action) != nil {
NCDeepLinkHandler().parseDeepLink(url, controller: controller)
}
return
} else {
let applicationHandle = NCApplicationHandle()
let isHandled = applicationHandle.applicationOpenURL(url)
Expand Down

0 comments on commit aae2a7d

Please sign in to comment.