mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 21:33:26 +00:00
Show user statuses in mention suggestions.
This commit is contained in:
+2
-1
@@ -87,7 +87,8 @@ final class CompletionSuggestionService: CompletionSuggestionServiceProtocol {
|
|||||||
Self.shouldIncludeMember(userID: member.userID, displayName: member.displayName, searchText: suggestionTrigger.text) else {
|
Self.shouldIncludeMember(userID: member.userID, displayName: member.displayName, searchText: suggestionTrigger.text) else {
|
||||||
return nil
|
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,
|
if canMentionAllUsers,
|
||||||
|
|||||||
+16
-6
@@ -32,6 +32,7 @@ struct SuggestionItem: Identifiable, Equatable {
|
|||||||
let id: String
|
let id: String
|
||||||
let displayName: String?
|
let displayName: String?
|
||||||
let avatarURL: URL?
|
let avatarURL: URL?
|
||||||
|
var status = UserStatus()
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Room: Equatable {
|
struct Room: Equatable {
|
||||||
@@ -59,22 +60,31 @@ struct SuggestionItem: Identifiable, Equatable {
|
|||||||
var displayName: String {
|
var displayName: String {
|
||||||
switch suggestionType {
|
switch suggestionType {
|
||||||
case .allUsers:
|
case .allUsers:
|
||||||
return PillUtilities.everyone
|
PillUtilities.everyone
|
||||||
case .user(let user):
|
case .user(let user):
|
||||||
return user.displayName ?? user.id
|
user.displayName ?? user.id
|
||||||
case .room(let room):
|
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? {
|
var subtitle: String? {
|
||||||
switch suggestionType {
|
switch suggestionType {
|
||||||
case .allUsers:
|
case .allUsers:
|
||||||
return PillUtilities.atRoom
|
PillUtilities.atRoom
|
||||||
case .user(let user):
|
case .user(let user):
|
||||||
return user.displayName == nil ? nil : user.id
|
user.displayName == nil ? nil : user.id
|
||||||
case .room(let room):
|
case .room(let room):
|
||||||
return room.canonicalAlias
|
room.canonicalAlias
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-2
@@ -110,8 +110,19 @@ struct CompletionSuggestion_Previews: PreviewProvider, TestablePreview {
|
|||||||
// Putting them is VStack allows the preview to work properly in tests
|
// Putting them is VStack allows the preview to work properly in tests
|
||||||
VStack(spacing: 8) {
|
VStack(spacing: 8) {
|
||||||
CompletionSuggestionView(mediaProvider: MediaProviderMock(.init()),
|
CompletionSuggestionView(mediaProvider: MediaProviderMock(.init()),
|
||||||
items: [.init(suggestionType: .user(.init(id: "@user_mention_1:matrix.org", displayName: "User 1", avatarURL: nil)), range: .init(), rawSuggestionText: ""),
|
items: [
|
||||||
.init(suggestionType: .user(.init(id: "@user_mention_2:matrix.org", displayName: "User 2", avatarURL: .mockMXCUserAvatar)), range: .init(), rawSuggestionText: "")]) { _ in }
|
.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) {
|
VStack(spacing: 8) {
|
||||||
|
|||||||
+60
-9
@@ -6,6 +6,7 @@
|
|||||||
// Please see LICENSE files in the repository root for full details.
|
// Please see LICENSE files in the repository root for full details.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
import Compound
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct MentionSuggestionItemView: View {
|
struct MentionSuggestionItemView: View {
|
||||||
@@ -13,19 +14,29 @@ struct MentionSuggestionItemView: View {
|
|||||||
let item: SuggestionItem
|
let item: SuggestionItem
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(alignment: .center, spacing: 16) {
|
HStack(alignment: .center, spacing: 12) {
|
||||||
avatar
|
avatar
|
||||||
.accessibilityHidden(true)
|
.accessibilityHidden(true)
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
Text(item.displayName)
|
HStack(spacing: 2) {
|
||||||
.font(.compound.bodyLG)
|
Text(item.displayName)
|
||||||
.foregroundColor(.compound.textPrimary)
|
.lineLimit(1)
|
||||||
.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 {
|
if let subtitle = item.subtitle {
|
||||||
Text(subtitle)
|
Text(subtitle)
|
||||||
.font(.compound.bodySM)
|
.font(.compound.bodySM)
|
||||||
.foregroundColor(.compound.textSecondary)
|
.foregroundStyle(.compound.textSecondary)
|
||||||
.lineLimit(1)
|
.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 let mockMediaProvider = MediaProviderMock(.init())
|
||||||
|
|
||||||
static var previews: some View {
|
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")
|
.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")
|
.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")
|
.previewDisplayName("All users")
|
||||||
|
|
||||||
MentionSuggestionItemView(mediaProvider: mockMediaProvider,
|
MentionSuggestionItemView(mediaProvider: mockMediaProvider,
|
||||||
item: .init(suggestionType: .room(.init(id: "room",
|
item: .init(suggestionType: .room(.init(id: "room",
|
||||||
canonicalAlias: "#room:matrix.org",
|
canonicalAlias: "#room:matrix.org",
|
||||||
|
|||||||
Reference in New Issue
Block a user