7e175465bd
Some Org Social clients (org-social.el and Mastodon-bridge clients)
write the :MOOD: value or a reaction emoji as a colon-wrapped
shortcode like 💓 instead of the Unicode glyph. Until now we
just printed the raw shortcode, which looked like a bug to users.
EmojiShortcode.resolve(_:) maps the most common reaction shortcodes to
Unicode and leaves anything unknown unchanged (so private/custom
shortcodes still display rather than vanishing). Applied to:
- the per-post reaction chip in PostRowView
- the "Reacted X" badge for pure-reaction posts
- the navigation title of ReactorsSheet
5 new tests pin known/unknown/inline/multiple/empty inputs.
57 lines
2.1 KiB
Swift
57 lines
2.1 KiB
Swift
import SwiftUI
|
|
import OrgSocialKit
|
|
|
|
/// `.sheet(item:)` requires `Identifiable`; the lib's `OrgSocialMood` isn't
|
|
/// (it doesn't need to be, the App/UI layer supplies the identity instead).
|
|
struct IdentifiedMood: Identifiable, Equatable {
|
|
let mood: OrgSocialMood
|
|
var id: String { mood.emoji }
|
|
}
|
|
|
|
/// Lists the feed URLs that reacted with a given emoji. The reactor post URL
|
|
/// shape is `https://host/social.org#<timestamp>`, so we derive both the
|
|
/// host (shown as the primary label) and the timestamp (shown as a tappable
|
|
/// link to the reaction post itself) with no extra network round-trips.
|
|
struct ReactorsSheet: View {
|
|
let mood: OrgSocialMood
|
|
@Environment(\.dismiss) private var dismiss
|
|
|
|
var body: some View {
|
|
NavigationStack {
|
|
List {
|
|
Section {
|
|
ForEach(mood.posts, id: \.self) { reactorPostURL in
|
|
reactorRow(reactorPostURL)
|
|
}
|
|
} header: {
|
|
Text("\(mood.posts.count) \(mood.posts.count == 1 ? "reaction" : "reactions")")
|
|
}
|
|
}
|
|
.listStyle(.plain)
|
|
.navigationTitle(Text(EmojiShortcode.resolve(mood.emoji)))
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
.toolbar {
|
|
ToolbarItem(placement: .cancellationAction) {
|
|
Button("Done") { dismiss() }
|
|
}
|
|
}
|
|
}
|
|
.presentationDetents([.medium, .large])
|
|
}
|
|
|
|
@ViewBuilder
|
|
private func reactorRow(_ reactorPostURL: String) -> some View {
|
|
let parts = reactorPostURL.split(separator: "#", maxSplits: 1, omittingEmptySubsequences: false)
|
|
let feedURLString = parts.first.map(String.init) ?? reactorPostURL
|
|
let host = URL(string: feedURLString)?.host ?? feedURLString
|
|
HStack(spacing: 10) {
|
|
Image(systemName: "person.circle.fill")
|
|
.foregroundStyle(.secondary)
|
|
VStack(alignment: .leading, spacing: 2) {
|
|
Text(host).font(.subheadline.weight(.medium))
|
|
Text(feedURLString).font(.caption).foregroundStyle(.secondary).lineLimit(1)
|
|
}
|
|
}
|
|
}
|
|
}
|