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.

More instrumentation

authored by

Hima Aramona and committed by
Chad Miller
b103cf64 bd896df6

+44
+2
Grain/GrainApp.swift
··· 8 8 @main 9 9 struct GrainApp: App { 10 10 init() { 11 + LaunchMetrics.beginTFP() 12 + LaunchMetrics.beginPreBody() 11 13 appSignposter.emitEvent("GrainAppInitBegin") 12 14 // Defer Nuke DataCache setup off the main-thread init path — no images 13 15 // load during the ~800ms before MainTabView.task fires, so this is safe.
+33
Grain/Utilities/LaunchMetrics.swift
··· 1 + import os 2 + 3 + @MainActor 4 + enum LaunchMetrics { 5 + static let signposter = OSSignposter(subsystem: "social.grain.grain", category: "AppLaunch") 6 + 7 + private static var tfpState: OSSignpostIntervalState? 8 + private static var preBodyState: OSSignpostIntervalState? 9 + private static var preBodyEnded = false 10 + private static var tfpEnded = false 11 + 12 + static func beginTFP() { 13 + tfpState = signposter.beginInterval("TFP", id: signposter.makeSignpostID()) 14 + } 15 + 16 + static func endTFPOnce() { 17 + guard !tfpEnded, let state = tfpState else { return } 18 + tfpEnded = true 19 + signposter.endInterval("TFP", state) 20 + tfpState = nil 21 + } 22 + 23 + static func beginPreBody() { 24 + preBodyState = signposter.beginInterval("PreBody", id: signposter.makeSignpostID()) 25 + } 26 + 27 + static func endPreBodyOnce() { 28 + guard !preBodyEnded, let state = preBodyState else { return } 29 + preBodyEnded = true 30 + signposter.endInterval("PreBody", state) 31 + preBodyState = nil 32 + } 33 + }
+8
Grain/Views/Feed/FeedView.swift
··· 71 71 } 72 72 .task { 73 73 guard !isPreview else { return } 74 + let prefsSpid = launchSignposter.makeSignpostID() 75 + let prefsState = launchSignposter.beginInterval("FeedPrefsLoad", id: prefsSpid) 74 76 await prefsViewModel.loadIfNeeded(auth: auth.authContext()) 77 + launchSignposter.endInterval("FeedPrefsLoad", prefsState) 75 78 launchSignposter.emitEvent("FeedPrefsReady") 76 79 await storyViewModel.load(auth: auth.authContext(), storyStatusCache: storyStatusCache) 77 80 } ··· 469 472 return 470 473 } 471 474 if !viewModel.hasFetchedInitial { 475 + let initialSpid = launchSignposter.makeSignpostID() 476 + let initialState = launchSignposter.beginInterval("FeedInitialLoad", id: initialSpid) 477 + launchSignposter.emitEvent("FeedInitialLoadStart") 472 478 await viewModel.loadInitial(auth: auth.authContext()) 479 + launchSignposter.endInterval("FeedInitialLoad", initialState) 473 480 launchSignposter.emitEvent("FeedFirstContent") 481 + LaunchMetrics.endTFPOnce() 474 482 lastLoadTime = .now 475 483 } 476 484 if showSuggestedUsers, !suggestedLoaded, let did = auth.userDID {
+1
Grain/Views/MainTabView.swift
··· 46 46 47 47 var body: some View { 48 48 let _ = launchSignposter.emitEvent("MainTabViewBodyBegin") 49 + let _ = LaunchMetrics.endPreBodyOnce() 49 50 let _ = Self.badgeAppearanceConfigured 50 51 Group { 51 52 if let client {