diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index de48cf1181..cd8f46112c 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -85,6 +85,12 @@ AFCE353727E4ED7B00FEA6C2 /* NCShareCells.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353627E4ED7B00FEA6C2 /* NCShareCells.swift */; }; AFCE353927E5DE0500FEA6C2 /* Shareable.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353827E5DE0400FEA6C2 /* Shareable.swift */; }; CB3666201AF7550816B5CD6A /* NCContextMenuComment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8932E90EC4278026D86CCCC9 /* NCContextMenuComment.swift */; }; + AFCE353927E5DE0500FEA6C2 /* NCShare+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353827E5DE0400FEA6C2 /* NCShare+Helper.swift */; }; + B568C2B12DA7AA5F0072FCB4 /* MoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B568C2B02DA7AA5F0072FCB4 /* MoreTests.swift */; }; + B568C2B32DA7AAAE0072FCB4 /* NCMoreUserCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B568C2B22DA7AAAE0072FCB4 /* NCMoreUserCell.xib */; }; + B568C2B52DA7AADD0072FCB4 /* NCMoreUserCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B568C2B42DA7AADD0072FCB4 /* NCMoreUserCell.swift */; }; + C04E2F232A17BB4D001BAD85 /* FilesIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C04E2F222A17BB4D001BAD85 /* FilesIntegrationTests.swift */; }; + D575039F27146F93008DC9DC /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A0D1342591FBC5008F8A13 /* String+Extension.swift */; }; D5B6AA7827200C7200D49C24 /* NCActivityTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B6AA7727200C7200D49C24 /* NCActivityTableViewCell.swift */; }; F310B1EF2BA862F1001C42F5 /* NCViewerMedia+VisionKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = F310B1EE2BA862F1001C42F5 /* NCViewerMedia+VisionKit.swift */; }; F31165022F9674A1009A1E37 /* AppIcon.icon in Resources */ = {isa = PBXBuildFile; fileRef = F31165012F9674A1009A1E37 /* AppIcon.icon */; }; @@ -1263,6 +1269,10 @@ AFCE353827E5DE0400FEA6C2 /* Shareable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Shareable.swift; sourceTree = ""; }; B4C7A5B36D1ED178FB6B76CB /* NCContextMenuPlayerTracks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCContextMenuPlayerTracks.swift; sourceTree = ""; }; BB7697C94BA14450A0867940 /* NCContextMenuProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCContextMenuProfile.swift; sourceTree = ""; }; + AFCE353827E5DE0400FEA6C2 /* NCShare+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCShare+Helper.swift"; sourceTree = ""; }; + B568C2B02DA7AA5F0072FCB4 /* MoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoreTests.swift; sourceTree = ""; }; + B568C2B22DA7AAAE0072FCB4 /* NCMoreUserCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCMoreUserCell.xib; sourceTree = ""; }; + B568C2B42DA7AADD0072FCB4 /* NCMoreUserCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMoreUserCell.swift; sourceTree = ""; }; C0046CDA2A17B98400D87C9D /* NextcloudUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NextcloudUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; C04E2F202A17BB4D001BAD85 /* NextcloudIntegrationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NextcloudIntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; D5B6AA7727200C7200D49C24 /* NCActivityTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCActivityTableViewCell.swift; sourceTree = ""; }; @@ -2087,6 +2097,8 @@ children = ( F34BDB3B2F574A58007A222C /* BidiSafeFilenameTests.swift */, AA52EB452D42AC5A0089C348 /* Placeholder.swift */, + B568C2B02DA7AA5F0072FCB4 /* MoreTests.swift */, + AF8ED1FB2757821000B8DBC4 /* NextcloudUnitTests.swift */, ); path = NextcloudUnitTests; sourceTree = ""; @@ -4052,6 +4064,8 @@ F7381EE5218218C9000B1560 /* NCOffline.storyboard in Resources */, F768822D2C0DD1E7001CF441 /* Acknowledgements.rtf in Resources */, F76D3CF32428B94E005DFA87 /* NCViewerPDFSearchCell.xib in Resources */, + B568C2B32DA7AAAE0072FCB4 /* NCMoreUserCell.xib in Resources */, + F7CA212E25F1333300826ABB /* NCAccountRequest.storyboard in Resources */, F717402D24F699A5000C87D5 /* NCFavorite.storyboard in Resources */, F723B3DD22FC6D1D00301EFE /* NCShareCommentsCell.xib in Resources */, F78ACD4B21903F850088454D /* NCTrashListCell.xib in Resources */, @@ -4726,6 +4740,7 @@ F76882342C0DD1E7001CF441 /* NCDisplayView.swift in Sources */, F7C30DF6291BC0CA0017149B /* NCNetworkingE2EEUpload.swift in Sources */, F3DDFE232F1FB4C300A784C8 /* NCAssistantChatModel.swift in Sources */, + B568C2B52DA7AADD0072FCB4 /* NCMoreUserCell.swift in Sources */, F7501C332212E57500FB1415 /* NCMedia.swift in Sources */, F7411C552D7B26D700F57358 /* NCNetworking+ServerError.swift in Sources */, F72944F22A84246400246839 /* NCEndToEndMetadataV2.swift in Sources */, diff --git a/Tests/NextcloudUnitTests/MoreTests.swift b/Tests/NextcloudUnitTests/MoreTests.swift new file mode 100644 index 0000000000..0a96912994 --- /dev/null +++ b/Tests/NextcloudUnitTests/MoreTests.swift @@ -0,0 +1,37 @@ +// +// MoreTests.swift +// NextcloudTests +// +// Created by A200020526 on 09/06/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +@testable import Nextcloud +import XCTest + +final class MoreTests: XCTestCase { + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + // Any test you write for XCTest can be annotated as throws and async. + // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. + // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. + } + + func testPerformanceExample() throws { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. + } + } + +} diff --git a/iOSClient/More/Cells/BaseNCMoreCell.swift b/iOSClient/More/Cells/BaseNCMoreCell.swift new file mode 100644 index 0000000000..9b5b705cd1 --- /dev/null +++ b/iOSClient/More/Cells/BaseNCMoreCell.swift @@ -0,0 +1,62 @@ +// +// BaseNCMoreCell.swift +// Nextcloud +// +// Created by Milen on 15.06.23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// 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 . +// + +import Foundation +import UIKit + +class BaseNCMoreCell: UITableViewCell { + let selectionColor: UIView = UIView() + let defaultCornerRadius: CGFloat = 10.0 + + override var frame: CGRect { + get { + return super.frame + } + set (newFrame) { + var frame = newFrame + let newWidth = frame.width * 0.90 + let space = (frame.width - newWidth) / 2 + frame.size.width = newWidth + frame.origin.x += space + super.frame = frame + } + } + + open func setupCell(account: String, controller: NCMainTabBarController?) {} + + override func awakeFromNib() { + super.awakeFromNib() + + selectedBackgroundView = selectionColor + backgroundColor = .secondarySystemGroupedBackground + applyCornerRadius() + } + + func applyCornerRadius() { + layer.cornerRadius = defaultCornerRadius + } + + func removeCornerRadius() { + layer.cornerRadius = 0 + } +} diff --git a/iOSClient/More/Cells/NCMoreAppSuggestionsCell.swift b/iOSClient/More/Cells/NCMoreAppSuggestionsCell.swift new file mode 100644 index 0000000000..52dfb9e3f7 --- /dev/null +++ b/iOSClient/More/Cells/NCMoreAppSuggestionsCell.swift @@ -0,0 +1,97 @@ +// +// NCMoreAppSuggestionsCell.swift +// Nextcloud +// +// Created by Milen on 14.06.23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// 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 . +// + +import Foundation +import UIKit +import SafariServices +import SwiftUI +import NextcloudKit + +class NCMoreAppSuggestionsCell: BaseNCMoreCell { + @IBOutlet weak var assistantView: UIStackView! + @IBOutlet weak var talkView: UIStackView! + @IBOutlet weak var notesView: UIStackView! + @IBOutlet weak var moreAppsView: UIStackView! + + static let reuseIdentifier = "NCMoreAppSuggestionsCell" + var controller: NCMainTabBarController? + + static func fromNib() -> UINib { + return UINib(nibName: "NCMoreAppSuggestionsCell", bundle: nil) + } + + override func awakeFromNib() { + super.awakeFromNib() + backgroundColor = .clear + + assistantView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(assistantTapped(_:)))) + talkView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(talkTapped(_:)))) + notesView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(notesTapped(_:)))) + moreAppsView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(moreAppsTapped(_:)))) + } + + override func setupCell(account: String, controller: NCMainTabBarController?) { + guard let capabilities = NCNetworking.shared.capabilities[account] else { + return + } + + assistantView.isHidden = !capabilities.assistantEnabled + self.controller = controller + } + + @objc func assistantTapped(_ sender: Any?) { + if let viewController = self.window?.rootViewController { + let assistant = NCAssistant() + .environmentObject(NCAssistantModel(controller: self.controller)) + let hostingController = UIHostingController(rootView: assistant) + viewController.present(hostingController, animated: true, completion: nil) + } + } + + @objc func talkTapped(_ sender: Any?) { + guard let url = URL(string: NCGlobal.shared.talkSchemeUrl) else { return } + + if UIApplication.shared.canOpenURL(url) { + UIApplication.shared.open(url) + } else { + guard let url = URL(string: NCGlobal.shared.talkAppStoreUrl) else { return } + UIApplication.shared.open(url) + } + } + + @objc func notesTapped(_ sender: Any?) { + guard let url = URL(string: NCGlobal.shared.notesSchemeUrl) else { return } + + if UIApplication.shared.canOpenURL(url) { + UIApplication.shared.open(url) + } else { + guard let url = URL(string: NCGlobal.shared.notesAppStoreUrl) else { return } + UIApplication.shared.open(url) + } + } + + @objc func moreAppsTapped(_ sender: Any?) { + guard let url = URL(string: NCGlobal.shared.moreAppsUrl) else { return } + UIApplication.shared.open(url) + } +} diff --git a/iOSClient/More/Cells/NCMoreUserCell.swift b/iOSClient/More/Cells/NCMoreUserCell.swift new file mode 100644 index 0000000000..1d6e30cece --- /dev/null +++ b/iOSClient/More/Cells/NCMoreUserCell.swift @@ -0,0 +1,44 @@ +// +// NCMoreUserCell.swift +// Nextcloud +// +// Created by Milen on 14.06.23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// 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 . +// + +import Foundation +import MarqueeLabel + +class NCMoreUserCell: BaseNCMoreCell { + @IBOutlet weak var displayName: UILabel! + @IBOutlet weak var avatar: UIImageView! + @IBOutlet weak var icon: UIImageView! + @IBOutlet weak var status: MarqueeLabel! + + static let reuseIdentifier = "NCMoreUserCell" + + static func fromNib() -> UINib { + return UINib(nibName: "NCMoreUserCell", bundle: nil) + } + + override func awakeFromNib() { + super.awakeFromNib() + + icon.makeCircularBackground(withColor: .systemBackground) + } +} diff --git a/iOSClient/More/Cells/NCMoreUserCell.xib b/iOSClient/More/Cells/NCMoreUserCell.xib new file mode 100755 index 0000000000..477fe2539e --- /dev/null +++ b/iOSClient/More/Cells/NCMoreUserCell.xib @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/More/NCMore.storyboard b/iOSClient/More/NCMore.storyboard new file mode 100644 index 0000000000..57caeedfce --- /dev/null +++ b/iOSClient/More/NCMore.storyboard @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/More/NCMore.swift b/iOSClient/More/NCMore.swift new file mode 100644 index 0000000000..11b04a1ea4 --- /dev/null +++ b/iOSClient/More/NCMore.swift @@ -0,0 +1,451 @@ +// +// NCMore.swift +// Nextcloud +// +// Created by Marino Faggiana on 03/04/17. +// Copyright © 2017 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// 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 . +// + +import UIKit +import NextcloudKit +import SafariServices +import SwiftUI +import Foundation + +class NCMore: UIViewController, UITableViewDelegate, UITableViewDataSource { + @IBOutlet weak var tableView: UITableView! + @IBOutlet weak var labelQuota: UILabel! + @IBOutlet weak var labelQuotaExternalSite: UILabel! + @IBOutlet weak var progressQuota: UIProgressView! + @IBOutlet weak var viewQuota: UIView! + + private var userMenu: [NKExternalSite] = [] + private var functionMenu: [NKExternalSite] = [] + private var externalSiteMenu: [NKExternalSite] = [] + private var settingsMenu: [NKExternalSite] = [] + private var quotaMenu: [NKExternalSite] = [] + private let applicationHandle = NCApplicationHandle() + private let utilityFileSystem = NCUtilityFileSystem() + private let utility = NCUtility() + private let database = NCManageDatabase.shared + + private struct Section { + var items: [NKExternalSite] + var type: SectionType + + enum SectionType { + case moreApps + case regular + } + } + private var sections: [Section] = [] + + @MainActor + private var session: NCSession.Session { + NCSession.shared.getSession(controller: tabBarController) + } + + private var controller: NCMainTabBarController? { + self.tabBarController as? NCMainTabBarController + } + + var mainNavigationController: NCMainNavigationController? { + self.navigationController as? NCMainNavigationController + } + + // MARK: - View Life Cycle + + override func viewDidLoad() { + super.viewDidLoad() + + self.navigationItem.title = NSLocalizedString("_more_", comment: "") + view.backgroundColor = .systemGroupedBackground + + tableView.insetsContentViewsToSafeArea = false + tableView.delegate = self + tableView.dataSource = self + tableView.backgroundColor = .systemGroupedBackground + tableView.register(NCMoreAppSuggestionsCell.fromNib(), forCellReuseIdentifier: NCMoreAppSuggestionsCell.reuseIdentifier) + + // create tap gesture recognizer + let tapQuota = UITapGestureRecognizer(target: self, action: #selector(tapLabelQuotaExternalSite(_:))) + labelQuotaExternalSite.isUserInteractionEnabled = true + labelQuotaExternalSite.addGestureRecognizer(tapQuota) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + Task { + let capabilities = await database.getCapabilities(account: self.session.account) ?? NKCapabilities.Capabilities() + await mainNavigationController?.createPlusMenu(session: self.session, capabilities: capabilities, isHidden: true) + } + + loadItems() + tableView.reloadData() + } + + // MARK: - + + func loadItems() { + guard let tableAccount = self.database.getTableAccount(predicate: NSPredicate(format: "account == %@", session.account)), + let capabilities = NCNetworking.shared.capabilities[tableAccount.account] else { + return + } + var item = NKExternalSite() + var quota: String = "" + + // Clear + userMenu.removeAll() + functionMenu.removeAll() + externalSiteMenu.removeAll() + settingsMenu.removeAll() + quotaMenu.removeAll() + sections.removeAll() + labelQuotaExternalSite.text = "" + progressQuota.progressTintColor = NCBrandColor.shared.getElement(account: session.account) + + // ITEM : User + item = NKExternalSite() +// item.name = tableAccount.email + if !tableAccount.email.isEmpty { + item.name = tableAccount.email + } else if tableAccount.email.isEmpty {//}|| tableAccount.alias.isEmpty { + item.name = tableAccount.displayName + } else { + item.name = tableAccount.alias + } + item.icon = "user"//utility.loadUserImage(for: tableAccount.user, displayName: tableAccount.displayName, urlBase: tableAccount.urlBase) +// item.url = "segueRecent" +// item.order = 10 + userMenu.append(item) + + // ITEM : Recent + item = NKExternalSite() + item.name = "_recent_" + item.icon = "History" //"clock.arrow.circlepath" + item.url = "segueRecent" + item.order = 20 + functionMenu.append(item) + + /* + if capabilities.capabilityActivityEnabled { + // ITEM : Activity + item = NKExternalSite() + item.name = "_activity_" + item.icon = "bolt" + item.url = "segueActivity" + item.order = 30 + functionMenu.append(item) + } + */ + + if capabilities.assistantEnabled, NCBrandOptions.shared.disable_show_more_nextcloud_apps_in_settings { + // ITEM : Assistant + item = NKExternalSite() + item.name = "_assistant_" + item.icon = "sparkles" + item.url = "openAssistant" + item.order = 40 + functionMenu.append(item) + } + + // ITEM : Shares + if capabilities.fileSharingApiEnabled { + item = NKExternalSite() + item.name = "_list_shares_" + item.icon = "share" //"person.badge.plus" + item.url = "segueShares" + item.order = 50 + functionMenu.append(item) + } + + // ITEM : Offline + item = NKExternalSite() + item.name = "_manage_file_offline_" + item.icon = "cloudDownload" + item.url = "segueOffline" + item.order = 60 + functionMenu.append(item) + + // ITEM : Groupfolders + if capabilities.groupfoldersEnabled { + item = NKExternalSite() + item.name = "_group_folders_" + item.icon = "person.2" + item.url = "segueGroupfolders" + item.order = 61 + functionMenu.append(item) + } + + // ITEM : Scan + item = NKExternalSite() + item.name = "_scanned_images_" + item.icon = "scan" //"doc.text.viewfinder" + item.url = "openStoryboardNCScan" + item.order = 70 + functionMenu.append(item) + + // ITEM : Trash + item = NKExternalSite() + item.name = "_trash_view_" + item.icon = "trashIcon" + item.url = "segueTrash" + item.order = 80 + functionMenu.append(item) + + // ITEM : HANDLE + applicationHandle.loadItems(functionMenu: &functionMenu) + + // ORDER ITEM + functionMenu = functionMenu.sorted(by: { $0.order < $1.order }) + + // ITEM : Settings + item = NKExternalSite() + item.name = "_settings_" + item.icon = "settings" + item.url = "openSettings" + settingsMenu.append(item) + + if !quotaMenu.isEmpty { + let item = quotaMenu[0] + labelQuotaExternalSite.text = item.name + } + + // Display Name user & Quota + if tableAccount.quotaRelative > 0 { + progressQuota.progress = Float(tableAccount.quotaRelative) / 100 + } else { + progressQuota.progress = 0 + } + + switch tableAccount.quotaTotal { + case -1: + quota = "0" + case -2: + quota = NSLocalizedString("_quota_space_unknown_", comment: "") + case -3: + quota = NSLocalizedString("_quota_space_unlimited_", comment: "") + default: + quota = utilityFileSystem.transformedSize(tableAccount.quotaTotal) + } + let quotaUsed: String = utilityFileSystem.transformedSize(tableAccount.quotaUsed) + + labelQuota.text = String.localizedStringWithFormat(NSLocalizedString("_quota_using_", comment: ""), quotaUsed, quota) + + // ITEM : External + if NCBrandOptions.shared.disable_more_external_site == false, + capabilities.externalSites { + if let externalSites = self.database.getAllExternalSites(account: session.account) { + for externalSite in externalSites { + if !externalSite.name.isEmpty, !externalSite.url.isEmpty, let urlEncoded = externalSite.url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) { + item = NKExternalSite() + item.name = externalSite.name + item.url = urlEncoded + item.icon = "network" + if externalSite.type == "settings" { + item.icon = "settings" + } + externalSiteMenu.append(item) + } + } + } + } + + loadSections() + } + + private func loadSections() { + if !NCBrandOptions.shared.disable_show_more_nextcloud_apps_in_settings { + sections.append(Section(items: [NKExternalSite()], type: .moreApps)) + } + + if !userMenu.isEmpty { + sections.append(Section(items: userMenu, type: .regular)) + } + + if !functionMenu.isEmpty { + sections.append(Section(items: functionMenu, type: .regular)) + } + + if !externalSiteMenu.isEmpty { + sections.append(Section(items: externalSiteMenu, type: .regular)) + } + + if !settingsMenu.isEmpty { + sections.append(Section(items: settingsMenu, type: .regular)) + } + } + + // MARK: - Action + + @objc func tapLabelQuotaExternalSite(_ sender: Any?) { + if !quotaMenu.isEmpty { + let item = quotaMenu[0] + if let browserWebVC = UIStoryboard(name: "NCBrowserWeb", bundle: nil).instantiateInitialViewController() as? NCBrowserWeb { + browserWebVC.urlBase = item.url + browserWebVC.isHiddenButtonExit = true + + self.navigationController?.pushViewController(browserWebVC, animated: true) + self.navigationController?.navigationBar.isHidden = false + } + } + } + + // MARK: - + + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return 50 + } + + func numberOfSections(in tableView: UITableView) -> Int { + return sections.count + } + + func tableView(_ tableView: UITableView, heightForHeaderInSection index: Int) -> CGFloat { + let section = sections[index] + + if section.type == .moreApps || (index > 0 && sections[index - 1].type == .moreApps) { + return 1 + } else { + return 20 + } + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection index: Int) -> Int { + return sections[index].items.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let section = sections[indexPath.section] + + if section.type == .moreApps { + guard let cell = tableView.dequeueReusableCell(withIdentifier: NCMoreAppSuggestionsCell.reuseIdentifier, for: indexPath) as? NCMoreAppSuggestionsCell else { return UITableViewCell() } + cell.setupCell(account: session.account, controller: controller) + return cell + } else { + guard let cell = tableView.dequeueReusableCell(withIdentifier: CCCellMore.reuseIdentifier, for: indexPath) as? CCCellMore else { return UITableViewCell() } + + cell.setupCell(account: session.account, controller: controller) + + let item = sections[indexPath.section].items[indexPath.row] + + cell.imageIcon?.image = utility.loadImage(named: item.icon, colors: [NCBrandColor.shared.iconImageColor], size: 24).withTintColor(NCBrandColor.shared.iconImageColor) + cell.imageIcon?.contentMode = .scaleAspectFit + cell.labelText?.text = NSLocalizedString(item.name, comment: "") + cell.labelText.textColor = NCBrandColor.shared.textColor + + if indexPath.section == 0 { + if indexPath.row == 0 { + cell.accessoryType = UITableViewCell.AccessoryType.none + } + } + else { + cell.accessoryType = UITableViewCell.AccessoryType.disclosureIndicator + } + cell.separator.backgroundColor = .separator + cell.separatorHeigth.constant = 0.4 + + cell.removeCornerRadius() + let rows = tableView.numberOfRows(inSection: indexPath.section) + + if indexPath.row == 0 { + cell.applyCornerRadius() + if indexPath.row == rows - 1 { + cell.separator.backgroundColor = .clear + cell.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner, .layerMaxXMaxYCorner, .layerMinXMaxYCorner] + } else { + cell.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMinXMinYCorner] + } + } else if indexPath.row == rows - 1 { + cell.applyCornerRadius() + cell.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMinXMaxYCorner] + cell.separator.backgroundColor = .clear + } + + return cell + } + } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let item = sections[indexPath.section].items[indexPath.row] + + // Action + if item.url.contains("segue") && !item.url.contains("//") { + self.navigationController?.performSegue(withIdentifier: item.url, sender: self) + } else if item.url.contains("openStoryboard") && !item.url.contains("//") { + let nameStoryboard = item.url.replacingOccurrences(of: "openStoryboard", with: "") + let storyboard = UIStoryboard(name: nameStoryboard, bundle: nil) + if let controller = storyboard.instantiateInitialViewController() { + if let vc = controller.topMostViewController() as? NCScan { + vc.controller = self.controller + } + controller.modalPresentationStyle = UIModalPresentationStyle.pageSheet + present(controller, animated: true, completion: nil) + } + } else if item.url.contains("//") { + if let browserWebVC = UIStoryboard(name: "NCBrowserWeb", bundle: nil).instantiateInitialViewController() as? NCBrowserWeb { + browserWebVC.urlBase = item.url + browserWebVC.isHiddenButtonExit = true + browserWebVC.titleBrowser = item.name + self.navigationController?.pushViewController(browserWebVC, animated: true) + self.navigationController?.navigationBar.isHidden = false + } + } else if item.url == "logout" { + let alertController = UIAlertController(title: "", message: NSLocalizedString("_want_delete_", comment: ""), preferredStyle: .alert) + let actionYes = UIAlertAction(title: NSLocalizedString("_yes_delete_", comment: ""), style: .default) { (_: UIAlertAction) in + if NCBrandOptions.shared.disable_intro { + if let viewController = UIStoryboard(name: "NCLogin", bundle: nil).instantiateViewController(withIdentifier: "NCLogin") as? NCLogin { + viewController.controller = self.controller + let navigationController = UINavigationController(rootViewController: viewController) + navigationController.modalPresentationStyle = .fullScreen + self.present(navigationController, animated: true) + } + } else { + if let navigationController = UIStoryboard(name: "NCIntro", bundle: nil).instantiateInitialViewController() as? UINavigationController { + if let viewController = navigationController.topViewController as? NCIntroViewController { + viewController.controller = self.controller + } + navigationController.modalPresentationStyle = .fullScreen + self.present(navigationController, animated: true) + } + } + } + + let actionNo = UIAlertAction(title: NSLocalizedString("_no_delete_", comment: ""), style: .default) { (_: UIAlertAction) in + print("You've pressed No button") + } + + alertController.addAction(actionYes) + alertController.addAction(actionNo) + self.present(alertController, animated: true, completion: nil) + } else if item.url == "openAssistant" { + let assistant = NCAssistant() + .environmentObject(NCAssistantModel(controller: self.controller)) + let hostingController = UIHostingController(rootView: assistant) + present(hostingController, animated: true, completion: nil) + } else if item.url == "openSettings" { + let settingsView = NCSettingsView(model: NCSettingsModel(controller: self.controller)) + let settingsController = UIHostingController(rootView: settingsView) + settingsController.title = NSLocalizedString("_settings_", comment: "") + navigationController?.pushViewController(settingsController, animated: true) + } else { + applicationHandle.didSelectItem(item, viewController: self) + } + } +}