Skip to content

Commit

Permalink
Fixes #2508 - Offer user to transition to SSS
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanceriu committed Sep 10, 2024
1 parent 5394523 commit 6b6835d
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 21 deletions.
4 changes: 4 additions & 0 deletions ElementX.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
09AAF04B27732046C755D914 /* SoftLogoutViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32C5DAA1773F57653BF1C4F9 /* SoftLogoutViewModelTests.swift */; };
09C83DDDB07C28364F325209 /* MockRoomTimelineController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52D7074991B3267B26D89B22 /* MockRoomTimelineController.swift */; };
09D3D7D115318CAD131B4FE7 /* ResolveVerifiedUserSendFailureScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57084488B03BDB33C7B7CA0E /* ResolveVerifiedUserSendFailureScreenViewModelTests.swift */; };
0A0625A271EE5B06D2AAA069 /* HomeScreenSlidingSyncMigrationBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4691B8DE1D51DE152680098A /* HomeScreenSlidingSyncMigrationBanner.swift */; };
0A194F5E70B5A628C1BF4476 /* AdvancedSettingsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4999B5FD50AED7CB0F590FF8 /* AdvancedSettingsScreenModels.swift */; };
0ACAA31FD0399CEEBA3ECC21 /* UserDetailsEditScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85149F56BA333619900E2410 /* UserDetailsEditScreenViewModelProtocol.swift */; };
0AE0AB1952F186EB86719B4F /* HomeScreenRoomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED044D00F2176681CC02CD54 /* HomeScreenRoomCell.swift */; };
Expand Down Expand Up @@ -1492,6 +1493,7 @@
45D8149FDDA0315CDC553B4B /* UserNotificationCenterProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserNotificationCenterProtocol.swift; sourceTree = "<group>"; };
4629710C0337ADD9C8909542 /* ka */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ka; path = ka.lproj/Localizable.strings; sourceTree = "<group>"; };
466C71A0FED9BFF287613C82 /* RoomDetailsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsScreenModels.swift; sourceTree = "<group>"; };
4691B8DE1D51DE152680098A /* HomeScreenSlidingSyncMigrationBanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenSlidingSyncMigrationBanner.swift; sourceTree = "<group>"; };
46A2AD86F7E618F468F6FAF5 /* VoiceMessageRecordingButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageRecordingButton.swift; sourceTree = "<group>"; };
46C208DA43CE25D13E670F40 /* UITestsAppCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITestsAppCoordinator.swift; sourceTree = "<group>"; };
46D0BA44B1838E65B507B277 /* NotificationPermissionsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationPermissionsScreen.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3354,6 +3356,7 @@
05512FB13987D221B7205DE0 /* HomeScreenRecoveryKeyConfirmationBanner.swift */,
ED044D00F2176681CC02CD54 /* HomeScreenRoomCell.swift */,
C7661EFFCAA307A97D71132A /* HomeScreenRoomList.swift */,
4691B8DE1D51DE152680098A /* HomeScreenSlidingSyncMigrationBanner.swift */,
84AF32E4136FD6F159D86C2C /* RoomDirectorySearchView.swift */,
037A5661B26EC6BE068188D7 /* Filters */,
);
Expand Down Expand Up @@ -6372,6 +6375,7 @@
B04E9EB589CE99C3929E817A /* HomeScreenRecoveryKeyConfirmationBanner.swift in Sources */,
0AE0AB1952F186EB86719B4F /* HomeScreenRoomCell.swift in Sources */,
A10D6CCDE2010C09EEA1A593 /* HomeScreenRoomList.swift in Sources */,
0A0625A271EE5B06D2AAA069 /* HomeScreenSlidingSyncMigrationBanner.swift in Sources */,
DE4F8C4E0F1DB4832F09DE97 /* HomeScreenViewModel.swift in Sources */,
56F0A22972A3BB519DA2261C /* HomeScreenViewModelProtocol.swift in Sources */,
2BBE320EE426A347AAE5C7DA /* IdentityConfirmationScreen.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -407,12 +407,14 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
settingsFlowCoordinator.handleAppRoute(.chatBackupSettings, animated: true)
case .presentStartChatScreen:
stateMachine.processEvent(.showStartChatScreen)
case .logout:
Task { await self.runLogoutFlow() }
case .presentGlobalSearch:
presentGlobalSearch()
case .presentRoomDirectorySearch:
stateMachine.processEvent(.showRoomDirectorySearchScreen)
case .logoutWithoutConfirmation:
self.actionsSubject.send(.logout)
case .logout:
Task { await self.runLogoutFlow() }
}
}
.store(in: &cancellables)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ enum HomeScreenCoordinatorAction {
case presentStartChatScreen
case presentGlobalSearch
case presentRoomDirectorySearch
case logoutWithoutConfirmation
case logout
}

Expand Down Expand Up @@ -64,14 +65,16 @@ final class HomeScreenCoordinator: CoordinatorProtocol {
actionsSubject.send(.presentSettingsScreen)
case .presentSecureBackupSettings:
actionsSubject.send(.presentSecureBackupSettings)
case .logout:
actionsSubject.send(.logout)
case .presentStartChatScreen:
actionsSubject.send(.presentStartChatScreen)
case .presentGlobalSearch:
actionsSubject.send(.presentGlobalSearch)
case .presentRoomDirectorySearch:
actionsSubject.send(.presentRoomDirectorySearch)
case .logoutWithoutConfirmation:
actionsSubject.send(.logoutWithoutConfirmation)
case .logout:
actionsSubject.send(.logout)
}
}
.store(in: &cancellables)
Expand Down
15 changes: 8 additions & 7 deletions ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ enum HomeScreenViewModelAction {
case presentStartChatScreen
case presentGlobalSearch
case presentRoomDirectorySearch
case logoutWithoutConfirmation
case logout
}

Expand All @@ -31,6 +32,8 @@ enum HomeScreenViewAction {
case startChat
case confirmRecoveryKey
case skipRecoveryKeyConfirmation
case confirmSlidingSyncUpgrade
case skipSlidingSyncUpgrade
case updateVisibleItemRange(Range<Int>)
case globalSearch
case markRoomAsUnread(roomIdentifier: String)
Expand Down Expand Up @@ -59,18 +62,20 @@ enum HomeScreenRoomListMode: CustomStringConvertible {
}
}

enum SecurityBannerMode {
enum HomeScreenBannerMode {
case none
case dismissed
case recoveryKeyConfirmation
case shown
}

struct HomeScreenViewState: BindableState {
let userID: String
var userDisplayName: String?
var userAvatarURL: URL?

var securityBannerMode = SecurityBannerMode.none
var securityBannerMode = HomeScreenBannerMode.none
var slidingSyncMigrationBannerMode = HomeScreenBannerMode.none

var requiresExtraAccountSetup = false

var rooms: [HomeScreenRoom] = []
Expand Down Expand Up @@ -110,10 +115,6 @@ struct HomeScreenViewState: BindableState {
var shouldShowFilters: Bool {
!bindings.isSearchFieldFocused && roomListMode == .rooms
}

var shouldShowRecoveryKeyConfirmationBanner: Bool {
securityBannerMode == .recoveryKeyConfirmation
}
}

struct HomeScreenViewStateBindings {
Expand Down
70 changes: 63 additions & 7 deletions ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import AnalyticsEvents
import Combine
import MatrixRustSDK
import SwiftUI

typealias HomeScreenViewModelType = StateStoreViewModel<HomeScreenViewState, HomeScreenViewAction>
Expand Down Expand Up @@ -62,7 +63,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
state.requiresExtraAccountSetup = true

if state.securityBannerMode != .dismissed {
state.securityBannerMode = .recoveryKeyConfirmation
state.securityBannerMode = .shown
}
default:
state.securityBannerMode = .none
Expand Down Expand Up @@ -117,6 +118,10 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
setupRoomListSubscriptions()

updateRooms()

Task {
await checkSlidingSyncMigration()
}
}

// MARK: - Public
Expand All @@ -137,6 +142,10 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
actionsSubject.send(.presentSecureBackupSettings)
case .skipRecoveryKeyConfirmation:
state.securityBannerMode = .dismissed
case .confirmSlidingSyncUpgrade:
actionsSubject.send(.logout)
case .skipSlidingSyncUpgrade:
state.slidingSyncMigrationBannerMode = .dismissed
case .updateVisibleItemRange(let range):
roomSummaryProvider?.updateVisibleRange(range)
case .startChat:
Expand Down Expand Up @@ -192,12 +201,15 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol

// perphery: ignore - used in release mode
func presentCrashedLastRunAlert() {
state.bindings.alertInfo = AlertInfo(id: UUID(),
title: L10n.crashDetectionDialogContent(InfoPlistReader.main.bundleDisplayName),
primaryButton: .init(title: L10n.actionNo, action: nil),
secondaryButton: .init(title: L10n.actionYes) { [weak self] in
self?.actionsSubject.send(.presentFeedbackScreen)
})
// Delay setting the alert otherwise it automatically gets dismissed. Same as the force logout one.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.state.bindings.alertInfo = AlertInfo(id: UUID(),
title: L10n.crashDetectionDialogContent(InfoPlistReader.main.bundleDisplayName),
primaryButton: .init(title: L10n.actionNo, action: nil),
secondaryButton: .init(title: L10n.actionYes) { [weak self] in
self?.actionsSubject.send(.presentFeedbackScreen)
})
}
}

// MARK: - Private
Expand Down Expand Up @@ -287,7 +299,40 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol

state.rooms = rooms
}

/// Check whether we can inform the user about potential migrations
/// or have him logout as his proxy is no longer available
private func checkSlidingSyncMigration() async {
// Not logged in with a proxy, don't need to do anything
guard userSession.clientProxy.slidingSyncVersion.isProxy else {
return
}

let versions = await userSession.clientProxy.availableSlidingSyncVersions

// Native not available, nothing we can do
guard versions.contains(.native) else {
return
}

if versions.contains(.native) {
// Both available, prompt for migration
if versions.contains(where: \.isProxy) {
state.slidingSyncMigrationBannerMode = .shown
} else { // The proxy has been removed and logout is needed
// Delay setting the alert otherwise it automatically gets dismissed. Same as the crashed last run one
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.state.bindings.alertInfo = AlertInfo(id: UUID(),
title: L10n.bannerMigrateToNativeSlidingSyncForceLogoutTitle,
primaryButton: .init(title: L10n.bannerMigrateToNativeSlidingSyncAction,
action: { [weak self] in
self?.actionsSubject.send(.logoutWithoutConfirmation)
}))
}
}
}
}

private func markRoomAsFavourite(_ roomID: String, isFavourite: Bool) async {
guard case let .joined(roomProxy) = await userSession.clientProxy.roomForIdentifier(roomID) else {
MXLog.error("Failed retrieving room for identifier: \(roomID)")
Expand Down Expand Up @@ -412,3 +457,14 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
message: L10n.errorUnknown)
}
}

extension SlidingSyncVersion {
var isProxy: Bool {
switch self {
case .proxy:
return true
default:
return false
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,16 @@ struct HomeScreenContent: View {
private var topSection: some View {
// An empty VStack causes glitches within the room list
if context.viewState.shouldShowFilters ||
context.viewState.shouldShowRecoveryKeyConfirmationBanner {
context.viewState.securityBannerMode == .shown ||
context.viewState.slidingSyncMigrationBannerMode == .shown {
VStack(spacing: 0) {
if context.viewState.shouldShowFilters {
RoomListFiltersView(state: $context.filtersState)
}

if context.viewState.shouldShowRecoveryKeyConfirmationBanner {

if context.viewState.slidingSyncMigrationBannerMode == .shown {
HomeScreenSlidingSyncMigrationBanner(context: context)
} else if context.viewState.securityBannerMode == .shown {
HomeScreenRecoveryKeyConfirmationBanner(context: context)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//
// Copyright 2024 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only
// Please see LICENSE in the repository root for full details.
//

import Combine
import SwiftUI

struct HomeScreenSlidingSyncMigrationBanner: View {
@ObservedObject var context: HomeScreenViewModel.Context

var body: some View {
VStack(alignment: .leading, spacing: 16) {
VStack(alignment: .leading, spacing: 4) {
HStack(spacing: 16) {
Text(L10n.bannerMigrateToNativeSlidingSyncTitle)
.font(.compound.bodyLGSemibold)
.foregroundColor(.compound.textPrimary)

Spacer()

Button {
context.send(viewAction: .skipSlidingSyncUpgrade)
} label: {
Image(systemName: "xmark")
.foregroundColor(.compound.iconSecondary)
.frame(width: 12, height: 12)
}
}
Text(L10n.bannerMigrateToNativeSlidingSyncDescription)
.font(.compound.bodyMD)
.foregroundColor(.compound.textSecondary)
}

Button(L10n.bannerMigrateToNativeSlidingSyncAction) {
context.send(viewAction: .confirmSlidingSyncUpgrade)
}
.frame(maxWidth: .infinity)
.buttonStyle(.compound(.primary, size: .medium))
}
.padding(16)
.background(Color.compound.bgSubtleSecondary)
.cornerRadius(14)
.padding(.horizontal, 16)
}
}

struct HomeScreenSlidingSyncMigrationBanner_Previews: PreviewProvider, TestablePreview {
static let viewModel = buildViewModel()

static var previews: some View {
HomeScreenSlidingSyncMigrationBanner(context: viewModel.context)
}

static func buildViewModel() -> HomeScreenViewModel {
let clientProxy = ClientProxyMock(.init())

let userSession = UserSessionMock(.init(clientProxy: clientProxy))

return HomeScreenViewModel(userSession: userSession,
analyticsService: ServiceLocator.shared.analytics,
appSettings: ServiceLocator.shared.settings,
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
userIndicatorController: ServiceLocator.shared.userIndicatorController)
}
}

0 comments on commit 6b6835d

Please sign in to comment.