Knock Requests List Screen (#3533)

* created the basic navigation and files

* updated the logic

so that the buttons that do not have permissions won't show

* added the empty state

* progress in making the list UI

* update tests

* UI improvements

* fixed an issue with media provider

* update button style

* fixed a navigation bug

* pr suggestions

* pr suggestions
This commit is contained in:
Mauro
2024-11-21 20:14:05 +01:00
committed by GitHub
parent 7e1476d973
commit e315451448
85 changed files with 701 additions and 145 deletions
@@ -0,0 +1,96 @@
//
// Copyright 2022-2024 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only
// Please see LICENSE in the repository root for full details.
//
import Compound
import SwiftUI
struct KnockRequestsListScreen: View {
@ObservedObject var context: KnockRequestsListScreenViewModel.Context
var body: some View {
mainContent
.navigationBarTitleDisplayMode(.inline)
.navigationTitle(L10n.screenKnockRequestsListTitle)
.background(.compound.bgCanvasDefault)
.overlay {
if context.viewState.requests.isEmpty {
KnockRequestsListEmptyStateView()
}
}
.safeAreaInset(edge: .bottom) {
if !context.viewState.requests.isEmpty {
acceptAllButton
}
}
}
@ViewBuilder
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)
})
}
}
.padding(.top, 40)
}
}
private var acceptAllButton: some View {
Button(L10n.screenKnockRequestsListAcceptAllButtonTitle) {
context.send(viewAction: .acceptAllRequests)
}
.buttonStyle(.compound(.secondary))
.padding(.horizontal, 16)
.padding(.top, 16)
.padding(.bottom, 4)
.background(.compound.bgCanvasDefault)
}
private func onAccept(userID: String) {
context.send(viewAction: .acceptRequest(userID: userID))
}
private func onDecline(userID: String) {
context.send(viewAction: .declineRequest(userID: userID))
}
private func onDeclineAndBan(userID: String) {
context.send(viewAction: .ban(userID: userID))
}
}
// MARK: - Previews
struct KnockRequestsListScreen_Previews: PreviewProvider, TestablePreview {
static let emptyViewModel = KnockRequestsListScreenViewModel.mockWithInitialState(.init())
static let viewModel = KnockRequestsListScreenViewModel.mockWithInitialState(.init(requests: [.init(id: "@alice:matrix.org", displayName: "Alice", avatarUrl: nil, timestamp: "Now", reason: "Hello"),
// 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))
static var previews: some View {
NavigationStack {
KnockRequestsListScreen(context: viewModel.context)
}
NavigationStack {
KnockRequestsListScreen(context: emptyViewModel.context)
}
.previewDisplayName("Empty state")
}
}