From 3d9eddf3f2a202cdca1c770ddb62b15104a4e9c9 Mon Sep 17 00:00:00 2001 From: TSI-amrutwaghmare <96108296+TSI-amrutwaghmare@users.noreply.github.com> Date: Mon, 23 Oct 2023 14:24:51 +0530 Subject: [PATCH 1/4] NMC 1935 - Notification screen customisation --- .../NCNotificationText.swift | 85 ++++++++ .../Notification/NCNotification.storyboard | 202 ++++++++---------- iOSClient/Notification/NCNotification.swift | 30 +-- 3 files changed, 187 insertions(+), 130 deletions(-) create mode 100644 Tests/NextcloudUnitTests/NCNotificationText.swift diff --git a/Tests/NextcloudUnitTests/NCNotificationText.swift b/Tests/NextcloudUnitTests/NCNotificationText.swift new file mode 100644 index 0000000000..1a7e0b2345 --- /dev/null +++ b/Tests/NextcloudUnitTests/NCNotificationText.swift @@ -0,0 +1,85 @@ +// +// NCNotificationText.swift +// NextcloudUnitTests +// +// Created by Amrut Waghmare on 18/10/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +@testable import Nextcloud +import XCTest +import NextcloudKit + +class NCNotificationText: XCTestCase { + var viewController : NCNotification! + + override func setUpWithError() throws { + // Step 1. Create an instance of UIStoryboard + let storyboard = UIStoryboard(name: "NCNotification", bundle: nil) + // Step 2. Instantiate UIViewController with Storyboard ID + viewController = storyboard.instantiateViewController(withIdentifier: "NCNotification.storyboard") as? NCNotification + + // Step 3. Make the viewDidLoad() execute. + viewController.loadViewIfNeeded() + } + + override func tearDownWithError() throws { + viewController = nil + } + + //Test that a cell with the correct reuse identifier is dequeued + func testTableViewCellDequeue() { + let notification = NKNotifications() + viewController.notifications = [notification] + let tableView = UITableView() + tableView.register(NCNotificationCell.self, forCellReuseIdentifier: "Cell") + let indexPath = IndexPath(row: 0, section: 0) + let cell = viewController.tableView(tableView, cellForRowAt: indexPath) as? NCNotificationCell + XCTAssertNotNil(cell) + XCTAssertEqual(cell?.reuseIdentifier, "Cell") + } + + //Test that the cell's icon is set image + func testTableViewCellIcon() { + let notification = NKNotifications() + viewController.notifications = [notification] + let tableView = UITableView() + tableView.register(NCNotificationCell.self, forCellReuseIdentifier: "Cell") + let indexPath = IndexPath(row: 0, section: 0) + let cell = viewController.tableView(tableView, cellForRowAt: indexPath) as? NCNotificationCell + XCTAssertNotNil(cell?.icon.image) + } + + //Test that the cell's primary and secondary buttons are set up correctly + func testTableViewCellButtons() { + let notification = NKNotifications() + notification.actions = Data("[{\"label\":\"OK\",\"primary\":true},{\"label\":\"Cancel\",\"primary\":false}]".utf8) + viewController.notifications = [notification] + let tableView = UITableView() + tableView.register(NCNotificationCell.self, forCellReuseIdentifier: "Cell") + let indexPath = IndexPath(row: 0, section: 0) + let cell = viewController.tableView(tableView, cellForRowAt: indexPath) as? NCNotificationCell + XCTAssertEqual(cell?.primary.title(for: .normal), "OK") + XCTAssertEqual(cell?.secondary.title(for: .normal), "Cancel") + } + + //Test that the cell's date label is set correctly + func testTableViewCellDate() { + let notification = NKNotifications() + notification.date = NSDate() + viewController.notifications = [notification] + let tableView = UITableView() + tableView.register(NCNotificationCell.self, forCellReuseIdentifier: "Cell") + let indexPath = IndexPath(row: 0, section: 0) + let cell = viewController.tableView(tableView, cellForRowAt: indexPath) as? NCNotificationCell + XCTAssertEqual(cell?.date.text, "less than a minute ago") + } + + //Test with a color that is image not nil + func testImageNotNil() { + let color = UIColor(red: 0.5, green: 0.5, blue: 0.5, alpha: 1.0) + let image = UIImage().imageColor(color) + XCTAssertNotNil(image, "Image should not be nil.") + + } +} diff --git a/iOSClient/Notification/NCNotification.storyboard b/iOSClient/Notification/NCNotification.storyboard index fb122ec81a..a89ba02d24 100644 --- a/iOSClient/Notification/NCNotification.storyboard +++ b/iOSClient/Notification/NCNotification.storyboard @@ -1,193 +1,163 @@ - + - + - + - - + + - - + + - - + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + - - + + - - + + - - - - - - - - - - - - - - - - - - - + - + + diff --git a/iOSClient/Notification/NCNotification.swift b/iOSClient/Notification/NCNotification.swift index 5abf19d3b6..f011b5bb8d 100644 --- a/iOSClient/Notification/NCNotification.swift +++ b/iOSClient/Notification/NCNotification.swift @@ -56,6 +56,7 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate { tableView.rowHeight = UITableView.automaticDimension tableView.estimatedRowHeight = 50.0 tableView.backgroundColor = .systemBackground + tableView.allowsSelection = false refreshControl?.action(for: .valueChanged) { _ in Task { @@ -89,6 +90,11 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate { @objc func viewClose() { self.dismiss(animated: true, completion: nil) } + + // MARK: - NotificationCenter + @objc func initialize() { + getNetwokingNotification() + } // MARK: - Table @@ -133,6 +139,8 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate { if let image = image { cell.icon.image = image.withTintColor(NCBrandColor.shared.getElement(account: session.account), renderingMode: .alwaysOriginal) + } else { + cell.icon.image = utility.loadImage(named: "bell", color: NCBrandColor.shared.iconColor) } // Avatar @@ -173,23 +181,15 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate { cell.primary.isEnabled = false cell.primary.isHidden = true cell.primary.titleLabel?.font = .systemFont(ofSize: 15) - cell.primary.layer.cornerRadius = 15 - cell.primary.layer.masksToBounds = true - cell.primary.layer.backgroundColor = NCBrandColor.shared.getElement(account: session.account).cgColor cell.primary.setTitleColor(.white, for: .normal) - - cell.more.isEnabled = false - cell.more.isHidden = true - cell.more.titleLabel?.font = .systemFont(ofSize: 15) - cell.more.layer.cornerRadius = 15 - cell.more.layer.masksToBounds = true - cell.more.layer.backgroundColor = NCBrandColor.shared.getElement(account: session.account).cgColor - cell.more.setTitleColor(.white, for: .normal) + cell.primary.layer.cornerRadius = 10 + cell.primary.layer.masksToBounds = true + cell.primary.layer.backgroundColor = NCBrandColor.shared.notificationAction.cgColor cell.secondary.isEnabled = false cell.secondary.isHidden = true cell.secondary.titleLabel?.font = .systemFont(ofSize: 15) - cell.secondary.layer.cornerRadius = 15 + cell.secondary.layer.cornerRadius = 10 cell.secondary.layer.masksToBounds = true cell.secondary.layer.borderWidth = 1 cell.secondary.layer.borderColor = NCBrandColor.shared.iconImageColor2.cgColor @@ -225,7 +225,10 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate { cell.secondary.setTitle(label, for: .normal) } } - } else if jsonActions.count >= 3 { + } + + let widthPrimary = cell.primary.intrinsicContentSize.width + 48; + let widthSecondary = cell.secondary.intrinsicContentSize.width + 48; cell.more.isEnabled = true cell.more.isHidden = false @@ -369,7 +372,6 @@ class NCNotificationCell: UITableViewCell { @IBOutlet weak var remove: UIButton! @IBOutlet weak var primary: UIButton! @IBOutlet weak var secondary: UIButton! - @IBOutlet weak var more: UIButton! @IBOutlet weak var avatarLeadingMargin: NSLayoutConstraint! @IBOutlet weak var primaryWidth: NSLayoutConstraint! @IBOutlet weak var secondaryWidth: NSLayoutConstraint! From c7e8c5b648e3f2b4aeeb08b43d1e6c8d3aa59cf6 Mon Sep 17 00:00:00 2001 From: harshada-15-tsys Date: Wed, 9 Apr 2025 16:56:28 +0530 Subject: [PATCH 2/4] NMC 1935 - Notification screen customisation --- Nextcloud.xcodeproj/project.pbxproj | 10 ++++ iOSClient/Notification/NCNotification.swift | 61 +++++++++++++++++---- 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index da11cd9ed5..6833a1230c 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -85,6 +85,10 @@ 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 */; }; + B543154C2DA690B700981E7E /* NCNotificationText.swift in Sources */ = {isa = PBXBuildFile; fileRef = B543154B2DA690B700981E7E /* NCNotificationText.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 +1267,8 @@ 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 = ""; }; + B543154B2DA690B700981E7E /* NCNotificationText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCNotificationText.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 +2093,8 @@ children = ( F34BDB3B2F574A58007A222C /* BidiSafeFilenameTests.swift */, AA52EB452D42AC5A0089C348 /* Placeholder.swift */, + B543154B2DA690B700981E7E /* NCNotificationText.swift */, + AF8ED1FB2757821000B8DBC4 /* NextcloudUnitTests.swift */, ); path = NextcloudUnitTests; sourceTree = ""; @@ -4220,6 +4228,8 @@ F34BDB3C2F574A58007A222C /* BidiSafeFilenameTests.swift in Sources */, F372087D2BAB4C0F006B5430 /* TestConstants.swift in Sources */, F78E2D6C29AF02DB0024D4F3 /* Database.swift in Sources */, + B543154C2DA690B700981E7E /* NCNotificationText.swift in Sources */, + F7817CFE29801A3500FFBC65 /* Data+Extension.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/iOSClient/Notification/NCNotification.swift b/iOSClient/Notification/NCNotification.swift index f011b5bb8d..cd744d99e9 100644 --- a/iOSClient/Notification/NCNotification.swift +++ b/iOSClient/Notification/NCNotification.swift @@ -26,11 +26,13 @@ import UIKit import NextcloudKit import SwiftyJSON -class NCNotification: UITableViewController, NCNotificationCellDelegate { +class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmptyDataSetDelegate { let utilityFileSystem = NCUtilityFileSystem() let utility = NCUtility() var notifications: [NKNotifications] = [] var session: NCSession.Session! + private let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! + var emptyDataSet: NCEmptyDataSet? @MainActor var controller: NCMainTabBarController? { @@ -51,6 +53,7 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate { view.backgroundColor = .systemBackground navigationController?.setNavigationBarAppearance() + self.session = NCSession.shared.getSession(controller: controller) tableView.tableFooterView = UIView() tableView.rowHeight = UITableView.automaticDimension @@ -67,8 +70,17 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate { let close = UIBarButtonItem(title: NSLocalizedString("_close_", comment: ""), style: .plain) { self.dismiss(animated: true) } + // Empty + let offset = (self.navigationController?.navigationBar.bounds.height ?? 0) - 20 + emptyDataSet = NCEmptyDataSet(view: tableView, offset: -offset, delegate: self) + + } - self.navigationItem.leftBarButtonItems = [close] + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + appDelegate.activeViewController = self + navigationController?.setNavigationBarAppearance() + AnalyticsHelper.shared.trackEvent(eventName: .SCREEN_EVENT__NOTIFICATIONS) } override func viewDidAppear(_ animated: Bool) { @@ -93,18 +105,43 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate { // MARK: - NotificationCenter @objc func initialize() { - getNetwokingNotification() + getNetwokingNotification(nil) } + // MARK: - Empty + + func emptyDataSetView(_ view: NCEmptyView) { + + if self.dataSourceTask?.state == .running { + view.emptyImage.image = UIImage(named: "networkInProgress")?.image(color: .gray, size: UIScreen.main.bounds.width) + view.emptyTitle.text = NSLocalizedString("_request_in_progress_", comment: "") + view.emptyDescription.text = "" + } else { + view.emptyImage.image = utility.loadImage(named: "bell", colors: [.gray], size: UIScreen.main.bounds.width) + view.emptyTitle.text = NSLocalizedString("_no_notification_", comment: "") + view.emptyDescription.text = "" + } + } + // MARK: - Table override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + emptyDataSet?.numberOfItemsInSection(notifications.count, section: section) return notifications.count } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { +// let notification = notifications[indexPath.row] + let notification = notifications[indexPath.row] + if notification.app == "files_sharing" { + NCActionCenter.shared.viewerFile(account: session.account, fileId: notification.objectId, viewController: self) + } else { + NCApplicationHandle().didSelectNotification(notification, viewController: self) + } + guard let notification = NCApplicationHandle().didSelectNotification(notifications[indexPath.row], viewController: self) else { return } + do { if let subjectRichParameters = notification.subjectRichParameters, let json = try JSONSerialization.jsonObject(with: subjectRichParameters, options: .mutableContainers) as? [String: Any], @@ -138,9 +175,9 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate { } if let image = image { - cell.icon.image = image.withTintColor(NCBrandColor.shared.getElement(account: session.account), renderingMode: .alwaysOriginal) + cell.icon.image = image.withTintColor(NCBrandColor.shared.iconColor, renderingMode: .alwaysOriginal) } else { - cell.icon.image = utility.loadImage(named: "bell", color: NCBrandColor.shared.iconColor) + cell.icon.image = utility.loadImage(named: "bell", colors: [NCBrandColor.shared.iconColor]) } // Avatar @@ -169,14 +206,14 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate { cell.date.text = DateFormatter.localizedString(from: notification.date as Date, dateStyle: .medium, timeStyle: .medium) cell.notification = notification - cell.date.text = utility.getRelativeDateTitle(notification.date as Date) - cell.date.textColor = NCBrandColor.shared.iconImageColor2 + cell.date.text = utility.dateDiff(notification.date as Date) + cell.date.textColor = .gray cell.subject.text = notification.subject cell.subject.textColor = NCBrandColor.shared.textColor cell.message.text = notification.message.replacingOccurrences(of: "
", with: "\n") - cell.message.textColor = NCBrandColor.shared.textColor2 + cell.message.textColor = .gray - cell.remove.setImage(utility.loadImage(named: "xmark", colors: [NCBrandColor.shared.iconImageColor]), for: .normal) + cell.remove.setImage(UIImage(named: "xmark")!.image(color: .gray, size: 20), for: .normal) cell.primary.isEnabled = false cell.primary.isHidden = true @@ -192,9 +229,9 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate { cell.secondary.layer.cornerRadius = 10 cell.secondary.layer.masksToBounds = true cell.secondary.layer.borderWidth = 1 - cell.secondary.layer.borderColor = NCBrandColor.shared.iconImageColor2.cgColor - cell.secondary.layer.backgroundColor = UIColor.secondarySystemBackground.cgColor - cell.secondary.setTitleColor(NCBrandColor.shared.iconImageColor2, for: .normal) + cell.secondary.layer.borderColor = NCBrandColor.shared.notificationAction.cgColor + cell.secondary.layer.backgroundColor = UIColor.clear.cgColor + cell.secondary.setTitleColor(NCBrandColor.shared.notificationAction, for: .normal) // Action if let actions = notification.actions, From 2a4be50b4f63ed8a3e17205f3df71ab13ee44db3 Mon Sep 17 00:00:00 2001 From: harshada-15-tsys Date: Tue, 30 Sep 2025 22:04:13 +0530 Subject: [PATCH 3/4] NMC 1935 - Notification screen customisation changes --- iOSClient/Notification/NCNotification.swift | 97 ++++++++++----------- 1 file changed, 45 insertions(+), 52 deletions(-) diff --git a/iOSClient/Notification/NCNotification.swift b/iOSClient/Notification/NCNotification.swift index cd744d99e9..bf67feeb06 100644 --- a/iOSClient/Notification/NCNotification.swift +++ b/iOSClient/Notification/NCNotification.swift @@ -30,6 +30,7 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty let utilityFileSystem = NCUtilityFileSystem() let utility = NCUtility() var notifications: [NKNotifications] = [] + var dataSourceTask: URLSessionTask? var session: NCSession.Session! private let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! var emptyDataSet: NCEmptyDataSet? @@ -105,7 +106,7 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty // MARK: - NotificationCenter @objc func initialize() { - getNetwokingNotification(nil) + getNetwokingNotification() } // MARK: - Empty @@ -175,7 +176,8 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty } if let image = image { - cell.icon.image = image.withTintColor(NCBrandColor.shared.iconColor, renderingMode: .alwaysOriginal) + cell.icon.image = image.withTintColor(NCBrandColor.shared.brandElement, renderingMode: .alwaysOriginal) +// cell.icon.image = image.withTintColor(NCBrandColor.shared.getElement(account: session.account), renderingMode: .alwaysOriginal) } else { cell.icon.image = utility.loadImage(named: "bell", colors: [NCBrandColor.shared.iconColor]) } @@ -206,7 +208,7 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty cell.date.text = DateFormatter.localizedString(from: notification.date as Date, dateStyle: .medium, timeStyle: .medium) cell.notification = notification - cell.date.text = utility.dateDiff(notification.date as Date) + cell.date.text = utility.getRelativeDateTitle(notification.date as Date) cell.date.textColor = .gray cell.subject.text = notification.subject cell.subject.textColor = NCBrandColor.shared.textColor @@ -290,15 +292,9 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty // MARK: - tap Action - func tapRemove(with notification: NKNotifications, sender: Any?) { - NextcloudKit.shared.setNotification(serverUrl: nil, idNotification: notification.idNotification, method: "DELETE", account: session.account) { task in - Task { - let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: self.session.account, - path: "\(notification.idNotification)", - name: "setNotification") - await NCNetworking.shared.networkingTasks.track(identifier: identifier, task: task) - } - } completion: { _, _, error in + func tapRemove(with notification: NKNotifications) { + + NextcloudKit.shared.setNotification(serverUrl: nil, idNotification: notification.idNotification, method: "DELETE", account: session.account) { _, _, error in if error == .success { if let index = self.notifications .firstIndex(where: { $0.idNotification == notification.idNotification }) { @@ -315,38 +311,36 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty } } - func tapAction(with notification: NKNotifications, label: String, sender: Any?) { - guard let actions = notification.actions, - let jsonActions = JSON(actions).array, - let action = jsonActions.first(where: { $0["label"].string == label }) - else { return } - - let serverUrl = action["link"].stringValue - let method = action["type"].stringValue - - if method == "WEB", var url = action["link"].url { - if notification.app == NCGlobal.shared.spreedName, - let roomToken = notification.objectId.split(separator: "/").first, - let talkUrl = URL(string: "nextcloudtalk://open-conversation?server=\(session.urlBase)&user=\(session.userId)&withRoomToken=\(roomToken)"), - UIApplication.shared.canOpenURL(talkUrl) { - - url = talkUrl + func tapAction(with notification: NKNotifications, label: String) { + if notification.app == NCGlobal.shared.spreedName, + let roomToken = notification.objectId.split(separator: "/").first, + let talkUrl = URL(string: "nextcloudtalk://open-conversation?server=\(session.urlBase)&user=\(session.userId)&withRoomToken=\(roomToken)"), + UIApplication.shared.canOpenURL(talkUrl) { + UIApplication.shared.open(talkUrl) + } else if let actions = notification.actions, + let jsonActions = JSON(actions).array, + let action = jsonActions.first(where: { $0["label"].string == label }) { + let serverUrl = action["link"].stringValue + let method = action["type"].stringValue + + if method == "WEB", let url = action["link"].url { + UIApplication.shared.open(url, options: [:], completionHandler: nil) + return } - UIApplication.shared.open(url) - return - } - - NextcloudKit.shared.setNotification(serverUrl: serverUrl, idNotification: 0, method: method, account: session.account) { task in - Task { - let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: self.session.account, - name: "setNotification") - await NCNetworking.shared.networkingTasks.track(identifier: identifier, task: task) - } - } completion: { _, _, error in - if error == .success { - if let index = self.notifications.firstIndex(where: { $0.idNotification == notification.idNotification }) { - self.notifications.remove(at: index) + NextcloudKit.shared.setNotification(serverUrl: serverUrl, idNotification: 0, method: method, account: session.account) { _, _, error in + if error == .success { + if let index = self.notifications.firstIndex(where: { $0.idNotification == notification.idNotification }) { + self.notifications.remove(at: index) + } + self.tableView.reloadData() + if self.navigationController?.presentingViewController != nil, notification.app == NCGlobal.shared.twoFactorNotificatioName { + self.dismiss(animated: true) + } + } else if error != .success { + NCContentPresenter().showError(error: error) + } else { + print("[Error] The user has been changed during networking process.") } self.tableView.reloadData() if self.navigationController?.presentingViewController != nil, notification.app == NCGlobal.shared.twoFactorNotificatioName { @@ -359,17 +353,16 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty } else { print("[Error] The user has been changed during networking process.") } - } + } // else: Action not found + } + + func tapMore(with notification: NKNotifications) { + toggleMenu(notification: notification) } // MARK: - Load notification networking - @MainActor - func getNetwokingNotification() async { - // If is already in-flight, do nothing - if await NCNetworking.shared.networkingTasks.isReading(identifier: "NCNotification") { - return - } + @objc func getNetwokingNotification() { self.tableView.reloadData() @@ -421,7 +414,7 @@ class NCNotificationCell: UITableViewCell { @IBAction func touchUpInsideRemove(_ sender: Any) { guard let notification = notification else { return } - delegate?.tapRemove(with: notification, sender: sender) + delegate?.tapRemove(with: notification) } @IBAction func touchUpInsidePrimary(_ sender: Any) { @@ -429,7 +422,7 @@ class NCNotificationCell: UITableViewCell { let button = sender as? UIButton, let label = button.titleLabel?.text else { return } - delegate?.tapAction(with: notification, label: label, sender: sender) + delegate?.tapAction(with: notification, label: label) } @IBAction func touchUpInsideSecondary(_ sender: Any) { @@ -437,7 +430,7 @@ class NCNotificationCell: UITableViewCell { let button = sender as? UIButton, let label = button.titleLabel?.text else { return } - delegate?.tapAction(with: notification, label: label, sender: sender) + delegate?.tapAction(with: notification, label: label) } } From 2dfba9e9ad8b8c16e86108afe5c0593a397f7822 Mon Sep 17 00:00:00 2001 From: harshada-15-tsys Date: Mon, 15 Dec 2025 15:20:04 +0530 Subject: [PATCH 4/4] NMC 1935 - Notification screen customisation changes --- .../Notification/NCNotification.storyboard | 202 ++++++++++-------- iOSClient/Notification/NCNotification.swift | 173 +++++++-------- 2 files changed, 196 insertions(+), 179 deletions(-) diff --git a/iOSClient/Notification/NCNotification.storyboard b/iOSClient/Notification/NCNotification.storyboard index a89ba02d24..fb122ec81a 100644 --- a/iOSClient/Notification/NCNotification.storyboard +++ b/iOSClient/Notification/NCNotification.storyboard @@ -1,163 +1,193 @@ - + - + - + - - + + - - + + - - + + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + + - - + + - - + + - + + + + + + + + + + + + + + + + + + + - - + diff --git a/iOSClient/Notification/NCNotification.swift b/iOSClient/Notification/NCNotification.swift index bf67feeb06..adf29943d0 100644 --- a/iOSClient/Notification/NCNotification.swift +++ b/iOSClient/Notification/NCNotification.swift @@ -26,14 +26,11 @@ import UIKit import NextcloudKit import SwiftyJSON -class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmptyDataSetDelegate { +class NCNotification: UITableViewController, NCNotificationCellDelegate { let utilityFileSystem = NCUtilityFileSystem() let utility = NCUtility() var notifications: [NKNotifications] = [] - var dataSourceTask: URLSessionTask? var session: NCSession.Session! - private let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! - var emptyDataSet: NCEmptyDataSet? @MainActor var controller: NCMainTabBarController? { @@ -54,13 +51,11 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty view.backgroundColor = .systemBackground navigationController?.setNavigationBarAppearance() - self.session = NCSession.shared.getSession(controller: controller) tableView.tableFooterView = UIView() tableView.rowHeight = UITableView.automaticDimension tableView.estimatedRowHeight = 50.0 tableView.backgroundColor = .systemBackground - tableView.allowsSelection = false refreshControl?.action(for: .valueChanged) { _ in Task { @@ -71,17 +66,8 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty let close = UIBarButtonItem(title: NSLocalizedString("_close_", comment: ""), style: .plain) { self.dismiss(animated: true) } - // Empty - let offset = (self.navigationController?.navigationBar.bounds.height ?? 0) - 20 - emptyDataSet = NCEmptyDataSet(view: tableView, offset: -offset, delegate: self) - - } - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - appDelegate.activeViewController = self - navigationController?.setNavigationBarAppearance() - AnalyticsHelper.shared.trackEvent(eventName: .SCREEN_EVENT__NOTIFICATIONS) + self.navigationItem.leftBarButtonItems = [close] } override func viewDidAppear(_ animated: Bool) { @@ -103,31 +89,10 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty @objc func viewClose() { self.dismiss(animated: true, completion: nil) } - - // MARK: - NotificationCenter - @objc func initialize() { - getNetwokingNotification() - } - - // MARK: - Empty - func emptyDataSetView(_ view: NCEmptyView) { - - if self.dataSourceTask?.state == .running { - view.emptyImage.image = UIImage(named: "networkInProgress")?.image(color: .gray, size: UIScreen.main.bounds.width) - view.emptyTitle.text = NSLocalizedString("_request_in_progress_", comment: "") - view.emptyDescription.text = "" - } else { - view.emptyImage.image = utility.loadImage(named: "bell", colors: [.gray], size: UIScreen.main.bounds.width) - view.emptyTitle.text = NSLocalizedString("_no_notification_", comment: "") - view.emptyDescription.text = "" - } - } - // MARK: - Table override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - emptyDataSet?.numberOfItemsInSection(notifications.count, section: section) return notifications.count } @@ -176,10 +141,7 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty } if let image = image { - cell.icon.image = image.withTintColor(NCBrandColor.shared.brandElement, renderingMode: .alwaysOriginal) -// cell.icon.image = image.withTintColor(NCBrandColor.shared.getElement(account: session.account), renderingMode: .alwaysOriginal) - } else { - cell.icon.image = utility.loadImage(named: "bell", colors: [NCBrandColor.shared.iconColor]) + cell.icon.image = image.withTintColor(NCBrandColor.shared.getElement(account: session.account), renderingMode: .alwaysOriginal) } // Avatar @@ -209,31 +171,39 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty cell.date.text = DateFormatter.localizedString(from: notification.date as Date, dateStyle: .medium, timeStyle: .medium) cell.notification = notification cell.date.text = utility.getRelativeDateTitle(notification.date as Date) - cell.date.textColor = .gray + cell.date.textColor = NCBrandColor.shared.iconImageColor2 cell.subject.text = notification.subject cell.subject.textColor = NCBrandColor.shared.textColor cell.message.text = notification.message.replacingOccurrences(of: "
", with: "\n") - cell.message.textColor = .gray + cell.message.textColor = NCBrandColor.shared.textColor2 - cell.remove.setImage(UIImage(named: "xmark")!.image(color: .gray, size: 20), for: .normal) + cell.remove.setImage(utility.loadImage(named: "xmark", colors: [NCBrandColor.shared.iconImageColor]), for: .normal) cell.primary.isEnabled = false cell.primary.isHidden = true cell.primary.titleLabel?.font = .systemFont(ofSize: 15) - cell.primary.setTitleColor(.white, for: .normal) - cell.primary.layer.cornerRadius = 10 + cell.primary.layer.cornerRadius = 15 cell.primary.layer.masksToBounds = true - cell.primary.layer.backgroundColor = NCBrandColor.shared.notificationAction.cgColor + cell.primary.layer.backgroundColor = NCBrandColor.shared.getElement(account: session.account).cgColor + cell.primary.setTitleColor(.white, for: .normal) + + cell.more.isEnabled = false + cell.more.isHidden = true + cell.more.titleLabel?.font = .systemFont(ofSize: 15) + cell.more.layer.cornerRadius = 15 + cell.more.layer.masksToBounds = true + cell.more.layer.backgroundColor = NCBrandColor.shared.getElement(account: session.account).cgColor + cell.more.setTitleColor(.white, for: .normal) cell.secondary.isEnabled = false cell.secondary.isHidden = true cell.secondary.titleLabel?.font = .systemFont(ofSize: 15) - cell.secondary.layer.cornerRadius = 10 + cell.secondary.layer.cornerRadius = 15 cell.secondary.layer.masksToBounds = true cell.secondary.layer.borderWidth = 1 - cell.secondary.layer.borderColor = NCBrandColor.shared.notificationAction.cgColor - cell.secondary.layer.backgroundColor = UIColor.clear.cgColor - cell.secondary.setTitleColor(NCBrandColor.shared.notificationAction, for: .normal) + cell.secondary.layer.borderColor = NCBrandColor.shared.iconImageColor2.cgColor + cell.secondary.layer.backgroundColor = UIColor.secondarySystemBackground.cgColor + cell.secondary.setTitleColor(NCBrandColor.shared.iconImageColor2, for: .normal) // Action if let actions = notification.actions, @@ -264,10 +234,7 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty cell.secondary.setTitle(label, for: .normal) } } - } - - let widthPrimary = cell.primary.intrinsicContentSize.width + 48; - let widthSecondary = cell.secondary.intrinsicContentSize.width + 48; + } else if jsonActions.count >= 3 { cell.more.isEnabled = true cell.more.isHidden = false @@ -292,9 +259,15 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty // MARK: - tap Action - func tapRemove(with notification: NKNotifications) { - - NextcloudKit.shared.setNotification(serverUrl: nil, idNotification: notification.idNotification, method: "DELETE", account: session.account) { _, _, error in + func tapRemove(with notification: NKNotifications, sender: Any?) { + NextcloudKit.shared.setNotification(serverUrl: nil, idNotification: notification.idNotification, method: "DELETE", account: session.account) { task in + Task { + let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: self.session.account, + path: "\(notification.idNotification)", + name: "setNotification") + await NCNetworking.shared.networkingTasks.track(identifier: identifier, task: task) + } + } completion: { _, _, error in if error == .success { if let index = self.notifications .firstIndex(where: { $0.idNotification == notification.idNotification }) { @@ -311,36 +284,38 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty } } - func tapAction(with notification: NKNotifications, label: String) { - if notification.app == NCGlobal.shared.spreedName, - let roomToken = notification.objectId.split(separator: "/").first, - let talkUrl = URL(string: "nextcloudtalk://open-conversation?server=\(session.urlBase)&user=\(session.userId)&withRoomToken=\(roomToken)"), - UIApplication.shared.canOpenURL(talkUrl) { - UIApplication.shared.open(talkUrl) - } else if let actions = notification.actions, - let jsonActions = JSON(actions).array, - let action = jsonActions.first(where: { $0["label"].string == label }) { - let serverUrl = action["link"].stringValue - let method = action["type"].stringValue - - if method == "WEB", let url = action["link"].url { - UIApplication.shared.open(url, options: [:], completionHandler: nil) - return + func tapAction(with notification: NKNotifications, label: String, sender: Any?) { + guard let actions = notification.actions, + let jsonActions = JSON(actions).array, + let action = jsonActions.first(where: { $0["label"].string == label }) + else { return } + + let serverUrl = action["link"].stringValue + let method = action["type"].stringValue + + if method == "WEB", var url = action["link"].url { + if notification.app == NCGlobal.shared.spreedName, + let roomToken = notification.objectId.split(separator: "/").first, + let talkUrl = URL(string: "nextcloudtalk://open-conversation?server=\(session.urlBase)&user=\(session.userId)&withRoomToken=\(roomToken)"), + UIApplication.shared.canOpenURL(talkUrl) { + + url = talkUrl } - NextcloudKit.shared.setNotification(serverUrl: serverUrl, idNotification: 0, method: method, account: session.account) { _, _, error in - if error == .success { - if let index = self.notifications.firstIndex(where: { $0.idNotification == notification.idNotification }) { - self.notifications.remove(at: index) - } - self.tableView.reloadData() - if self.navigationController?.presentingViewController != nil, notification.app == NCGlobal.shared.twoFactorNotificatioName { - self.dismiss(animated: true) - } - } else if error != .success { - NCContentPresenter().showError(error: error) - } else { - print("[Error] The user has been changed during networking process.") + UIApplication.shared.open(url) + return + } + + NextcloudKit.shared.setNotification(serverUrl: serverUrl, idNotification: 0, method: method, account: session.account) { task in + Task { + let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: self.session.account, + name: "setNotification") + await NCNetworking.shared.networkingTasks.track(identifier: identifier, task: task) + } + } completion: { _, _, error in + if error == .success { + if let index = self.notifications.firstIndex(where: { $0.idNotification == notification.idNotification }) { + self.notifications.remove(at: index) } self.tableView.reloadData() if self.navigationController?.presentingViewController != nil, notification.app == NCGlobal.shared.twoFactorNotificatioName { @@ -353,16 +328,21 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty } else { print("[Error] The user has been changed during networking process.") } - } // else: Action not found + } } - func tapMore(with notification: NKNotifications) { - toggleMenu(notification: notification) + func tapMore(with notification: NKNotifications, sender: Any?) { + toggleMenu(notification: notification, sender: sender) } // MARK: - Load notification networking - @objc func getNetwokingNotification() { + @MainActor + func getNetwokingNotification() async { + // If is already in-flight, do nothing + if await NCNetworking.shared.networkingTasks.isReading(identifier: "NCNotification") { + return + } self.tableView.reloadData() @@ -402,6 +382,7 @@ class NCNotificationCell: UITableViewCell { @IBOutlet weak var remove: UIButton! @IBOutlet weak var primary: UIButton! @IBOutlet weak var secondary: UIButton! + @IBOutlet weak var more: UIButton! @IBOutlet weak var avatarLeadingMargin: NSLayoutConstraint! @IBOutlet weak var primaryWidth: NSLayoutConstraint! @IBOutlet weak var secondaryWidth: NSLayoutConstraint! @@ -414,7 +395,7 @@ class NCNotificationCell: UITableViewCell { @IBAction func touchUpInsideRemove(_ sender: Any) { guard let notification = notification else { return } - delegate?.tapRemove(with: notification) + delegate?.tapRemove(with: notification, sender: sender) } @IBAction func touchUpInsidePrimary(_ sender: Any) { @@ -422,7 +403,7 @@ class NCNotificationCell: UITableViewCell { let button = sender as? UIButton, let label = button.titleLabel?.text else { return } - delegate?.tapAction(with: notification, label: label) + delegate?.tapAction(with: notification, label: label, sender: sender) } @IBAction func touchUpInsideSecondary(_ sender: Any) { @@ -430,11 +411,17 @@ class NCNotificationCell: UITableViewCell { let button = sender as? UIButton, let label = button.titleLabel?.text else { return } - delegate?.tapAction(with: notification, label: label) + delegate?.tapAction(with: notification, label: label, sender: sender) + } + + @IBAction func touchUpInsideMore(_ sender: Any) { + guard let notification = notification else { return } + delegate?.tapMore(with: notification, sender: sender) } } protocol NCNotificationCellDelegate: AnyObject { func tapRemove(with notification: NKNotifications, sender: Any?) func tapAction(with notification: NKNotifications, label: String, sender: Any?) + func tapMore(with notification: NKNotifications, sender: Any?) }