mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 21:33:26 +00:00
Show the multi-account announcement on the HomeScreen (#6265)
* Present the multi-account announcement when nothing else is showing The user session flow owns onboarding, verification and settings, so it presents the announcement in the tab sheet slot with the lowest priority: once the verification state is known, and whenever onboarding, settings or a verification sheet is dismissed. Routes and sign-out dismiss settings without triggering it, and it is marked as seen when presented. * Show the multi-account announcement on the home screen Following review, the announcement is a best-effort sheet on the home screen instead of a UserSessionFlowCoordinator state. It's presented when the room list appears with the flag on, the announcement armed and the session verified, and counts as seen once its content appears. - Restore UserSessionFlowCoordinator to develop. - HomeScreenViewModel presents the announcement through a binding and waits for a known verification state, so it never competes with the identity confirmation onboarding. - Add account only closes the sheet until the add account flow exists. - Rename MultiAccountAnnouncementScreen to MultiAccountAnnouncementView and drop its unused coordinator and view model protocol. - Size the sheet from the measured navigation bar height and match the Figma spacing; the hard-coded 44pt pushed the content under the button. * Present the multi-account announcement from the home screen view model The announcement no longer needs its own view model: the view takes the home screen's context and presents through a boolean binding, like the home screen banners. - Drop MultiAccountAnnouncementViewModel and its models. The view sends home screen actions to close or add an account and builds its own attributed subtitle. - Check the verification state when the room list appears instead of waiting for it. Restored sessions already know it by then, unverified ones get the identity confirmation cover first and the room list appears again once it's dismissed. Nothing is left subscribed, so the sheet can no longer turn up later wherever the user is.
This commit is contained in:
@@ -380,10 +380,92 @@ final class HomeScreenViewModelTests {
|
||||
#expect(userSettings.hasSeenNewSoundBanner)
|
||||
}
|
||||
|
||||
@Test
|
||||
func multiAccountAnnouncement() async throws {
|
||||
userSettings.multiAccountEnabled = true
|
||||
setupViewModel()
|
||||
|
||||
// Arming it after the view model exists (Developer options) doesn't present it on its own.
|
||||
userSettings.hasSeenMultiAccountAnnouncement = false
|
||||
let deferredFailure = deferFailure(context.$viewState, timeout: .seconds(1)) { $0.bindings.isPresentingMultiAccountAnnouncement }
|
||||
try await deferredFailure.fulfill()
|
||||
|
||||
let deferred = deferFulfillment(context.$viewState) { $0.bindings.isPresentingMultiAccountAnnouncement }
|
||||
context.send(viewAction: .screenAppeared)
|
||||
try await deferred.fulfill()
|
||||
#expect(!userSettings.hasSeenMultiAccountAnnouncement)
|
||||
|
||||
context.send(viewAction: .multiAccountAnnouncementAppeared)
|
||||
#expect(userSettings.hasSeenMultiAccountAnnouncement)
|
||||
#expect(context.viewState.bindings.isPresentingMultiAccountAnnouncement)
|
||||
|
||||
// A swipe down dismisses it without any of the announcement's actions.
|
||||
context.isPresentingMultiAccountAnnouncement = false
|
||||
let deferredReappearance = deferFailure(context.$viewState, timeout: .seconds(1)) { $0.bindings.isPresentingMultiAccountAnnouncement }
|
||||
context.send(viewAction: .screenAppeared)
|
||||
try await deferredReappearance.fulfill()
|
||||
}
|
||||
|
||||
@Test(arguments: [HomeScreenViewAction.dismissMultiAccountAnnouncement, .addAccount])
|
||||
func multiAccountAnnouncementActionsDismissIt(_ action: HomeScreenViewAction) async throws {
|
||||
userSettings.multiAccountEnabled = true
|
||||
userSettings.hasSeenMultiAccountAnnouncement = false
|
||||
setupViewModel()
|
||||
|
||||
let deferred = deferFulfillment(context.$viewState) { $0.bindings.isPresentingMultiAccountAnnouncement }
|
||||
context.send(viewAction: .screenAppeared)
|
||||
try await deferred.fulfill()
|
||||
|
||||
context.send(viewAction: action)
|
||||
#expect(!context.viewState.bindings.isPresentingMultiAccountAnnouncement)
|
||||
}
|
||||
|
||||
@Test(arguments: MultiAccountAnnouncementHiddenCase.allCases)
|
||||
func multiAccountAnnouncementHidden(_ hiddenCase: MultiAccountAnnouncementHiddenCase) async throws {
|
||||
userSettings.multiAccountEnabled = hiddenCase != .flagOff
|
||||
userSettings.hasSeenMultiAccountAnnouncement = hiddenCase == .alreadySeen
|
||||
let verificationState: SessionVerificationState = switch hiddenCase {
|
||||
case .unverified: .unverified
|
||||
case .unknownVerificationState: .unknown
|
||||
case .flagOff, .alreadySeen: .verified
|
||||
}
|
||||
let securityStateSubject = CurrentValueSubject<SessionSecurityState, Never>(.init(verificationState: verificationState, recoveryState: .enabled))
|
||||
setupViewModel(securityStatePublisher: securityStateSubject.asCurrentValuePublisher())
|
||||
|
||||
let deferred = deferFailure(context.$viewState, timeout: .seconds(1)) { $0.bindings.isPresentingMultiAccountAnnouncement }
|
||||
context.send(viewAction: .screenAppeared)
|
||||
try await deferred.fulfill()
|
||||
#expect(userSettings.hasSeenMultiAccountAnnouncement == (hiddenCase == .alreadySeen))
|
||||
}
|
||||
|
||||
@Test
|
||||
func multiAccountAnnouncementPresentsOnTheNextAppearanceOnceVerified() async throws {
|
||||
userSettings.multiAccountEnabled = true
|
||||
userSettings.hasSeenMultiAccountAnnouncement = false
|
||||
let securityStateSubject = CurrentValueSubject<SessionSecurityState, Never>(.init(verificationState: .unverified, recoveryState: .enabled))
|
||||
setupViewModel(securityStatePublisher: securityStateSubject.asCurrentValuePublisher())
|
||||
|
||||
let deferredFailure = deferFailure(context.$viewState, timeout: .seconds(1)) { $0.bindings.isPresentingMultiAccountAnnouncement }
|
||||
context.send(viewAction: .screenAppeared)
|
||||
try await deferredFailure.fulfill()
|
||||
|
||||
// Becoming verified doesn't present it on its own…
|
||||
securityStateSubject.send(.init(verificationState: .verified, recoveryState: .enabled))
|
||||
let deferredVerifiedFailure = deferFailure(context.$viewState, timeout: .seconds(1)) { $0.bindings.isPresentingMultiAccountAnnouncement }
|
||||
try await deferredVerifiedFailure.fulfill()
|
||||
|
||||
// …the room list appearing again does, e.g. once the identity confirmation cover is dismissed.
|
||||
let deferred = deferFulfillment(context.$viewState) { $0.bindings.isPresentingMultiAccountAnnouncement }
|
||||
context.send(viewAction: .screenAppeared)
|
||||
try await deferred.fulfill()
|
||||
}
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
enum InviteType { case rooms, spaces }
|
||||
|
||||
enum MultiAccountAnnouncementHiddenCase: CaseIterable { case flagOff, alreadySeen, unverified, unknownVerificationState }
|
||||
|
||||
@Test
|
||||
func roomListModeIsSetSynchronouslyOnAWarmLaunch() {
|
||||
setupViewModel()
|
||||
|
||||
Reference in New Issue
Block a user