@@ -33,6 +33,8 @@ struct AvatarPickerView: View {
3333 @State var avatars : [ String : String ] ?
3434 @State var selectedAvatar : NSImage ?
3535 @State var avatarChanged : Bool = false
36+ @State private var randomSelectedAvatarKey : String ?
37+ @State private var highlightedItems : Set < String > = [ ]
3638
3739 private func loadAvatars( category: AvatarCategory ) -> [ String : String ] ? {
3840 debugPrint ( " Loading Avatar category: \( category) " )
@@ -74,21 +76,11 @@ struct AvatarPickerView: View {
7476 cornerRadius: 72 ,
7577 size: CGSize ( width: 144 , height: 144 ) ,
7678 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
8481 } ,
8582 deleteAction: {
86- do {
87- selectedAvatar = nil
88- }
89- catch {
90- debugPrint ( " failed to remove planet avatar: \( error) " )
91- }
83+ self . selectedAvatar = nil
9284 }
9385 )
9486 . padding ( . bottom, 20 )
@@ -98,53 +90,59 @@ struct AvatarPickerView: View {
9890
9991 VStack ( spacing: 0 ) {
10092 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) " )
130125 let image = NSImage ( named: aKey)
131126 if let image = image, let avatarURL = image. temporaryURL
132127 {
133128 selectedAvatar = image
134129 avatarChanged = true
135- debugPrint ( " Set planet avatar to \( aKey) " )
130+ debugPrint ( " Set planet avatar to \( aKey) , at: \( avatarURL ) " )
136131 }
137132 }
138- catch {
139- debugPrint ( " failed to update planet avatar: \( error ) " )
133+ else {
134+ debugPrint ( " Cannot set planet avatar" )
140135 }
141136 }
142- else {
143- debugPrint ( " Cannot set planet avatar " )
144- }
145-
146137 }
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+ }
148146 }
149147 }
150148 }
@@ -215,7 +213,23 @@ struct AvatarPickerView: View {
215213 if let image = image, let avatarURL = image. temporaryURL {
216214 selectedAvatar = image
217215 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+ }
219233 }
220234 }
221235 }
0 commit comments