mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-07 16:28:38 +09:00
Dactyloidae iOS initial commit
This commit is contained in:
parent
daa6179d22
commit
7154a0497e
2123 changed files with 197052 additions and 0 deletions
178
mobile/ios/Client/Helpers/TabEventHandler.swift
Normal file
178
mobile/ios/Client/Helpers/TabEventHandler.swift
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import Foundation
|
||||
import Storage
|
||||
|
||||
/**
|
||||
* A handler can be a plain old swift object. It does not need to extend any
|
||||
* other object, but can.
|
||||
*
|
||||
* Handlers should register for tab events with the `registerFor` method, and
|
||||
* cleanup with the `unregister` method.
|
||||
*
|
||||
* ```
|
||||
* class HandoffHandler {
|
||||
* var tabObservers: TabObservers!
|
||||
*
|
||||
* init() {
|
||||
* tabObservers = registerFor(.didLoadFavicon, .didLoadPageMetadata)
|
||||
* }
|
||||
*
|
||||
* deinit {
|
||||
* unregister(tabObservers)
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Handlers can implement any or all `TabEventHandler` methods. If you
|
||||
* implement a method, you should probably `registerFor` the event above.
|
||||
*
|
||||
* ```
|
||||
* extension HandoffHandler: TabEventHandler {
|
||||
* func tab(_ tab: Tab, didLoadPageMetadata metadata: PageMetadata) {
|
||||
* print("\(tab) has \(pageMetadata)")
|
||||
* }
|
||||
*
|
||||
* func tab(_ tab: Tab, didLoadFavicon favicon: Favicon) {
|
||||
* print("\(tab) has \(favicon)")
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Tab events should probably be only posted from one place, to avoid cycles.
|
||||
*
|
||||
* ```
|
||||
* TabEvent.post(.didLoadPageMetadata(aPageMetadata), for: tab)
|
||||
* ```
|
||||
*
|
||||
* In this manner, we are able to use the notification center and have type safety.
|
||||
*
|
||||
*/
|
||||
// As we want more events we add more here.
|
||||
// Each event needs:
|
||||
// 1. a method in the TabEventHandler.
|
||||
// 2. a default implementation of the method – so not everyone needs to implement it
|
||||
// 3. a TabEventLabel, which is needed for registration
|
||||
// 4. a TabEvent, with whatever parameters are needed.
|
||||
// i) a case to map the event to the event label (var label)
|
||||
// ii) a case to map the event to the event handler (func handle:with:)
|
||||
protocol TabEventHandler {
|
||||
func tab(_ tab: Tab, didChangeURL url: URL)
|
||||
func tab(_ tab: Tab, didLoadPageMetadata metadata: PageMetadata)
|
||||
func tab(_ tab: Tab, didLoadFavicon favicon: Favicon?, with: Data?)
|
||||
func tabDidGainFocus(_ tab: Tab)
|
||||
func tabDidLoseFocus(_ tab: Tab)
|
||||
func tabDidClose(_ tab: Tab)
|
||||
}
|
||||
|
||||
// Provide default implmentations, because we don't want to litter the code with
|
||||
// empty methods, and `@objc optional` doesn't really work very well.
|
||||
extension TabEventHandler {
|
||||
func tab(_ tab: Tab, didChangeURL url: URL) {}
|
||||
func tab(_ tab: Tab, didLoadPageMetadata metadata: PageMetadata) {}
|
||||
func tab(_ tab: Tab, didLoadFavicon favicon: Favicon?, with: Data?) {}
|
||||
func tabDidGainFocus(_ tab: Tab) {}
|
||||
func tabDidLoseFocus(_ tab: Tab) {}
|
||||
func tabDidClose(_ tab: Tab) {}
|
||||
}
|
||||
|
||||
enum TabEventLabel: String {
|
||||
case didChangeURL
|
||||
case didLoadPageMetadata
|
||||
case didLoadFavicon
|
||||
case didGainFocus
|
||||
case didLoseFocus
|
||||
case didClose
|
||||
}
|
||||
|
||||
enum TabEvent {
|
||||
case didChangeURL(URL)
|
||||
case didLoadPageMetadata(PageMetadata)
|
||||
case didLoadFavicon(Favicon?, with: Data?)
|
||||
case didGainFocus
|
||||
case didLoseFocus
|
||||
case didClose
|
||||
|
||||
var label: TabEventLabel {
|
||||
switch self {
|
||||
case .didChangeURL:
|
||||
return .didChangeURL
|
||||
case .didLoadPageMetadata:
|
||||
return .didLoadPageMetadata
|
||||
case .didLoadFavicon:
|
||||
return .didLoadFavicon
|
||||
case .didGainFocus:
|
||||
return .didGainFocus
|
||||
case .didLoseFocus:
|
||||
return .didLoseFocus
|
||||
case .didClose:
|
||||
return .didClose
|
||||
}
|
||||
}
|
||||
|
||||
func handle(_ tab: Tab, with handler: TabEventHandler) {
|
||||
switch self {
|
||||
case .didChangeURL(let url):
|
||||
handler.tab(tab, didChangeURL: url)
|
||||
case .didLoadPageMetadata(let metadata):
|
||||
handler.tab(tab, didLoadPageMetadata: metadata)
|
||||
case .didLoadFavicon(let favicon, let data):
|
||||
handler.tab(tab, didLoadFavicon: favicon, with: data)
|
||||
case .didGainFocus:
|
||||
handler.tabDidGainFocus(tab)
|
||||
case .didLoseFocus:
|
||||
handler.tabDidLoseFocus(tab)
|
||||
case .didClose:
|
||||
handler.tabDidClose(tab)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Hide some of the machinery away from the boiler plate above.
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
extension TabEventLabel {
|
||||
var name: Notification.Name {
|
||||
return Notification.Name(self.rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
extension TabEvent {
|
||||
func notification(for tab: Any) -> Notification {
|
||||
return Notification(name: label.name, object: tab, userInfo: ["payload": self])
|
||||
}
|
||||
|
||||
/// Use this method to post notifications to any concerned listeners.
|
||||
static func post(_ event: TabEvent, for tab: Any) {
|
||||
center.post(event.notification(for: tab))
|
||||
}
|
||||
}
|
||||
|
||||
// These methods are used by TabEventHandler implementers.
|
||||
// Their usage remains consistent, even as we add more event types and handler methods.
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
private let center = NotificationCenter()
|
||||
|
||||
typealias TabObservers = [NSObjectProtocol]
|
||||
extension TabEventHandler {
|
||||
/// Implementations of handles should use this method to register for events.
|
||||
/// `TabObservers` should be preserved for unregistering later.
|
||||
func registerFor(_ tabEvents: TabEventLabel..., queue: OperationQueue? = nil) -> TabObservers {
|
||||
return tabEvents.map { eventType in
|
||||
center.addObserver(forName: eventType.name, object: nil, queue: queue) { notification in
|
||||
guard let tab = notification.object as? Tab,
|
||||
let event = notification.userInfo?["payload"] as? TabEvent else {
|
||||
return
|
||||
}
|
||||
event.handle(tab, with: self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func unregister(_ observers: TabObservers) {
|
||||
observers.forEach { observer in
|
||||
center.removeObserver(observer)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue