Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions Flipcash/Core/Screens/Main/Username/UsernameLookupScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ private let logger = Logger(label: "flipcash.username-lookup")
/// verification screens use (`PhoneVerificationViewModel.swift:320-329`), and so
/// is the push.
///
/// This screen then drops out from under the chat, since a chat's Back belongs
/// on the chat list. It goes while the push is still animating: the removal is a
/// whole-path rewrite, which remounts the chat, and a freshly-mounted chat
/// settles its layout a beat after it appears. Under the transition that settle
/// is hidden — the same way it is on every other push into a chat.
/// The route in then drops out from under the chat — this screen and the New
/// Chat picker above the list — since a chat's Back belongs on the chat list. It
/// goes while the push is still animating: the removal is a whole-path rewrite,
/// which remounts the chat, and a freshly-mounted chat settles its layout a beat
/// after it appears. Under the transition that settle is hidden — the same way
/// it is on every other push into a chat.
struct UsernameLookupScreen: View {

@Environment(Container.self) private var container
Expand Down Expand Up @@ -158,6 +159,12 @@ struct UsernameLookupScreen: View {
lookupTask = nil

let chat = AppRouter.Destination.tipConversationForUser(userID)

// Measured rather than assumed: this screen is reached through
// the New Chat picker today and was reached straight off the
// chat list before it, so a fixed depth silently stops matching
// the moment a screen is added to or removed from the route.
let depthWithChat = router[.tips].count + 1
router.push(chat)

// Well inside the push transition, so the remounted chat settles
Expand All @@ -169,7 +176,7 @@ struct UsernameLookupScreen: View {

// Unless they went back while it landed: the lookup left with
// them, and rewriting the path would drag the chat back.
guard router[.tips].count == 2 else { return }
guard router[.tips].count == depthWithChat else { return }

// Unanimated, because nothing is arriving — only the entry
// underneath is leaving. Animated, SwiftUI stages the remount as
Expand Down
34 changes: 34 additions & 0 deletions FlipcashTests/UsernameLookupRoutingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,40 @@ struct UsernameLookupRoutingTests {
#expect(ConversationContext.existing(chatID).resolvedContact(in: [contact]) != nil)
}

// MARK: - Back stack -

@Test("The chat list is not a fixed number of screens below the lookup")
func backStack_routeInHasNoFixedDepth() {
// The lookup was pushed straight off the chat list until the New Chat
// picker went in between (#790). A screen that assumed the depth it had
// then is a screen that stops unwinding the moment the route changes.
let router = AppRouter()
router.activeTabStack = .tips

router.push(.newChat)
router.push(.usernameLookup)

#expect(router[.tips].count == 2)
}

@Test("Back from a chat opened by handle lands on the chat list")
func backStack_rewriteLeavesOnlyTheChat() {
let router = AppRouter()
router.activeTabStack = .tips
router.push(.newChat)
router.push(.usernameLookup)

let chat = AppRouter.Destination.tipConversationForUser(UUID())
let depthWithChat = router[.tips].count + 1
router.push(chat)
#expect(router[.tips].count == depthWithChat)

// What the screen does once the push has started: neither the picker
// nor the lookup is somewhere Back belongs, and the list is the root.
router.setPath([chat], on: .tips)
#expect(router[.tips].count == 1)
}

// MARK: - Counterpart -

@Test("The fetched profile supplies the name and handle the chat shows")
Expand Down
Loading