Skip to content

Commit

Permalink
Knock Requests banner display logic (#3550)
Browse files Browse the repository at this point in the history
* added the join rule to the info

* update SDK and added logic to display the banner

in the room screen

* added the logic to display the banner
  • Loading branch information
Velin92 authored Nov 25, 2024
1 parent 9180bac commit 26e07f2
Show file tree
Hide file tree
Showing 16 changed files with 131 additions and 42 deletions.
2 changes: 1 addition & 1 deletion ElementX.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8195,7 +8195,7 @@
repositoryURL = "https://github.com/element-hq/matrix-rust-components-swift";
requirement = {
kind = exactVersion;
version = 1.0.73;
version = 1.0.74;
};
};
701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */ = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/element-hq/matrix-rust-components-swift",
"state" : {
"revision" : "b3f97292695e8d63469c0d3ec608eb74423c6a2e",
"version" : "1.0.73"
"revision" : "66d32e79ae20dd31201cd16eced53cfcc0c3239d",
"version" : "1.0.74"
}
},
{
Expand Down
3 changes: 2 additions & 1 deletion ElementX/Sources/Mocks/InvitedRoomProxyMock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ extension RoomInfo {
numUnreadMessages: 0,
numUnreadNotifications: 0,
numUnreadMentions: 0,
pinnedEventIds: [])
pinnedEventIds: [],
joinRule: .invite)
}
}

Expand Down
4 changes: 3 additions & 1 deletion ElementX/Sources/Mocks/JoinedRoomProxyMock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ struct JoinedRoomProxyMockConfiguration {
var canUserPin = true

var shouldUseAutoUpdatingTimeline = false
var joinRule: JoinRule?
}

extension JoinedRoomProxyMock {
Expand Down Expand Up @@ -166,6 +167,7 @@ extension RoomInfo {
numUnreadMessages: 0,
numUnreadNotifications: 0,
numUnreadMentions: 0,
pinnedEventIds: Array(configuration.pinnedEventIDs))
pinnedEventIds: Array(configuration.pinnedEventIDs),
joinRule: configuration.joinRule)
}
}
3 changes: 2 additions & 1 deletion ElementX/Sources/Mocks/KnockedRoomProxyMock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ extension RoomInfo {
numUnreadMessages: 0,
numUnreadNotifications: 0,
numUnreadMentions: 0,
pinnedEventIds: [])
pinnedEventIds: [],
joinRule: .knock)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,17 @@ enum KnockRequestsListScreenViewModelAction { }

struct KnockRequestsListScreenViewState: BindableState {
var requests: [KnockRequestCellInfo] = []
var canAccept = false
var canDecline = false
var canBan = false
// If you are in this view one of these must have been true so by default we assume all of them to be true
var canAccept = true
var canDecline = true
var canBan = true
var isKnockableRoom = true

// If all the permissions are denied or the join rule changes while we are in the view
// we want to stop displaying any request
var shouldDisplayRequests: Bool {
!requests.isEmpty && isKnockableRoom && (canAccept || canDecline || canBan)
}
}

enum KnockRequestsListScreenViewAction {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class KnockRequestsListScreenViewModel: KnockRequestsListScreenViewModelType, Kn
self.roomProxy = roomProxy
super.init(initialViewState: KnockRequestsListScreenViewState(), mediaProvider: mediaProvider)

updateRoomInfo(roomInfo: roomProxy.infoPublisher.value)
Task {
await updatePermissions()
}
Expand All @@ -48,13 +49,23 @@ class KnockRequestsListScreenViewModel: KnockRequestsListScreenViewModelType, Kn

private func setupSubscriptions() {
roomProxy.infoPublisher
.throttle(for: .milliseconds(200), scheduler: DispatchQueue.main, latest: true)
.sink { [weak self] _ in
.receive(on: DispatchQueue.main)
.sink { [weak self] roomInfo in
self?.updateRoomInfo(roomInfo: roomInfo)
Task { await self?.updatePermissions() }
}
.store(in: &cancellables)
}

private func updateRoomInfo(roomInfo: RoomInfoProxy) {
switch roomInfo.joinRule {
case .knock, .knockRestricted:
state.isKnockableRoom = true
default:
state.isKnockableRoom = false
}
}

private func updatePermissions() async {
state.canAccept = await (try? roomProxy.canUserInvite(userID: roomProxy.ownUserID).get()) == true
state.canDecline = await (try? roomProxy.canUserKick(userID: roomProxy.ownUserID).get()) == true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ struct KnockRequestsListScreen: View {
.navigationTitle(L10n.screenKnockRequestsListTitle)
.background(.compound.bgCanvasDefault)
.overlay {
if context.viewState.requests.isEmpty {
if !context.viewState.shouldDisplayRequests {
KnockRequestsListEmptyStateView()
}
}
.safeAreaInset(edge: .bottom) {
if !context.viewState.requests.isEmpty {
if context.viewState.shouldDisplayRequests {
acceptAllButton
}
}
Expand All @@ -32,14 +32,16 @@ struct KnockRequestsListScreen: View {
private var mainContent: some View {
ScrollView {
LazyVStack(spacing: 0) {
ForEach(context.viewState.requests) { requestInfo in
ListRow(kind: .custom {
KnockRequestCell(cellInfo: requestInfo,
mediaProvider: context.mediaProvider,
onAccept: context.viewState.canAccept ? onAccept : nil,
onDecline: context.viewState.canDecline ? onDecline : nil,
onDeclineAndBan: context.viewState.canBan ? onDeclineAndBan : nil)
})
if context.viewState.shouldDisplayRequests {
ForEach(context.viewState.requests) { requestInfo in
ListRow(kind: .custom {
KnockRequestCell(cellInfo: requestInfo,
mediaProvider: context.mediaProvider,
onAccept: context.viewState.canAccept ? onAccept : nil,
onDecline: context.viewState.canDecline ? onDecline : nil,
onDeclineAndBan: context.viewState.canBan ? onDeclineAndBan : nil)
})
}
}
}
.padding(.top, 40)
Expand Down Expand Up @@ -79,10 +81,7 @@ struct KnockRequestsListScreen_Previews: PreviewProvider, TestablePreview {
// swiftlint:disable:next line_length
.init(id: "@bob:matrix.org", displayName: "Bob", avatarUrl: nil, timestamp: "Now", reason: "Hello this one is a very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very long reason"),
.init(id: "@charlie:matrix.org", displayName: "Charlie", avatarUrl: nil, timestamp: "Now", reason: nil),
.init(id: "@dan:matrix.org", displayName: "Dan", avatarUrl: nil, timestamp: "Now", reason: "Hello! It's a me! Dan!")],
canAccept: true,
canDecline: true,
canBan: true))
.init(id: "@dan:matrix.org", displayName: "Dan", avatarUrl: nil, timestamp: "Now", reason: "Hello! It's a me! Dan!")]))

static var previews: some View {
NavigationStack {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,10 @@ struct RoomDetailsScreenViewState: BindableState {
var canJoinCall = false
var pinnedEventsActionState = RoomDetailsScreenPinnedEventsActionState.loading
var knockingEnabled = false
var isKnockableRoom = false

var canSeeKnockingRequests: Bool {
knockingEnabled && dmRecipient == nil && (canInviteUsers || canKickUsers || canBanUsers)
knockingEnabled && dmRecipient == nil && isKnockableRoom && (canInviteUsers || canKickUsers || canBanUsers)
}

var canEdit: Bool {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,12 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
state.topicSummary = topic?.unattributedStringByReplacingNewlinesWithSpaces()
state.joinedMembersCount = roomInfo.joinedMembersCount
state.bindings.isFavourite = roomInfo.isFavourite
switch roomInfo.joinRule {
case .knock, .knockRestricted:
state.isKnockableRoom = true
default:
state.isKnockableRoom = false
}
}

private func fetchMembersIfNeeded() async {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,8 @@ struct RoomDetailsScreen_Previews: PreviewProvider, TestablePreview {
isDirect: false,
isEncrypted: true,
canonicalAlias: "#alias:domain.com",
members: members))
members: members,
joinRule: .knock))

var notificationSettingsProxyMockConfiguration = NotificationSettingsProxyMockConfiguration()
notificationSettingsProxyMockConfiguration.roomMode.isDefault = false
Expand Down Expand Up @@ -378,7 +379,8 @@ struct RoomDetailsScreen_Previews: PreviewProvider, TestablePreview {
name: "Room A",
isDirect: false,
isEncrypted: false,
members: members))
members: members,
joinRule: .knock))
let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init())

return RoomDetailsScreenViewModel(roomProxy: roomProxy,
Expand Down
12 changes: 12 additions & 0 deletions ElementX/Sources/Screens/RoomScreen/RoomScreenModels.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,18 @@ struct RoomScreenViewState: BindableState {
var hasOngoingCall: Bool
var shouldShowCallButton = true

var isKnockingEnabled = false
var isKnockableRoom = false
var canAcceptKnocks = false
var canDeclineKnocks = false
var canBan = false
// TODO: We still don't know how to get these, but these will be the non already seen knock requests of the room, for now we are using this as a mock for testing purposes
var unseenKnockRequests: [KnockRequestInfo] = [.init(displayName: "Alice", avatarURL: nil, userID: "@alice:matrix.org", reason: "Helloooo")]

var shouldSeeKnockRequests: Bool {
isKnockingEnabled && isKnockableRoom && !unseenKnockRequests.isEmpty && (canAcceptKnocks || canDeclineKnocks || canBan)
}

var footerDetails: RoomScreenFooterViewDetails?

var bindings: RoomScreenViewStateBindings
Expand Down
18 changes: 15 additions & 3 deletions ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
// MARK: - Private

private func setupSubscriptions(ongoingCallRoomIDPublisher: CurrentValuePublisher<String?, Never>) {
appSettings.$knockingEnabled
.weakAssign(to: \.state.isKnockingEnabled, on: self)
.store(in: &cancellables)

let roomInfoSubscription = roomProxy
.infoPublisher

Expand Down Expand Up @@ -236,10 +240,18 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
state.pinnedEventsBannerState = .loading(numbersOfEvents: pinnedEventIDs.count)
}

let userID = roomProxy.ownUserID
if case let .success(permission) = await roomProxy.canUserJoinCall(userID: userID) {
state.canJoinCall = permission
switch (roomProxy.isEncryptedOneToOneRoom, roomInfo.joinRule) {
case (false, .knock), (false, .knockRestricted):
state.isKnockableRoom = true
default:
state.isKnockableRoom = false
}

let ownUserID = roomProxy.ownUserID
state.canJoinCall = await (try? roomProxy.canUserJoinCall(userID: ownUserID).get()) == true
state.canAcceptKnocks = await (try? roomProxy.canUserInvite(userID: ownUserID).get()) == true
state.canDeclineKnocks = await (try? roomProxy.canUserKick(userID: ownUserID).get()) == true
state.canBan = await (try? roomProxy.canUserBan(userID: ownUserID).get()) == true
}

private func setupPinnedEventsTimelineProviderIfNeeded() {
Expand Down
53 changes: 43 additions & 10 deletions ElementX/Sources/Screens/RoomScreen/View/RoomScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,11 @@ struct RoomScreen: View {
timeline
.background(Color.compound.bgCanvasDefault.ignoresSafeArea())
.overlay(alignment: .top) {
Group {
if roomContext.viewState.shouldShowPinnedEventsBanner {
pinnedItemsBanner
}
}
.animation(.elementDefault, value: roomContext.viewState.shouldShowPinnedEventsBanner)
pinnedItemsBanner
}
// This can overlay on top of the pinnedItemsBanner
.overlay(alignment: .top) {
knockRequestsBanner
}
.safeAreaInset(edge: .bottom, spacing: 0) {
VStack(spacing: 0) {
Expand Down Expand Up @@ -119,11 +118,45 @@ struct RoomScreen: View {
}
}

@ViewBuilder
private var pinnedItemsBanner: some View {
PinnedItemsBannerView(state: roomContext.viewState.pinnedEventsBannerState,
onMainButtonTap: { roomContext.send(viewAction: .tappedPinnedEventsBanner) },
onViewAllButtonTap: { roomContext.send(viewAction: .viewAllPins) })
.transition(.move(edge: .top))
Group {
if roomContext.viewState.shouldShowPinnedEventsBanner {
PinnedItemsBannerView(state: roomContext.viewState.pinnedEventsBannerState,
onMainButtonTap: { roomContext.send(viewAction: .tappedPinnedEventsBanner) },
onViewAllButtonTap: { roomContext.send(viewAction: .viewAllPins) })
.transition(.move(edge: .top))
}
}
.animation(.elementDefault, value: roomContext.viewState.shouldShowPinnedEventsBanner)
}

@ViewBuilder
private var knockRequestsBanner: some View {
Group {
if roomContext.viewState.shouldSeeKnockRequests {
KnockRequestsBannerView(requests: roomContext.viewState.unseenKnockRequests,
onDismiss: dismissKnockRequestsBanner,
onAccept: roomContext.viewState.canAcceptKnocks ? acceptKnockRequest : nil,
onViewAll: onViewAllKnockRequests,
mediaProvider: roomContext.mediaProvider)
.padding(.top, 16)
.transition(.move(edge: .top))
}
}
.animation(.elementDefault, value: roomContext.viewState.shouldSeeKnockRequests)
}

private func dismissKnockRequestsBanner() {
// TODO: Implement
}

private func acceptKnockRequest(userID: String) {
// TODO: Implement
}

private func onViewAllKnockRequests() {
// TODO: Implement
}

private var scrollToBottomButton: some View {
Expand Down
1 change: 1 addition & 0 deletions ElementX/Sources/Services/Room/RoomInfoProxy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ struct RoomInfoProxy: BaseRoomInfoProxyProtocol {
var unreadNotificationsCount: UInt { UInt(roomInfo.numUnreadNotifications) }
var unreadMentionsCount: UInt { UInt(roomInfo.numUnreadMentions) }
var pinnedEventIDs: Set<String> { Set(roomInfo.pinnedEventIds) }
var joinRule: JoinRule? { roomInfo.joinRule }
}

struct RoomPreviewInfoProxy: BaseRoomInfoProxyProtocol {
Expand Down
2 changes: 1 addition & 1 deletion project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ packages:
# Element/Matrix dependencies
MatrixRustSDK:
url: https://github.com/element-hq/matrix-rust-components-swift
exactVersion: 1.0.73
exactVersion: 1.0.74
# path: ../matrix-rust-sdk
Compound:
url: https://github.com/element-hq/compound-ios
Expand Down

0 comments on commit 26e07f2

Please sign in to comment.