Grr. Seriously, this was not working when I posted. Even after cleans and rebuilds. But now... it works. I even made a demo app, but it works there too. So to quote Emily, "Nevermind!"
Post
Replies
Boosts
Views
Activity
I only needed to add "iTunes/Media Access", not "Full Disk Access". I'd done that for a prior IT app I'd written but forgot the access toggle. I'll suggest they update the docs. [Edit: suggested at FB16323701]
Answer by @shenlong2210 worked for me, though for zsh I needed slightly different syntax:
sudo rm -rfv /Library/Caches/com.apple.iconservices.store
sudo find /private/var/folders/ \( -name com.apple.dock.iconcache -or -name com.apple.iconservices \) -exec rm -rfv {} \;
sleep 3
sudo touch /Applications/*
touch ~/Applications/*
killall Dock
killall Finder
(I didn't use the touch commands and it seemed to work for my situation.)
I wish. On a closely related topic, I put in FB15164782 asking for documentation on how SwiftData encodes/decodes struct-valued attributes, but yes, more general documentation would help. And better runtime diagnostics. Adding iCloud support to a store further limits the attribute types allowed.
I put in FB15164782 asking for documentation on how SwiftData encodes/decodes struct-valued attributes.
Ditto here. All the other advice on the subject of struct-typed model attributes asserts the struct must be Codable and it stored in a single column. The evidence shows the struct's properties are stored as individual columns, spreading the structure out and using some truly unexpected Encoder/Decoder that's not JSON. For instance, I defined
struct ComplexNumber: Codable {
var real: Double
var imaginary: Double
}
and
@Model
final class Item {
var timestamp: Date
var number1: ComplexNumber
var number2: ComplexNumber
and got this in SQLite:
This works fine when fetching the records, but in my app it fails to decode when some of the struct's properties are Optional. I can write decoder() to deal with the optionals, but apparently SwiftData's Decoder can't cope. I suppose there's some similar limitation for Dictionary properties.
The purpose of the aux view is to give access to a set of semi-advanced search controls. The controls I want to present are more in the line of filter presets, like, say, an Amazon search's filter sidebar, but using Picker popups or toggles.
In the screen GIF below, you'll see me tapping the "primary" search field and how it animates into search mode: The field moves up and shrinks to make space for the Cancel button. When canceling or submitting the search, search mode ends and it animates in reverse.
My hacky aux view here is just a VStack with a couple of TextFields, for testing purposes. When I add it to MyListView it animates in nicely when isSearching becomes true, but animates out badly when it becomes false. To wit, the removal transition works correctly until it's done, and then the scroll view snaps up, hiding the primary search field. Without putting in the conditional aux view the primary search field stays visible. For an example of that, try the Notes app's search field.
@Claude31, I want the aux view to only be visible only while the .searchable primary search field is active. When it's not active the aux view hides away.
@DTS Engineer, the goal is a few critical preset filters. I believe using search suggestions (or tokens) would be worse as they would fill up/clog up the search text field and make it hard for a user to refine the search with their own typed text.
Thanks for your replies and ideas.
If I can't avoid the animation problem, I'll abandon this design goal and go with an "Advanced Search" sheet instead. Not as good as a compact live search, but OK.
Workaround: Perform this command in Terminal...
defaults delete com.apple.dt.Xcode
Here is a solution I'm quite happy with. It involves making the custom ViewModifier, which is fine since that pretty much what f(redMarks) is:
struct CartoonMotion: ViewModifier {
let marks: [Mark]
func body(content: Content) -> some View {
content
.keyframeAnimator(initialValue: marks[0]) { content, value in
content
.rotationEffect(value.angle)
.offset(value.offset)
} keyframes: { _ in
KeyframeTrack(\.offset) {
for value in marks.dropFirst() {
LinearKeyframe(value.offset, duration: 1.0)
}
}
KeyframeTrack(\.angle) {
for value in marks.dropFirst() {
LinearKeyframe(value.angle, duration: 1.0)
}
}
}
}
}
extension View {
func cartoonMotion(_ marks: [Mark]) -> some View {
modifier(CartoonMotion(marks: marks))
}
}
In the main cartoon scene each "sprite" looks like this:
Rectangle().fill(.red).frame(width: 20, height: 30)
.cartoonMotion(Self.redMarks)
This gives. Avery compact scene view that hides the details of converting Marks to KeyframeTrack and xxxKeyframes. Thanks to DTS Engineer for contributing to this solution.
That doesn't hide all the KeyframeTrack items as well. It helps a bit, though:
Rectangle().fill(.red).frame(width: 20, height: 30)
.keyframeAnimator(initialValue: Self.blackMarks[0]) { content, value in
content
.rotationEffect(value.angle)
.offset(value.offset)
} keyframes: { _ in
/* f(redMarks) */
KeyframeTrack(\.offset) {
for value in Self.redMarks.dropFirst() {
LinearKeyframe(value.offset, duration: 1.0)
}
}
KeyframeTrack(\.angle) {
for value in Self.redMarks.dropFirst() {
LinearKeyframe(value.angle, duration: 1.0)
}
}
That's still a lot of code for the keyframes parameter. The ideal solution would keep the code very tight in the view's body, and look like something this for readability:
Rectangle().fill(.red).frame(width: 20, height: 30)
.keyframeAnimator(initialValue: Self.blackMarks[0]) { content, value in
content
.rotationEffect(value.angle)
.offset(value.offset)
} keyframes: { _ in tracks(Self.redMarks) }
Here is a more complete example of what I'm trying for:
import SwiftUI
struct Mark {
var offset: CGSize
var angle: Angle
init(offset: CGSize, angle: Angle) {
self.offset = offset
self.angle = angle
}
init(x: CGFloat, y: CGFloat, angle: Angle) {
self.offset = CGSize(width: x, height: y)
self.angle = angle
}
}
struct ContentView: View {
static let blackMarks: [Mark] = [
Mark(x: 0, y: 0, angle: .degrees(0)),
Mark(x: 50, y: 0, angle: .degrees(-90)),
Mark(x: 50, y: -100, angle: .degrees(-180)),
Mark(x: 0, y: -100, angle: .degrees(-270)),
Mark(x: 0, y: 0, angle: .degrees(-360))
]
static let redMarks: [Mark] = [
Mark(x: 0, y: 0, angle: .degrees(0)),
Mark(x: -50, y: 0, angle: .degrees(90)),
Mark(x: -50, y: 100, angle: .degrees(180)),
Mark(x: 0, y: 100, angle: .degrees(270)),
Mark(x: 0, y: 0, angle: .degrees(360))
]
var body: some View {
ZStack {
Rectangle().fill(.black).frame(width: 20, height: 30)
.keyframeAnimator(initialValue: Self.blackMarks[0]) { content, value in
content
.rotationEffect(value.angle)
.offset(value.offset)
} keyframes: { _ in
KeyframeTrack(\.offset) {
LinearKeyframe(Self.blackMarks[1].offset, duration: 1.0)
LinearKeyframe(Self.blackMarks[2].offset, duration: 1.0)
LinearKeyframe(Self.blackMarks[3].offset, duration: 1.0)
LinearKeyframe(Self.blackMarks[4].offset, duration: 1.0)
}
KeyframeTrack(\.angle) {
LinearKeyframe(Self.blackMarks[1].angle, duration: 1.0)
LinearKeyframe(Self.blackMarks[2].angle, duration: 1.0)
LinearKeyframe(Self.blackMarks[3].angle, duration: 1.0)
LinearKeyframe(Self.blackMarks[4].angle, duration: 1.0)
}
}
Rectangle().fill(.red).frame(width: 20, height: 30)
.keyframeAnimator(initialValue: Self.blackMarks[0]) { content, value in
content
.rotationEffect(value.angle)
.offset(value.offset)
} keyframes: { _ in
/* Now, generate the equivalent tracks and keyframes as a function of redMarks */
}
}
}
}
#Preview {
ContentView()
}
Solved my problem. I needed to add focusable:
MyView()
.focusable()
.onPlayPauseCommand {...}
FB13378024
I just tried this:
struct createTabTipHomePage: Tip {
let id = "MyViewName.createTabTipHomePage"
And now the tip will remember its state properly. And yet my other tips don't need this, so I don't know what's going on.
I've tried these same steps and can't get the tip from popping up each new app launch.