Show user statuses in mention suggestions.

This commit is contained in:
Doug
2026-07-10 13:16:03 +01:00
committed by Doug
parent 6199ab596f
commit e80717f63d
4 changed files with 91 additions and 18 deletions
@@ -87,7 +87,8 @@ final class CompletionSuggestionService: CompletionSuggestionServiceProtocol {
Self.shouldIncludeMember(userID: member.userID, displayName: member.displayName, searchText: suggestionTrigger.text) else {
return nil
}
return .init(suggestionType: .user(.init(id: member.userID, displayName: member.displayName, avatarURL: member.avatarURL)), range: suggestionTrigger.range, rawSuggestionText: suggestionTrigger.text)
return .init(suggestionType: .user(.init(id: member.userID, displayName: member.displayName, avatarURL: member.avatarURL, status: member.status)),
range: suggestionTrigger.range, rawSuggestionText: suggestionTrigger.text)
}
if canMentionAllUsers,
@@ -32,6 +32,7 @@ struct SuggestionItem: Identifiable, Equatable {
let id: String
let displayName: String?
let avatarURL: URL?
var status = UserStatus()
}
struct Room: Equatable {
@@ -59,22 +60,31 @@ struct SuggestionItem: Identifiable, Equatable {
var displayName: String {
switch suggestionType {
case .allUsers:
return PillUtilities.everyone
PillUtilities.everyone
case .user(let user):
return user.displayName ?? user.id
user.displayName ?? user.id
case .room(let room):
return room.name
room.name
}
}
var statusEmoji: Character? {
switch suggestionType {
case .user(let user):
user.status.displayed?.emoji
case .allUsers, .room:
nil
}
}
var subtitle: String? {
switch suggestionType {
case .allUsers:
return PillUtilities.atRoom
PillUtilities.atRoom
case .user(let user):
return user.displayName == nil ? nil : user.id
user.displayName == nil ? nil : user.id
case .room(let room):
return room.canonicalAlias
room.canonicalAlias
}
}
}
@@ -110,8 +110,19 @@ struct CompletionSuggestion_Previews: PreviewProvider, TestablePreview {
// Putting them is VStack allows the preview to work properly in tests
VStack(spacing: 8) {
CompletionSuggestionView(mediaProvider: MediaProviderMock(.init()),
items: [.init(suggestionType: .user(.init(id: "@user_mention_1:matrix.org", displayName: "User 1", avatarURL: nil)), range: .init(), rawSuggestionText: ""),
.init(suggestionType: .user(.init(id: "@user_mention_2:matrix.org", displayName: "User 2", avatarURL: .mockMXCUserAvatar)), range: .init(), rawSuggestionText: "")]) { _ in }
items: [
.init(suggestionType: .user(.init(id: "@user_mention_1:matrix.org",
displayName: "User 1",
avatarURL: nil)),
range: .init(),
rawSuggestionText: ""),
.init(suggestionType: .user(.init(id: "@user_mention_2:matrix.org",
displayName: "User 2",
avatarURL: .mockMXCUserAvatar,
status: .mockCall)),
range: .init(),
rawSuggestionText: "")
]) { _ in }
}
VStack(spacing: 8) {
@@ -6,6 +6,7 @@
// Please see LICENSE files in the repository root for full details.
//
import Compound
import SwiftUI
struct MentionSuggestionItemView: View {
@@ -13,19 +14,29 @@ struct MentionSuggestionItemView: View {
let item: SuggestionItem
var body: some View {
HStack(alignment: .center, spacing: 16) {
HStack(alignment: .center, spacing: 12) {
avatar
.accessibilityHidden(true)
VStack(alignment: .leading, spacing: 0) {
Text(item.displayName)
.font(.compound.bodyLG)
.foregroundColor(.compound.textPrimary)
.lineLimit(1)
HStack(spacing: 2) {
Text(item.displayName)
.lineLimit(1)
.padding(.vertical, 1) // Compensation for Figma line height.
if let statusEmoji = item.statusEmoji {
Text(String(statusEmoji))
}
}
.font(.compound.bodyLG)
.foregroundStyle(.compound.textPrimary)
if let subtitle = item.subtitle {
Text(subtitle)
.font(.compound.bodySM)
.foregroundColor(.compound.textSecondary)
.foregroundStyle(.compound.textSecondary)
.lineLimit(1)
.padding(.vertical, 1) // Compensation for Figma line height.
}
}
}
@@ -49,12 +60,52 @@ struct MentionSuggestionItemView_Previews: PreviewProvider, TestablePreview {
static let mockMediaProvider = MediaProviderMock(.init())
static var previews: some View {
MentionSuggestionItemView(mediaProvider: mockMediaProvider, item: .init(suggestionType: .user(.init(id: "test", displayName: "Test", avatarURL: .mockMXCUserAvatar)), range: .init(), rawSuggestionText: ""))
MentionSuggestionItemView(mediaProvider: mockMediaProvider,
item: .init(suggestionType: .user(.init(id: "test", displayName: "Test", avatarURL: .mockMXCUserAvatar)),
range: .init(),
rawSuggestionText: ""))
.previewDisplayName("User")
MentionSuggestionItemView(mediaProvider: mockMediaProvider, item: .init(suggestionType: .user(.init(id: "test2", displayName: nil, avatarURL: nil)), range: .init(), rawSuggestionText: ""))
VStack(alignment: .leading, spacing: 8) {
MentionSuggestionItemView(mediaProvider: mockMediaProvider,
item: .init(suggestionType: .user(.init(id: "@john.smith:example.com",
displayName: "John Smith",
avatarURL: nil,
status: .mockHoliday)),
range: .init(),
rawSuggestionText: ""))
MentionSuggestionItemView(mediaProvider: mockMediaProvider,
item: .init(suggestionType: .user(.init(id: "@alice.liddel:example.com",
displayName: "Alice Liddell",
avatarURL: nil,
status: .mockCall)),
range: .init(),
rawSuggestionText: ""))
MentionSuggestionItemView(mediaProvider: mockMediaProvider,
item: .init(suggestionType: .user(.init(id: "@long.name:example.com",
displayName: "I have a long name that doesn't fit on one line",
avatarURL: nil,
status: .mock(text: "Travelling", emoji: "🚆"))),
range: .init(),
rawSuggestionText: ""))
}
.padding(16)
.previewDisplayName("User with status")
MentionSuggestionItemView(mediaProvider: mockMediaProvider,
item: .init(suggestionType: .user(.init(id: "test2", displayName: nil, avatarURL: nil)),
range: .init(),
rawSuggestionText: ""))
.previewDisplayName("User no display name")
MentionSuggestionItemView(mediaProvider: mockMediaProvider, item: .init(suggestionType: .allUsers(.room(id: "room", name: "Room", avatarURL: .mockMXCAvatar)), range: .init(), rawSuggestionText: ""))
MentionSuggestionItemView(mediaProvider: mockMediaProvider,
item: .init(suggestionType: .allUsers(.room(id: "room", name: "Room", avatarURL: .mockMXCAvatar)),
range: .init(),
rawSuggestionText: ""))
.previewDisplayName("All users")
MentionSuggestionItemView(mediaProvider: mockMediaProvider,
item: .init(suggestionType: .room(.init(id: "room",
canonicalAlias: "#room:matrix.org",