-
Notifications
You must be signed in to change notification settings - Fork 46
Release 4.0.0 #27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Release 4.0.0 #27
Conversation
Warning Rate limit exceeded@efremidze has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 13 minutes and 7 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (3)
WalkthroughThe changes collectively update the project for a new major release (version 4.0.0), raising the minimum supported iOS version to 13.0 and introducing Core Haptics support. The codebase removes conditional checks and availability attributes related to earlier iOS versions, simplifies protocol declarations, and updates documentation and metadata to reflect the new requirements. A new haptic playback system using Core Haptics is added while maintaining legacy support, and public APIs are adjusted to expose both playback methods. The README and changelog are revised to clarify version compatibility and installation instructions. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Haptic
participant CoreHaptics
participant LegacySystem
User->>Haptic: play(pattern, delay, legacy)
alt legacy == true
Haptic->>LegacySystem: Parse pattern to [LegacyNote]
LegacySystem->>LegacySystem: Enqueue operations for haptic/wait
LegacySystem->>User: Haptic feedback (legacy)
else
Haptic->>CoreHaptics: Parse pattern to [Note]
Haptic->>CoreHaptics: Prepare CHHapticEngine
CoreHaptics->>CoreHaptics: Schedule and play haptic events
CoreHaptics->>User: Haptic feedback (Core Haptics)
end
Poem
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🔭 Outside diff range comments (1)
Sources/Extensions.swift (1)
11-19
:⚠️ Potential issue
UIControl.Event
already conforms toHashable
; this extension breaks the build
UIControl.Event
(anOptionSet
) automatically inheritsHashable
&Equatable
.
Adding:extension UIControl.Event: @retroactive Hashable { … }causes the pipeline errors you’re seeing:
Unknown attribute 'retroactive'
Inheritance from non-protocol type 'any Hashable'
Simply remove the entire extension (and the custom
==
helper) – the type is hashable out-of-the-box.-@retroactive extension UIControl.Event: Hashable { - public var hashValue: Int { - return Int(rawValue) - } -} - -func == (lhs: UIControl.Event, rhs: UIControl.Event) -> Bool { - return lhs.rawValue == rhs.rawValue -}If you still need a custom hash for older Swift versions, use
hash(into:)
, but that is unnecessary for the current minimum toolchain.🧰 Tools
🪛 SwiftLint (0.57.0)
[Warning] 12-12: Prefer using the
hash(into:)
function instead of overridinghashValue
(legacy_hashing)
🪛 GitHub Actions: Swift
[error] 11-11: Unknown attribute 'retroactive' used in extension declaration.
[error] 11-11: Inheritance from non-protocol type 'any Hashable' is not allowed.
[error] 11-11: Unknown attribute 'retroactive' used in extension declaration.
[error] 11-11: Inheritance from non-protocol type 'any Hashable' is not allowed.
🧹 Nitpick comments (3)
Example/ViewController.swift (1)
14-48
: Consider DRY-ing up the repetitive outlet configurationEvery
UIButton
outlet repeats the same pattern:
<button>.addHaptic(.<style>, forControlEvents: .touchDown)
If more styles are added later, boiler-plate will grow. A tiny helper keeps the controller leaner and less error-prone:
class ViewController: UIViewController { @IBOutlet private var hapticButtons: [UIButton]! // hook up all 8 buttons override func viewDidLoad() { super.viewDidLoad() let styles: [Haptic] = [ .selection, .impact(.light), .impact(.medium), .impact(.heavy), .impact(.soft), .impact(.rigid), .notification(.success), .notification(.warning), .notification(.error) ] zip(hapticButtons, styles).forEach { $0.addHaptic($1, forControlEvents: .touchDown) } } }That single loop replaces 9 separate
didSet
blocks and makes future maintenance trivial.
No functional change, purely readability and maintainability.Sources/Pattern.swift (2)
9-10
: Duplicateimport CoreHaptics
directive
CoreHaptics
is imported twice (lines 9 and 94).
This is harmless but noisy and picked up by SwiftLint.-import CoreHaptics // ← keep this one … -import CoreHaptics // ← removeAlso applies to: 94-95
170-191
: Sanity-check haptic parameter rangesCore Haptics expects
intensity
&sharpness
between 0 … 1.
Your mapping currently stays within range – good – but any future edit risks going out of bounds, which throws at runtime.Safeguard with
min(max(value,0),1)
or assert ininit?
:case .haptic(let i, let s): let intensity = max(0, min(i, 1)) let sharpness = max(0, min(s, 1))This turns a crash into a benign clamp.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
CHANGELOG.md
(1 hunks)Example/ViewController.swift
(2 hunks)Haptica.podspec
(1 hunks)Haptica.xcodeproj/project.pbxproj
(4 hunks)Package.swift
(1 hunks)README.md
(1 hunks)Sources/Extensions.swift
(1 hunks)Sources/Haptic.swift
(0 hunks)Sources/Hapticable.swift
(1 hunks)Sources/Pattern.swift
(6 hunks)
💤 Files with no reviewable changes (1)
- Sources/Haptic.swift
🧰 Additional context used
🧬 Code Graph Analysis (1)
Example/ViewController.swift (1)
Sources/Hapticable.swift (1)
addHaptic
(50-54)
🪛 GitHub Actions: Swift
Sources/Extensions.swift
[error] 11-11: Unknown attribute 'retroactive' used in extension declaration.
[error] 11-11: Inheritance from non-protocol type 'any Hashable' is not allowed.
[error] 11-11: Unknown attribute 'retroactive' used in extension declaration.
[error] 11-11: Inheritance from non-protocol type 'any Hashable' is not allowed.
🪛 SwiftLint (0.57.0)
Sources/Pattern.swift
[Warning] 94-94: Imports should be unique
(duplicate_imports)
🔇 Additional comments (6)
Sources/Hapticable.swift (1)
15-15
: Modernize class-only protocol declaration
Replacing the deprecatedclass
constraint withAnyObject
is the correct approach in modern Swift (5+). This aligns with the updated iOS 13 deployment target and Swift tools version without any change in functionality.CHANGELOG.md (1)
3-7
: Verify dropped platform support consistency
The changelog notes “Dropped iOS 12 Support” (min iOS 13.0), so please ensure all project targets (Package.swift, Xcode project, Podspec) and documentation reflect iOS 13.0 as the minimum.README.md (1)
18-18
: Minimum deployment target updated correctly
The README now accurately states that Haptica 4.x requires iOS 13.0+ while 3.x supports iOS 9.0+. This matches the rest of the project.Package.swift (1)
1-1
: Swift tools version and platform target bump are correct
Theswift-tools-version:5.9
directive andplatforms: [.iOS(.v13)]
align with CoreHaptics requirements and the raised deployment target. Ensure your CI and Xcode project settings are in sync.Also applies to: 9-9
Haptica.podspec (1)
11-11
: Podspec version bumped for 4.0.0 release
Updatings.version
to'4.0.0'
is correct for this release.Haptica.xcodeproj/project.pbxproj (1)
359-363
: Deployment-target mismatch between framework and Example appThe framework target’s
IPHONEOS_DEPLOYMENT_TARGET
is bumped to 13.0 (👍),
but the Example app target inherits the old value (not explicitly set).On Xcode ≤14 this results in:
ld: warning: object file compiled with newer iOS version (13.0) than being linked (9.0)
and the app may crash at runtime when
.soft
/.rigid
haptics are used.Please set the same deployment target on the Example target (or remove the explicit setting on the framework so both inherit).
No code change required – just update the build-setting.Also applies to: 417-423
Sources/Pattern.swift
Outdated
public extension Haptic { | ||
static var engine: CHHapticEngine? | ||
|
||
static func prepareHaptics() { | ||
guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else { return } | ||
|
||
do { | ||
engine = try CHHapticEngine() | ||
try engine?.start() | ||
|
||
// The engine stops automatically when it goes into the background | ||
engine?.stoppedHandler = { reason in | ||
print("Haptic engine stopped: \(reason)") | ||
} | ||
|
||
engine?.resetHandler = { | ||
print("Haptic engine reset") | ||
do { | ||
try engine?.start() | ||
} catch { | ||
print("Failed to restart engine: \(error)") | ||
} | ||
} | ||
} catch { | ||
print("Failed to create haptic engine: \(error)") | ||
} | ||
} | ||
|
||
static func play(_ notes: [Note]) { | ||
guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else { return } | ||
|
||
if engine == nil { | ||
prepareHaptics() | ||
} | ||
|
||
guard let engine else { return } | ||
|
||
do { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Potential data race on the shared CHHapticEngine
engine
is a static mutable singleton that is:
- lazily created in
prepareHaptics()
- accessed & mutated from
play(_:)
(which may be called from any thread)
Because CHHapticEngine
is not thread-safe, simultaneous calls to Haptic.play
from multiple threads could:
- create two engines,
- race on
engine.start()
, - or read a tearing pointer.
A lightweight fix is to wrap engine access in a serial queue:
private static let engineQueue = DispatchQueue(label: "Haptica.engine")
static func prepareHaptics() {
engineQueue.sync {
guard engine == nil else { return }
guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else { return }
…
}
}
static func play(_ notes: [Note]) {
engineQueue.sync {
if engine == nil { prepareHaptics() }
guard let engine else { return }
…
}
}
This keeps the public API unchanged while eliminating the race window.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (1)
README.md (1)
121-124
: Clarify separation of SPM dependency blocksHaving two
dependencies:
arrays in the same fragment can be confusing. Consider labeling or splitting these into two distinct code fences—one for iOS 13+ (4.x) and one for iOS 9 (3.x)—so users know to choose the appropriate snippet.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
README.md
(3 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
README.md
141-141: Bare URL used
null
(MD034, no-bare-urls)
144-144: Bare URL used
null
(MD034, no-bare-urls)
🔇 Additional comments (3)
README.md (3)
18-18
: Verify consistency of minimum iOS version across Podspec and READMEThe README states Haptica 4.x requires iOS 13.0+, but the Podspec was updated to iOS 12.0. Ensure these minimum deployment targets are aligned across documentation and Podspec to avoid confusion.
111-111
: Great addition of Swift Package Manager sectionThe new
### Swift Package Manager
header and introductory text clearly guide users on adding Haptica via SPM.
116-119
: Correct SPM snippet for iOS 13+ projectsThe package declaration for iOS 13+ (
.package(url: "https://github.com/efremidze/Haptica.git", from: "4.0.0")
) is accurate and follows SPM conventions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (2)
Sources/Pattern.swift (1)
27-29
:⚠️ Potential issueFix potential data race on shared
CHHapticEngine
.The static
engine
property is accessed from multiple places without thread synchronization. SinceCHHapticEngine
is not thread-safe, this could lead to race conditions ifplay(_:)
is called from multiple threads simultaneously.Implement a thread-safe approach using a serial queue:
+ private static let engineQueue = DispatchQueue(label: "Haptica.engine") + static var engine: CHHapticEngine? static func prepareHaptics() { + engineQueue.sync { guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else { return } do { engine = try CHHapticEngine() try engine?.start() engine?.resetHandler = { do { try engine?.start() } catch { HapticaLog.error("Failed to restart engine: \(error)") } } } catch { HapticaLog.error("Failed to create haptic engine: \(error)") } + } }Apply similar changes to the
play(_:)
method as well.README.md (1)
149-153
: 🛠️ Refactor suggestionFix Carthage installation instructions.
The current Carthage section doesn't specify version constraints for different iOS targets.
### Carthage ```ruby -github "efremidze/Haptica" +# For Haptica 3.x (iOS 9+) +github "efremidze/Haptica" ~> 3.0 + +# For Haptica 4.x (iOS 13+) +github "efremidze/Haptica" ~> 4.0</blockquote></details> </blockquote></details> <details> <summary>🧹 Nitpick comments (8)</summary><blockquote> <details> <summary>Sources/Logs.swift (2)</summary><blockquote> `9-9`: **Consider using OS Logger API instead of just importing the module.** You're importing `os.log` but only using basic `print` statements. For better integration with the system logging framework and improved performance, consider using the actual OS Logger API. ```diff -import os.log +import os + +// Define a subsystem and category for your logs +private let logger = Logger(subsystem: "com.efremidze.haptica", category: "haptics")
And then in your logging methods:
static func info(_ message: String) { - if isEnabled { print("[Haptica] \(message)") } + if isEnabled { logger.info("[\(message)]") } }
12-12
: Implement conditional compilation for debug logging.Your comment suggests conditionally compiling with a DEBUG flag, but this isn't implemented. Using actual conditional compilation would be more efficient.
- static var isEnabled = true // or conditionally compile with DEBUG flag + #if DEBUG + static var isEnabled = true + #else + static var isEnabled = false + #endifSources/Pattern.swift (5)
49-90
: Consider handling engine state more robustly.The current implementation creates a new engine if it's nil, but doesn't handle the case where the engine might be in a stopped state or might have failed.
static func play(_ notes: [Note]) { guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else { return } - if engine == nil { - prepareHaptics() - } - - guard let engine else { return } + // Get or create engine with proper error handling + guard let currentEngine = engineQueue.sync(execute: { () -> CHHapticEngine? in + if engine == nil { + prepareHaptics() + } + + if let engine = engine, engine.state != .stopped { + return engine + } else if let engine = engine { + do { + try engine.start() + return engine + } catch { + HapticaLog.error("Failed to start engine: \(error)") + return nil + } + } + return nil + }) else { return } do { var events = [CHHapticEvent]() var currentTime: TimeInterval = 0 for note in notes { switch note { case .haptic(let intensity, let sharpness): // Create and add haptic event let event = CHHapticEvent( eventType: .hapticTransient, parameters: [ CHHapticEventParameter(parameterID: .hapticIntensity, value: intensity), CHHapticEventParameter(parameterID: .hapticSharpness, value: sharpness) ], relativeTime: currentTime ) events.append(event) currentTime += 0.1 // Default duration for transient events case .wait(let interval): currentTime += interval } } // Create pattern from events let pattern = try CHHapticPattern(events: events, parameters: []) // Create player and play pattern - let player = try engine.makePlayer(with: pattern) + let player = try currentEngine.makePlayer(with: pattern) try player.start(atTime: 0) } catch { HapticaLog.error("Failed to play pattern: \(error)") } }🧰 Tools
🪛 GitHub Actions: Swift
[error] 89-89: Cannot find 'HapticaLog' in scope at line 89.
114-114
: Complete the TODO comment with a proper description.Empty TODO comments should include a description of what needs to be done.
-/// TODO +/// Represents a haptic note with customizable intensity and sharpness, +/// or a timed wait interval for pattern-based haptic feedback.🧰 Tools
🪛 SwiftLint (0.57.0)
[Warning] 114-114: TODOs should be resolved
(todo)
139-139
: Complete the TODO comment with a proper description.Empty TODO comments should include a description of what needs to be done.
-/// TODO +/// Represents a legacy haptic note using predefined impact types, +/// or a timed wait interval for pattern-based haptic feedback.🧰 Tools
🪛 SwiftLint (0.57.0)
[Warning] 139-139: TODOs should be resolved
(todo)
168-178
: Document why Sendable conformance is force-unwrapped.When using
@unchecked Sendable
, it's important to document why the type is considered thread-safe even though the compiler cannot verify it.+/** + * A operation that generates haptic feedback. + * + * This class is marked as @unchecked Sendable because: + * - All member variables are immutable + * - The haptic generation is synchronized to the main thread + * - No mutable state is shared between threads + */ class HapticOperation: Operation, @unchecked Sendable { let haptic: Haptic init(_ haptic: Haptic) { self.haptic = haptic } override func main() { DispatchQueue.main.sync { self.haptic.generate() } } }
180-188
: Document why Sendable conformance is force-unwrapped.Similar to the HapticOperation class, document why the WaitOperation is considered thread-safe.
+/** + * An operation that introduces a timed wait interval. + * + * This class is marked as @unchecked Sendable because: + * - All member variables are immutable + * - Thread.sleep is thread-safe + * - No mutable state is shared between threads + */ class WaitOperation: Operation, @unchecked Sendable { let duration: TimeInterval init(_ duration: TimeInterval) { self.duration = duration } override func main() { Thread.sleep(forTimeInterval: duration) } }README.md (1)
81-87
: Document the benefits of Core Haptics.While you mention Core Haptics support, it would be helpful to explain the benefits of using Core Haptics over the legacy API.
### 🔧 Core Haptics Support -Haptica uses **Core Haptics** by default. To use the legacy API: +Haptica uses **Core Haptics** by default, which offers: + +- More precise control over haptic intensity and sharpness +- Support for complex haptic patterns and timing +- Better integration with Apple's latest haptic hardware + +To use the legacy API for backward compatibility: ```swift Haptic.play(notes, legacy: true)</blockquote></details> </blockquote></details> <details> <summary>📜 Review details</summary> **Configuration used: CodeRabbit UI** **Review profile: CHILL** **Plan: Pro** <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between 473458a71a103ed3d3b772c7ca1c30f5293abd0f and 0dd1fadd15b0673d043df7305b2e39b9304125ff. </details> <details> <summary>📒 Files selected for processing (4)</summary> * `Haptica.podspec` (1 hunks) * `README.md` (1 hunks) * `Sources/Logs.swift` (1 hunks) * `Sources/Pattern.swift` (4 hunks) </details> <details> <summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary> * Haptica.podspec </details> <details> <summary>🧰 Additional context used</summary> <details> <summary>🧬 Code Graph Analysis (1)</summary> <details> <summary>Sources/Pattern.swift (1)</summary><blockquote> <details> <summary>Sources/Logs.swift (1)</summary> * `error` (18-20) </details> </blockquote></details> </details><details> <summary>🪛 SwiftLint (0.57.0)</summary> <details> <summary>Sources/Pattern.swift</summary> [Warning] 114-114: TODOs should be resolved (todo) --- [Warning] 139-139: TODOs should be resolved (todo) </details> </details> <details> <summary>🪛 GitHub Actions: Swift</summary> <details> <summary>Sources/Pattern.swift</summary> [error] 41-41: Cannot find 'HapticaLog' in scope at line 41. --- [error] 45-45: Cannot find 'HapticaLog' in scope at line 45. --- [error] 89-89: Cannot find 'HapticaLog' in scope at line 89. </details> </details> <details> <summary>🪛 markdownlint-cli2 (0.17.2)</summary> <details> <summary>README.md</summary> 15-15: Dollar signs used before commands without showing output null (MD014, commands-show-output) </details> </details> </details> <details> <summary>🔇 Additional comments (1)</summary><blockquote> <details> <summary>README.md (1)</summary> `22-27`: **LGTM! Clear version compatibility table.** The version compatibility table clearly shows that Haptica 4.x requires iOS 13+, which aligns with the Core Haptics support introduced in this release. </details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (2)
README.md (1)
166-168
: Fixed Carthage section as requested in previous review.The Carthage section has been simplified with the correct syntax.
Sources/Pattern.swift (1)
33-56
:⚠️ Potential issuePotential data race on the shared
CHHapticEngine
.The static
engine
property is accessed and modified from multiple methods without synchronization. This could lead to thread safety issues ifplay
is called concurrently from different threads.Implement thread-safety for
engine
access:+private static let engineQueue = DispatchQueue(label: "Haptica.engine") static func prepareHaptics() { + engineQueue.sync { guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else { return } do { engine = try CHHapticEngine() try engine?.start() engine?.resetHandler = { do { try engine?.start() } catch { HapticaLog.error("Failed to restart engine: \(error)") } } } catch { HapticaLog.error("Failed to create haptic engine: \(error)") } + } }And similarly protect engine access in the
play
method:static func play(_ notes: [Note]) { + engineQueue.sync { guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else { return } if engine == nil { prepareHaptics() } guard let engine else { return } // ... rest of method ... + } }
🧹 Nitpick comments (1)
README.md (1)
10-17
: Improved introduction and project description.The updated intro clearly positions Haptica as a "simple and expressive haptic feedback generator for iOS" and includes a proper pod try command.
The console command could be updated to show expected output as per markdownlint suggestions:
-```bash -$ pod try Haptica -``` +```console +$ pod try Haptica +# This will install and open the Haptica example project +```🧰 Tools
🪛 markdownlint-cli2 (0.17.2)
15-15: Dollar signs used before commands without showing output
null(MD014, commands-show-output)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
Haptica.xcodeproj/project.pbxproj
(8 hunks)README.md
(1 hunks)Sources/Haptic.swift
(1 hunks)Sources/Pattern.swift
(4 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
Sources/Pattern.swift (1)
Sources/Logs.swift (1)
error
(18-20)
🪛 markdownlint-cli2 (0.17.2)
README.md
15-15: Dollar signs used before commands without showing output
null
(MD014, commands-show-output)
🔇 Additional comments (18)
Haptica.xcodeproj/project.pbxproj (3)
21-21
: Added logging capabilities to the framework.The new
Logs.swift
file has been properly integrated into the project structure, providing a centralized logging mechanism for the framework.Also applies to: 67-67, 124-124, 268-268
363-363
: Raised minimum iOS deployment target to iOS 13.0.This is a breaking change that enables Core Haptics usage but drops support for iOS 9-12. This aligns with the major version increment (4.0.0) and matches the requirements documented in the README.
Make sure this change is clearly communicated in your release notes and CHANGELOG so users are aware of the breaking change when upgrading.
Also applies to: 421-421
445-445
: Updated marketing version to 4.0.0.Version bump appropriately reflects the breaking changes in minimum iOS version requirement and the addition of Core Haptics support.
Also applies to: 465-465
Sources/Haptic.swift (4)
11-15
: Improved documentation for haptic feedback types.Adding clear documentation comments improves API clarity and helps developers understand the purpose of each haptic feedback style.
23-26
: Enhanced documentation for notification feedback types.Good clarification about the intended usage of notification feedback types for task outcomes.
34-48
: Added semantic haptic variants.The new semantic variants (
start
,stop
,increase
,decrease
,success
,failure
,warning
) provide more expressive, domain-specific haptic feedback options. This enhances the API's usability by making code more readable and intention-revealing.
67-82
: Implemented semantic variant mappings.The implementation elegantly maps each semantic variant to an appropriate underlying haptic feedback type, maintaining compatibility while expanding the API surface.
README.md (5)
22-27
: Added comprehensive version compatibility table.The requirements table clearly communicates which versions of Haptica support different iOS, Swift, and Xcode versions, making it easier for users to choose the appropriate version.
54-68
: Documented new semantic haptic types.The documentation for the new semantic types matches the implementation in
Haptic.swift
and provides clear examples of how to use these expressive variants.
96-102
: Added Core Haptics support documentation.Clear explanation of the new Core Haptics support with instructions on how to use the legacy API if needed.
149-155
: Updated Swift Package Manager installation instructions.The SPM instructions now include version-specific guidance for iOS 13+ (v4.0.0) and iOS 9 (v3.0.0), which is helpful for users who need to support older iOS versions.
188-189
: Improved license information with direct link.The license section now includes a direct link to the LICENSE file, making it easier for users to access the full license text.
Sources/Pattern.swift (6)
9-28
: Added dual-API support for both Core Haptics and legacy feedback.The enhanced
play
method now supports both Core Haptics (default) and legacy UIKit-based haptic feedback via alegacy
parameter. This maintains backward compatibility while providing access to new functionality.
61-103
: Implemented Core Haptics pattern player.The new implementation creates a sequence of haptic events with precise control over intensity, sharpness, and timing parameters. This provides much more expressive haptic feedback compared to the legacy API.
107-126
: Organized legacy haptic feedback as a separate component.Good separation of concerns by isolating the legacy haptic functionality in its own extension. This maintains backward compatibility while keeping the code organized.
133-160
: Enhanced Note enum with precise haptic parameters.The updated
Note
enum now supports explicit intensity and sharpness values for Core Haptics, providing much finer control over the haptic experience compared to the legacy API.
162-183
: Added hapticNote mapping for semantic types.This extension elegantly maps the semantic haptic types to appropriate CoreHaptics parameters, ensuring consistent behavior across both APIs.
221-231
: Added @unchecked Sendable to operation classes.The
@unchecked Sendable
attribute allows these classes to be used in concurrent contexts. However, make sure the classes are actually thread-safe.Verify that these classes properly handle their mutable state in concurrent environments. The
HapticOperation
class correctly usesDispatchQueue.main.sync
to ensure thread-safety when generating haptic feedback.Also applies to: 234-242
Checklist
Motivation and Context
Description
Summary by CodeRabbit
New Features
Breaking Changes
Documentation
Other Improvements