diff --git a/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/MockUserOtherSessionsScreenState.swift b/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/MockUserOtherSessionsScreenState.swift index 3e1821406..ffcc4f003 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/MockUserOtherSessionsScreenState.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/MockUserOtherSessionsScreenState.swift @@ -25,6 +25,7 @@ enum MockUserOtherSessionsScreenState: MockScreenState, CaseIterable { // mock that screen. case inactiveSessions + case unverifiedSessions /// The associated screen var screenType: Any.Type { @@ -34,15 +35,23 @@ enum MockUserOtherSessionsScreenState: MockScreenState, CaseIterable { /// A list of screen state definitions static var allCases: [MockUserOtherSessionsScreenState] { // Each of the presence statuses - [.inactiveSessions] + [.inactiveSessions, .unverifiedSessions] } /// Generate the view struct for the screen state. var screenView: ([Any], AnyView) { - let viewModel = UserOtherSessionsViewModel(sessionInfos: inactiveSessions(), + let viewModel: UserOtherSessionsViewModel + switch self { + case .inactiveSessions: + viewModel = UserOtherSessionsViewModel(sessionInfos: inactiveSessions(), filter: .inactive, title: VectorL10n.userOtherSessionSecurityRecommendationTitle) + case .unverifiedSessions: + viewModel = UserOtherSessionsViewModel(sessionInfos: unverifiedSessions(), + filter: .unverified, + title: VectorL10n.userOtherSessionSecurityRecommendationTitle) + } // can simulate service and viewModel actions here if needs be. @@ -118,4 +127,40 @@ enum MockUserOtherSessionsScreenState: MockScreenState, CaseIterable { isActive: false, isCurrent: false)] } + + private func unverifiedSessions() -> [UserSessionInfo] { + [UserSessionInfo(id: "0", + name: "iOS", + deviceType: .mobile, + isVerified: false, + lastSeenIP: "10.0.0.10", + lastSeenTimestamp: nil, + applicationName: nil, + applicationVersion: nil, + applicationURL: nil, + deviceModel: nil, + deviceOS: nil, + lastSeenIPLocation: nil, + clientName: nil, + clientVersion: nil, + isActive: true, + isCurrent: true), + UserSessionInfo(id: "1", + name: "macOS", + deviceType: .desktop, + isVerified: false, + lastSeenIP: "1.0.0.1", + lastSeenTimestamp: Date().timeIntervalSince1970 - 8000000, + applicationName: nil, + applicationVersion: nil, + applicationURL: nil, + deviceModel: nil, + deviceOS: nil, + lastSeenIPLocation: nil, + clientName: nil, + clientVersion: nil, + isActive: true, + isCurrent: false) + ] + } } diff --git a/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/Test/UI/UserOtherSessionsUITests.swift b/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/Test/UI/UserOtherSessionsUITests.swift index e5ae0f0c1..719c31190 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/Test/UI/UserOtherSessionsUITests.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/Test/UI/UserOtherSessionsUITests.swift @@ -31,4 +31,17 @@ class UserOtherSessionsUITests: MockScreenTestCase { XCTAssertTrue(app.buttons["RiotSwiftUI Mobile: iOS, Inactive for 90+ days"].exists) } + + func test_whenOtherSessionsWithUnverifiedSessionFilterPresented_correctHeaderDisplayed() { + app.goToScreenWithIdentifier(MockUserOtherSessionsScreenState.unverifiedSessions.title) + + XCTAssertTrue(app.staticTexts[VectorL10n.userSessionsOverviewSecurityRecommendationsUnverifiedTitle].exists) + XCTAssertTrue(app.staticTexts[VectorL10n.userOtherSessionUnverifiedSessionsHeaderSubtitle].exists) + } + + func test_whenOtherSessionsWithUnverifiedSessionFilterPresented_correctItemsDisplayed() { + app.goToScreenWithIdentifier(MockUserOtherSessionsScreenState.unverifiedSessions.title) + + XCTAssertTrue(app.buttons["RiotSwiftUI Mobile: iOS, Unverified ยท Your current session"].exists) + } } diff --git a/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/UserOtherSessionsViewModel.swift b/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/UserOtherSessionsViewModel.swift index 56a6a44ea..4673bb7a0 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/UserOtherSessionsViewModel.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserOtherSessions/UserOtherSessionsViewModel.swift @@ -53,11 +53,19 @@ class UserOtherSessionsViewModel: UserOtherSessionsViewModelType, UserOtherSessi // MARK: - Private private func updateViewState(sessionInfos: [UserSessionInfo], filter: OtherUserSessionsFilter) { - let sectionItems = filterSessions(sessionInfos: sessionInfos, by: filter).asViewData() + let sectionItems = createSectionItems(sessionInfos: sessionInfos, filter: filter) let sectionHeader = createHeaderData(filter: filter) state.sections = [.sessionItems(header: sectionHeader, items: sectionItems)] } + private func createSectionItems(sessionInfos: [UserSessionInfo], filter: OtherUserSessionsFilter) -> [UserSessionListItemViewData] { + filterSessions(sessionInfos: sessionInfos, by: filter) + .map { + UserSessionListItemViewDataFactory().create(from: $0, + highlightSessionDetails: filter == .unverified && $0.isCurrent) + } + } + private func filterSessions(sessionInfos: [UserSessionInfo], by filter: OtherUserSessionsFilter) -> [UserSessionInfo] { switch filter { case .all: diff --git a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/View/UserSessionListItemViewDataFactory.swift b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/View/UserSessionListItemViewDataFactory.swift index 2eb9a62b8..8adb72c3c 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/View/UserSessionListItemViewDataFactory.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/View/UserSessionListItemViewDataFactory.swift @@ -18,7 +18,7 @@ import Foundation struct UserSessionListItemViewDataFactory { - func create(from sessionInfo: UserSessionInfo) -> UserSessionListItemViewData { + func create(from sessionInfo: UserSessionInfo, highlightSessionDetails: Bool = false) -> UserSessionListItemViewData { let sessionName = UserSessionNameFormatter.sessionName(deviceType: sessionInfo.deviceType, sessionDisplayName: sessionInfo.name) let sessionDetails = buildSessionDetails(sessionInfo: sessionInfo) @@ -27,7 +27,7 @@ struct UserSessionListItemViewDataFactory { return UserSessionListItemViewData(sessionId: sessionInfo.id, sessionName: sessionName, sessionDetails: sessionDetails, - highlightSessionDetails: sessionInfo.isCurrent, + highlightSessionDetails: highlightSessionDetails, deviceAvatarViewData: deviceAvatarViewData, sessionDetailsIcon: getSessionDetailsIcon(isActive: sessionInfo.isActive)) }