Files
andros a54853d3d1 Simplify timeline filter: hide every body-less post
The previous rule kept migration posts visible via their :MIGRATION:
badge. Dropping that exception — a body-less post of any kind is now
hidden everywhere (timeline, profile, mergeOwnFeed). Consequence:
migration announcements no longer surface in the timeline; the user
accepted this trade-off for a simpler, single-rule filter.
2026-04-24 10:54:57 +02:00

96 lines
3.3 KiB
Swift

import Foundation
public struct OrgSocialPost: Sendable, Equatable {
/// RFC 3339 timestamp, unique identifier for the post.
public var timestamp: String
/// Parsed date from `timestamp`.
public var date: Date
/// Body text of the post (Org Mode syntax preserved, comment and property lines stripped).
public var text: String
/// ISO 639-1 language code.
public var lang: String?
/// Space-separated tags parsed into individual strings.
public var tags: [String]
/// Client that created the post.
public let client: String?
/// URL#timestamp of the post being replied to.
public let replyTo: String?
/// URL#timestamp of the post being boosted/reshared.
public let include: String?
/// Poll close date.
public let pollEnd: Date?
/// Selected option when this post is a poll vote.
public let pollOption: String?
/// "Group Name relay-url" when posted to a group.
public let group: String?
/// Mood/reaction emoji.
public var mood: String?
/// "old-url new-url" for account migration posts.
public let migration: String?
/// `"public"` or `"mention"`. `nil` defaults to public.
public var visibility: String?
// Populated during timeline assembly, not by the parser.
public var authorNick: String?
public var authorURL: URL?
public var authorAvatar: URL?
public var feedURL: URL?
/// Stable unique ID combining feed URL and timestamp safe for ForEach in merged timelines.
public var stableID: String {
"\(feedURL?.absoluteString ?? "unknown")#\(timestamp)"
}
/// Whether this post has nothing to render as a standalone timeline row
/// i.e. its body is empty. Covers every protocol artefact (pure reaction,
/// pure boost, poll vote, migration announcement) plus the accidental
/// empty post. Quote-boosts, text posts and polls all carry a body and
/// are NOT flagged.
///
/// Used by timeline and profile views to hide these rows so the original
/// content they reference is shown only in its authoritative location.
public var isPureInteraction: Bool {
text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
}
public init(
timestamp: String,
date: Date,
text: String,
lang: String? = nil,
tags: [String] = [],
client: String? = nil,
replyTo: String? = nil,
include: String? = nil,
pollEnd: Date? = nil,
pollOption: String? = nil,
group: String? = nil,
mood: String? = nil,
migration: String? = nil,
visibility: String? = nil,
authorNick: String? = nil,
authorURL: URL? = nil,
authorAvatar: URL? = nil,
feedURL: URL? = nil
) {
self.timestamp = timestamp
self.date = date
self.text = text
self.lang = lang
self.tags = tags
self.client = client
self.replyTo = replyTo
self.include = include
self.pollEnd = pollEnd
self.pollOption = pollOption
self.group = group
self.mood = mood
self.migration = migration
self.visibility = visibility
self.authorNick = authorNick
self.authorURL = authorURL
self.authorAvatar = authorAvatar
self.feedURL = feedURL
}
}