iOS client for Grain grain.social
ios photography atproto
7
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: profile avatar press animation and story viewer re-open reliability

Remove .interactive() from liquidGlassCircle to fix color blowout on
press. Add custom scale animation via simultaneousGesture. Switch
profile story viewer from customFullScreenCover to standard
fullScreenCover to eliminate blocking delay on re-open.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

+12 -2
+1 -1
Grain/Utilities/LiquidGlass.swift
··· 9 9 /// Applies iOS 26 Liquid Glass effect in a circular shape. 10 10 func liquidGlassCircle() -> some View { 11 11 self.clipShape(Circle()) 12 - .glassEffect(.regular.interactive()) 12 + .glassEffect(.regular) 13 13 } 14 14 }
+11 -1
Grain/Views/Profile/ProfileView.swift
··· 19 19 @State private var viewMode: ProfileViewMode = .grid 20 20 @State private var zoomState = ImageZoomState() 21 21 @State private var cardStoryAuthor: GrainStoryAuthor? 22 + @State private var avatarPressed = false 22 23 let client: XRPCClient 23 24 let actor: String 24 25 var isRoot = false ··· 53 54 AvatarView(url: profile.avatar, size: 80) 54 55 .liquidGlassCircle() 55 56 } 57 + .scaleEffect(avatarPressed ? 1.08 : 1.0) 58 + .animation(.spring(response: 0.2, dampingFraction: 0.6), value: avatarPressed) 59 + .contentShape(Circle()) 56 60 .onTapGesture { 57 61 if !viewModel.stories.isEmpty { 58 62 showStoryViewer = true ··· 60 64 showAvatarOverlay = true 61 65 } 62 66 } 67 + .simultaneousGesture( 68 + DragGesture(minimumDistance: 0) 69 + .onChanged { _ in if !avatarPressed { avatarPressed = true } } 70 + .onEnded { _ in avatarPressed = false } 71 + ) 63 72 64 73 HStack(spacing: 0) { 65 74 StatView(count: profile.galleryCount ?? 0, label: "Galleries") ··· 255 264 .navigationDestination(item: $selectedHashtag) { tag in 256 265 HashtagFeedView(client: client, tag: tag) 257 266 } 258 - .customFullScreenCover(isPresented: $showStoryViewer) { 267 + .fullScreenCover(isPresented: $showStoryViewer) { 259 268 if let profile = viewModel.profile { 260 269 StoryViewer( 261 270 authors: [GrainStoryAuthor( ··· 271 280 }, 272 281 onDismiss: { showStoryViewer = false } 273 282 ) 283 + .environment(auth) 274 284 } 275 285 } 276 286 .fullScreenCover(item: $cardStoryAuthor) { author in