Custom emojis in display name

This commit is contained in:
Thomas Ricouard 2022-12-21 17:39:48 +01:00
parent ae9f78e737
commit c2a2fe1f86
11 changed files with 75 additions and 20 deletions

View file

@ -98,7 +98,7 @@ struct AccountDetailHeaderView: View {
accountAvatarView
HStack {
VStack(alignment: .leading, spacing: 0) {
Text(account.displayName)
account.displayNameWithEmojis
.font(.headline)
Text(account.acct)
.font(.callout)

View file

@ -25,6 +25,7 @@ public struct Account: Codable, Identifiable, Equatable, Hashable {
public let lastStatusAt: String?
public let fields: [Field]
public let locked: Bool
public let emojis: [Emoji]
public static func placeholder() -> Account {
.init(id: UUID().uuidString,
@ -40,6 +41,7 @@ public struct Account: Codable, Identifiable, Equatable, Hashable {
statusesCount: 10,
lastStatusAt: nil,
fields: [],
locked: false)
locked: false,
emojis: [])
}
}

View file

@ -16,9 +16,11 @@ extension HTMLString {
public var asSafeAttributedString: AttributedString {
do {
// Add space between hashtags that follow each other
let markdown = asMarkdown.replacingOccurrences(of: ")[#", with: ") [#")
let options = AttributedString.MarkdownParsingOptions(allowsExtendedAttributes: true,
interpretedSyntax: .inlineOnlyPreservingWhitespace)
return try AttributedString(markdown: asMarkdown, options: options)
return try AttributedString(markdown: markdown, options: options)
} catch {
return AttributedString(stringLiteral: self)
}

View file

@ -0,0 +1,17 @@
import Foundation
public struct Emoji: Codable, Hashable, Identifiable {
public func hash(into hasher: inout Hasher) {
hasher.combine(shortcode)
}
public var id: String {
shortcode
}
public let shortcode: String
public let url: URL
public let staticUrl: URL
public let visibleInPicker: Bool
}

View file

@ -0,0 +1,27 @@
import Foundation
import SwiftUI
extension Account {
public var displayNameWithEmojis: some View {
let splittedDisplayName = displayName.split(separator: ":")
return HStack(spacing: 0) {
ForEach(splittedDisplayName, id: \.self) { part in
if let emoji = emojis.first(where: { $0.shortcode == part }) {
AsyncImage(
url: emoji.url,
content: { image in
image.resizable()
.aspectRatio(contentMode: .fit)
.frame(maxWidth: 20, maxHeight: 20)
},
placeholder: {
ProgressView()
}
)
} else {
Text(part)
}
}
}
}
}

View file

@ -24,7 +24,7 @@ public struct Notification: Codable, Identifiable {
}
public static func placeholders() -> [Notification] {
[.placeholder(), .placeholder(), .placeholder(), .placeholder(), .placeholder()]
[.placeholder(), .placeholder(), .placeholder(), .placeholder(), .placeholder(), .placeholder(), .placeholder(), .placeholder()]
}
}

View file

@ -14,6 +14,7 @@ public protocol AnyStatus {
var favourited: Bool { get }
var reblogged: Bool { get }
var pinned: Bool? { get }
var emojis: [Emoji] { get }
}
public struct Status: AnyStatus, Codable, Identifiable {
@ -31,6 +32,7 @@ public struct Status: AnyStatus, Codable, Identifiable {
public let favourited: Bool
public let reblogged: Bool
public let pinned: Bool?
public let emojis: [Emoji]
public static func placeholder() -> Status {
.init(id: UUID().uuidString,
@ -46,7 +48,8 @@ public struct Status: AnyStatus, Codable, Identifiable {
card: nil,
favourited: false,
reblogged: false,
pinned: false)
pinned: false,
emojis: [])
}
public static func placeholders() -> [Status] {
@ -68,4 +71,5 @@ public struct ReblogStatus: AnyStatus, Codable, Identifiable {
public let favourited: Bool
public let reblogged: Bool
public let pinned: Bool?
public let emojis: [Emoji]
}

View file

@ -25,12 +25,12 @@ struct NotificationRowView: View {
.aspectRatio(contentMode: .fit)
.padding(.horizontal, 4)
if type.displayAccountName() {
Text(notification.account.displayName)
.font(.headline) +
notification.account.displayNameWithEmojis
.font(.subheadline)
Text(" ")
}
Text(type.label())
.font(.body)
.font(.subheadline)
Spacer()
}
if let status = notification.status {
@ -91,7 +91,7 @@ extension Models.Notification.NotificationType {
case .status:
return "pencil"
case .mention:
return "at"
return "at.circle.fill"
case .reblog:
return "arrow.left.arrow.right.circle.fill"
case .follow, .follow_request:

View file

@ -7,7 +7,6 @@ import DesignSystem
public struct NotificationsListView: View {
@EnvironmentObject private var client: Client
@StateObject private var viewModel = NotificationsViewModel()
@State private var didAppear: Bool = false
public init() { }
@ -25,15 +24,13 @@ public struct NotificationsListView: View {
.padding(.top, DS.Constants.layoutPadding)
}
.task {
if !didAppear {
didAppear = true
viewModel.client = client
await viewModel.fetchNotifications()
}
}
.refreshable {
Task {
await viewModel.fetchNotifications()
}
}
.navigationTitle(Text("Notifications"))
.navigationBarTitleDisplayMode(.inline)
}

View file

@ -22,7 +22,9 @@ class NotificationsViewModel: ObservableObject {
func fetchNotifications() async {
guard let client else { return }
do {
if notifications.isEmpty {
state = .loading
}
notifications = try await client.get(endpoint: Notifications.notifications(maxId: nil))
state = .display(notifications: notifications, nextPageState: .hasNextPage)
} catch {

View file

@ -31,11 +31,15 @@ public struct StatusRowView: View {
if viewModel.status.reblog != nil {
HStack(spacing: 2) {
Image(systemName:"arrow.left.arrow.right.circle")
Text("\(viewModel.status.account.displayName) reblogged")
viewModel.status.account.displayNameWithEmojis
Text("boosted")
}
.font(.footnote)
.foregroundColor(.gray)
.fontWeight(.semibold)
.onTapGesture {
routeurPath.navigate(to: .accountDetailWithAccount(account: viewModel.status.account))
}
}
}
@ -71,8 +75,8 @@ public struct StatusRowView: View {
@ViewBuilder
private func makeAccountView(status: AnyStatus) -> some View {
AvatarView(url: status.account.avatar)
VStack(alignment: .leading) {
Text(status.account.displayName)
VStack(alignment: .leading, spacing: 0) {
status.account.displayNameWithEmojis
.font(.subheadline)
.fontWeight(.semibold)
Group {