Skip to content

Commit

Permalink
Add new @Application modifier
Browse files Browse the repository at this point in the history
  • Loading branch information
Supereg committed Feb 17, 2024
1 parent c96968e commit dbc6c45
Show file tree
Hide file tree
Showing 20 changed files with 477 additions and 254 deletions.
39 changes: 39 additions & 0 deletions Sources/Spezi/Capabilities/ApplicationPropertyWrapper.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//
// This source file is part of the Stanford Spezi open-source project
//
// SPDX-FileCopyrightText: 2024 Stanford University and the project authors (see CONTRIBUTORS.md)
//
// SPDX-License-Identifier: MIT
//


@propertyWrapper
public class _ApplicationPropertyWrapper<Value> { // swiftlint:disable:this type_name

Check failure on line 11 in Sources/Spezi/Capabilities/ApplicationPropertyWrapper.swift

View workflow job for this annotation

GitHub Actions / SwiftLint / SwiftLint / SwiftLint

Missing Docs Violation: public declarations should be documented (missing_docs)
private let keyPath: KeyPath<Spezi, Value>

private weak var spezi: Spezi?


public var wrappedValue: Value {

Check failure on line 17 in Sources/Spezi/Capabilities/ApplicationPropertyWrapper.swift

View workflow job for this annotation

GitHub Actions / SwiftLint / SwiftLint / SwiftLint

Missing Docs Violation: public declarations should be documented (missing_docs)
guard let spezi else {
preconditionFailure("Underlying Spezi instance was not yet injected. @Application cannot be accessed within the initializer!")
}
return spezi[keyPath: keyPath]
}

public init(_ keyPath: KeyPath<Spezi, Value>) {

Check failure on line 24 in Sources/Spezi/Capabilities/ApplicationPropertyWrapper.swift

View workflow job for this annotation

GitHub Actions / SwiftLint / SwiftLint / SwiftLint

Missing Docs Violation: public declarations should be documented (missing_docs)
self.keyPath = keyPath
}
}


extension _ApplicationPropertyWrapper: SpeziPropertyWrapper {
func inject(spezi: Spezi) {
self.spezi = spezi
}
}


extension Module {
public typealias Application<Value> = _ApplicationPropertyWrapper<Value>

Check failure on line 38 in Sources/Spezi/Capabilities/ApplicationPropertyWrapper.swift

View workflow job for this annotation

GitHub Actions / SwiftLint / SwiftLint / SwiftLint

Missing Docs Violation: public declarations should be documented (missing_docs)
}
219 changes: 174 additions & 45 deletions Sources/Spezi/Capabilities/Lifecycle/LifecycleHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,6 @@ import os
import SwiftUI


// TODO: Docs
#if os(iOS) || os(visionOS) || os(tvOS)
public typealias LaunchOptionsKey = UIApplication.LaunchOptionsKey
#else
// Launch options are not part of WKApplicationDelegate or NSApplicationDelegate
public typealias LaunchOptionsKey = Never
#endif


/// Delegate methods are related to the `UIApplication` and ``Spezi/Spezi`` lifecycle.
///
/// Conform to the `LifecycleHandler` protocol to get updates about the application lifecycle similar to the `UIApplicationDelegate` on an app basis.
Expand All @@ -28,111 +19,249 @@ public typealias LaunchOptionsKey = Never
/// - ``LifecycleHandler/applicationWillTerminate(_:)-35fxv``
///
/// All methods supported by the module capability are listed blow.
@available(
*,
deprecated,
message: """
Please use the new @Application property wrapper to access delegate functionality. \
Otherwise use the SwiftUI onReceive(_:perform:) for UI related notifications.
"""
)
public protocol LifecycleHandler {
#if os(iOS) || os(visionOS) || os(tvOS)
/// Replicates the `application(_: UIApplication, willFinishLaunchingWithOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool`
/// functionality of the `UIApplicationDelegate`.
///
/// Tells the delegate that the launch process has begun but that state restoration hasn't occurred.
/// - Parameters:
/// - application: The singleton app object.
/// - launchOptions: A dictionary indicating the reason the app was launched (if any). The contents of this dictionary may be empty in situations where the user launched the app directly. For information about the possible keys in this dictionary and how to handle them, see UIApplication.LaunchOptionsKey.
func willFinishLaunchingWithOptions(launchOptions: [LaunchOptionsKey: Any])

@available(
*,
deprecated,
message: """
Please use the new @Application(\\.launchOptions) property wrapper within your Module \
to access launchOptions in a platform independent way.
"""
)
func willFinishLaunchingWithOptions(_ application: UIApplication, launchOptions: [UIApplication.LaunchOptionsKey: Any])

/// Replicates the `sceneWillEnterForeground(_: UIScene)` functionality of the `UISceneDelegate`.
///
/// Tells the delegate that the scene is about to begin running in the foreground and become visible to the user.
///
/// - Important: This method is deprecated. This method is only called on iOS and not supported on other platforms.
///
///
/// - Parameter scene: The scene that is about to enter the foreground.
func sceneWillEnterForeground()

@available(
*,
deprecated,
message: """
Using UISceneDelegate is deprecated. \
Use the SwiftUI onReceive(_:perform:) modifier with the UIScene.willEnterForegroundNotification publisher on iOS \
or other platform-specific mechanisms as a replacement.
"""
)
func sceneWillEnterForeground(_ scene: UIScene)

/// Replicates the `sceneDidBecomeActive(_: UIScene)` functionality of the `UISceneDelegate`.
///
/// Tells the delegate that the scene became active and is now responding to user events.
/// - Parameter scene: The scene that became active and is now responding to user events.
func sceneDidBecomeActive()
@available(
*,
deprecated,
message: """
Using UISceneDelegate is deprecated. \
Use the SwiftUI onReceive(_:perform:) modifier with the UIScene.didActivateNotification publisher on iOS \
or other platform-specific mechanisms as a replacement.
"""
)
func sceneDidBecomeActive(_ scene: UIScene)

/// Replicates the `sceneWillResignActive(_: UIScene)` functionality of the `UISceneDelegate`.
///
/// Tells the delegate that the scene is about to resign the active state and stop responding to user events.
/// - Parameter scene: The scene that is about to stop responding to user events.
func sceneWillResignActive()

@available(
*,
deprecated,
message: """
Using UISceneDelegate is deprecated. \
Use the SwiftUI onReceive(_:perform:) modifier with the UIScene.willDeactivateNotification publisher on iOS \
or other platform-specific mechanisms as a replacement.
"""
)
func sceneWillResignActive(_ scene: UIScene)

/// Replicates the `sceneDidEnterBackground(_: UIScene)` functionality of the `UISceneDelegate`.
///
/// Tells the delegate that the scene is running in the background and is no longer onscreen.
/// - Parameter scene: The scene that entered the background.
func sceneDidEnterBackground()

@available(
*,
deprecated,
message: """
Using UISceneDelegate is deprecated. \
Use the SwiftUI onReceive(_:perform:) modifier with the UIScene.didEnterBackgroundNotification publisher on iOS \
or other platform-specific mechanisms as a replacement.
"""
)
func sceneDidEnterBackground(_ scene: UIScene)

/// Replicates the `applicationWillTerminate(_: UIApplication)` functionality of the `UIApplicationDelegate`.
///
/// Tells the delegate when the app is about to terminate.
/// - Parameter application: Your singleton app object.
func applicationWillTerminate()

// TODO: update ALL docs
@available(
*,
deprecated,
message: """
Using UISceneDelegate is deprecated. \
Use the SwiftUI onReceive(_:perform:) modifier with the UIApplication.willTerminateNotification publisher on iOS \
or other platform-specific mechanisms as a replacement.
"""
)
func applicationWillTerminate(_ application: UIApplication)
#endif
}


@available(
*,
deprecated,
message: """
Please use the new @Application property wrapper to access delegate functionality. \
Otherwise use the SwiftUI onReceive(_:perform:) for UI related notifications.
"""
)
extension LifecycleHandler {
#if os(iOS) || os(visionOS) || os(tvOS)
// A documentation for this method exists in the `LifecycleHandler` type which SwiftLint doesn't recognize.
// swiftlint:disable:next missing_docs
public func willFinishLaunchingWithOptions(launchOptions: [LaunchOptionsKey: Any]) {}
public func willFinishLaunchingWithOptions(_ application: UIApplication, launchOptions: [UIApplication.LaunchOptionsKey: Any]) {}

// A documentation for this method exists in the `LifecycleHandler` type which SwiftLint doesn't recognize.
// swiftlint:disable:next missing_docs
public func sceneWillEnterForeground() { }
public func sceneWillEnterForeground(_ scene: UIScene) { }

// A documentation for this method exists in the `LifecycleHandler` type which SwiftLint doesn't recognize.
// swiftlint:disable:next missing_docs
public func sceneDidBecomeActive() { }
public func sceneDidBecomeActive(_ scene: UIScene) { }

// A documentation for this method exists in the `LifecycleHandler` type which SwiftLint doesn't recognize.
// swiftlint:disable:next missing_docs
public func sceneWillResignActive() { }
public func sceneWillResignActive(_ scene: UIScene) { }

// A documentation for this method exists in the `LifecycleHandler` type which SwiftLint doesn't recognize.
// swiftlint:disable:next missing_docs
public func sceneDidEnterBackground() { }
public func sceneDidEnterBackground(_ scene: UIScene) { }

// A documentation for this method exists in the `LifecycleHandler` type which SwiftLint doesn't recognize.
// swiftlint:disable:next missing_docs
public func applicationWillTerminate() { }
public func applicationWillTerminate(_ application: UIApplication) { }
#endif
}


@available(
*,
deprecated,
message: """
Please use the new @Application property wrapper to access delegate functionality. \
Otherwise use the SwiftUI onReceive(_:perform:) for UI related notifications.
"""
)
extension Array: LifecycleHandler where Element == LifecycleHandler {
public func willFinishLaunchingWithOptions(launchOptions: [LaunchOptionsKey: Any]) {
#if os(iOS) || os(visionOS) || os(tvOS)
@available(
*,
deprecated,
message: """
Please use the new @Application(\\.launchOptions) property wrapper within your Module \
to access launchOptions in a platform independent way.
"""
)
public func willFinishLaunchingWithOptions(_ application: UIApplication, launchOptions: [UIApplication.LaunchOptionsKey: Any]) {
for lifecycleHandler in self {
lifecycleHandler.willFinishLaunchingWithOptions(launchOptions: launchOptions)
lifecycleHandler.willFinishLaunchingWithOptions(application, launchOptions: launchOptions)
}
}

public func sceneWillEnterForeground() {

@available(
*,
deprecated,
message: """
Using UISceneDelegate is deprecated. \
Use the SwiftUI onReceive(_:perform:) modifier with the UIScene.willEnterForegroundNotification publisher on iOS \
or other platform-specific mechanisms as a replacement.
"""
)
public func sceneWillEnterForeground(_ scene: UIScene) {
for lifecycleHandler in self {
lifecycleHandler.sceneWillEnterForeground()
lifecycleHandler.sceneWillEnterForeground(scene)
}
}

public func sceneDidBecomeActive() {
@available(
*,
deprecated,
message: """
Using UISceneDelegate is deprecated. \
Use the SwiftUI onReceive(_:perform:) modifier with the UIScene.didActivateNotification publisher on iOS \
or other platform-specific mechanisms as a replacement.
"""
)
public func sceneDidBecomeActive(_ scene: UIScene) {
for lifecycleHandler in self {
lifecycleHandler.sceneDidBecomeActive()
lifecycleHandler.sceneDidBecomeActive(scene)
}
}

public func sceneWillResignActive() {
@available(
*,
deprecated,
message: """
Using UISceneDelegate is deprecated. \
Use the SwiftUI onReceive(_:perform:) modifier with the UIScene.willDeactivateNotification publisher on iOS \
or other platform-specific mechanisms as a replacement.
"""
)
public func sceneWillResignActive(_ scene: UIScene) {
for lifecycleHandler in self {
lifecycleHandler.sceneWillResignActive()
lifecycleHandler.sceneWillResignActive(scene)
}
}

public func sceneDidEnterBackground() {
@available(
*,
deprecated,
message: """
Using UISceneDelegate is deprecated. \
Use the SwiftUI onReceive(_:perform:) modifier with the UIScene.didEnterBackgroundNotification publisher on iOS \
or other platform-specific mechanisms as a replacement.
"""
)
public func sceneDidEnterBackground(_ scene: UIScene) {
for lifecycleHandler in self {
lifecycleHandler.sceneDidEnterBackground()
lifecycleHandler.sceneDidEnterBackground(scene)
}
}

public func applicationWillTerminate() {

@available(
*,
deprecated,
message: """
Using UISceneDelegate is deprecated. \
Use the SwiftUI onReceive(_:perform:) modifier with the UIApplication.willTerminateNotification publisher on iOS \
or other platform-specific mechanisms as a replacement.
"""
)
public func applicationWillTerminate(_ application: UIApplication) {
for lifecycleHandler in self {
lifecycleHandler.applicationWillTerminate()
lifecycleHandler.applicationWillTerminate(application)
}
}
#endif
}
46 changes: 0 additions & 46 deletions Sources/Spezi/Capabilities/Lifecycle/Spezi+LifecycleHandlers.swift

This file was deleted.

Loading

0 comments on commit dbc6c45

Please sign in to comment.