mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 01:20:12 +00:00
Space Settings UI tweaks (#4678)
* design tweaks for the space settings flow * pr suggestions * update proj
This commit is contained in:
@@ -91,6 +91,10 @@ extension AccessibilityTests {
|
|||||||
try await performAccessibilityAudit(named: "ComposerToolbar_Previews")
|
try await performAccessibilityAudit(named: "ComposerToolbar_Previews")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testCopyTextButton() async throws {
|
||||||
|
try await performAccessibilityAudit(named: "CopyTextButton_Previews")
|
||||||
|
}
|
||||||
|
|
||||||
func testCreateRoom() async throws {
|
func testCreateRoom() async throws {
|
||||||
try await performAccessibilityAudit(named: "CreateRoom_Previews")
|
try await performAccessibilityAudit(named: "CreateRoom_Previews")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -540,6 +540,7 @@
|
|||||||
6298AB0906DDD3525CD78C6B /* LoremSwiftum in Frameworks */ = {isa = PBXBuildFile; productRef = 1A6B622CCFDEFB92D9CF1CA5 /* LoremSwiftum */; };
|
6298AB0906DDD3525CD78C6B /* LoremSwiftum in Frameworks */ = {isa = PBXBuildFile; productRef = 1A6B622CCFDEFB92D9CF1CA5 /* LoremSwiftum */; };
|
||||||
62A7FC3A0191BC7181AA432B /* AudioRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 907FA4DE17DEA1A3738EFB83 /* AudioRecorder.swift */; };
|
62A7FC3A0191BC7181AA432B /* AudioRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 907FA4DE17DEA1A3738EFB83 /* AudioRecorder.swift */; };
|
||||||
62C5876C4254C58C2086F0DE /* HomeScreenContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3B4B58B79A6FA250B24A1EC /* HomeScreenContent.swift */; };
|
62C5876C4254C58C2086F0DE /* HomeScreenContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3B4B58B79A6FA250B24A1EC /* HomeScreenContent.swift */; };
|
||||||
|
633501761094E09DFBEBFFAD /* CopyTextButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B682FE2C44C5E163E7023B05 /* CopyTextButton.swift */; };
|
||||||
63780F9DA06573E38A471ECA /* GenericCallLinkWidgetDriver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28C202C1C7E330F124981A31 /* GenericCallLinkWidgetDriver.swift */; };
|
63780F9DA06573E38A471ECA /* GenericCallLinkWidgetDriver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28C202C1C7E330F124981A31 /* GenericCallLinkWidgetDriver.swift */; };
|
||||||
6386EA3C898AD1A4BC1DC8A5 /* TimelineMediaPreviewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FD40B92FCF20165658296AD /* TimelineMediaPreviewModifier.swift */; };
|
6386EA3C898AD1A4BC1DC8A5 /* TimelineMediaPreviewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FD40B92FCF20165658296AD /* TimelineMediaPreviewModifier.swift */; };
|
||||||
639A0A27383EC655B0E81E95 /* SpaceScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 459A3921046977CBF4F3C359 /* SpaceScreenViewModelProtocol.swift */; };
|
639A0A27383EC655B0E81E95 /* SpaceScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 459A3921046977CBF4F3C359 /* SpaceScreenViewModelProtocol.swift */; };
|
||||||
@@ -2458,6 +2459,7 @@
|
|||||||
B61C339A2FDDBD067FF6635C /* ConfettiScene.scn */ = {isa = PBXFileReference; path = ConfettiScene.scn; sourceTree = "<group>"; };
|
B61C339A2FDDBD067FF6635C /* ConfettiScene.scn */ = {isa = PBXFileReference; path = ConfettiScene.scn; sourceTree = "<group>"; };
|
||||||
B6404166CBF5CC88673FF9E2 /* RoomDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetails.swift; sourceTree = "<group>"; };
|
B6404166CBF5CC88673FF9E2 /* RoomDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetails.swift; sourceTree = "<group>"; };
|
||||||
B65DDCF8E41759890355ACBC /* AuthenticationStartScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationStartScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
B65DDCF8E41759890355ACBC /* AuthenticationStartScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationStartScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||||
|
B682FE2C44C5E163E7023B05 /* CopyTextButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopyTextButton.swift; sourceTree = "<group>"; };
|
||||||
B68B31232312AFC844440BFE /* DeclineAndBlockScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeclineAndBlockScreenModels.swift; sourceTree = "<group>"; };
|
B68B31232312AFC844440BFE /* DeclineAndBlockScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeclineAndBlockScreenModels.swift; sourceTree = "<group>"; };
|
||||||
B69AEA8755382DB34892FB7B /* ThreadTimelineScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadTimelineScreenModels.swift; sourceTree = "<group>"; };
|
B69AEA8755382DB34892FB7B /* ThreadTimelineScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadTimelineScreenModels.swift; sourceTree = "<group>"; };
|
||||||
B6A293D06BAB2B7A17D9314B /* VoiceMessageRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageRoomTimelineView.swift; sourceTree = "<group>"; };
|
B6A293D06BAB2B7A17D9314B /* VoiceMessageRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageRoomTimelineView.swift; sourceTree = "<group>"; };
|
||||||
@@ -3584,6 +3586,7 @@
|
|||||||
07934EF08BB39353E4A94272 /* BlurEffectView.swift */,
|
07934EF08BB39353E4A94272 /* BlurEffectView.swift */,
|
||||||
8CC23C63849452BC86EA2852 /* ButtonStyle.swift */,
|
8CC23C63849452BC86EA2852 /* ButtonStyle.swift */,
|
||||||
FEC4B431B0117BDEE697DB4A /* ComposerDisabledView.swift */,
|
FEC4B431B0117BDEE697DB4A /* ComposerDisabledView.swift */,
|
||||||
|
B682FE2C44C5E163E7023B05 /* CopyTextButton.swift */,
|
||||||
E2776E63E02719B20758EB78 /* EditRoomAddressListRow.swift */,
|
E2776E63E02719B20758EB78 /* EditRoomAddressListRow.swift */,
|
||||||
8F4F0AB250EFA7B71FB2BDB2 /* HorizontalHighlightGradient.swift */,
|
8F4F0AB250EFA7B71FB2BDB2 /* HorizontalHighlightGradient.swift */,
|
||||||
F320003F490B11F808ECC5E9 /* JoinedMembersBadgeView.swift */,
|
F320003F490B11F808ECC5E9 /* JoinedMembersBadgeView.swift */,
|
||||||
@@ -5848,6 +5851,13 @@
|
|||||||
path = MapLibre;
|
path = MapLibre;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
C18958141C8ED6D778F779A4 /* CreateRoom */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
);
|
||||||
|
path = CreateRoom;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
C1CD278862878F9545608040 /* SessionVerificationScreen */ = {
|
C1CD278862878F9545608040 /* SessionVerificationScreen */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -6230,6 +6240,7 @@
|
|||||||
53FB148CD26AFB6A5B9E20B3 /* BugReportScreen */,
|
53FB148CD26AFB6A5B9E20B3 /* BugReportScreen */,
|
||||||
1185EECDD07495D65AC84AFC /* CallScreen */,
|
1185EECDD07495D65AC84AFC /* CallScreen */,
|
||||||
90DC2E28718955ED87AD1456 /* CreatePollScreen */,
|
90DC2E28718955ED87AD1456 /* CreatePollScreen */,
|
||||||
|
C18958141C8ED6D778F779A4 /* CreateRoom */,
|
||||||
821EB0D1C0019E3C7BBAEDBB /* CreateRoomScreen */,
|
821EB0D1C0019E3C7BBAEDBB /* CreateRoomScreen */,
|
||||||
3E1CCC4B607946CE90B4A827 /* DeclineAndBlockScreen */,
|
3E1CCC4B607946CE90B4A827 /* DeclineAndBlockScreen */,
|
||||||
45F2BCFD6E9A6F040CC20582 /* EditRoomAddressScreen */,
|
45F2BCFD6E9A6F040CC20582 /* EditRoomAddressScreen */,
|
||||||
@@ -7707,6 +7718,7 @@
|
|||||||
EA6613B29BA671F39CE1B1D2 /* ConfirmationDialog.swift in Sources */,
|
EA6613B29BA671F39CE1B1D2 /* ConfirmationDialog.swift in Sources */,
|
||||||
AC7AA215D60FBC307F984028 /* Consumable.swift in Sources */,
|
AC7AA215D60FBC307F984028 /* Consumable.swift in Sources */,
|
||||||
C3522917C0C367C403429EEC /* CoordinatorProtocol.swift in Sources */,
|
C3522917C0C367C403429EEC /* CoordinatorProtocol.swift in Sources */,
|
||||||
|
633501761094E09DFBEBFFAD /* CopyTextButton.swift in Sources */,
|
||||||
CE8296D4AD30DDC6D0C67A74 /* CreateRoomScreen.swift in Sources */,
|
CE8296D4AD30DDC6D0C67A74 /* CreateRoomScreen.swift in Sources */,
|
||||||
D38E59C48BE5499A48D12031 /* CreateRoomScreenCoordinator.swift in Sources */,
|
D38E59C48BE5499A48D12031 /* CreateRoomScreenCoordinator.swift in Sources */,
|
||||||
9DBF6524DFD8143A4D6A17F0 /* CreateRoomScreenModels.swift in Sources */,
|
9DBF6524DFD8143A4D6A17F0 /* CreateRoomScreenModels.swift in Sources */,
|
||||||
|
|||||||
@@ -500,9 +500,11 @@
|
|||||||
"screen_bottom_sheet_manage_room_member_ban_member_confirmation_action" = "Ban";
|
"screen_bottom_sheet_manage_room_member_ban_member_confirmation_action" = "Ban";
|
||||||
"screen_bottom_sheet_manage_room_member_ban_member_confirmation_description" = "They won’t be able to join again if invited.";
|
"screen_bottom_sheet_manage_room_member_ban_member_confirmation_description" = "They won’t be able to join again if invited.";
|
||||||
"screen_bottom_sheet_manage_room_member_ban_member_confirmation_title" = "Are you sure you want to ban this member?";
|
"screen_bottom_sheet_manage_room_member_ban_member_confirmation_title" = "Are you sure you want to ban this member?";
|
||||||
|
"screen_bottom_sheet_manage_room_member_ban_member_from_space_confirmation_description" = "They won’t be able to join this space again if invited, but they’ll still keep their memberships of any rooms or subspaces.";
|
||||||
"screen_bottom_sheet_manage_room_member_banning_user" = "Banning %1$@";
|
"screen_bottom_sheet_manage_room_member_banning_user" = "Banning %1$@";
|
||||||
"screen_bottom_sheet_manage_room_member_kick_member_confirmation_action" = "Remove";
|
"screen_bottom_sheet_manage_room_member_kick_member_confirmation_action" = "Remove";
|
||||||
"screen_bottom_sheet_manage_room_member_kick_member_confirmation_title" = "Are you sure you want to remove this member?";
|
"screen_bottom_sheet_manage_room_member_kick_member_confirmation_title" = "Are you sure you want to remove this member?";
|
||||||
|
"screen_bottom_sheet_manage_room_member_kick_member_from_space_confirmation_description" = "They will be able to join this space again if invited, and they’ll still keep their memberships of any rooms or subspaces.";
|
||||||
"screen_bottom_sheet_manage_room_member_member_user_info" = "View profile";
|
"screen_bottom_sheet_manage_room_member_member_user_info" = "View profile";
|
||||||
"screen_bottom_sheet_manage_room_member_remove" = "Remove user";
|
"screen_bottom_sheet_manage_room_member_remove" = "Remove user";
|
||||||
"screen_bottom_sheet_manage_room_member_remove_confirmation_title" = "Remove member and ban from joining in the future?";
|
"screen_bottom_sheet_manage_room_member_remove_confirmation_title" = "Remove member and ban from joining in the future?";
|
||||||
|
|||||||
@@ -1322,6 +1322,8 @@ internal enum L10n {
|
|||||||
internal static var screenBottomSheetManageRoomMemberBanMemberConfirmationDescription: String { return L10n.tr("Localizable", "screen_bottom_sheet_manage_room_member_ban_member_confirmation_description") }
|
internal static var screenBottomSheetManageRoomMemberBanMemberConfirmationDescription: String { return L10n.tr("Localizable", "screen_bottom_sheet_manage_room_member_ban_member_confirmation_description") }
|
||||||
/// Are you sure you want to ban this member?
|
/// Are you sure you want to ban this member?
|
||||||
internal static var screenBottomSheetManageRoomMemberBanMemberConfirmationTitle: String { return L10n.tr("Localizable", "screen_bottom_sheet_manage_room_member_ban_member_confirmation_title") }
|
internal static var screenBottomSheetManageRoomMemberBanMemberConfirmationTitle: String { return L10n.tr("Localizable", "screen_bottom_sheet_manage_room_member_ban_member_confirmation_title") }
|
||||||
|
/// They won’t be able to join this space again if invited, but they’ll still keep their memberships of any rooms or subspaces.
|
||||||
|
internal static var screenBottomSheetManageRoomMemberBanMemberFromSpaceConfirmationDescription: String { return L10n.tr("Localizable", "screen_bottom_sheet_manage_room_member_ban_member_from_space_confirmation_description") }
|
||||||
/// Banning %1$@
|
/// Banning %1$@
|
||||||
internal static func screenBottomSheetManageRoomMemberBanningUser(_ p1: Any) -> String {
|
internal static func screenBottomSheetManageRoomMemberBanningUser(_ p1: Any) -> String {
|
||||||
return L10n.tr("Localizable", "screen_bottom_sheet_manage_room_member_banning_user", String(describing: p1))
|
return L10n.tr("Localizable", "screen_bottom_sheet_manage_room_member_banning_user", String(describing: p1))
|
||||||
@@ -1332,6 +1334,8 @@ internal enum L10n {
|
|||||||
internal static var screenBottomSheetManageRoomMemberKickMemberConfirmationDescription: String { return L10n.tr("Localizable", "screen_bottom_sheet_manage_room_member_kick_member_confirmation_description") }
|
internal static var screenBottomSheetManageRoomMemberKickMemberConfirmationDescription: String { return L10n.tr("Localizable", "screen_bottom_sheet_manage_room_member_kick_member_confirmation_description") }
|
||||||
/// Are you sure you want to remove this member?
|
/// Are you sure you want to remove this member?
|
||||||
internal static var screenBottomSheetManageRoomMemberKickMemberConfirmationTitle: String { return L10n.tr("Localizable", "screen_bottom_sheet_manage_room_member_kick_member_confirmation_title") }
|
internal static var screenBottomSheetManageRoomMemberKickMemberConfirmationTitle: String { return L10n.tr("Localizable", "screen_bottom_sheet_manage_room_member_kick_member_confirmation_title") }
|
||||||
|
/// They will be able to join this space again if invited, and they’ll still keep their memberships of any rooms or subspaces.
|
||||||
|
internal static var screenBottomSheetManageRoomMemberKickMemberFromSpaceConfirmationDescription: String { return L10n.tr("Localizable", "screen_bottom_sheet_manage_room_member_kick_member_from_space_confirmation_description") }
|
||||||
/// View profile
|
/// View profile
|
||||||
internal static var screenBottomSheetManageRoomMemberMemberUserInfo: String { return L10n.tr("Localizable", "screen_bottom_sheet_manage_room_member_member_user_info") }
|
internal static var screenBottomSheetManageRoomMemberMemberUserInfo: String { return L10n.tr("Localizable", "screen_bottom_sheet_manage_room_member_member_user_info") }
|
||||||
/// Remove user
|
/// Remove user
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
//
|
||||||
|
// Copyright 2025 New Vector Ltd.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
|
// Please see LICENSE files in the repository root for full details.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Compound
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
/// A button that contains text that is copied on tap
|
||||||
|
struct CopyTextButton: View {
|
||||||
|
let content: String
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Button {
|
||||||
|
UIPasteboard.general.string = content
|
||||||
|
} label: {
|
||||||
|
Label {
|
||||||
|
Text(content)
|
||||||
|
.lineLimit(1)
|
||||||
|
} icon: {
|
||||||
|
CompoundIcon(\.copy, size: .small, relativeTo: .compound.bodyLG)
|
||||||
|
.accessibilityHidden(true)
|
||||||
|
}
|
||||||
|
.font(.compound.bodyLG)
|
||||||
|
.foregroundStyle(.compound.textSecondary)
|
||||||
|
.labelStyle(.custom(spacing: 4, iconLayout: .trailing))
|
||||||
|
}
|
||||||
|
.accessibilityHint(L10n.actionCopy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CopyTextButton_Previews: PreviewProvider, TestablePreview {
|
||||||
|
static var previews: some View {
|
||||||
|
CopyTextButton(content: "Copy me!")
|
||||||
|
.previewLayout(.sizeThatFits)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,6 +30,7 @@ enum TestablePreviewsDictionary {
|
|||||||
"CollapsibleRoomTimelineView_Previews" : CollapsibleRoomTimelineView_Previews.self,
|
"CollapsibleRoomTimelineView_Previews" : CollapsibleRoomTimelineView_Previews.self,
|
||||||
"CompletionSuggestion_Previews" : CompletionSuggestion_Previews.self,
|
"CompletionSuggestion_Previews" : CompletionSuggestion_Previews.self,
|
||||||
"ComposerToolbar_Previews" : ComposerToolbar_Previews.self,
|
"ComposerToolbar_Previews" : ComposerToolbar_Previews.self,
|
||||||
|
"CopyTextButton_Previews" : CopyTextButton_Previews.self,
|
||||||
"CreateRoom_Previews" : CreateRoom_Previews.self,
|
"CreateRoom_Previews" : CreateRoom_Previews.self,
|
||||||
"DeactivateAccountScreen_Previews" : DeactivateAccountScreen_Previews.self,
|
"DeactivateAccountScreen_Previews" : DeactivateAccountScreen_Previews.self,
|
||||||
"DeclineAndBlockScreen_Previews" : DeclineAndBlockScreen_Previews.self,
|
"DeclineAndBlockScreen_Previews" : DeclineAndBlockScreen_Previews.self,
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ class ManageRoomMemberSheetViewModel: ManageRoomMemberSheetViewModelType, Manage
|
|||||||
case .kick:
|
case .kick:
|
||||||
state.bindings.alertInfo = .init(id: alertType,
|
state.bindings.alertInfo = .init(id: alertType,
|
||||||
title: L10n.screenBottomSheetManageRoomMemberKickMemberConfirmationTitle,
|
title: L10n.screenBottomSheetManageRoomMemberKickMemberConfirmationTitle,
|
||||||
message: L10n.screenBottomSheetManageRoomMemberKickMemberConfirmationDescription,
|
message: roomProxy.infoPublisher.value.isSpace ? L10n.screenBottomSheetManageRoomMemberKickMemberFromSpaceConfirmationDescription : L10n.screenBottomSheetManageRoomMemberKickMemberConfirmationDescription,
|
||||||
primaryButton: .init(title: L10n.actionCancel, role: .cancel) { },
|
primaryButton: .init(title: L10n.actionCancel, role: .cancel) { },
|
||||||
secondaryButton: .init(title: L10n.screenBottomSheetManageRoomMemberKickMemberConfirmationAction) { [weak self] in Task { await self?.kickMember(id: memberID, name: memberName, reason: reason) } },
|
secondaryButton: .init(title: L10n.screenBottomSheetManageRoomMemberKickMemberConfirmationAction) { [weak self] in Task { await self?.kickMember(id: memberID, name: memberName, reason: reason) } },
|
||||||
textFields: [.init(placeholder: L10n.commonReason,
|
textFields: [.init(placeholder: L10n.commonReason,
|
||||||
@@ -69,7 +69,7 @@ class ManageRoomMemberSheetViewModel: ManageRoomMemberSheetViewModelType, Manage
|
|||||||
case .ban:
|
case .ban:
|
||||||
state.bindings.alertInfo = .init(id: alertType,
|
state.bindings.alertInfo = .init(id: alertType,
|
||||||
title: L10n.screenBottomSheetManageRoomMemberBanMemberConfirmationTitle,
|
title: L10n.screenBottomSheetManageRoomMemberBanMemberConfirmationTitle,
|
||||||
message: L10n.screenBottomSheetManageRoomMemberBanMemberConfirmationDescription,
|
message: roomProxy.infoPublisher.value.isSpace ? L10n.screenBottomSheetManageRoomMemberBanMemberFromSpaceConfirmationDescription : L10n.screenBottomSheetManageRoomMemberBanMemberConfirmationDescription,
|
||||||
primaryButton: .init(title: L10n.actionCancel, role: .cancel) { },
|
primaryButton: .init(title: L10n.actionCancel, role: .cancel) { },
|
||||||
secondaryButton: .init(title: L10n.screenBottomSheetManageRoomMemberBanMemberConfirmationAction) { [weak self] in Task { await self?.banMember(id: memberID, name: memberName, reason: reason) } },
|
secondaryButton: .init(title: L10n.screenBottomSheetManageRoomMemberBanMemberConfirmationAction) { [weak self] in Task { await self?.banMember(id: memberID, name: memberName, reason: reason) } },
|
||||||
textFields: [.init(placeholder: L10n.commonReason,
|
textFields: [.init(placeholder: L10n.commonReason,
|
||||||
|
|||||||
@@ -28,6 +28,10 @@ struct SpaceHeaderView: View {
|
|||||||
.foregroundStyle(.compound.textPrimary)
|
.foregroundStyle(.compound.textPrimary)
|
||||||
.multilineTextAlignment(.center)
|
.multilineTextAlignment(.center)
|
||||||
|
|
||||||
|
if let alias = spaceRoomProxy.canonicalAlias {
|
||||||
|
CopyTextButton(content: alias)
|
||||||
|
}
|
||||||
|
|
||||||
spaceDetails
|
spaceDetails
|
||||||
|
|
||||||
JoinedMembersBadgeView(heroes: spaceRoomProxy.heroes,
|
JoinedMembersBadgeView(heroes: spaceRoomProxy.heroes,
|
||||||
@@ -62,7 +66,7 @@ struct SpaceHeaderView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var spaceDetails: some View {
|
private var spaceDetails: some View {
|
||||||
Label {
|
Label {
|
||||||
Text(spaceDetailsVisibilityTitle)
|
Text(spaceDetailsVisibilityTitle)
|
||||||
.font(.compound.bodyLG)
|
.font(.compound.bodyLG)
|
||||||
@@ -74,7 +78,7 @@ struct SpaceHeaderView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var spaceDetailsVisibilityTitle: String {
|
private var spaceDetailsVisibilityTitle: String {
|
||||||
switch spaceRoomProxy.visibility {
|
switch spaceRoomProxy.visibility {
|
||||||
case .public: L10n.commonPublicSpace
|
case .public: L10n.commonPublicSpace
|
||||||
case .private: L10n.commonPrivateSpace
|
case .private: L10n.commonPrivateSpace
|
||||||
@@ -83,7 +87,7 @@ struct SpaceHeaderView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var spaceDetailsVisibilityIcon: KeyPath<CompoundIcons, Image> {
|
private var spaceDetailsVisibilityIcon: KeyPath<CompoundIcons, Image> {
|
||||||
switch spaceRoomProxy.visibility {
|
switch spaceRoomProxy.visibility {
|
||||||
case .public: \.public
|
case .public: \.public
|
||||||
case .private: \.lock
|
case .private: \.lock
|
||||||
@@ -122,6 +126,7 @@ struct SpaceHeaderView_Previews: PreviewProvider, TestablePreview {
|
|||||||
childrenCount: 20,
|
childrenCount: 20,
|
||||||
joinedMembersCount: 78,
|
joinedMembersCount: 78,
|
||||||
topic: "Description of the space goes right here.",
|
topic: "Description of the space goes right here.",
|
||||||
|
canonicalAlias: "#space:matrix.org",
|
||||||
joinRule: .public)),
|
joinRule: .public)),
|
||||||
SpaceRoomProxyMock(.init(id: "!space3:matrix.org",
|
SpaceRoomProxyMock(.init(id: "!space3:matrix.org",
|
||||||
name: "Subspace",
|
name: "Subspace",
|
||||||
@@ -135,6 +140,7 @@ struct SpaceHeaderView_Previews: PreviewProvider, TestablePreview {
|
|||||||
"Sem amet enim habitant nibh augue mauris.",
|
"Sem amet enim habitant nibh augue mauris.",
|
||||||
"Interdum mauris ultrices tincidunt proin morbi erat aenean risus nibh.",
|
"Interdum mauris ultrices tincidunt proin morbi erat aenean risus nibh.",
|
||||||
"Diam amet sit fermentum vulputate faucibus."].joined(separator: " "),
|
"Diam amet sit fermentum vulputate faucibus."].joined(separator: " "),
|
||||||
|
canonicalAlias: "#subspace:matrix.org",
|
||||||
joinRule: .knockRestricted(rules: [.roomMembership(roomId: "")])))
|
joinRule: .knockRestricted(rules: [.roomMembership(roomId: "")])))
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,12 @@ struct SpaceScreenViewState: BindableState {
|
|||||||
var selectedSpaceRoomID: String?
|
var selectedSpaceRoomID: String?
|
||||||
var joiningRoomIDs: Set<String> = []
|
var joiningRoomIDs: Set<String> = []
|
||||||
|
|
||||||
var isSpaceManagementEnabled = false
|
var canEditBaseInfo = false
|
||||||
|
var canEditRolesAndPermissions = false
|
||||||
|
|
||||||
|
var isSpaceManagementEnabled: Bool {
|
||||||
|
canEditBaseInfo || canEditRolesAndPermissions
|
||||||
|
}
|
||||||
|
|
||||||
var bindings = SpaceScreenViewStateBindings()
|
var bindings = SpaceScreenViewStateBindings()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,7 +80,17 @@ class SpaceScreenViewModel: SpaceScreenViewModelType, SpaceScreenViewModelProtoc
|
|||||||
}
|
}
|
||||||
|
|
||||||
appSettings.$spaceSettingsEnabled
|
appSettings.$spaceSettingsEnabled
|
||||||
.weakAssign(to: \.state.isSpaceManagementEnabled, on: self)
|
.combineLatest(roomProxy.infoPublisher)
|
||||||
|
.sink { [weak self] isEnabled, roomInfo in
|
||||||
|
guard let self else { return }
|
||||||
|
guard isEnabled, let powerLevels = roomInfo.powerLevels else {
|
||||||
|
state.canEditBaseInfo = false
|
||||||
|
state.canEditRolesAndPermissions = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
state.canEditBaseInfo = powerLevels.canOwnUserEditBaseInfo()
|
||||||
|
state.canEditRolesAndPermissions = powerLevels.canOwnUserEditRolesAndPermissions()
|
||||||
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ struct LeaveSpaceView: View {
|
|||||||
Label(leaveHandle.confirmationTitle, icon: \.leave)
|
Label(leaveHandle.confirmationTitle, icon: \.leave)
|
||||||
}
|
}
|
||||||
.buttonStyle(.compound(.primary))
|
.buttonStyle(.compound(.primary))
|
||||||
} else if context.viewState.isSpaceManagementEnabled {
|
} else if context.viewState.canEditRolesAndPermissions {
|
||||||
Button {
|
Button {
|
||||||
context.send(viewAction: .rolesAndPermissions)
|
context.send(viewAction: .rolesAndPermissions)
|
||||||
} label: {
|
} label: {
|
||||||
|
|||||||
@@ -114,6 +114,7 @@ struct SpaceScreen_Previews: PreviewProvider, TestablePreview {
|
|||||||
joinedMembersCount: 76,
|
joinedMembersCount: 76,
|
||||||
heroes: [.mockDan, .mockBob, .mockCharlie, .mockVerbose],
|
heroes: [.mockDan, .mockBob, .mockCharlie, .mockVerbose],
|
||||||
topic: "Description of the space goes right here. Lorem ipsum dolor sit amet consectetur. Leo viverra morbi habitant in.",
|
topic: "Description of the space goes right here. Lorem ipsum dolor sit amet consectetur. Leo viverra morbi habitant in.",
|
||||||
|
canonicalAlias: "#engineering-team:element.io",
|
||||||
joinRule: .knockRestricted(rules: [.roomMembership(roomId: "")])))
|
joinRule: .knockRestricted(rules: [.roomMembership(roomId: "")])))
|
||||||
let spaceRoomListProxy = SpaceRoomListProxyMock(.init(spaceRoomProxy: spaceRoomProxy,
|
let spaceRoomListProxy = SpaceRoomListProxyMock(.init(spaceRoomProxy: spaceRoomProxy,
|
||||||
initialSpaceRooms: .mockSpaceList))
|
initialSpaceRooms: .mockSpaceList))
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ struct SpaceSettingsScreenViewState: BindableState {
|
|||||||
var joinedMembersCount: Int
|
var joinedMembersCount: Int
|
||||||
var hasMemberIdentityVerificationStateViolations = false
|
var hasMemberIdentityVerificationStateViolations = false
|
||||||
|
|
||||||
|
var canEditBaseInfo = false
|
||||||
var canEditRolesOrPermissions = false
|
var canEditRolesOrPermissions = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ class SpaceSettingsScreenViewModel: SpaceSettingsScreenViewModelType, SpaceSetti
|
|||||||
|
|
||||||
if let powerLevels = roomInfo.powerLevels {
|
if let powerLevels = roomInfo.powerLevels {
|
||||||
state.canEditRolesOrPermissions = powerLevels.canOwnUserEditRolesAndPermissions()
|
state.canEditRolesOrPermissions = powerLevels.canOwnUserEditRolesAndPermissions()
|
||||||
|
state.canEditBaseInfo = powerLevels.canOwnUserEditBaseInfo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+32
-10
@@ -26,17 +26,24 @@ struct SpaceSettingsScreen: View {
|
|||||||
|
|
||||||
private var editSection: some View {
|
private var editSection: some View {
|
||||||
Section {
|
Section {
|
||||||
ListRow(kind: .custom {
|
ListRow(kind: .custom { editRow })
|
||||||
Button {
|
|
||||||
context.send(viewAction: .processTapEdit)
|
|
||||||
} label: {
|
|
||||||
editSectionContent
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var editSectionContent: some View {
|
@ViewBuilder
|
||||||
|
private var editRow: some View {
|
||||||
|
if context.viewState.canEditBaseInfo {
|
||||||
|
Button {
|
||||||
|
context.send(viewAction: .processTapEdit)
|
||||||
|
} label: {
|
||||||
|
editRowContent
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
editRowContent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var editRowContent: some View {
|
||||||
HStack(spacing: 12) {
|
HStack(spacing: 12) {
|
||||||
RoomAvatarImage(avatar: context.viewState.details.avatar,
|
RoomAvatarImage(avatar: context.viewState.details.avatar,
|
||||||
avatarSize: .room(on: .spaceSettings),
|
avatarSize: .room(on: .spaceSettings),
|
||||||
@@ -57,8 +64,10 @@ struct SpaceSettingsScreen: View {
|
|||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
|
|
||||||
|
if context.viewState.canEditBaseInfo {
|
||||||
ListRowAccessory.navigationLink
|
ListRowAccessory.navigationLink
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.padding(.horizontal, ListRowPadding.horizontal)
|
.padding(.horizontal, ListRowPadding.horizontal)
|
||||||
.padding(.vertical, 16)
|
.padding(.vertical, 16)
|
||||||
}
|
}
|
||||||
@@ -108,16 +117,29 @@ struct SpaceSettingsScreen: View {
|
|||||||
// MARK: - Previews
|
// MARK: - Previews
|
||||||
|
|
||||||
struct SpaceSettingsScreen_Previews: PreviewProvider, TestablePreview {
|
struct SpaceSettingsScreen_Previews: PreviewProvider, TestablePreview {
|
||||||
static let viewModel = SpaceSettingsScreenViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "Space",
|
static let ownerViewModel = SpaceSettingsScreenViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "Space",
|
||||||
avatarURL: .mockMXCAvatar,
|
avatarURL: .mockMXCAvatar,
|
||||||
isSpace: true,
|
isSpace: true,
|
||||||
canonicalAlias: "#space:matrix.org",
|
canonicalAlias: "#space:matrix.org",
|
||||||
members: .allMembersAsCreator)),
|
members: .allMembersAsCreator)),
|
||||||
userSession: UserSessionMock(.init()))
|
userSession: UserSessionMock(.init()))
|
||||||
|
|
||||||
|
static let userViewModel = SpaceSettingsScreenViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "Space",
|
||||||
|
avatarURL: .mockMXCAvatar,
|
||||||
|
isSpace: true,
|
||||||
|
canonicalAlias: "#space:matrix.org",
|
||||||
|
members: .allMembers)),
|
||||||
|
userSession: UserSessionMock(.init()))
|
||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
SpaceSettingsScreen(context: viewModel.context)
|
SpaceSettingsScreen(context: ownerViewModel.context)
|
||||||
}
|
}
|
||||||
|
.previewDisplayName("Owner")
|
||||||
|
|
||||||
|
NavigationStack {
|
||||||
|
SpaceSettingsScreen(context: userViewModel.context)
|
||||||
|
}
|
||||||
|
.previewDisplayName("User")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,3 +36,12 @@ protocol RoomPowerLevelsProxyProtocol {
|
|||||||
func canUserPinOrUnpin(userID: String) -> Result<Bool, RoomProxyError>
|
func canUserPinOrUnpin(userID: String) -> Result<Bool, RoomProxyError>
|
||||||
func canUserJoinCall(userID: String) -> Result<Bool, RoomProxyError>
|
func canUserJoinCall(userID: String) -> Result<Bool, RoomProxyError>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Helpers
|
||||||
|
|
||||||
|
extension RoomPowerLevelsProxyProtocol {
|
||||||
|
/// Can own user edit either the room name, avatar or topic
|
||||||
|
func canOwnUserEditBaseInfo() -> Bool {
|
||||||
|
canOwnUser(sendStateEvent: .roomAvatar) || canOwnUser(sendStateEvent: .roomName) || canOwnUser(sendStateEvent: .roomTopic)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -137,6 +137,12 @@ extension PreviewTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testCopyTextButton() async throws {
|
||||||
|
for (index, preview) in CopyTextButton_Previews._allPreviews.enumerated() {
|
||||||
|
try await assertSnapshots(matching: preview, step: index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func testCreateRoom() async throws {
|
func testCreateRoom() async throws {
|
||||||
for (index, preview) in CreateRoom_Previews._allPreviews.enumerated() {
|
for (index, preview) in CreateRoom_Previews._allPreviews.enumerated() {
|
||||||
try await assertSnapshots(matching: preview, step: index)
|
try await assertSnapshots(matching: preview, step: index)
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:b3d494a30652c54d4ab3d503eecfb1b849db78f7ea372d392f5b93efc2a3ecd7
|
||||||
|
size 5941
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:b3d494a30652c54d4ab3d503eecfb1b849db78f7ea372d392f5b93efc2a3ecd7
|
||||||
|
size 5941
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:824417be28d83b6cf5a3200e3e792e639c648b3a6288bc29fe461b85b069a7ae
|
||||||
|
size 4544
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:824417be28d83b6cf5a3200e3e792e639c648b3a6288bc29fe461b85b069a7ae
|
||||||
|
size 4544
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:41a11b24dc33a848b1e92e221ebf6f7eed9da0d17883baba30b49488a8dd916d
|
oid sha256:486d97c665bfd6f9ac41c3c65182476080467159d4dda64e89e725960ac8a3f7
|
||||||
size 203835
|
size 216418
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:80abb6f07c275acaedb46078abfac094b304d3c799c050003e1d20dca3d745fa
|
oid sha256:dfc40f590b6c37545bfa46c7569ee27b6a0ae868a55960a53e2fd3d74c564412
|
||||||
size 206909
|
size 219887
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:f972c103ce2c14ed5c676741f9a3f8f480702815e677749d46908abd0fa7dada
|
oid sha256:5778379ebc5f0df879016579fa4dccfce7e9546dc06fd5b9cb5fa3cfd3e8f050
|
||||||
size 132742
|
size 143496
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:430dfde8c142f7ad7474be587c0c217daa9cb9801fe0ff0eff291f8f9cbf57cf
|
oid sha256:5adc8046dfeadc62fb0d22fba84e0f5c0c61c7bb780a432b800e2cdb29066427
|
||||||
size 139505
|
size 149951
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:f0657e0d482b9a3bc949d0bd9b2206baa14413c58031a9333cdd105ccecab4d8
|
oid sha256:96f0a0f4dd66edce3a75e51a16d059bdfbe32ef61dc8e78ccbb22868205c36ea
|
||||||
size 234610
|
size 233953
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:2f770bab4c29db4148a4266a9d2956f4b6268ec473b8a013a5aa89219613f5db
|
oid sha256:c4c8eb821de73289ae5c220b9c1fa9f2e58c33e3617634ae0cacb5d9043e587f
|
||||||
size 264406
|
size 263913
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:5b2acf1f719ab9acb6887d700607a3e741ec69ae7cabbfd3fd2d00ebef7c7ced
|
oid sha256:8891be05350788529385e39d9edf71e52c7d2536a471773b831358278b316973
|
||||||
size 175169
|
size 175952
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:f68408d2eca92a7dec827ef79f01179ae58c4a5b55dd4d2c6de425d525d06842
|
oid sha256:a46b3ab9af6aeca9bc98ffd6efe3669a03361c8efc6cba99e303d04f11fdbc07
|
||||||
size 200045
|
size 197703
|
||||||
|
|||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:e172a847ec495abaf46e8a42879252a75db06fa3e2cd4ff1c31964726f08422e
|
||||||
|
size 125408
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:d2133099664d02d4c53a86ad516f1e6c321e852455504ac18acd135267d109f6
|
||||||
|
size 129691
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:5e2b5de1805e2d163be5b82ef98814cedacef5c02ee18160f55856a8fd7bd1b9
|
||||||
|
size 78430
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:e83067633005469ed20f25d0d6e1c92d436983c230860faed77b65bebb3c0bc0
|
||||||
|
size 82233
|
||||||
Reference in New Issue
Block a user