-
-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Platform support, Application property wrapper and notifications supp…
…ort (#98) # Platform support, Application property wrapper and notifications support ## ♻️ Current situation & Problem Currently, the Core Spezi infrastructure is only developed for iOS. However, we are aiming to support Spezi on all Apple platforms. This step required to reengineer some Spezi infrastructure that was heavily tailored towards the iOS platform (e.g., the `LifecycleHandler`). This PR deprecates the `LifecycleHandler` in favor of using SwiftUI native approaches like the [`ScenePhase`](https://developer.apple.com/documentation/swiftui/scenephase) environment property or platform-specific publisher-based solutions like [`willEnterForegroundNotification`](https://developer.apple.com/documentation/uikit/uiscene/3197925-willenterforegroundnotification). Further we introduce the new `@Application` property wrapper for `Modules` and the `Standard` to access application-specific properties like `launchOptions`. Based on the new `@Application` infrastructure we resolve issues like #80 to provide Modules with Module-specific Logger instances. To further validate our `@Application` approach, we added infrastructure around (Remote Push) Notifications. You can use `@Application` to trigger application actions like `registerRemoteNotifications` or `unregisterRemoteNotifications` and additionally adopt protocols like `NotificationTokenHandler` and `NotificationHandler` to react to notification actions, control how notifications are delivered in foreground or fetch additional content for background notifications. ## ⚙️ Release Notes * Add support for visionOS, tvOS, watchOS and macOS. * Deprecated the `LifecycleHandler` protocol. * Added new `@Application` property wrapper to access application properties and actions in a a platform-agnostic way. * New protocol `NotificationTokenHandler` and `NotificationHandler` to easily support notification handling within your apps. ## 📚 Documentation There are two new articles `Interactions with Application` and `User Notifications` that provide an overview for those new infrastructure elements. ## ✅ Testing _TBA_ ## 📝 Code of Conduct & Contributing Guidelines By submitting creating this pull request, you agree to follow our [Code of Conduct](https://github.com/StanfordSpezi/.github/blob/main/CODE_OF_CONDUCT.md) and [Contributing Guidelines](https://github.com/StanfordSpezi/.github/blob/main/CONTRIBUTING.md): - [x] I agree to follow the [Code of Conduct](https://github.com/StanfordSpezi/.github/blob/main/CODE_OF_CONDUCT.md) and [Contributing Guidelines](https://github.com/StanfordSpezi/.github/blob/main/CONTRIBUTING.md).
- Loading branch information
Showing
46 changed files
with
1,707 additions
and
278 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
72 changes: 72 additions & 0 deletions
72
Sources/Spezi/Capabilities/ApplicationPropertyWrapper.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// | ||
// 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 | ||
// | ||
|
||
|
||
/// Refer to the documentation of ``Module/Application``. | ||
@propertyWrapper | ||
public class _ApplicationPropertyWrapper<Value> { // swiftlint:disable:this type_name | ||
private let keyPath: KeyPath<Spezi, Value> | ||
|
||
private weak var spezi: Spezi? | ||
/// Some KeyPaths are declared to copy the value upon injection and not query them every time. | ||
private var shadowCopy: Value? | ||
|
||
|
||
/// Access the application property. | ||
public var wrappedValue: Value { | ||
if let shadowCopy { | ||
return shadowCopy | ||
} | ||
|
||
guard let spezi else { | ||
preconditionFailure("Underlying Spezi instance was not yet injected. @Application cannot be accessed within the initializer!") | ||
} | ||
return spezi[keyPath: keyPath] | ||
} | ||
|
||
/// Initialize a new `@Application` property wrapper | ||
/// - Parameter keyPath: The property to access. | ||
public init(_ keyPath: KeyPath<Spezi, Value>) { | ||
self.keyPath = keyPath | ||
} | ||
} | ||
|
||
|
||
extension _ApplicationPropertyWrapper: SpeziPropertyWrapper { | ||
func inject(spezi: Spezi) { | ||
self.spezi = spezi | ||
if spezi.createsCopy(keyPath) { | ||
self.shadowCopy = spezi[keyPath: keyPath] | ||
} | ||
} | ||
} | ||
|
||
|
||
extension Module { | ||
/// Access a property or action of the application. | ||
/// | ||
/// The `@Application` property wrapper can be used inside your `Module` to | ||
/// access a property or action of your application. | ||
/// | ||
/// - Note: You can access the contents of `@Application` once your ``Module/configure()-5pa83`` method is called | ||
/// (e.g., it must not be used in the `init`). | ||
/// | ||
/// Below is a short code example: | ||
/// | ||
/// ```swift | ||
/// class ExampleModule: Module { | ||
/// @Application(\.logger) | ||
/// var logger | ||
/// | ||
/// func configure() { | ||
/// logger.info("Module is being configured ...") | ||
/// } | ||
/// } | ||
/// ``` | ||
public typealias Application<Value> = _ApplicationPropertyWrapper<Value> | ||
} |
Oops, something went wrong.