From 22459153243ed563020780f90b990ac46489d264 Mon Sep 17 00:00:00 2001 From: Anbalagan D Date: Wed, 13 Mar 2024 22:46:19 +0530 Subject: [PATCH] * Code Refraction * Enhancement --- LibraryManagement.xcodeproj/project.pbxproj | 4 + .../Extension/DateExtension.swift | 26 +++++++ .../Extension/StringExtension.swift | 4 +- .../Modules/Book/BookListController.swift | 2 +- .../AddBookRequestController.swift | 40 +--------- .../Modules/BookRequest/BookRequest.swift | 4 +- .../Modules/Cells/BookRequsetCell.swift | 2 +- .../Modules/Cells/NotificationCell.swift | 6 +- .../Modules/Common/BookManger.swift | 12 ++- .../Modules/Common/NotificationManager.swift | 75 ++++++++++++++++++- .../Notification/LibraryNotification.swift | 6 +- .../Notification/NotificationController.swift | 2 +- .../Modules/Setting/SettingController.swift | 16 +++- LibraryManagement/Support/AppDelegate.swift | 39 +--------- 14 files changed, 142 insertions(+), 96 deletions(-) create mode 100644 LibraryManagement/Extension/DateExtension.swift diff --git a/LibraryManagement.xcodeproj/project.pbxproj b/LibraryManagement.xcodeproj/project.pbxproj index 099c17d..393cc72 100644 --- a/LibraryManagement.xcodeproj/project.pbxproj +++ b/LibraryManagement.xcodeproj/project.pbxproj @@ -44,6 +44,7 @@ 54CD5A18229D352300B73CC1 /* NotificationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54CD5A17229D352300B73CC1 /* NotificationCell.swift */; }; 54CD5A1A229D39C400B73CC1 /* LibraryNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54CD5A19229D39C400B73CC1 /* LibraryNotification.swift */; }; 54E1170A229817020026C6CD /* ShortcutIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54E11709229817020026C6CD /* ShortcutIdentifier.swift */; }; + 993118982BA20DE1007B0A34 /* DateExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 993118972BA20DE1007B0A34 /* DateExtension.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -86,6 +87,7 @@ 54CD5A17229D352300B73CC1 /* NotificationCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationCell.swift; sourceTree = ""; }; 54CD5A19229D39C400B73CC1 /* LibraryNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryNotification.swift; sourceTree = ""; }; 54E11709229817020026C6CD /* ShortcutIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutIdentifier.swift; sourceTree = ""; }; + 993118972BA20DE1007B0A34 /* DateExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateExtension.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -174,6 +176,7 @@ 540B3664228C3A3800D123EE /* StringExtension.swift */, 540B3666228C3AB300D123EE /* ViewControllerExtension.swift */, 54673FF22ADCE00D0073B0A6 /* UIViewExtension.swift */, + 993118972BA20DE1007B0A34 /* DateExtension.swift */, ); path = Extension; sourceTree = ""; @@ -348,6 +351,7 @@ 54C355FF229293BC0003E57D /* BookRequestController.swift in Sources */, 5415911A229519A4002EAF66 /* BookRequest.swift in Sources */, 5420912D228ECF70002320A4 /* SideMenuController.swift in Sources */, + 993118982BA20DE1007B0A34 /* DateExtension.swift in Sources */, 5407B6F4228D7FFA000B1580 /* SlideTransitionAnimator.swift in Sources */, 540B365F228C35F100D123EE /* BookListController.swift in Sources */, 540B3667228C3AB300D123EE /* ViewControllerExtension.swift in Sources */, diff --git a/LibraryManagement/Extension/DateExtension.swift b/LibraryManagement/Extension/DateExtension.swift new file mode 100644 index 0000000..acd86af --- /dev/null +++ b/LibraryManagement/Extension/DateExtension.swift @@ -0,0 +1,26 @@ +// +// DateExtension.swift +// LibraryManagement +// +// Created by Anbalagan on 13/03/24. +// Copyright © 2024 Anbalagan D. All rights reserved. +// + +import Foundation + +extension Date { + func toString(format: String) -> String { + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = format + return dateFormatter.string(from: self) + } + +#if DEBUG + static func randomDate(in range: ClosedRange) -> Date { + let randomInterval = Double.random( + in: range.lowerBound.timeIntervalSince1970 ... range.upperBound.timeIntervalSince1970 + ) + return Date(timeIntervalSince1970: randomInterval) + } +#endif +} diff --git a/LibraryManagement/Extension/StringExtension.swift b/LibraryManagement/Extension/StringExtension.swift index 8cd8486..3b96b5d 100644 --- a/LibraryManagement/Extension/StringExtension.swift +++ b/LibraryManagement/Extension/StringExtension.swift @@ -9,9 +9,7 @@ import Foundation extension String { - static var empty: String { - return "" - } + static let empty: String = "" func substring( fromIndex: Int, diff --git a/LibraryManagement/Modules/Book/BookListController.swift b/LibraryManagement/Modules/Book/BookListController.swift index 3570841..294af97 100644 --- a/LibraryManagement/Modules/Book/BookListController.swift +++ b/LibraryManagement/Modules/Book/BookListController.swift @@ -278,7 +278,7 @@ extension BookListController: UITableViewDelegate, UITableViewDataSource { ] ) } - + func tableView( _ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, diff --git a/LibraryManagement/Modules/BookRequest/AddBookRequestController.swift b/LibraryManagement/Modules/BookRequest/AddBookRequestController.swift index ff0298f..d55fd47 100644 --- a/LibraryManagement/Modules/BookRequest/AddBookRequestController.swift +++ b/LibraryManagement/Modules/BookRequest/AddBookRequestController.swift @@ -27,20 +27,14 @@ final class AddBookRequestController: UIViewController { setupView() } - @objc private func requestBookTapped(_: UIButton) { + @objc private func requestBookTapped() { if let book = selectedBook { bookNotSelectedErrorLabel.isHidden = true - let formatter = DateFormatter() - formatter.dateFormat = "dd/MM/yyyy 'at' HH:mm a" - formatter.amSymbol = "AM" - formatter.pmSymbol = "PM" - let date = formatter.string(from: Date()) - let bookRequest = BookRequest( id: UUID().uuidString.substring(fromIndex: 0, count: 8), userName: "Anbalagan D", - date: date, + date: .now, bookName: book.name, status: .pending, bookId: book.id @@ -51,35 +45,7 @@ final class AddBookRequestController: UIViewController { navigationController?.popViewController(animated: true) if AppSettings.isNotificationEnable { - let content = UNMutableNotificationContent() - content.title = "New Book Request" - content.body = "\(bookRequest.userName) is request \(bookRequest.bookName)" - content.sound = UNNotificationSound.default - - let trigger = UNTimeIntervalNotificationTrigger( - timeInterval: 0.1, - repeats: false - ) - let notificationRequest = UNNotificationRequest( - identifier: "newBookRequest", - content: content, - trigger: trigger - ) - - let notificationDateFormatter = DateFormatter() - notificationDateFormatter.dateFormat = "dd/MM/yyyy" - let notificationDate = notificationDateFormatter.string(from: Date()) - NotificationManager.shared.addNotification( - notification: LibraryNotification( - title: content.title, - detail: content.body, - date: notificationDate - ) - ) - - UNUserNotificationCenter.current().add(notificationRequest) { error in - print(error?.localizedDescription ?? "Error") - } + NotificationManager.shared.addNotification(notification: bookRequest) } } else { bookNotSelectedErrorLabel.isHidden = false diff --git a/LibraryManagement/Modules/BookRequest/BookRequest.swift b/LibraryManagement/Modules/BookRequest/BookRequest.swift index 291201a..b0ef1de 100644 --- a/LibraryManagement/Modules/BookRequest/BookRequest.swift +++ b/LibraryManagement/Modules/BookRequest/BookRequest.swift @@ -6,10 +6,12 @@ // Copyright © 2019 Anbalagan D. All rights reserved. // +import Foundation + struct BookRequest { let id: String let userName: String - let date: String + let date: Date let bookName: String var status: BookRequestStatus var bookId: String diff --git a/LibraryManagement/Modules/Cells/BookRequsetCell.swift b/LibraryManagement/Modules/Cells/BookRequsetCell.swift index 3b9a3d5..eda690b 100644 --- a/LibraryManagement/Modules/Cells/BookRequsetCell.swift +++ b/LibraryManagement/Modules/Cells/BookRequsetCell.swift @@ -42,7 +42,7 @@ final class BookRequsetCell: UITableViewCell { userNameLabel.text = data.userName requestIdLabel.text = "#\(data.id)" - dateLabel.text = data.date + dateLabel.text = data.date.toString(format: "dd/MM/yyyy 'at' hh:mm a") bookNameLabel.text = data.bookName updateStatus(data.status) diff --git a/LibraryManagement/Modules/Cells/NotificationCell.swift b/LibraryManagement/Modules/Cells/NotificationCell.swift index b019300..1abdc64 100644 --- a/LibraryManagement/Modules/Cells/NotificationCell.swift +++ b/LibraryManagement/Modules/Cells/NotificationCell.swift @@ -25,9 +25,9 @@ final class NotificationCell: UITableViewCell { } func setupData(data: LibraryNotification) { - notificationTitleLabel.text = data.title - dateLabel.text = data.date - notificationDetailLabel.text = data.detail + notificationTitleLabel.text = "New Book Request" + dateLabel.text = data.date.toString(format: "dd/MM/yyyy") + notificationDetailLabel.text = "\(data.userName) is request \(data.bookName)" } } diff --git a/LibraryManagement/Modules/Common/BookManger.swift b/LibraryManagement/Modules/Common/BookManger.swift index 732ef4c..59f8936 100644 --- a/LibraryManagement/Modules/Common/BookManger.swift +++ b/LibraryManagement/Modules/Common/BookManger.swift @@ -23,7 +23,9 @@ final class BookManager { private var bookList = [Book]() private init() { + #if DEBUG addMockData() + #endif } func getBooks() -> [Book] { @@ -96,6 +98,7 @@ final class BookManager { } } + #if DEBUG private func addMockData() { bookList.append(contentsOf: [ Book( @@ -136,12 +139,12 @@ final class BookManager { ) ]) - // Book Request List + let startDate = Date().addingTimeInterval(-(60 * 60 * 24 * 30)) // From last one month bookRequestList.append(contentsOf: [ BookRequest( id: UUID().uuidString.substring(fromIndex: 0, count: 8), userName: "Anbalagan D", - date: "13/05/2019 at 12:05 PM", + date: .randomDate(in: startDate ... .now), bookName: "Java Programming 8", status: .pending, bookId: bookList[0].id @@ -149,7 +152,7 @@ final class BookManager { BookRequest( id: UUID().uuidString.substring(fromIndex: 0, count: 8), userName: "Anbalagan D", - date: "15/05/2019 at 06:43 AM", + date: .randomDate(in: startDate ... .now), bookName: "Advanced C# Programming", status: .pending, bookId: bookList[3].id @@ -157,11 +160,12 @@ final class BookManager { BookRequest( id: UUID().uuidString.substring(fromIndex: 0, count: 8), userName: "Anbalagan D", - date: "20/05/2019 at 01:27 PM", + date: .randomDate(in: startDate ... .now), bookName: "Kotlin for Android", status: .pending, bookId: bookList[2].id ) ]) } + #endif } diff --git a/LibraryManagement/Modules/Common/NotificationManager.swift b/LibraryManagement/Modules/Common/NotificationManager.swift index ff51c19..c5f1eb2 100644 --- a/LibraryManagement/Modules/Common/NotificationManager.swift +++ b/LibraryManagement/Modules/Common/NotificationManager.swift @@ -7,13 +7,39 @@ // import Foundation +import UserNotifications -final class NotificationManager { +final class NotificationManager: NSObject { static let shared = NotificationManager() private var notificationList = [LibraryNotification]() - private init() {} + private override init() { + super.init() + initalSetup() + } + + private func initalSetup() { + UNUserNotificationCenter.current().delegate = self + } + + func requestNotificationAuthorization(_ completion: @escaping (Bool) -> Void) { + UNUserNotificationCenter.current().requestAuthorization( + options: [.alert, .badge, .sound] + ) { granted, _ in + completion(granted) + } + } + + func checkHasNotificationPermission(_ completion: @escaping (Bool) -> Void) { + UNUserNotificationCenter.current().getNotificationSettings { notificationSettings in + completion(notificationSettings.authorizationStatus == .authorized) + } + } + + func setNotificationBadgeCount(_ count: Int) { + UNUserNotificationCenter.current().setBadgeCount(count) + } func getNotification() -> [LibraryNotification] { return notificationList @@ -21,5 +47,50 @@ final class NotificationManager { func addNotification(notification: LibraryNotification) { notificationList.append(notification) + triggerNotification(notification) + } + + private func triggerNotification(_ notification: LibraryNotification) { + let content = UNMutableNotificationContent() + content.title = "New Book Request" + content.body = "\(notification.userName) is request \(notification.bookName)" + content.sound = UNNotificationSound.default + + let trigger = UNTimeIntervalNotificationTrigger( + timeInterval: 0.1, + repeats: false + ) + let notificationRequest = UNNotificationRequest( + identifier: "newBookRequest", + content: content, + trigger: trigger + ) + + UNUserNotificationCenter.current().add(notificationRequest) { error in + if let error { + print(error.localizedDescription) + } + } + } +} + +extension NotificationManager: UNUserNotificationCenterDelegate { + func userNotificationCenter( + _ center: UNUserNotificationCenter, + didReceive response: UNNotificationResponse, + withCompletionHandler completionHandler: @escaping () -> Void + ) { + setNotificationBadgeCount(0) + print(response.notification.request.content.title) + completionHandler() + } + + func userNotificationCenter( + _ center: UNUserNotificationCenter, + willPresent notification: UNNotification, + withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void + ) { + setNotificationBadgeCount(0) + completionHandler([.list, .banner, .badge, .sound]) } } diff --git a/LibraryManagement/Modules/Notification/LibraryNotification.swift b/LibraryManagement/Modules/Notification/LibraryNotification.swift index 4b78e1d..6b3f7c4 100644 --- a/LibraryManagement/Modules/Notification/LibraryNotification.swift +++ b/LibraryManagement/Modules/Notification/LibraryNotification.swift @@ -6,8 +6,4 @@ // Copyright © 2019 Anbalagan D. All rights reserved. // -struct LibraryNotification { - let title: String - let detail: String - let date: String -} +typealias LibraryNotification = BookRequest diff --git a/LibraryManagement/Modules/Notification/NotificationController.swift b/LibraryManagement/Modules/Notification/NotificationController.swift index 662b06b..5e14228 100644 --- a/LibraryManagement/Modules/Notification/NotificationController.swift +++ b/LibraryManagement/Modules/Notification/NotificationController.swift @@ -63,7 +63,7 @@ extension NotificationController { notificationTableView.trailingAnchor.constraint(equalTo: view.safeTrailingAnchor), notificationTableView.topAnchor.constraint(equalTo: view.safeTopAnchor), notificationTableView.bottomAnchor.constraint(equalTo: view.safeBottomAnchor), - + emptyImageView.centerYAnchor.constraint(equalTo: emptyView.centerYAnchor, constant: -20), emptyImageView.centerXAnchor.constraint(equalTo: emptyView.centerXAnchor), emptyImageView.heightAnchor.constraint(equalToConstant: 120), diff --git a/LibraryManagement/Modules/Setting/SettingController.swift b/LibraryManagement/Modules/Setting/SettingController.swift index 3843ad1..5c1ab94 100644 --- a/LibraryManagement/Modules/Setting/SettingController.swift +++ b/LibraryManagement/Modules/Setting/SettingController.swift @@ -11,6 +11,7 @@ import UserNotifications final class SettingController: UIViewController { private var notificationSwitch: UISwitch! + private let notificationManager = NotificationManager.shared override func viewDidLoad() { super.viewDidLoad() @@ -23,7 +24,20 @@ final class SettingController: UIViewController { } @objc private func notificationChanged(_ sender: UISwitch) { - AppSettings.isNotificationEnable = sender.isOn + notificationManager.requestNotificationAuthorization { granded in + DispatchQueue.main.async { + if granded { + AppSettings.isNotificationEnable = sender.isOn + } else { + if sender.isOn { + sender.isOn = false + if let url = URL(string: UIApplication.openSettingsURLString) { + UIApplication.shared.open(url) + } + } + } + } + } } @objc private func onLogout() { diff --git a/LibraryManagement/Support/AppDelegate.swift b/LibraryManagement/Support/AppDelegate.swift index 277433b..e9b71a1 100644 --- a/LibraryManagement/Support/AppDelegate.swift +++ b/LibraryManagement/Support/AppDelegate.swift @@ -7,39 +7,25 @@ // import UIKit -import UserNotifications @main final class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - var launchedShortcutItem: UIApplicationShortcutItem? - func application( _ application: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { - window = UIWindow(frame: UIScreen.main.bounds) - - UNUserNotificationCenter.current().requestAuthorization( - options: [.alert, .badge, .sound] - ) { granted, _ in - if !granted { - print("User has declined notification") - } - } - UNUserNotificationCenter.current().delegate = self - UNUserNotificationCenter.current().setBadgeCount(0) let navController = UINavigationController(rootViewController: BookListController()) + window = UIWindow(frame: UIScreen.main.bounds) window?.rootViewController = navController - window?.makeKeyAndVisible() window?.tintColor = .orange return true } func applicationDidBecomeActive(_ application: UIApplication) { - UNUserNotificationCenter.current().setBadgeCount(0) + NotificationManager.shared.setNotificationBadgeCount(0) } func application( @@ -68,24 +54,3 @@ final class AppDelegate: UIResponder, UIApplicationDelegate { } } } - -extension AppDelegate: UNUserNotificationCenterDelegate { - func userNotificationCenter( - _: UNUserNotificationCenter, - didReceive response: UNNotificationResponse, - withCompletionHandler completionHandler: @escaping () -> Void - ) { - UNUserNotificationCenter.current().setBadgeCount(0) - print(response.notification.request.content.title) - completionHandler() - } - - func userNotificationCenter( - _: UNUserNotificationCenter, - willPresent _: UNNotification, - withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void - ) { - UNUserNotificationCenter.current().setBadgeCount(0) - completionHandler([.list, .banner, .badge, .sound]) - } -}