Invites list (#787)

* Setup invites SS window

* Add invites label in the home screen

* Add empty invtes list

* Setup navigation to invites list

* Inject invitesSummaryProvider

* Show invites

* Add InviteCell

* Refine InviteCell UI

* Push invites

* Amend SS configuration

* Add inviter in RoomProxyProtocol

* Add Invite model type

* Improve InviteCell

* Fix media provider injection

* Refine InviteCell

* Refine invite cell

* Add invites feature flag

* Try different SS config for invites

* Regiester invites view in configureViewsPostInitialSync

* Cleanup

* Start tests

* Cleanup code

* Add changelog.d file

* Add tests

* Handle canonical alias

* Add InvitesListScreen previews

* Add localisations and improve UI tests

* Add reference screenshots

* Cleanup code

* Fix UT build errors

* Refactor InvitesList -> Invites

* Apply pr comments

* Remove reduntant @MainActor

* Naming cleanup

* Fix InvitesScreenCell.title

* Add accept/decline InvitesViewAction

* Revert Package.resolved

* Add warning in InvitesScreenCell

* Improve PlaceholderAvatarImage

* Record snapshots again

* Refactor Invite -> InvitesRoomDeatils

* Rename identifier in PlaceholderAvatarImage
This commit is contained in:
Alfonso Grillo
2023-04-14 12:49:57 +02:00
committed by GitHub
parent 69e696afca
commit 41994baa4f
44 changed files with 910 additions and 35 deletions
@@ -338,6 +338,16 @@ class RoomProxy: RoomProxyProtocol {
}
}
func inviter() async -> RoomMemberProxyProtocol? {
let inviter = await Task.dispatch(on: .global()) {
self.room.inviter()
}
return inviter.map {
RoomMemberProxy(member: $0, backgroundTaskService: self.backgroundTaskService)
}
}
// MARK: - Private
/// Force the timeline to load member details so it can populate sender profiles whenever we add a timeline listener
@@ -88,6 +88,8 @@ protocol RoomProxyProtocol {
func leaveRoom() async -> Result<Void, RoomProxyError>
func updateMembers() async
func inviter() async -> RoomMemberProxyProtocol?
}
extension RoomProxyProtocol {
@@ -19,7 +19,7 @@ import Foundation
enum MockRoomSummaryProviderState {
case loading
case loaded
case loaded([RoomSummary])
}
class MockRoomSummaryProvider: RoomSummaryProviderProtocol {
@@ -37,38 +37,59 @@ class MockRoomSummaryProvider: RoomSummaryProviderProtocol {
roomListPublisher = .init([])
statePublisher = .init(.notLoaded)
countPublisher = .init(0)
case .loaded:
roomListPublisher = .init(Self.rooms)
case .loaded(let rooms):
roomListPublisher = .init(rooms)
statePublisher = .init(.fullyLoaded)
countPublisher = .init(UInt(Self.rooms.count))
countPublisher = .init(UInt(rooms.count))
}
}
func updateVisibleRange(_ range: Range<Int>, timelineLimit: UInt) { }
// MARK: - Private
static let rooms: [RoomSummary] = [
}
extension Array where Element == RoomSummary {
static let mockRooms: [Element] = [
.filled(details: RoomSummaryDetails(id: "1", name: "First room",
isDirect: true,
avatarURL: nil,
lastMessage: AttributedString("Prosciutto beef ribs pancetta filet mignon kevin hamburger, chuck ham venison picanha. Beef ribs chislic turkey biltong tenderloin."),
lastMessageFormattedTimestamp: "Now",
unreadNotificationCount: 4)),
unreadNotificationCount: 4,
canonicalAlias: nil)),
.filled(details: RoomSummaryDetails(id: "2",
name: "Second room",
isDirect: true,
avatarURL: URL.picturesDirectory,
lastMessage: nil,
lastMessageFormattedTimestamp: nil,
unreadNotificationCount: 1)),
unreadNotificationCount: 1,
canonicalAlias: nil)),
.filled(details: RoomSummaryDetails(id: "3",
name: "Third room",
isDirect: true,
avatarURL: nil,
lastMessage: try? AttributedString(markdown: "**@mock:client.com**: T-bone beef ribs bacon"),
lastMessageFormattedTimestamp: "Later",
unreadNotificationCount: 0)),
unreadNotificationCount: 0,
canonicalAlias: nil)),
.empty
]
static let mockInvites: [Element] = [
.filled(details: RoomSummaryDetails(id: "someAwesomeRoomId1", name: "First room",
isDirect: false,
avatarURL: URL.picturesDirectory,
lastMessage: nil,
lastMessageFormattedTimestamp: nil,
unreadNotificationCount: 0,
canonicalAlias: "#footest:somewhere.org")),
.filled(details: RoomSummaryDetails(id: "someAwesomeRoomId2",
name: "Second room",
isDirect: true,
avatarURL: nil,
lastMessage: nil,
lastMessageFormattedTimestamp: nil,
unreadNotificationCount: 0,
canonicalAlias: nil))
]
}
@@ -24,6 +24,7 @@ struct RoomSummaryDetails {
let lastMessage: AttributedString?
let lastMessageFormattedTimestamp: String?
let unreadNotificationCount: UInt
let canonicalAlias: String?
}
extension RoomSummaryDetails: CustomStringConvertible {
@@ -111,7 +111,9 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
}
}
let avatarURL = room.fullRoom()?.avatarUrl().flatMap(URL.init(string:))
let fullRoom = room.fullRoom()
let avatarURL = fullRoom?.avatarUrl().flatMap(URL.init(string:))
let canonicalAlias = fullRoom?.canonicalAlias()
let details = RoomSummaryDetails(id: room.roomId(),
name: room.name() ?? room.roomId(),
@@ -119,7 +121,8 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
avatarURL: avatarURL,
lastMessage: attributedLastMessage,
lastMessageFormattedTimestamp: lastMessageFormattedTimestamp,
unreadNotificationCount: UInt(room.unreadNotifications().notificationCount()))
unreadNotificationCount: UInt(room.unreadNotifications().notificationCount()),
canonicalAlias: canonicalAlias)
return invalidated ? .invalidated(details: details) : .filled(details: details)
}