mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 21:39:12 +00:00
Final changes for Room Moderation (#2576)
* Add confirmation that the user would like to discard unsaved changes. * Update string on permissions screen. * Fix UI tests and update snapshots. * Fix integration tests. * Run periphery for Moderation feature.
This commit is contained in:
parent
668c5188fb
commit
3ba34c0704
@ -499,7 +499,7 @@
|
|||||||
"screen_room_attachment_text_formatting" = "Text Formatting";
|
"screen_room_attachment_text_formatting" = "Text Formatting";
|
||||||
"screen_room_change_permissions_administrators" = "Admins only";
|
"screen_room_change_permissions_administrators" = "Admins only";
|
||||||
"screen_room_change_permissions_ban_people" = "Ban people";
|
"screen_room_change_permissions_ban_people" = "Ban people";
|
||||||
"screen_room_change_permissions_delete_messages" = "Delete messages";
|
"screen_room_change_permissions_delete_messages" = "Remove messages";
|
||||||
"screen_room_change_permissions_invite_people" = "Invite people";
|
"screen_room_change_permissions_invite_people" = "Invite people";
|
||||||
"screen_room_change_permissions_moderators" = "Admins and moderators";
|
"screen_room_change_permissions_moderators" = "Admins and moderators";
|
||||||
"screen_room_change_permissions_remove_people" = "Remove people";
|
"screen_room_change_permissions_remove_people" = "Remove people";
|
||||||
|
@ -50,6 +50,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
private let analytics: AnalyticsService
|
private let analytics: AnalyticsService
|
||||||
private let userIndicatorController: UserIndicatorControllerProtocol
|
private let userIndicatorController: UserIndicatorControllerProtocol
|
||||||
|
|
||||||
|
// periphery:ignore - used to avoid deallocation
|
||||||
private var rolesAndPermissionsFlowCoordinator: RoomRolesAndPermissionsFlowCoordinator?
|
private var rolesAndPermissionsFlowCoordinator: RoomRolesAndPermissionsFlowCoordinator?
|
||||||
|
|
||||||
private let stateMachine: StateMachine<State, Event> = .init(state: .initial)
|
private let stateMachine: StateMachine<State, Event> = .init(state: .initial)
|
||||||
|
@ -1215,7 +1215,7 @@ internal enum L10n {
|
|||||||
internal static var screenRoomChangePermissionsAdministrators: String { return L10n.tr("Localizable", "screen_room_change_permissions_administrators") }
|
internal static var screenRoomChangePermissionsAdministrators: String { return L10n.tr("Localizable", "screen_room_change_permissions_administrators") }
|
||||||
/// Ban people
|
/// Ban people
|
||||||
internal static var screenRoomChangePermissionsBanPeople: String { return L10n.tr("Localizable", "screen_room_change_permissions_ban_people") }
|
internal static var screenRoomChangePermissionsBanPeople: String { return L10n.tr("Localizable", "screen_room_change_permissions_ban_people") }
|
||||||
/// Delete messages
|
/// Remove messages
|
||||||
internal static var screenRoomChangePermissionsDeleteMessages: String { return L10n.tr("Localizable", "screen_room_change_permissions_delete_messages") }
|
internal static var screenRoomChangePermissionsDeleteMessages: String { return L10n.tr("Localizable", "screen_room_change_permissions_delete_messages") }
|
||||||
/// Everyone
|
/// Everyone
|
||||||
internal static var screenRoomChangePermissionsEveryone: String { return L10n.tr("Localizable", "screen_room_change_permissions_everyone") }
|
internal static var screenRoomChangePermissionsEveryone: String { return L10n.tr("Localizable", "screen_room_change_permissions_everyone") }
|
||||||
|
@ -43,6 +43,8 @@ struct RoomChangePermissionsScreenViewStateBindings: BindableState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum RoomChangePermissionsScreenAlertType {
|
enum RoomChangePermissionsScreenAlertType {
|
||||||
|
/// A confirmation that the user would like to discard any unsaved changes.
|
||||||
|
case discardChanges
|
||||||
/// The generic error message.
|
/// The generic error message.
|
||||||
case generic
|
case generic
|
||||||
}
|
}
|
||||||
@ -50,6 +52,8 @@ enum RoomChangePermissionsScreenAlertType {
|
|||||||
enum RoomChangePermissionsScreenViewAction {
|
enum RoomChangePermissionsScreenViewAction {
|
||||||
/// Save the permissions.
|
/// Save the permissions.
|
||||||
case save
|
case save
|
||||||
|
/// Discard any changes and hide the screen.
|
||||||
|
case cancel
|
||||||
}
|
}
|
||||||
|
|
||||||
extension RoomChangePermissionsScreenViewState {
|
extension RoomChangePermissionsScreenViewState {
|
||||||
|
@ -49,6 +49,8 @@ class RoomChangePermissionsScreenViewModel: RoomChangePermissionsScreenViewModel
|
|||||||
switch viewAction {
|
switch viewAction {
|
||||||
case .save:
|
case .save:
|
||||||
Task { await save() }
|
Task { await save() }
|
||||||
|
case .cancel:
|
||||||
|
confirmDiscardChanges()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,6 +85,14 @@ class RoomChangePermissionsScreenViewModel: RoomChangePermissionsScreenViewModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func confirmDiscardChanges() {
|
||||||
|
state.bindings.alertInfo = AlertInfo(id: .discardChanges,
|
||||||
|
title: L10n.screenRoomChangeRoleUnsavedChangesTitle,
|
||||||
|
message: L10n.screenRoomChangeRoleUnsavedChangesDescription,
|
||||||
|
primaryButton: .init(title: L10n.actionSave) { Task { await self.save() } },
|
||||||
|
secondaryButton: .init(title: L10n.actionDiscard, role: .cancel) { self.actionsSubject.send(.complete) })
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Loading indicator
|
// MARK: Loading indicator
|
||||||
|
|
||||||
private static let indicatorID = "SavingRoomPermissions"
|
private static let indicatorID = "SavingRoomPermissions"
|
||||||
|
@ -35,6 +35,7 @@ struct RoomChangePermissionsScreen: View {
|
|||||||
.compoundList()
|
.compoundList()
|
||||||
.navigationTitle(context.viewState.title)
|
.navigationTitle(context.viewState.title)
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
|
.navigationBarBackButtonHidden(context.viewState.hasChanges)
|
||||||
.toolbar { toolbar }
|
.toolbar { toolbar }
|
||||||
.alert(item: $context.alertInfo)
|
.alert(item: $context.alertInfo)
|
||||||
}
|
}
|
||||||
@ -47,6 +48,14 @@ struct RoomChangePermissionsScreen: View {
|
|||||||
}
|
}
|
||||||
.disabled(!context.viewState.hasChanges)
|
.disabled(!context.viewState.hasChanges)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if context.viewState.hasChanges {
|
||||||
|
ToolbarItem(placement: .cancellationAction) {
|
||||||
|
Button(L10n.actionCancel) {
|
||||||
|
context.send(viewAction: .cancel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,6 +89,8 @@ struct RoomChangeRolesScreenViewStateBindings {
|
|||||||
enum RoomChangeRolesScreenAlertType {
|
enum RoomChangeRolesScreenAlertType {
|
||||||
/// A warning that a particular promotion can't be undone.
|
/// A warning that a particular promotion can't be undone.
|
||||||
case promotionWarning
|
case promotionWarning
|
||||||
|
/// A confirmation that the user would like to discard any unsaved changes.
|
||||||
|
case discardChanges
|
||||||
/// The generic error message.
|
/// The generic error message.
|
||||||
case error
|
case error
|
||||||
}
|
}
|
||||||
@ -100,4 +102,6 @@ enum RoomChangeRolesScreenViewAction {
|
|||||||
case demoteMember(RoomMemberDetails)
|
case demoteMember(RoomMemberDetails)
|
||||||
/// Save all the changes that the user has made.
|
/// Save all the changes that the user has made.
|
||||||
case save
|
case save
|
||||||
|
/// Discard any changes and hide the screen.
|
||||||
|
case cancel
|
||||||
}
|
}
|
||||||
|
@ -74,6 +74,8 @@ class RoomChangeRolesScreenViewModel: RoomChangeRolesScreenViewModelType, RoomCh
|
|||||||
} else {
|
} else {
|
||||||
Task { await save() }
|
Task { await save() }
|
||||||
}
|
}
|
||||||
|
case .cancel:
|
||||||
|
confirmDiscardChanges()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,6 +150,14 @@ class RoomChangeRolesScreenViewModel: RoomChangeRolesScreenViewModelType, RoomCh
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func confirmDiscardChanges() {
|
||||||
|
state.bindings.alertInfo = AlertInfo(id: .discardChanges,
|
||||||
|
title: L10n.screenRoomChangeRoleUnsavedChangesTitle,
|
||||||
|
message: L10n.screenRoomChangeRoleUnsavedChangesDescription,
|
||||||
|
primaryButton: .init(title: L10n.actionSave) { Task { await self.save() } },
|
||||||
|
secondaryButton: .init(title: L10n.actionDiscard, role: .cancel) { self.actionsSubject.send(.complete) })
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Loading indicator
|
// MARK: Loading indicator
|
||||||
|
|
||||||
private static let indicatorID = "SavingRoomRoles"
|
private static let indicatorID = "SavingRoomRoles"
|
||||||
|
@ -61,15 +61,6 @@ struct RoomChangeRolesScreen: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var noResultsContent: some View {
|
|
||||||
Text(L10n.commonNoResults)
|
|
||||||
.font(.compound.bodyLG)
|
|
||||||
.foregroundColor(.compound.textSecondary)
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
.listRowBackground(Color.clear)
|
|
||||||
.accessibilityIdentifier(A11yIdentifiers.startChatScreen.searchNoResults)
|
|
||||||
}
|
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private var membersSection: some View {
|
private var membersSection: some View {
|
||||||
if !context.viewState.visibleMembers.isEmpty {
|
if !context.viewState.visibleMembers.isEmpty {
|
||||||
@ -123,6 +114,14 @@ struct RoomChangeRolesScreen: View {
|
|||||||
}
|
}
|
||||||
.disabled(!context.viewState.hasChanges)
|
.disabled(!context.viewState.hasChanges)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if context.viewState.hasChanges {
|
||||||
|
ToolbarItem(placement: .cancellationAction) {
|
||||||
|
Button(L10n.actionCancel) {
|
||||||
|
context.send(viewAction: .cancel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ class RoomRolesAndPermissionsScreenViewModel: RoomRolesAndPermissionsScreenViewM
|
|||||||
case .editRoles(let role):
|
case .editRoles(let role):
|
||||||
actionsSubject.send(.editRoles(role))
|
actionsSubject.send(.editRoles(role))
|
||||||
case .editOwnUserRole:
|
case .editOwnUserRole:
|
||||||
state.bindings.alertInfo = AlertInfo(id: .resetConfirmation,
|
state.bindings.alertInfo = AlertInfo(id: .editOwnRole,
|
||||||
title: L10n.screenRoomRolesAndPermissionsChangeMyRole,
|
title: L10n.screenRoomRolesAndPermissionsChangeMyRole,
|
||||||
message: L10n.screenRoomChangeRoleConfirmDemoteSelfDescription,
|
message: L10n.screenRoomChangeRoleConfirmDemoteSelfDescription,
|
||||||
primaryButton: .init(title: L10n.actionCancel, role: .cancel) { },
|
primaryButton: .init(title: L10n.actionCancel, role: .cancel) { },
|
||||||
|
@ -18,7 +18,7 @@ import XCTest
|
|||||||
|
|
||||||
extension XCUIApplication {
|
extension XCUIApplication {
|
||||||
func login(currentTestCase: XCTestCase) {
|
func login(currentTestCase: XCTestCase) {
|
||||||
let getStartedButton = buttons[A11yIdentifiers.onboardingScreen.signIn]
|
let getStartedButton = buttons[A11yIdentifiers.authenticationStartScreen.signIn]
|
||||||
|
|
||||||
XCTAssertTrue(getStartedButton.waitForExistence(timeout: 10.0))
|
XCTAssertTrue(getStartedButton.waitForExistence(timeout: 10.0))
|
||||||
getStartedButton.tap()
|
getStartedButton.tap()
|
||||||
@ -128,7 +128,7 @@ extension XCUIApplication {
|
|||||||
alertLogoutButton.tap()
|
alertLogoutButton.tap()
|
||||||
|
|
||||||
// Check that we're back on the login screen
|
// Check that we're back on the login screen
|
||||||
let getStartedButton = buttons[A11yIdentifiers.onboardingScreen.signIn]
|
let getStartedButton = buttons[A11yIdentifiers.authenticationStartScreen.signIn]
|
||||||
XCTAssertTrue(getStartedButton.waitForExistence(timeout: 10.0))
|
XCTAssertTrue(getStartedButton.waitForExistence(timeout: 10.0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -23,7 +23,7 @@ class AuthenticationFlowCoordinatorUITests: XCTestCase {
|
|||||||
let app = Application.launch(.authenticationFlow)
|
let app = Application.launch(.authenticationFlow)
|
||||||
|
|
||||||
// Splash Screen: Tap get started button
|
// Splash Screen: Tap get started button
|
||||||
app.buttons[A11yIdentifiers.onboardingScreen.signIn].tap()
|
app.buttons[A11yIdentifiers.authenticationStartScreen.signIn].tap()
|
||||||
|
|
||||||
// Server Confirmation: Tap continue button
|
// Server Confirmation: Tap continue button
|
||||||
app.buttons[A11yIdentifiers.serverConfirmationScreen.continue].tap()
|
app.buttons[A11yIdentifiers.serverConfirmationScreen.continue].tap()
|
||||||
@ -45,7 +45,7 @@ class AuthenticationFlowCoordinatorUITests: XCTestCase {
|
|||||||
let app = Application.launch(.authenticationFlow)
|
let app = Application.launch(.authenticationFlow)
|
||||||
|
|
||||||
// Splash Screen: Tap get started button
|
// Splash Screen: Tap get started button
|
||||||
app.buttons[A11yIdentifiers.onboardingScreen.signIn].tap()
|
app.buttons[A11yIdentifiers.authenticationStartScreen.signIn].tap()
|
||||||
|
|
||||||
// Server Confirmation: Tap continue button
|
// Server Confirmation: Tap continue button
|
||||||
app.buttons[A11yIdentifiers.serverConfirmationScreen.continue].tap()
|
app.buttons[A11yIdentifiers.serverConfirmationScreen.continue].tap()
|
||||||
@ -69,7 +69,7 @@ class AuthenticationFlowCoordinatorUITests: XCTestCase {
|
|||||||
let app = Application.launch(.authenticationFlow)
|
let app = Application.launch(.authenticationFlow)
|
||||||
|
|
||||||
// Splash Screen: Tap get started button
|
// Splash Screen: Tap get started button
|
||||||
app.buttons[A11yIdentifiers.onboardingScreen.signIn].tap()
|
app.buttons[A11yIdentifiers.authenticationStartScreen.signIn].tap()
|
||||||
|
|
||||||
// Server Confirmation: Tap change server button
|
// Server Confirmation: Tap change server button
|
||||||
app.buttons[A11yIdentifiers.serverConfirmationScreen.changeServer].tap()
|
app.buttons[A11yIdentifiers.serverConfirmationScreen.changeServer].tap()
|
||||||
|
@ -19,7 +19,7 @@ import XCTest
|
|||||||
@MainActor
|
@MainActor
|
||||||
class AuthenticationStartScreenUITests: XCTestCase {
|
class AuthenticationStartScreenUITests: XCTestCase {
|
||||||
func testInitialStateComponents() async throws {
|
func testInitialStateComponents() async throws {
|
||||||
let app = Application.launch(.onboarding)
|
let app = Application.launch(.authenticationStartScreen)
|
||||||
try await app.assertScreenshot(.onboarding)
|
try await app.assertScreenshot(.authenticationStartScreen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.authenticationStartScreen.png
(Stored with Git LFS)
Normal file
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.authenticationStartScreen.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.onboarding.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.onboarding.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.roomRolesAndPermissionsFlow-4.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPad-9th-generation.roomRolesAndPermissionsFlow-4.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.authenticationStartScreen.png
(Stored with Git LFS)
Normal file
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.authenticationStartScreen.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.onboarding.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.onboarding.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.roomRolesAndPermissionsFlow-4.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/en-GB-iPhone-14.roomRolesAndPermissionsFlow-4.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPad-9th-generation.authenticationStartScreen.png
(Stored with Git LFS)
Normal file
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPad-9th-generation.authenticationStartScreen.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPad-9th-generation.onboarding.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPad-9th-generation.onboarding.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPad-9th-generation.roomRolesAndPermissionsFlow-4.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPad-9th-generation.roomRolesAndPermissionsFlow-4.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPhone-14.authenticationStartScreen.png
(Stored with Git LFS)
Normal file
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPhone-14.authenticationStartScreen.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPhone-14.onboarding.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPhone-14.onboarding.png
(Stored with Git LFS)
Binary file not shown.
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPhone-14.roomRolesAndPermissionsFlow-4.png
(Stored with Git LFS)
BIN
UITests/Sources/__Snapshots__/Application/pseudo-iPhone-14.roomRolesAndPermissionsFlow-4.png
(Stored with Git LFS)
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user