Space Settings UI tweaks (#4678)

* design tweaks for the space settings flow

* pr suggestions

* update proj
This commit is contained in:
Mauro
2025-10-31 12:52:56 +01:00
committed by GitHub
parent e95f442166
commit 0b3633ea57
37 changed files with 187 additions and 40 deletions

View File

@@ -28,6 +28,10 @@ struct SpaceHeaderView: View {
.foregroundStyle(.compound.textPrimary)
.multilineTextAlignment(.center)
if let alias = spaceRoomProxy.canonicalAlias {
CopyTextButton(content: alias)
}
spaceDetails
JoinedMembersBadgeView(heroes: spaceRoomProxy.heroes,
@@ -62,7 +66,7 @@ struct SpaceHeaderView: View {
}
}
var spaceDetails: some View {
private var spaceDetails: some View {
Label {
Text(spaceDetailsVisibilityTitle)
.font(.compound.bodyLG)
@@ -74,7 +78,7 @@ struct SpaceHeaderView: View {
}
}
var spaceDetailsVisibilityTitle: String {
private var spaceDetailsVisibilityTitle: String {
switch spaceRoomProxy.visibility {
case .public: L10n.commonPublicSpace
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 {
case .public: \.public
case .private: \.lock
@@ -122,6 +126,7 @@ struct SpaceHeaderView_Previews: PreviewProvider, TestablePreview {
childrenCount: 20,
joinedMembersCount: 78,
topic: "Description of the space goes right here.",
canonicalAlias: "#space:matrix.org",
joinRule: .public)),
SpaceRoomProxyMock(.init(id: "!space3:matrix.org",
name: "Subspace",
@@ -135,6 +140,7 @@ struct SpaceHeaderView_Previews: PreviewProvider, TestablePreview {
"Sem amet enim habitant nibh augue mauris.",
"Interdum mauris ultrices tincidunt proin morbi erat aenean risus nibh.",
"Diam amet sit fermentum vulputate faucibus."].joined(separator: " "),
canonicalAlias: "#subspace:matrix.org",
joinRule: .knockRestricted(rules: [.roomMembership(roomId: "")])))
]
}

View File

@@ -28,7 +28,12 @@ struct SpaceScreenViewState: BindableState {
var selectedSpaceRoomID: String?
var joiningRoomIDs: Set<String> = []
var isSpaceManagementEnabled = false
var canEditBaseInfo = false
var canEditRolesAndPermissions = false
var isSpaceManagementEnabled: Bool {
canEditBaseInfo || canEditRolesAndPermissions
}
var bindings = SpaceScreenViewStateBindings()
}

View File

@@ -80,7 +80,17 @@ class SpaceScreenViewModel: SpaceScreenViewModelType, SpaceScreenViewModelProtoc
}
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)
}
}

View File

@@ -97,7 +97,7 @@ struct LeaveSpaceView: View {
Label(leaveHandle.confirmationTitle, icon: \.leave)
}
.buttonStyle(.compound(.primary))
} else if context.viewState.isSpaceManagementEnabled {
} else if context.viewState.canEditRolesAndPermissions {
Button {
context.send(viewAction: .rolesAndPermissions)
} label: {

View File

@@ -114,6 +114,7 @@ struct SpaceScreen_Previews: PreviewProvider, TestablePreview {
joinedMembersCount: 76,
heroes: [.mockDan, .mockBob, .mockCharlie, .mockVerbose],
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: "")])))
let spaceRoomListProxy = SpaceRoomListProxyMock(.init(spaceRoomProxy: spaceRoomProxy,
initialSpaceRooms: .mockSpaceList))

View File

@@ -15,6 +15,7 @@ struct SpaceSettingsScreenViewState: BindableState {
var joinedMembersCount: Int
var hasMemberIdentityVerificationStateViolations = false
var canEditBaseInfo = false
var canEditRolesOrPermissions = false
}

View File

@@ -57,6 +57,7 @@ class SpaceSettingsScreenViewModel: SpaceSettingsScreenViewModelType, SpaceSetti
if let powerLevels = roomInfo.powerLevels {
state.canEditRolesOrPermissions = powerLevels.canOwnUserEditRolesAndPermissions()
state.canEditBaseInfo = powerLevels.canOwnUserEditBaseInfo()
}
}

View File

@@ -26,17 +26,24 @@ struct SpaceSettingsScreen: View {
private var editSection: some View {
Section {
ListRow(kind: .custom {
Button {
context.send(viewAction: .processTapEdit)
} label: {
editSectionContent
}
})
ListRow(kind: .custom { editRow })
}
}
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) {
RoomAvatarImage(avatar: context.viewState.details.avatar,
avatarSize: .room(on: .spaceSettings),
@@ -57,7 +64,9 @@ struct SpaceSettingsScreen: View {
}
.frame(maxWidth: .infinity, alignment: .leading)
ListRowAccessory.navigationLink
if context.viewState.canEditBaseInfo {
ListRowAccessory.navigationLink
}
}
.padding(.horizontal, ListRowPadding.horizontal)
.padding(.vertical, 16)
@@ -108,16 +117,29 @@ struct SpaceSettingsScreen: View {
// MARK: - Previews
struct SpaceSettingsScreen_Previews: PreviewProvider, TestablePreview {
static let viewModel = SpaceSettingsScreenViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "Space",
avatarURL: .mockMXCAvatar,
isSpace: true,
canonicalAlias: "#space:matrix.org",
members: .allMembersAsCreator)),
userSession: UserSessionMock(.init()))
static let ownerViewModel = SpaceSettingsScreenViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "Space",
avatarURL: .mockMXCAvatar,
isSpace: true,
canonicalAlias: "#space:matrix.org",
members: .allMembersAsCreator)),
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 {
NavigationStack {
SpaceSettingsScreen(context: viewModel.context)
SpaceSettingsScreen(context: ownerViewModel.context)
}
.previewDisplayName("Owner")
NavigationStack {
SpaceSettingsScreen(context: userViewModel.context)
}
.previewDisplayName("User")
}
}