diff options
Diffstat (limited to 'Example/Messaging/App/iOS/MessagingViewController.swift')
-rw-r--r-- | Example/Messaging/App/iOS/MessagingViewController.swift | 332 |
1 files changed, 332 insertions, 0 deletions
diff --git a/Example/Messaging/App/iOS/MessagingViewController.swift b/Example/Messaging/App/iOS/MessagingViewController.swift new file mode 100644 index 0000000..00ed3ff --- /dev/null +++ b/Example/Messaging/App/iOS/MessagingViewController.swift @@ -0,0 +1,332 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import UIKit + +import FirebaseDev + +enum Row: String { + case apnsToken = "apnsToken" + case apnsStatus = "apnsStatus" + case requestAPNSPermissions = "requestAPNSPermissions" + case fcmToken = "fcmToken" +} + +enum PermissionsButtonTitle: String { + case requestPermissions = "Request User Notifications" + case noAPNS = "Cannot Request Permissions (No APNs)" + case alreadyRequested = "Already Requested Permissions" + case simulator = "Cannot Request Permissions (Simulator)" +} + +class MessagingViewController: UIViewController { + + let tableView: UITableView + + var sections = [[Row]]() + var sectionHeaderTitles = [String?]() + + var allowedNotificationTypes: [NotificationsControllerAllowedNotificationType]? + + // Cached rows by Row type. Since this is largely a fixed table view, we'll + // keep track of our created cells and UI, rather than have all the logic + + required init?(coder aDecoder: NSCoder) { + tableView = UITableView(frame: CGRect.zero, style: .grouped) + tableView.rowHeight = UITableViewAutomaticDimension + tableView.estimatedRowHeight = 44 + // Allow UI Controls within the table to be immediately responsive + tableView.delaysContentTouches = false + super.init(coder: aDecoder) + tableView.dataSource = self + tableView.delegate = self + } + + override func loadView() { + super.loadView() + view = UIView(frame: CGRect.zero) + view.addSubview(self.tableView) + // Ensure that the tableView always is the size of the view + tableView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + } + + override func viewDidLoad() { + super.viewDidLoad() + let center = NotificationCenter.default + center.addObserver(self, + selector: #selector(onAPNSTokenReceived) , + name: APNSTokenReceivedNotification, + object: nil) + center.addObserver(self, + selector: #selector(onUserNotificationSettingsChanged), + name: UserNotificationsChangedNotification, + object: nil) + center.addObserver(self, + selector: #selector(onFCMTokenRefreshed), + name: Notification.Name.MessagingRegistrationTokenRefreshed, + object: nil) + updateAllowedNotificationTypes { + self.resetTableContents() + self.tableView.reloadData() + } + } + + func onAPNSTokenReceived() { + // Reload the appropriate cells + updateAllowedNotificationTypes { + if let tokenPath = self.indexPathFor(.apnsToken), + let statusPath = self.indexPathFor(.apnsStatus), + let requestPath = self.indexPathFor(.requestAPNSPermissions) { + self.updateIndexPaths(indexPaths: [tokenPath, statusPath, requestPath]) + } + } + } + + func onFCMTokenRefreshed() { + if let indexPath = indexPathFor(.fcmToken) { + updateIndexPaths(indexPaths: [indexPath]) + } + } + + func onUserNotificationSettingsChanged() { + updateAllowedNotificationTypes { + if let statusPath = self.indexPathFor(.apnsStatus), + let requestPath = self.indexPathFor(.requestAPNSPermissions) { + self.updateIndexPaths(indexPaths: [statusPath, requestPath]) + } + } + } + + private func updateIndexPaths(indexPaths: [IndexPath]) { + tableView.beginUpdates() + tableView.reloadRows(at: indexPaths, with: .none) + tableView.endUpdates() + } + + fileprivate func updateAllowedNotificationTypes(_ completion: (() -> Void)?) { + NotificationsController.shared.getAllowedNotificationTypes { (types) in + self.allowedNotificationTypes = types + self.updateRequestAPNSButton() + completion?() + } + } + + fileprivate func updateRequestAPNSButton() { + guard !Environment.isSimulator else { + requestPermissionsButton.isEnabled = false + requestPermissionsButton.setTitle(PermissionsButtonTitle.simulator.rawValue, for: .normal) + return + } + guard let allowedTypes = allowedNotificationTypes else { + requestPermissionsButton.isEnabled = false + requestPermissionsButton.setTitle(PermissionsButtonTitle.noAPNS.rawValue, for: .normal) + return + } + + requestPermissionsButton.isEnabled = + (allowedTypes.count == 1 && allowedTypes.first! == .silent) + + let title: PermissionsButtonTitle = + (requestPermissionsButton.isEnabled ? .requestPermissions : .alreadyRequested) + requestPermissionsButton.setTitle(title.rawValue, for: .normal) + } + + // MARK: UI (Cells and Buttons) Defined as lazy properties + lazy var apnsTableCell: UITableViewCell = { + let cell = UITableViewCell(style: .subtitle, reuseIdentifier: Row.apnsToken.rawValue) + cell.textLabel?.numberOfLines = 0 + cell.textLabel?.lineBreakMode = .byWordWrapping + return cell + }() + + lazy var apnsStatusTableCell: UITableViewCell = { + let cell = UITableViewCell(style: UITableViewCellStyle.value1, reuseIdentifier: Row.apnsStatus.rawValue) + cell.textLabel?.text = "Allowed:" + cell.detailTextLabel?.numberOfLines = 0 + cell.detailTextLabel?.lineBreakMode = .byWordWrapping + return cell + }() + + lazy var requestPermissionsButton: UIButton = { + let button = UIButton(type: .system) + button.setTitle(PermissionsButtonTitle.requestPermissions.rawValue, for: .normal) + button.setTitleColor(UIColor.gray, for: .highlighted) + button.setTitleColor(UIColor.gray, for: .disabled) + button.titleLabel?.font = UIFont.preferredFont(forTextStyle: .body) + button.addTarget(self, + action: #selector(onRequestUserNotificationsButtonTapped), + for: .touchUpInside) + return button + }() + + lazy var apnsRequestPermissionsTableCell: UITableViewCell = { + let cell = UITableViewCell(style: .default, + reuseIdentifier: Row.requestAPNSPermissions.rawValue) + cell.selectionStyle = .none + cell.contentView.addSubview(self.requestPermissionsButton) + self.requestPermissionsButton.frame = cell.contentView.bounds + self.requestPermissionsButton.autoresizingMask = [.flexibleWidth, .flexibleHeight] + return cell + }() + + lazy var fcmTokenTableCell: UITableViewCell = { + let cell = UITableViewCell(style: .subtitle, reuseIdentifier: Row.fcmToken.rawValue) + cell.textLabel?.numberOfLines = 0 + cell.textLabel?.lineBreakMode = .byCharWrapping + return cell + }() +} + +// MARK: - Configuring the table view and cells with information +extension MessagingViewController { + func resetTableContents() { + sections.removeAll() + sectionHeaderTitles.removeAll() + + // APNS + let apnsSection: [Row] = [.apnsToken, .apnsStatus, .requestAPNSPermissions] + sections.append(apnsSection) + sectionHeaderTitles.append("APNs") + + // FCM + let fcmSection: [Row] = [.fcmToken] + sections.append(fcmSection) + sectionHeaderTitles.append("FCM Token") + + } + + func indexPathFor(_ rowId: Row) -> IndexPath? { + var sectionIndex = 0 + for section in sections { + var rowIndex = 0 + for row in section { + if row == rowId { + return IndexPath(row: rowIndex, section: sectionIndex) + } + rowIndex += 1 + } + sectionIndex += 1 + } + return nil + } + + func configureCell(_ cell: UITableViewCell, withAPNSToken apnsToken: Data?) { + guard !Environment.isSimulator else { + cell.textLabel?.text = "APNs notifications are not supported in the simulator." + cell.detailTextLabel?.text = nil + return + } + if let apnsToken = apnsToken { + cell.textLabel?.text = apnsToken.hexByteString + cell.detailTextLabel?.text = "Tap to Share" + } else { + cell.textLabel?.text = "None" + cell.detailTextLabel?.text = nil + } + } + + func configureCellWithAPNSStatus(_ cell: UITableViewCell) { + if let allowedNotificationTypes = allowedNotificationTypes { + let displayableTypes: [String] = allowedNotificationTypes.map { return $0.rawValue } + cell.detailTextLabel?.text = displayableTypes.joined(separator: ", ") + } else { + cell.detailTextLabel?.text = "Retrieving..." + } + } + + func configureCell(_ cell: UITableViewCell, withFCMToken fcmToken: String?) { + if let fcmToken = fcmToken { + cell.textLabel?.text = fcmToken + cell.detailTextLabel?.text = "Tap to Share" + } else { + cell.textLabel?.text = "None" + cell.detailTextLabel?.text = nil + } + } +} + +// MARK: - UITableViewDataSource +extension MessagingViewController: UITableViewDataSource { + func numberOfSections(in tableView: UITableView) -> Int { + return sections.count + } + + public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return sections[section].count + } + + public func tableView(_ tableView: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let row = sections[indexPath.section][indexPath.row] + + let cell: UITableViewCell + switch row { + case .apnsToken: + cell = apnsTableCell + configureCell(cell, withAPNSToken: Messaging.messaging().apnsToken) + case .apnsStatus: + cell = apnsStatusTableCell + configureCellWithAPNSStatus(cell) + case .requestAPNSPermissions: + cell = apnsRequestPermissionsTableCell + case .fcmToken: + cell = fcmTokenTableCell + configureCell(cell, withFCMToken: Messaging.messaging().fcmToken) + } + return cell + } + + func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + return sectionHeaderTitles[section] + } +} + +// MARK: - UITableViewDelegate +extension MessagingViewController: UITableViewDelegate { + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + + let row = sections[indexPath.section][indexPath.row] + switch row { + case .apnsToken: + if let apnsToken = Messaging.messaging().apnsToken { + showActivityViewControllerFor(sharedItem: apnsToken.hexByteString) + } + case .fcmToken: + if let fcmToken = Messaging.messaging().fcmToken { + showActivityViewControllerFor(sharedItem: fcmToken) + } + default: break + } + } +} + +// MARK: - UI Controls +extension MessagingViewController { + func onRequestUserNotificationsButtonTapped(sender: UIButton) { + NotificationsController.shared.registerForUserFacingNotificationsFor(UIApplication.shared) + } +} + +// MARK: - Activity View Controller +extension MessagingViewController { + func showActivityViewControllerFor(sharedItem: Any) { + let activityViewController = UIActivityViewController(activityItems: [sharedItem], + applicationActivities: nil) + present(activityViewController, animated: true, completion: nil) + } +} + |