vector-im/element-x-ios/issues/31 - Implement simple SaS sesson verification

* vector-im/element-x-ios/issues/31 - Session verification unit and UI tests
* Fix ImageAnonymizer tests when running on Apple Silicon
* Rename SessionVerification to SessionVerificationScreen
This commit is contained in:
Stefan Ceriu
2022-07-01 13:56:52 +03:00
committed by GitHub
parent 266ca656fc
commit a6f9d1ba89
30 changed files with 1604 additions and 98 deletions
@@ -26,6 +26,7 @@ struct HomeScreenCoordinatorParameters {
enum HomeScreenCoordinatorAction {
case presentRoom(roomIdentifier: String)
case presentSettings
case verifySession
}
final class HomeScreenCoordinator: Coordinator, Presentable {
@@ -66,19 +67,31 @@ final class HomeScreenCoordinator: Coordinator, Presentable {
self.callback?(.presentRoom(roomIdentifier: roomIdentifier))
case .tapUserAvatar:
self.callback?(.presentSettings)
case .verifySession:
self.callback?(.verifySession)
}
}
parameters.userSession.clientProxy
.callbacks
.receive(on: DispatchQueue.main)
.sink { [weak self] action in
switch action {
case .updatedRoomsList:
.sink { [weak self] callback in
if case .updatedRoomsList = callback {
self?.updateRoomsList()
}
}.store(in: &cancellables)
parameters.userSession.callbacks
.receive(on: DispatchQueue.main)
.sink { [weak self] callback in
switch callback {
case .sessionVerificationNeeded:
self?.viewModel.showSessionVerificationBanner()
case .didVerifySession:
self?.viewModel.hideSessionVerificationBanner()
}
}.store(in: &cancellables)
updateRoomsList()
Task {
@@ -20,18 +20,22 @@ import UIKit
enum HomeScreenViewModelAction {
case selectRoom(roomIdentifier: String)
case tapUserAvatar
case verifySession
}
enum HomeScreenViewAction {
case loadRoomData(roomIdentifier: String)
case selectRoom(roomIdentifier: String)
case tapUserAvatar
case verifySession
}
struct HomeScreenViewState: BindableState {
var userDisplayName: String?
var userAvatar: UIImage?
var showSessionVerificationBanner: Bool = false
var rooms: [HomeScreenRoom] = []
var isLoadingRooms: Bool = false
@@ -27,7 +27,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
private var roomSummaries: [RoomSummaryProtocol]? {
didSet {
self.state.isLoadingRooms = (roomSummaries?.count ?? 0 == 0)
state.isLoadingRooms = (roomSummaries?.count ?? 0 == 0)
}
}
@@ -51,6 +51,8 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
callback?(.selectRoom(roomIdentifier: roomIdentifier))
case .tapUserAvatar:
callback?(.tapUserAvatar)
case .verifySession:
callback?(.verifySession)
}
}
@@ -84,11 +86,19 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
}
func updateWithUserAvatar(_ avatar: UIImage) {
self.state.userAvatar = avatar
state.userAvatar = avatar
}
func updateWithUserDisplayName(_ displayName: String) {
self.state.userDisplayName = displayName
state.userDisplayName = displayName
}
func showSessionVerificationBanner() {
state.showSessionVerificationBanner = true
}
func hideSessionVerificationBanner() {
state.showSessionVerificationBanner = false
}
// MARK: - Private
@@ -105,7 +115,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
private func buildOrUpdateRoomFromSummary(_ roomSummary: RoomSummaryProtocol) -> HomeScreenRoom {
let lastMessage = lastMessageFromEventBrief(roomSummary.lastMessage)
guard var room = self.state.rooms.first(where: { $0.id == roomSummary.id }) else {
guard var room = state.rooms.first(where: { $0.id == roomSummary.id }) else {
return HomeScreenRoom(id: roomSummary.id,
displayName: roomSummary.displayName,
topic: roomSummary.topic,
@@ -26,4 +26,7 @@ protocol HomeScreenViewModelProtocol {
func updateWithUserAvatar(_ avatar: UIImage)
func updateWithUserDisplayName(_ displayName: String)
func updateWithRoomSummaries(_ roomSummaries: [RoomSummaryProtocol])
func showSessionVerificationBanner()
func hideSessionVerificationBanner()
}
@@ -23,13 +23,27 @@ struct HomeScreen: View {
// MARK: Views
var body: some View {
VStack(spacing: 16.0) {
VStack(spacing: 0.0) {
if context.viewState.isLoadingRooms {
VStack {
Text(ElementL10n.loading)
ProgressView()
}
} else {
if context.viewState.showSessionVerificationBanner {
HStack {
Text(ElementL10n.verificationVerifyDevice)
Spacer()
Button(ElementL10n.startVerification) {
context.send(viewAction: .verifySession)
}
}
.padding()
.background(Color.element.quaternaryContent)
.padding(.top, 1)
}
List {
Section(ElementL10n.rooms) {
ForEach(context.viewState.visibleRooms) { room in
@@ -52,6 +66,8 @@ struct HomeScreen: View {
Spacer()
}
.background(Color.element.background)
.transition(.slide)
.animation(.default, value: context.viewState.showSessionVerificationBanner)
.ignoresSafeArea(.all, edges: .bottom)
.navigationBarTitleDisplayMode(.inline)
.toolbar {
@@ -100,6 +116,8 @@ struct HomeScreen: View {
struct RoomCell: View {
@ScaledMetric private var avatarSize = 32.0
let room: HomeScreenRoom
let context: HomeScreenViewModel.Context
@@ -112,12 +130,12 @@ struct RoomCell: View {
Image(uiImage: avatar)
.resizable()
.scaledToFill()
.frame(width: 40, height: 40)
.frame(width: avatarSize, height: avatarSize)
.clipShape(Circle())
} else {
PlaceholderAvatarImage(text: room.displayName ?? room.id)
.clipShape(Circle())
.frame(width: 40, height: 40)
.frame(width: avatarSize, height: avatarSize)
}
VStack(alignment: .leading, spacing: 2.0) {
@@ -182,6 +200,8 @@ struct HomeScreen_Previews: PreviewProvider {
viewModel.updateWithUserAvatar(avatarImage)
}
viewModel.showSessionVerificationBanner()
return NavigationView {
HomeScreen(context: viewModel.context)
}