@room pill (#1834)

* all users mention pill + red higlight for own mentions

* more tests

* changelog

* removed useless if let
This commit is contained in:
Mauro
2023-09-29 15:40:31 +02:00
committed by GitHub
parent 1e842fd8cf
commit b7c46ceac3
19 changed files with 326 additions and 98 deletions
+28 -48
View File
@@ -19,92 +19,72 @@ import Foundation
@MainActor
final class PillContext: ObservableObject {
enum PillViewState {
case loading(contentID: String)
case loaded(contentID: String, name: String, avatarURL: URL?)
struct PillViewState: Equatable {
let contentID: String
let isOwnMention: Bool
let name: String?
let displayText: String
let avatarURL: URL?
}
@Published private var state: PillViewState
var url: URL? {
switch state {
case .loading:
return nil
case .loaded(_, _, let url):
return url
}
}
var name: String? {
switch state {
case .loading:
return nil
case .loaded(_, let name, _):
return name
}
}
var displayText: String {
switch state {
case .loaded(_, let name, _):
return name
case .loading(let contentID):
return contentID
}
}
var contentID: String {
switch state {
case .loaded(let contentID, _, _), .loading(let contentID):
return contentID
}
}
@Published private(set) var viewState: PillViewState
private var cancellable: AnyCancellable?
init(roomContext: RoomScreenViewModel.Context, data: PillTextAttachmentData) {
switch data.type {
case let .user(id):
let isOwnMention = id == roomContext.viewState.ownUserID
if let profile = roomContext.viewState.members[id] {
state = .loaded(contentID: id, name: profile.displayName ?? id, avatarURL: profile.avatarURL)
let name = profile.displayName ?? id
viewState = PillViewState(contentID: id, isOwnMention: isOwnMention, name: name, displayText: name, avatarURL: profile.avatarURL)
} else {
state = .loading(contentID: id)
viewState = PillViewState(contentID: id, isOwnMention: isOwnMention, name: nil, displayText: id, avatarURL: nil)
cancellable = roomContext.$viewState.sink { [weak self] viewState in
guard let self else {
return
}
if let profile = viewState.members[id] {
state = .loaded(contentID: id, name: profile.displayName ?? id, avatarURL: profile.avatarURL)
let name = profile.displayName ?? id
self.viewState = PillViewState(contentID: id, isOwnMention: isOwnMention, name: name, displayText: name, avatarURL: profile.avatarURL)
cancellable = nil
}
}
}
case .allUsers:
viewState = PillViewState(contentID: roomContext.viewState.roomID, isOwnMention: true, name: roomContext.viewState.roomTitle, displayText: "@room", avatarURL: roomContext.viewState.roomAvatarURL)
}
}
}
extension PillContext {
enum MockType {
case loadUser
case loadedUser
case loadUser(isOwn: Bool)
case loadedUser(isOwn: Bool)
case allUsers
}
static func mock(type: MockType) -> PillContext {
let testID = "@test:test.com"
let pillType: PillType
switch type {
case .loadUser:
pillType = .user(userID: "@test:test.com")
case .loadUser(let isOwn):
pillType = .user(userID: testID)
let viewModel = PillContext(roomContext: RoomScreenViewModel.mock.context, data: PillTextAttachmentData(type: pillType, font: .preferredFont(forTextStyle: .body)))
viewModel.viewState = PillViewState(contentID: testID, isOwnMention: isOwn, name: nil, displayText: testID, avatarURL: nil)
Task {
try? await Task.sleep(for: .seconds(2))
viewModel.state = .loaded(contentID: "@test:test.com", name: "Test Longer Display Text", avatarURL: URL.documentsDirectory)
viewModel.viewState = PillViewState(contentID: "@test:test.com", isOwnMention: isOwn, name: nil, displayText: "Test Long Display Text", avatarURL: URL.documentsDirectory)
}
return viewModel
case .loadedUser:
case .loadedUser(let isOwn):
pillType = .user(userID: "@test:test.com")
let viewModel = PillContext(roomContext: RoomScreenViewModel.mock.context, data: PillTextAttachmentData(type: pillType, font: .preferredFont(forTextStyle: .body)))
viewModel.state = .loaded(contentID: "@test:test.com", name: "Very Very Long Test Display Text", avatarURL: URL.documentsDirectory)
viewModel.viewState = PillViewState(contentID: "@test:test.com", isOwnMention: isOwn, name: nil, displayText: "Very Very Long Test Display Text", avatarURL: URL.documentsDirectory)
return viewModel
case .allUsers:
pillType = .allUsers
return PillContext(roomContext: RoomScreenViewModel.mock.context, data: PillTextAttachmentData(type: pillType, font: .preferredFont(forTextStyle: .body)))
}
}
}