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.

refactor: DRY and dead-code cleanup in StoryViewer

- Remove nextStoryFromTrailing state var and its .transition(.asymmetric)
on the story image — within-story nav is never wrapped in withAnimation
so the transition never fired
- Consolidate showReportSheet + reportStoryUri + reportStoryCid (3 vars)
into reportTarget: GrainStory? using fullScreenCover(item:)
- Extract advanceStory(by:) to eliminate duplicated 5-line state reset
in goToNext and goToPrevious

+19 -31
+19 -31
Grain/Views/Stories/StoryViewer.swift
··· 71 71 @State private var isLoadingStories = false 72 72 @State private var timer = StoryTimer() 73 73 @State private var showDeleteConfirm = false 74 - @State private var showReportSheet = false 75 - @State private var reportStoryUri = "" 76 - @State private var reportStoryCid = "" 74 + @State private var reportTarget: GrainStory? 77 75 @State private var showLocationCopied = false 78 76 @State private var lastNavTime: Date = .distantPast 79 77 @State private var labelRevealed = false ··· 87 85 @State private var transitionGeneration = 0 88 86 @State private var authorHistory: [(authorIndex: Int, storyIndex: Int)] = [] 89 87 @State private var imagePrefetcher = ImagePrefetcher() 90 - @State private var nextStoryFromTrailing = true 91 88 @State private var isDragging = false 92 89 93 90 init(authors: [GrainStoryAuthor], startAuthorDid: String? = nil, client: XRPCClient, onProfileTap: ((String) -> Void)? = nil, onDismiss: (() -> Void)? = nil) { ··· 153 150 timer.start() 154 151 } 155 152 } 156 - .fullScreenCover(isPresented: $showReportSheet) { 157 - ReportView(client: client, subjectUri: reportStoryUri, subjectCid: reportStoryCid) 153 + .fullScreenCover(item: $reportTarget) { story in 154 + ReportView(client: client, subjectUri: story.uri, subjectCid: story.cid) 158 155 .environment(auth) 159 156 } 160 - .onChange(of: showReportSheet) { 161 - if !showReportSheet { 162 - timer.start() 163 - } 157 + .onChange(of: reportTarget?.uri) { 158 + if reportTarget == nil { timer.start() } 164 159 } 165 160 .task { 166 161 guard !isPreview else { return } ··· 332 327 } 333 328 } 334 329 .id(story.uri) 335 - .transition(.asymmetric( 336 - insertion: .move(edge: nextStoryFromTrailing ? .trailing : .leading).combined(with: .opacity), 337 - removal: .move(edge: nextStoryFromTrailing ? .leading : .trailing).combined(with: .opacity) 338 - )) 339 330 340 331 // Tap zones 341 332 VStack(spacing: 0) { ··· 355 346 } 356 347 } 357 348 } 358 - .allowsHitTesting(!showReportSheet && !showDeleteConfirm && (labelRevealed || storyLabelResult.action == .none || storyLabelResult.action == .badge)) 349 + .allowsHitTesting(reportTarget == nil && !showDeleteConfirm && (labelRevealed || storyLabelResult.action == .none || storyLabelResult.action == .badge)) 359 350 } else { 360 351 ProgressView() 361 352 .tint(.white) ··· 406 397 Button { 407 398 guard let story else { return } 408 399 timer.stop() 409 - reportStoryUri = story.uri 410 - reportStoryCid = story.cid 411 - showReportSheet = true 400 + reportTarget = story 412 401 } label: { 413 402 Image(systemName: "flag") 414 403 .foregroundStyle(.white) ··· 467 456 468 457 private func canNavigate() -> Bool { 469 458 !isLoadingStories && !stories.isEmpty 470 - && !showReportSheet && !showDeleteConfirm 459 + && reportTarget == nil && !showDeleteConfirm 471 460 && !isDragging 472 461 && Date().timeIntervalSince(lastNavTime) > 0.3 473 462 } ··· 484 473 timer.stop() 485 474 lastNavTime = Date() 486 475 if currentStoryIndex < stories.count - 1 { 487 - timer.progress = 0 488 - currentStoryIndex += 1 489 - imageLoaded = false 490 - labelRevealed = false 491 - showLocationCopied = false 492 - prefetchStoryImages() 476 + advanceStory(by: 1) 493 477 } else { 494 478 goToNextAuthor() 495 479 } ··· 500 484 timer.stop() 501 485 lastNavTime = Date() 502 486 if currentStoryIndex > 0 { 503 - timer.progress = 0 504 - currentStoryIndex -= 1 505 - imageLoaded = false 506 - labelRevealed = false 507 - showLocationCopied = false 508 - prefetchStoryImages() 487 + advanceStory(by: -1) 509 488 } else { 510 489 goToPreviousAuthor() 511 490 } 491 + } 492 + 493 + private func advanceStory(by delta: Int) { 494 + timer.progress = 0 495 + currentStoryIndex += delta 496 + imageLoaded = false 497 + labelRevealed = false 498 + showLocationCopied = false 499 + prefetchStoryImages() 512 500 } 513 501 514 502 private func goToNextAuthor() {