@@ -33,6 +33,8 @@ struct AvatarPickerView: View {
33
33
@State var avatars : [ String : String ] ?
34
34
@State var selectedAvatar : NSImage ?
35
35
@State var avatarChanged : Bool = false
36
+ @State private var randomSelectedAvatarKey : String ?
37
+ @State private var highlightedItems : Set < String > = [ ]
36
38
37
39
private func loadAvatars( category: AvatarCategory ) -> [ String : String ] ? {
38
40
debugPrint ( " Loading Avatar category: \( category) " )
@@ -74,21 +76,11 @@ struct AvatarPickerView: View {
74
76
cornerRadius: 72 ,
75
77
size: CGSize ( width: 144 , height: 144 ) ,
76
78
uploadAction: { url in
77
- do {
78
- selectedAvatar = NSImage ( contentsOf: url)
79
- avatarChanged = true
80
- }
81
- catch {
82
- debugPrint ( " failed to upload planet avatar: \( error) " )
83
- }
79
+ self . selectedAvatar = NSImage ( contentsOf: url)
80
+ self . avatarChanged = true
84
81
} ,
85
82
deleteAction: {
86
- do {
87
- selectedAvatar = nil
88
- }
89
- catch {
90
- debugPrint ( " failed to remove planet avatar: \( error) " )
91
- }
83
+ self . selectedAvatar = nil
92
84
}
93
85
)
94
86
. padding ( . bottom, 20 )
@@ -98,53 +90,59 @@ struct AvatarPickerView: View {
98
90
99
91
VStack ( spacing: 0 ) {
100
92
if let avatars = avatars, let keys = Array ( avatars. keys) as? [ String ] {
101
- ScrollView {
102
- LazyVGrid (
103
- columns: [ GridItem ( ) , GridItem ( ) , GridItem ( ) ] ,
104
- alignment: . center
105
- ) {
106
- ForEach ( keys. sorted ( ) , id: \. self) { aKey in
107
- VStack {
108
- Image ( aKey)
109
- . interpolation ( . high)
110
- . resizable ( )
111
- . frame ( width: 64 , height: 64 )
112
- . cornerRadius ( 32 )
113
- . overlay (
114
- RoundedRectangle ( cornerRadius: 32 )
115
- . stroke ( Color ( " BorderColor " ) , lineWidth: 1 )
116
- )
117
- . padding ( . top, 16 )
118
- . padding ( . horizontal, 16 )
119
- . padding ( . bottom, 8 )
120
-
121
- Text ( avatars [ aKey] ?? " " )
122
- . font ( . caption)
123
- . foregroundColor ( . primary)
124
- }
125
- . onTapGesture {
126
- debugPrint ( " Tapped on avatar: \( aKey) " )
127
- if case . myPlanet( let planet) = store. selectedView {
128
- debugPrint ( " About to set planet avatar to \( aKey) " )
129
- do {
93
+ ScrollViewReader { proxy in
94
+ ScrollView {
95
+ LazyVGrid (
96
+ columns: [ GridItem ( ) , GridItem ( ) , GridItem ( ) ] ,
97
+ alignment: . center
98
+ ) {
99
+ ForEach ( keys. sorted ( ) , id: \. self) { aKey in
100
+ VStack {
101
+ let isAnimation : Bool = highlightedItems. contains ( aKey)
102
+ Image ( aKey)
103
+ . interpolation ( . high)
104
+ . resizable ( )
105
+ . frame ( width: 64 , height: 64 )
106
+ . cornerRadius ( 32 )
107
+ . overlay (
108
+ RoundedRectangle ( cornerRadius: 32 )
109
+ . stroke ( isAnimation ? Color . accentColor : Color ( " BorderColor " ) , lineWidth: isAnimation ? 4 : 1 )
110
+ )
111
+ . padding ( . top, 16 )
112
+ . padding ( . horizontal, 16 )
113
+ . padding ( . bottom, 8 )
114
+ . scaleEffect ( isAnimation ? 1.05 : 1.0 )
115
+
116
+ Text ( avatars [ aKey] ?? " " )
117
+ . font ( . caption)
118
+ . foregroundColor ( . primary)
119
+ }
120
+ . id ( aKey)
121
+ . onTapGesture {
122
+ debugPrint ( " Tapped on avatar: \( aKey) " )
123
+ if case . myPlanet( let planet) = store. selectedView {
124
+ debugPrint ( " About to set planet \( planet. name) avatar to \( aKey) " )
130
125
let image = NSImage ( named: aKey)
131
126
if let image = image, let avatarURL = image. temporaryURL
132
127
{
133
128
selectedAvatar = image
134
129
avatarChanged = true
135
- debugPrint ( " Set planet avatar to \( aKey) " )
130
+ debugPrint ( " Set planet avatar to \( aKey) , at: \( avatarURL ) " )
136
131
}
137
132
}
138
- catch {
139
- debugPrint ( " failed to update planet avatar: \( error ) " )
133
+ else {
134
+ debugPrint ( " Cannot set planet avatar" )
140
135
}
141
136
}
142
- else {
143
- debugPrint ( " Cannot set planet avatar " )
144
- }
145
-
146
137
}
147
-
138
+ }
139
+ }
140
+ . onChange ( of: randomSelectedAvatarKey) { newValue in
141
+ guard let newValue else { return }
142
+ Task { @MainActor in
143
+ withAnimation ( . easeOut( duration: 0.3 ) ) {
144
+ proxy. scrollTo ( newValue, anchor: . top)
145
+ }
148
146
}
149
147
}
150
148
}
@@ -215,7 +213,23 @@ struct AvatarPickerView: View {
215
213
if let image = image, let avatarURL = image. temporaryURL {
216
214
selectedAvatar = image
217
215
avatarChanged = true
218
- debugPrint ( " Set planet avatar to \( randomKey) " )
216
+ debugPrint ( " Set planet avatar to \( randomKey) , at: \( avatarURL) " )
217
+ Task { @MainActor in
218
+ highlightedItems. removeAll ( )
219
+ randomSelectedAvatarKey = randomKey
220
+ Task . detached ( priority: . utility) {
221
+ try ? await Task . sleep ( nanoseconds: 300_000_000 )
222
+ let _ = await MainActor . run {
223
+ self . highlightedItems. insert ( randomKey)
224
+ }
225
+ try ? await Task . sleep ( nanoseconds: 600_000_000 )
226
+ await MainActor . run {
227
+ let _ = withAnimation ( . easeOut( duration: 0.4 ) ) {
228
+ highlightedItems. removeAll ( )
229
+ }
230
+ }
231
+ }
232
+ }
219
233
}
220
234
}
221
235
}
0 commit comments