diff --git a/RiotSwiftUI/Modules/UserSessions/Common/View/UserSessionCardView.swift b/RiotSwiftUI/Modules/UserSessions/Common/View/UserSessionCardView.swift index 864c727d9..eb6516645 100644 --- a/RiotSwiftUI/Modules/UserSessions/Common/View/UserSessionCardView.swift +++ b/RiotSwiftUI/Modules/UserSessions/Common/View/UserSessionCardView.swift @@ -30,8 +30,9 @@ struct UserSessionCardView: View { RoundedRectangle(cornerRadius: 8) } + let showLocationInformations: Bool private var showExtraInformations: Bool { - viewData.isCurrentSessionDisplayMode == false && (viewData.lastActivityDateString.isEmptyOrNil == false || viewData.lastSeenIPInfo.isEmptyOrNil == false) + viewData.isCurrentSessionDisplayMode == false && (viewData.lastActivityDateString.isEmptyOrNil == false || ipText.isEmptyOrNil == false) } var body: some View { @@ -77,8 +78,8 @@ struct UserSessionCardView: View { .multilineTextAlignment(.center) } } - if let lastSeenIPInfo = viewData.lastSeenIPInfo, lastSeenIPInfo.isEmpty == false { - Text(lastSeenIPInfo) + if showLocationInformations, let ipText = ipText { + Text(ipText) .font(theme.fonts.footnote) .foregroundColor(theme.colors.secondaryContent) .multilineTextAlignment(.center) @@ -117,6 +118,13 @@ struct UserSessionCardView: View { } } } + + private var ipText: String? { + guard let lastSeenIp = viewData.lastSeenIP, !lastSeenIp.isEmpty else { + return nil + } + return viewData.lastSeenIPLocation.map { "\(lastSeenIp) (\($0))" } ?? lastSeenIp + } } struct UserSessionCardViewPreview: View { @@ -146,7 +154,7 @@ struct UserSessionCardViewPreview: View { var body: some View { VStack { - UserSessionCardView(viewData: viewData) + UserSessionCardView(viewData: viewData, showLocationInformations: true) } .frame(maxWidth: .infinity) .background(theme.colors.system) diff --git a/RiotSwiftUI/Modules/UserSessions/Common/View/UserSessionCardViewData.swift b/RiotSwiftUI/Modules/UserSessions/Common/View/UserSessionCardViewData.swift index d34cda89e..1ab0c8f4a 100644 --- a/RiotSwiftUI/Modules/UserSessions/Common/View/UserSessionCardViewData.swift +++ b/RiotSwiftUI/Modules/UserSessions/Common/View/UserSessionCardViewData.swift @@ -34,7 +34,8 @@ struct UserSessionCardViewData { var lastActivityIcon: String? - let lastSeenIPInfo: String? + let lastSeenIP: String? + let lastSeenIPLocation: String? let deviceAvatarViewData: DeviceAvatarViewData @@ -95,6 +96,7 @@ struct UserSessionCardViewData { verificationState: UserSessionInfo.VerificationState, lastActivityTimestamp: TimeInterval?, lastSeenIP: String?, + lastSeenIPLocation: String?, isCurrentSessionDisplayMode: Bool = false, isActive: Bool) { self.sessionId = sessionId @@ -112,7 +114,8 @@ struct UserSessionCardViewData { } } self.lastActivityDateString = lastActivityDateString - lastSeenIPInfo = lastSeenIP + self.lastSeenIP = lastSeenIP + self.lastSeenIPLocation = lastSeenIPLocation deviceAvatarViewData = DeviceAvatarViewData(deviceType: deviceType, verificationState: verificationState) self.isCurrentSessionDisplayMode = isCurrentSessionDisplayMode @@ -127,6 +130,7 @@ extension UserSessionCardViewData { verificationState: sessionInfo.verificationState, lastActivityTimestamp: sessionInfo.lastSeenTimestamp, lastSeenIP: sessionInfo.lastSeenIP, + lastSeenIPLocation: sessionInfo.lastSeenIPLocation, isCurrentSessionDisplayMode: sessionInfo.isCurrent, isActive: sessionInfo.isActive) } diff --git a/RiotSwiftUI/Modules/UserSessions/UserSessionOverview/UserSessionOverviewModels.swift b/RiotSwiftUI/Modules/UserSessions/UserSessionOverview/UserSessionOverviewModels.swift index 46377e13e..516d82afa 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserSessionOverview/UserSessionOverviewModels.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserSessionOverview/UserSessionOverviewModels.swift @@ -36,12 +36,17 @@ enum UserSessionOverviewViewModelResult: Equatable { // MARK: View +struct UserSessionOverviewViewBindings { + var showLocationInfo = false +} + struct UserSessionOverviewViewState: BindableState { var cardViewData: UserSessionCardViewData let isCurrentSession: Bool var isPusherEnabled: Bool? var remotelyTogglingPushersAvailable: Bool var showLoadingIndicator: Bool + var bindings: UserSessionOverviewViewBindings = .init() } enum UserSessionOverviewViewAction { diff --git a/RiotSwiftUI/Modules/UserSessions/UserSessionOverview/View/UserSessionOverview.swift b/RiotSwiftUI/Modules/UserSessions/UserSessionOverview/View/UserSessionOverview.swift index e3132e460..244ef29ea 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserSessionOverview/View/UserSessionOverview.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserSessionOverview/View/UserSessionOverview.swift @@ -28,7 +28,7 @@ struct UserSessionOverview: View { }, onViewDetailsAction: { _ in viewModel.send(viewAction: .viewSessionDetails) - }) + }, showLocationInformations: viewModel.showLocationInfo) .padding(16) SwiftUI.Section { UserSessionOverviewItem(title: VectorL10n.userSessionOverviewSessionDetailsButtonTitle, @@ -68,6 +68,14 @@ struct UserSessionOverview: View { Label(VectorL10n.manageSessionRename, systemImage: "pencil") } .accessibilityIdentifier(VectorL10n.manageSessionRename) + + if viewModel.viewState.isCurrentSession == false { + Button { viewModel.showLocationInfo.toggle() } label: { + let text = viewModel.showLocationInfo ? VectorL10n.userSessionsHideLocationInfo : VectorL10n.userSessionsShowLocationInfo + let image = viewModel.showLocationInfo ? "eye.slash" : "eye" + Label(text, systemImage: image) + } + } } DestructiveButton { viewModel.send(viewAction: .logoutOfSession) diff --git a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/View/UserSessionsOverview.swift b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/View/UserSessionsOverview.swift index 68d6b4269..3d681bbb5 100644 --- a/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/View/UserSessionsOverview.swift +++ b/RiotSwiftUI/Modules/UserSessions/UserSessionsOverview/View/UserSessionsOverview.swift @@ -98,7 +98,7 @@ struct UserSessionsOverview: View { viewModel.send(viewAction: .verifyCurrentSession) }, onViewDetailsAction: { _ in viewModel.send(viewAction: .viewCurrentSessionDetails) - }) + }, showLocationInformations: viewModel.showLocationInfo) } header: { HStack(alignment: .firstTextBaseline) { Text(VectorL10n.userSessionsOverviewCurrentSessionSectionTitle)