emergetools / pow Goto Github PK
View Code? Open in Web Editor NEWDelightful SwiftUI effects for your app
Home Page: https://movingparts.io/pow
License: MIT License
Delightful SwiftUI effects for your app
Home Page: https://movingparts.io/pow
License: MIT License
Would you accept a PR that adds a podspec to the repo?
Building for iOS Simulator, but linking in dylib built for iOS, file '/Users/jdavis/Development/Games/LNGames/Pow.framework/Pow' for architecture arm64
I've tried adding the .xcframework and while the project builds and runs fine on device, Xcode previews gives me the above errors. :(
I couldn't get the animation to work with .repeatForever()
.
I would love if there was a way to trigger the Effect every 2 seconds for example
The website says usage is free for commercial and non-commercial use, but the library still warns about needing to call Pow.unlockPow(reason: .iDidBuyTheLicense)
. Of course, I did not buy the license because I can't. I'm curious if this prompt just needs to be removed.
A mini reproductive demo.
import SwiftUI
import Pow
@main
struct DemoApp: App {
@State private var sheet = false
var body: some Scene {
WindowGroup {
Button("Open Sheet") {
sheet.toggle()
}
.sheet(isPresented: $sheet) {
Text("Demo")
.conditionalEffect(.smoke, condition: true)
}
}
}
}
Env:
Xcode 15.2.0 + Swift 5.9.1
macOS 14.4.1
Related Issue: Lakr233/FixTim#10
I would like to use Pow in a Swift Package supporting iOS 14:
platforms: [
.iOS(.v14)
],
I’ve tried to include the package using the condition
parameter:
dependencies: [
.product(name: "Pow", package: "Pow", condition: .when(platforms: [.iOS(.v15), .macCatalyst]))
]
But somehow that doesn't work, Xcode is complaining like so:
Of course I’ll have to put these if #available(iOS 15.0, *)
flags every time I use Pow code.
Any idea how to achieve this?
I hope this is the right place to ask for more fine tuning, but either way thank you very much for the library!
I was trying to use the .shine
ChangeEffect for animating a button tap, but the animation duration is too long for my use case. I see that other ChangeEffect's have parameters to try and fine tune the animation, and was hoping that it would be possible to add additional parameters to .shine
. While I only want the timing to be faster, I could see the edges being exposed as a parameter being useful to others as well, but I'll leave that to your best discretion.
Happy to provide any more information that may be useful, and thank you again!
Hi,
Screenshots are not showing.
I'll investigate.
is the code in this repository proprietary or haven't you decided on a license yet?
Back again with more customizability requests, sorry if they get annoying. Similar to #30 I'm trying to have some control over the timing of this animation. I want make it a little faster and have the pulse expand a little less far out, but as the effect is currently constituted impossible to do.
Thanks as always!
I'm running into a crash after deploying a Mac app with Pow to TestFlight, at least I believe the issue is Pow-related. The app works fine when I build and run locally from Xcode but it crashes on launch when I download and run the app from TestFlight. I figured this might not be something you've run into since I don't believe you have a Mac version of your demo app, so I've included the crash report below.
Happy to provide any information you may need, hope this crash log helps!
-------------------------------------
Translated Report (Full Report Below)
-------------------------------------
Process: Short Circuit [3802]
Path: /Applications/Short Circuit.app/Contents/MacOS/Short Circuit
Identifier: com.redpandaclub.quickgpt
Version: 2.0 (118)
App Item ID: 1638522784
Code Type: ARM-64 (Native)
Parent Process: launchd [1]
User ID: 501
Date/Time: 2023-04-21 23:07:33.4847 -0400
OS Version: macOS 13.3 (22E252)
Report Version: 12
Anonymous UUID:
Sleep/Wake UUID: D26684FB-2A35-4AF0-9C26-C94B9A47557C
Time Awake Since Boot: 1300000 seconds
Time Since Wake: 1068 seconds
System Integrity Protection: enabled
Crashed Thread: 0
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Termination Reason: Namespace DYLD, Code 1 Library missing
Library not loaded: @rpath/Pow.framework/Versions/A/Pow
Referenced from: <B305073C-98E4-33B2-9BF5-00E49B690A5B> /Applications/Short Circuit.app/Contents/MacOS/Short Circuit
Reason: tried: '/Applications/Short Circuit.app/Contents/MacOS/Frameworks/Pow.framework/Versions/A/Pow' (no such file), '/Applications/Short Circuit.app/Contents/MacOS/Frameworks/Pow.framework/Versions/A/Pow' (no such file), '/Library/Frameworks/Pow.framework/Versions/A/Pow' (no such file), '/System/Library/Frameworks/Pow.framework/Versions/A/Pow' (no such file, not in dyld cache)
(terminated at launch; ignore backtrace)
Kernel Triage:
VM - (arg = 0x0) pmap_enter retried due to resource shortage
Thread 0 Crashed:
0 dyld 0x19b921118 __abort_with_payload + 8
1 dyld 0x19b92cd7c abort_with_payload_wrapper_internal + 104
2 dyld 0x19b92cdb0 abort_with_payload + 16
3 dyld 0x19b8b88a8 dyld4::halt(char const*) + 328
4 dyld 0x19b8b5590 dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*) + 4184
5 dyld 0x19b8b3e18 start + 1964
Thread 0 crashed with ARM Thread State (64-bit):
x0: 0x0000000000000006 x1: 0x0000000000000001 x2: 0x000000016b536930 x3: 0x0000000000000075
x4: 0x000000016b536530 x5: 0x0000000000000000 x6: 0x0000000000000000 x7: 0x0000000000000ba0
x8: 0x0000000000000020 x9: 0x0000000000000009 x10: 0x0000000000000001 x11: 0x000000000000000a
x12: 0x0000000000000000 x13: 0x0000000000000033 x14: 0x0000000000000004 x15: 0x0000000000008000
x16: 0x0000000000000209 x17: 0x000000019b8b135c x18: 0x0000000000000000 x19: 0x0000000000000000
x20: 0x000000016b536530 x21: 0x0000000000000075 x22: 0x000000016b536930 x23: 0x0000000000000001
x24: 0x0000000000000006 x25: 0x00000001f756acc0 x26: 0x0000000000000000 x27: 0x0000000000000000
x28: 0x0000000000000000 fp: 0x000000016b536500 lr: 0x000000019b92cd7c
sp: 0x000000016b5364c0 pc: 0x000000019b921118 cpsr: 0x00001000
far: 0x0000000105054000 esr: 0x56000080 Address size fault
Binary Images:
0x1048c8000 - 0x104e87fff com.redpandaclub.quickgpt (2.0) <b305073c-98e4-33b2-9bf5-00e49b690a5b> /Applications/Short Circuit.app/Contents/MacOS/Short Circuit
0x19b8ae000 - 0x19b93c53b dyld (*) <6f2c2bb8-4bbc-3b64-b927-d3f3193b6295> /usr/lib/dyld
External Modification Summary:
Calls made by other processes targeting this process:
task_for_pid: 0
thread_create: 0
thread_set_state: 0
Calls made by this process:
task_for_pid: 0
thread_create: 0
thread_set_state: 0
Calls made by all processes on this machine:
task_for_pid: 918
thread_create: 0
thread_set_state: 26116
VM Region Summary:
ReadOnly portion of Libraries: Total=807.6M resident=0K(0%) swapped_out_or_unallocated=807.6M(100%)
Writable regions: Total=8672K written=0K(0%) resident=0K(0%) swapped_out=0K(0%) unallocated=8672K(100%)
VIRTUAL REGION
REGION TYPE SIZE COUNT (non-coalesced)
=========== ======= =======
STACK GUARD 56.0M 1
Stack 8176K 1
VM_ALLOCATE 16K 1
__DATA 443K 3
__DATA_CONST 262K 2
__DATA_DIRTY 7K 1
__LINKEDIT 801.2M 2
__TEXT 6460K 2
dyld private memory 272K 2
=========== ======= =======
TOTAL 872.5M 15
-----------
Full Report
-----------
{"roots_installed":0,"app_cohort":"2|date=1682132400000&sf=143441&tid=bcc197b08b53e724d12a6df9ef804083813dbb17a241cd4c0b168e528b54758b&ttype=i","app_name":"Short Circuit","app_version":"2.0","timestamp":"2023-04-21 23:07:34.00 -0400","slice_uuid":"b305073c-98e4-33b2-9bf5-00e49b690a5b","adam_id":"1638522784","build_version":"118","platform":1,"bundleID":"com.redpandaclub.quickgpt","share_with_app_devs":0,"is_first_party":0,"bug_type":"309","os_version":"macOS 13.3 (22E252)","incident_id":"38C9DAD1-1B49-495C-AA6D-96C5FDD975E3","name":"Short Circuit","is_beta":1}
{
"uptime" : 1300000,
"procRole" : "Background",
"version" : 2,
"userID" : 501,
"deployVersion" : 210,
"modelCode" : "Mac14,2",
"coalitionID" : 159913,
"osVersion" : {
"train" : "macOS 13.3",
"build" : "22E252",
"releaseType" : "User"
},
"captureTime" : "2023-04-21 23:07:33.4847 -0400",
"incident" : "38C9DAD1-1B49-495C-AA6D-96C5FDD975E3",
"pid" : 3802,
"translated" : false,
"cpuType" : "ARM-64",
"roots_installed" : 0,
"bug_type" : "309",
"procLaunch" : "2023-04-21 23:07:33.2381 -0400",
"procStartAbsTime" : 32037126710606,
"procExitAbsTime" : 32037132603655,
"procName" : "Short Circuit",
"procPath" : "\/Applications\/Short Circuit.app\/Contents\/MacOS\/Short Circuit",
"bundleInfo" : {"CFBundleShortVersionString":"2.0","CFBundleVersion":"118","CFBundleIdentifier":"com.redpandaclub.quickgpt"},
"storeInfo" : {"storeCohortMetadata":"2|date=1682132400000&sf=143441&tid=bcc197b08b53e724d12a6df9ef804083813dbb17a241cd4c0b168e528b54758b&ttype=i","itemID":"1638522784","deviceIdentifierForVendor":"C7AAEBA0-358C-5C72-B430-2B7C9C5F1B03","thirdParty":true,"entitledBeta":true},
"parentProc" : "launchd",
"parentPid" : 1,
"coalitionName" : "com.redpandaclub.quickgpt",
"isBeta" : 1,
"throttleTimeout" : 2147483647,
"codeSigningID" : "com.redpandaclub.quickgpt",
"codeSigningTeamID" : "78QN6DA972",
"codeSigningFlags" : 570442241,
"codeSigningValidationCategory" : 2,
"codeSigningTrustLevel" : 0,
"wakeTime" : 1068,
"sleepWakeUUID" : "D26684FB-2A35-4AF0-9C26-C94B9A47557C",
"sip" : "enabled",
"exception" : {"codes":"0x0000000000000000, 0x0000000000000000","rawCodes":[0,0],"type":"EXC_CRASH","signal":"SIGABRT"},
"termination" : {"code":1,"flags":518,"namespace":"DYLD","indicator":"Library missing","details":["(terminated at launch; ignore backtrace)"],"reasons":["Library not loaded: @rpath\/Pow.framework\/Versions\/A\/Pow","Referenced from: <B305073C-98E4-33B2-9BF5-00E49B690A5B> \/Applications\/Short Circuit.app\/Contents\/MacOS\/Short Circuit","Reason: tried: '\/Applications\/Short Circuit.app\/Contents\/MacOS\/Frameworks\/Pow.framework\/Versions\/A\/Pow' (no such file), '\/Applications\/Short Circuit.app\/Contents\/MacOS\/Frameworks\/Pow.framework\/Versions\/A\/Pow' (no such file), '\/Library\/Frameworks\/Pow.framework\/Versions\/A\/Pow' (no such file), '\/System\/Library\/Frameworks\/Pow.framework\/Versions\/A\/Pow' (no such file, not in dyld cache)"]},
"ktriageinfo" : "VM - (arg = 0x0) pmap_enter retried due to resource shortage\n",
"extMods" : {"caller":{"thread_create":0,"thread_set_state":0,"task_for_pid":0},"system":{"thread_create":0,"thread_set_state":26116,"task_for_pid":918},"targeted":{"thread_create":0,"thread_set_state":0,"task_for_pid":0},"warnings":0},
"faultingThread" : 0,
"threads" : [{"triggered":true,"id":24672707,"threadState":{"x":[{"value":6},{"value":1},{"value":6095595824},{"value":117},{"value":6095594800},{"value":0},{"value":0},{"value":2976},{"value":32},{"value":9},{"value":1},{"value":10},{"value":0},{"value":51},{"value":4},{"value":32768},{"value":521},{"value":6904550236,"symbolLocation":416,"symbol":"__simple_bprintf"},{"value":0},{"value":0},{"value":6095594800},{"value":117},{"value":6095595824},{"value":1},{"value":6},{"value":8444619968,"symbolLocation":0,"symbol":"gProcessInfo"},{"value":0},{"value":0},{"value":0}],"flavor":"ARM_THREAD_STATE64","lr":{"value":6905056636},"cpsr":{"value":4096},"fp":{"value":6095594752},"sp":{"value":6095594688},"esr":{"value":1442840704,"description":" Address size fault"},"pc":{"value":6905008408,"matchesCrashFrame":1},"far":{"value":4379197440}},"frames":[{"imageOffset":471320,"symbol":"__abort_with_payload","symbolLocation":8,"imageIndex":1},{"imageOffset":519548,"symbol":"abort_with_payload_wrapper_internal","symbolLocation":104,"imageIndex":1},{"imageOffset":519600,"symbol":"abort_with_payload","symbolLocation":16,"imageIndex":1},{"imageOffset":43176,"symbol":"dyld4::halt(char const*)","symbolLocation":328,"imageIndex":1},{"imageOffset":30096,"symbol":"dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*)","symbolLocation":4184,"imageIndex":1},{"imageOffset":24088,"symbol":"start","symbolLocation":1964,"imageIndex":1}]}],
"usedImages" : [
{
"source" : "P",
"arch" : "arm64",
"base" : 4371283968,
"CFBundleShortVersionString" : "2.0",
"CFBundleIdentifier" : "com.redpandaclub.quickgpt",
"size" : 6029312,
"uuid" : "b305073c-98e4-33b2-9bf5-00e49b690a5b",
"path" : "\/Applications\/Short Circuit.app\/Contents\/MacOS\/Short Circuit",
"name" : "Short Circuit",
"CFBundleVersion" : "118"
},
{
"source" : "P",
"arch" : "arm64e",
"base" : 6904537088,
"size" : 582972,
"uuid" : "6f2c2bb8-4bbc-3b64-b927-d3f3193b6295",
"path" : "\/usr\/lib\/dyld",
"name" : "dyld"
}
],
"sharedCache" : {
"base" : 6903873536,
"size" : 3539501056,
"uuid" : "581a6955-d455-3735-973b-5233bd5dd16e"
},
"vmSummary" : "ReadOnly portion of Libraries: Total=807.6M resident=0K(0%) swapped_out_or_unallocated=807.6M(100%)\nWritable regions: Total=8672K written=0K(0%) resident=0K(0%) swapped_out=0K(0%) unallocated=8672K(100%)\n\n VIRTUAL REGION \nREGION TYPE SIZE COUNT (non-coalesced) \n=========== ======= ======= \nSTACK GUARD 56.0M 1 \nStack 8176K 1 \nVM_ALLOCATE 16K 1 \n__DATA 443K 3 \n__DATA_CONST 262K 2 \n__DATA_DIRTY 7K 1 \n__LINKEDIT 801.2M 2 \n__TEXT 6460K 2 \ndyld private memory 272K 2 \n=========== ======= ======= \nTOTAL 872.5M 15 \n",
"legacyInfo" : {
"threadTriggered" : {
}
},
"logWritingSignature" : "100824b69aefbe0b7fe8088ed736feede69b7e28",
"trialInfo" : {
"rollouts" : [
{
"rolloutId" : "63582c5f8a53461413999550",
"factorPackIds" : {
},
"deploymentId" : 240000002
},
{
"rolloutId" : "62c751b6bcb0435c2153fe92",
"factorPackIds" : {
"SIRI_UNDERSTANDING_ASR_ASSISTANT" : "6439ac8efc13953c10385c45",
"SIRI_UNDERSTANDING_MORPHUN" : "63f00b1c06644d312600c7bd"
},
"deploymentId" : 240000177
}
],
"experiments" : [
{
"treatmentId" : "c28e4ee6-1b08-4f90-8e05-2809e78310a3",
"experimentId" : "6317d2003d24842ff850182a",
"deploymentId" : 400000012
}
]
}
}
Model: Mac14,2, BootROM 8422.100.650, proc 8:4:4 processors, 24 GB, SMC
Graphics: Apple M2, Apple M2, Built-In
Display: Color LCD, 2560 x 1664 Retina, Main, MirrorOff, Online
Memory Module: LPDDR5, Hynix
AirPort: spairport_wireless_card_type_wifi (0x14E4, 0x4387), wl0: Mar 8 2023 18:27:05 version 20.96.27.0.8.7.144 FWID 01-ec2ac09e
Bluetooth: Version (null), 0 services, 0 devices, 0 incoming serial ports
Network Service: Wi-Fi, AirPort, en0
USB Device: USB31Bus
USB Device: USB31Bus
Thunderbolt Bus: MacBook Air, Apple Inc.
Thunderbolt Bus: MacBook Air, Apple Inc.
I really love the way that you've included a .haptic
ChangeEffect, and was wondering if it'd be possible to do the same for playing a sound.
Right now I have my own homegrown that I expose through the environment like so
@Environment(\.sounds) private var sounds
And it's invoked by calling the playSound
method like this.
sounds.playSound(effect: .plinkSound, source: self.preferences.preferredSoundSource)
I'm envisioning a solution that looks much like .changeEffect(.haptic(.success), value: someStateChanged)
, but instead of .haptic
it would be .changeEffect(.sound(.plinkSound), value: someStateChanged)
.
I'm also including the complete solution if it can be of any help, or provide any more context, please let me know if there's any more information that would be helpful.
public enum SoundEffect {
case dataAsset(NSDataAsset)
case file(filename: String, `extension`: String)
}
public final class Sounds {
public enum Source: String {
case none
case headphones
case speakers
}
private var player: AVAudioPlayer?
public init() {}
public func playSound(effect: SoundEffect, source: Source) {
let shouldPlaySound: Bool
#if targetEnvironment(simulator)
shouldPlaySound = true
#else
switch source {
case .none:
shouldPlaySound = false
case .headphones:
shouldPlaySound = AVAudioSession.sharedInstance().currentRoute.outputs.map(\.portType).contains(where: { $0 == .headphones || $0 == .bluetoothA2DP })
case .speakers:
shouldPlaySound = true
}
#endif
if shouldPlaySound {
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.mixWithOthers])
try AVAudioSession.sharedInstance().setActive(true)
switch effect {
case .dataAsset(let dataAsset):
self.player = try AVAudioPlayer(data: dataAsset.data)
case .file(let filename, let fileExtension):
guard let url = Bundle.module.url(forResource: filename, withExtension: fileExtension) else { return }
self.player = try AVAudioPlayer(contentsOf: url)
}
self.player?.play()
} catch let error {
print(error.localizedDescription)
}
}
}
}
private enum SoundEnvironmentKey: EnvironmentKey {
static let defaultValue = Sounds()
}
public extension EnvironmentValues {
var sounds: Sounds {
get { self[SoundEnvironmentKey.self] }
set { self[SoundEnvironmentKey.self] = newValue }
}
}
The smoke layer from the anvil animation has the top part of it clipped towards the end of the animation.
Tested on Simulator iPhone SE (3rd Generation)
It is possible to use this library in UIKit?
I would love to set custom animation curves like Animation.interpolatingSpring(mass: 0.13, stiffness: 5.7, damping: 1.2, initialVelocity: 10.0)
to adjust style and duration of effects.
Hi Robb, dose pow plan to add tvOS and watchOS support?
SmokeEffect references a couple particle images which aren't there, causing a forced crash with an unwrap.
The assets for the package only contains "anvil_smoke_gray" and "anvil_smoke_white", but the effect references the below:
let particles = [
"anvil_smoke_gray",
"anvil_smoke_gray_blur",
"anvil_smoke_gray_alt",
]
Assets |
---|
I'm trying to integrate Pow as a vendor framework in a component library we maintain in a private CocoaPod.
I downloaded the XCFramework from https://packages.movingparts.io/binaries/pow/0.2.1/Pow.xcframework.zip
and am referencing it in the .podspec
locally:
...
s.ios.vendored_frameworks = "ios/VendorFrameworks/Pow.xcframework"
...
Everything seems to be compiling fine but when I use it in our mobile client I see an error:
Generating Pods project
[!] Unable to install vendored xcframework `Pow` for Pod `CandleUI`, because it contains both static and dynamic frameworks.
error Command failed with exit code 1.
Do you think this could be because it includes dylibs like SwiftUI or is released as a dylib? I'm a little bit out of my depth here and would appreciate any suggestions you may have.
As mentioned in #11 I really love the .haptic
ChangeEffect you've included in Pow. I have my own homegrown solution that I've been using, but actually prefer the ergonomics of your version.
One advantage of what I've built is that it provides many haptic options, allowing me to call a variety of haptic providers, such as
@Environment(\.haptics) private var haptics: Haptics
haptics.selectionGenerator.selectionChanged()
Would it be possible to configure .changeEffect(.hapticFeedback(…))
so it could take more feedback generators?
This is the complete solution that I have if it can be of any help, or provide any more context, please let me know if there's any more information that would be helpful.
Thanks a lot for the library, it's quickly become a staple in my apps!
public struct Haptics {
public init() {}
public let lightImpactGenerator = UIImpactFeedbackGenerator(style: .light)
public let rigidImpactGenerator = UIImpactFeedbackGenerator(style: .rigid)
public let softImpactGenerator = UIImpactFeedbackGenerator(style: .soft)
public let mediumImpactGenerator = UIImpactFeedbackGenerator(style: .medium)
public let heavyImpactGenerator = UIImpactFeedbackGenerator(style: .heavy)
public let selectionGenerator = UISelectionFeedbackGenerator()
public let notificationGenerator = UINotificationFeedbackGenerator()
}
private enum HapticsEnvironmentKey: EnvironmentKey {
static let defaultValue = Haptics()
}
public extension EnvironmentValues {
var haptics: Haptics {
get { self[HapticsEnvironmentKey.self] }
set { self[HapticsEnvironmentKey.self] = newValue }
}
}
POW is not necessarily suitable for users who utilize voiceover. It can also damage the voiceover and occasionally create an excessively large accessibility rectangle with effects like (.spray, glow, etc..). I would like to propose a global option to disable POW effects when voiceover is activated. At present, I have to do this manually.
.if(!UIAccessibility.isVoiceOverRunning) {
$0.changeEffect(
.spray(origin: UnitPoint(x: 0.25, y: 0.5)) {
Image(systemName: isFavorite ? "heart.fill" : "xmark")
.foregroundStyle(isFavorite ? .red : .gray)
}, value: itemsModel.favoriteItems.contains(item))
}
Is there a simple way to disable a conditional animation after a duration?
For example, I have a computed property on the condition:
parameter of my conditional smoke effect which watches that computed property and runs the smoke effect when it changes - this works great (and also looks really nice!)
However, this runs for as long as that computed property is true - which in my case is true until the app closes.
I've currently added a work around which involves bookkeeping for that computed property's class's ID and keeping them in a set, using a timer to insert that ID in to a set after a Task.sleep runs for n seconds.
That's a bad explanation but the code is:
@State private var myThingIds: Set<MyThing.ID> = []
// ...
MyView()
.conditionalEffect(
.smoke,
condition: myThing.needsSmokeEffect && myThingIds.contains(myThing.id) == false
)
.onChange(of: myThing.needsSmokeEffect) { oldValue, newValue in
guard newValue == true else {
return
}
Task {
try? await Task.sleep(for: .seconds(5))
myThingIds.insert(myThing.id)
}
}
It feels like there's a simpler way to do this given the richness of this package - am I missing something obvious?
Pow seems really rad, but I'd really like to use it in some macOS applications! This is just an issue to start the discussion around this potentially rather large feature request.
I've recently found myself combining multiple effects, for example haptics and sounds or more complex effects like spinning and jumping an element at the same time.
I do this by adding two changeEffect
calls, like so.
.changeEffect([.feedback(hapticImpact: .medium)], value: self.hasAnimated)
.changeEffect([.feedback(SoundEffect(url: SoundEffect.plinkSound))], value: self.hasAnimated)
The more effects I wish to chain together the longer the code grows, and the more call-sites I need to change grow the more I tweak the animation.
Instead I'd like to propose a few options that could work, as syntax that takes two modifiers and chains them together.
The simplest is an array:
.changeEffect([.feedback(hapticImpact: .medium), .feedback(SoundEffect(url: SoundEffect.plinkSound))], value: self.hasAnimated)
Which could even become variadics, now that they've become more powerful:
.changeEffect(.feedback(hapticImpact: .medium), .feedback(SoundEffect(url: SoundEffect.plinkSound)), value: self.hasAnimated)
Alternatively a function like composed(with: )
or adding(_ effect:)
could be added to compose:
.changeEffect(.feedback(hapticImpact: .medium).composed(with: .feedback(SoundEffect(url: SoundEffect.plinkSound))), value: self.hasAnimated)
And lastly, perhaps using +
operator:
.changeEffect(.feedback(hapticImpact: .medium) + .feedback(SoundEffect(url: SoundEffect.plinkSound)), value: self.hasAnimated)
Thank you as always! Would love to hear what you think, and if any of those seem like a good idea.
Hi there, back again with another Pow request. 😄
I'm currently trying to create a wiggle animation that is somewhere between AnyChangeEffect.WiggleRate.default
and AnyChangeEffect.WiggleRate.fast
. I don't really know what the ideal wiggle looks like so I was hoping to experiment a bit, but I think at the moment I'm stuck with these two choices. Is there any chance more options could be available, or having the wiggle parameters be exposed directly?
I have this code that draws multiple circles when the user touches the screen. However, I noticed that after updating to the latest version (greater than 0.3.1), the touch is not captured after the first circle. It works as normal when I remove the .conditionalEffect.
ForEach(Array(touches.enumerated()), id: \.element.id) { index, touchInfo in
AnimatingCircle(
center: touchInfo.point,
index: index,
winnerIndex: winnerIndex
)
.id(index)
.conditionalEffect(
.repeat(.glow(color: winnerIndex == nil ? .white : .green, radius: 100), every: 1.0),
condition: getWinnerWorker != nil
)
}
I believe this issue existed previously and you resolved it. Could you please fix it again, as I am currently using version 0.3.1?
One of the most common times I find myself using a selection haptic is when I want to provide a user feedback upon tapping a button. I've been able to integrate Pow's new .changeEffect(.feedbackHapticSelection, value: someValue)
really effectively in picker-type controls, but unfortunately a button tap an imperative action, which does not work great out the box with SwiftUI's and Pow's declarative APIs.
A workaround I came up with is to hold my own state, in a way that isn't particularly pretty (and seems to create some sort of extra tap once in a while for some reason I can't track down in my code.)
What I'm doing is
View
that holds a Button
.changeEffect
, based on some internal state keeping track of whether the haptic feedback is active.activateSelectionHaptic
to set the haptic active, and set it inactive 0.5 seconds later.@State private var isActive = false
var body: some View {
Button("Selection Demo", action: {
print("Selected!")
Task { await self.activateSelectionHaptic(isActive: $isActive) }
})
.changeEffect(.feedbackHapticSelection, value: isActive == true, isEnabled: self.preferences.hasHapticsEnabled)
}
extension View {
func activateSelectionHaptic(isActive: Binding<Bool>) async {
isActive.wrappedValue = true
do {
try await Task.sleep(for: .seconds(0.5))
isActive.wrappedValue = false
} catch {
isActive.wrappedValue = false
}
}
}
This isn't pretty but it does wrap up some logic that I found myself rewriting often. I was wondering if you had any ideas for how I could make this better, or perhaps with first party access include a more semantically viable version built into Pow?
Thank you as always!
I figured it would be better to add to this issue rather than create a new issue. I was wondering if it makes more sense in a cross-platform codebase to make code like this no-op rather than throwing an error,
Type 'AnyChangeEffect' has no member 'feedbackHapticSelection'
..changeEffect(.feedbackHapticSelection, value: self.isShuffling, isEnabled: self.isShuffling)I'm porting an over to the Mac and while it's possible for me to add conditional compilation flags to solve this, there are a lot of call-sites (as I love Pow) and I figured it might be worth asking if the better approach was to have the API work but just not do anything on the Mac.
Originally posted by @mergesort in #18 (comment)
Pow fails to compile for visionOS at the moment.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.