Files
iOS/Sources/Extensions/NotificationContent/NotificationViewController.swift
Zac West 4d9a530637 Reorganize files in repo, pull out build settings from pbxproj (#1140)
This is somewhat in prep of being able to make the project file generated, but also just organizes things into more concrete directory structures.

This pulls out _all_ of the build settings from the root level, and most from the target level, into xcconfigs.

The new directory structure looks like:

- Sources
  - App
    - (everything from HomeAssistant/)
  - WatchApp
  - Shared
  - MacBridge
  - Extensions
    - Intents
    - NotificationContent
    - NotificationService
    - Share
    - Today
    - Watch
    - Widgets
- Tests
  - App
  - UI
  - Shared

Somewhat intentionally, the file structure under these is not yet standardized/organized.

The project targets are now:

- App
- WatchApp
- Shared-iOS
- Shared-watchOS
- MacBridge
- Tests-App
- Tests-UI
- Tests-Shared
- Extension-Intents
- Extension-NotificationContent
- Extension-NotificationService
- Extension-Share
- Extension-Today
- Extension-Widget
- WatchExtension-Watch

This does not yet clean up resources vs. sources, nor does it handle some of the "it's in Sources/App but it's part of Shared" crossover directory issues.
2020-10-03 00:15:04 -07:00

145 lines
5.0 KiB
Swift

//
// NotificationViewController.swift
// NotificationContentExtension
//
// Created by Robbie Trencheny on 9/9/16.
// Copyright © 2016 Robbie Trencheny. All rights reserved.
//
import UIKit
import UserNotifications
import UserNotificationsUI
import KeychainAccess
import Shared
import PromiseKit
import Alamofire
import MBProgressHUD
enum NotificationCategories: String {
case map
case map1
case map2
case map3
case map4
case camera
case camera1
case camera2
case camera3
case camera4
}
class NotificationViewController: UIViewController, UNNotificationContentExtension {
var activeViewController: (UIViewController & NotificationCategory)? {
willSet {
activeViewController?.willMove(toParent: nil)
newValue.flatMap { addChild($0) }
}
didSet {
oldValue?.view.removeFromSuperview()
oldValue?.removeFromParent()
if let viewController = activeViewController {
view.addSubview(viewController.view)
viewController.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
viewController.view.topAnchor.constraint(equalTo: view.topAnchor),
viewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
viewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
viewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
viewController.didMove(toParent: self)
}
}
}
func didReceive(_ notification: UNNotification) {
let catID = notification.request.content.categoryIdentifier.lowercased()
guard let category = NotificationCategories(rawValue: catID) else {
Current.Log.warning("Unknown category \(notification.request.content.categoryIdentifier)")
return
}
Current.Log.verbose("Received a \(category) notif with userInfo \(notification.request.content.userInfo)")
let controller: (UIViewController & NotificationCategory)
switch category {
case .camera, .camera1, .camera2, .camera3, .camera4:
controller = CameraViewController()
case .map, .map1, .map2, .map3, .map4:
controller = MapViewController()
}
let hud: MBProgressHUD? = {
guard controller.mediaPlayPauseButtonType == .none else {
// don't show the HUD for a screen that has pause/play because it already acts like a loading indicator
return nil
}
let hud = MBProgressHUD.showAdded(to: self.view, animated: true)
let loadTxt = L10n.Extensions.NotificationContent.Hud.loading(category.rawValue)
hud.offset = CGPoint(x: 0, y: -MBProgressMaxOffset+50)
hud.detailsLabel.text = loadTxt
return hud
}()
activeViewController = controller
controller.didReceive(
notification: notification,
extensionContext: extensionContext
).ensure {
hud?.hide(animated: true)
}.catch { [weak self] error in
Current.Log.error("finally failed: \(error)")
self?.activeViewController = NotificationErrorViewController(error: error)
}
}
var mediaPlayPauseButtonType: UNNotificationContentExtensionMediaPlayPauseButtonType {
activeViewController?.mediaPlayPauseButtonType ?? .none
}
var mediaPlayPauseButtonFrame: CGRect {
return CGRect(
x: view.bounds.width / 2.0 - 22,
y: view.bounds.height / 2.0 - 22,
width: 44,
height: 44
)
}
public func mediaPlay() {
activeViewController?.mediaPlay()
}
public func mediaPause() {
activeViewController?.mediaPause()
}
}
protocol NotificationCategory: NSObjectProtocol {
// This will be called to send the notification to be displayed by
// the extension. If the extension is being displayed and more related
// notifications arrive (eg. more messages for the same conversation)
// the same method will be called for each new notification.
func didReceive(
notification: UNNotification,
extensionContext: NSExtensionContext?
) -> Promise<Void>
// Implementing this method and returning a button type other that "None" will
// make the notification attempt to draw a play/pause button correctly styled
// for that type.
var mediaPlayPauseButtonType: UNNotificationContentExtensionMediaPlayPauseButtonType { get }
// Implementing this method and returning a non-empty frame will make
// the notification draw a button that allows the user to play and pause
// media content embedded in the notification.
var mediaPlayPauseButtonFrame: CGRect? { get }
// Called when the user taps the play or pause button.
func mediaPlay()
func mediaPause()
}