175 lines
5.9 KiB
Swift
175 lines
5.9 KiB
Swift
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
|
|
|
|
import WidgetKit
|
|
import SwiftUI
|
|
import MastodonSDK
|
|
import MastodonLocalization
|
|
import MastodonCore
|
|
|
|
struct HashtagWidgetProvider: IntentTimelineProvider {
|
|
func placeholder(in context: Context) -> HashtagWidgetTimelineEntry {
|
|
.placeholder
|
|
}
|
|
|
|
func getSnapshot(for configuration: HashtagIntent, in context: Context, completion: @escaping (HashtagWidgetTimelineEntry) -> Void) {
|
|
loadMostRecentHashtag(for: configuration, in: context, completion: completion)
|
|
}
|
|
|
|
func getTimeline(for configuration: HashtagIntent, in context: Context, completion: @escaping (Timeline<HashtagWidgetTimelineEntry>) -> Void) {
|
|
loadMostRecentHashtag(for: configuration, in: context) { entry in
|
|
completion(Timeline(entries: [entry], policy: .after(.now.addingTimeInterval(60 * 15))))
|
|
}
|
|
}
|
|
}
|
|
|
|
extension HashtagWidgetProvider {
|
|
func loadMostRecentHashtag(for configuration: HashtagIntent, in context: Context, completion: @escaping (HashtagWidgetTimelineEntry) -> Void ) {
|
|
|
|
AuthenticationServiceProvider.shared.restore()
|
|
|
|
guard
|
|
let authBox = WidgetExtension.appContext
|
|
.authenticationService
|
|
.mastodonAuthenticationBoxes
|
|
.first
|
|
else {
|
|
if context.isPreview {
|
|
return completion(.placeholder)
|
|
} else {
|
|
return completion(.unconfigured)
|
|
}
|
|
}
|
|
|
|
let desiredHashtag: String
|
|
|
|
if let hashtag = configuration.hashtag {
|
|
desiredHashtag = hashtag
|
|
} else {
|
|
return completion(.notFound("hashtag"))
|
|
}
|
|
|
|
Task {
|
|
|
|
do {
|
|
let mostRecentStatuses = try await WidgetExtension.appContext
|
|
.apiService
|
|
.hashtagTimeline(domain: authBox.domain, limit: 40, hashtag: desiredHashtag, authenticationBox: authBox)
|
|
.value
|
|
|
|
let filteredStatuses: [Mastodon.Entity.Status]
|
|
if configuration.ignoreContentWarnings?.boolValue == true {
|
|
filteredStatuses = mostRecentStatuses
|
|
} else {
|
|
filteredStatuses = mostRecentStatuses.filter { $0.sensitive == false }
|
|
}
|
|
|
|
if let mostRecentStatus = filteredStatuses.first {
|
|
|
|
let hashtagEntry = HashtagEntry(
|
|
accountName: mostRecentStatus.account.displayNameWithFallback,
|
|
account: mostRecentStatus.account.acct,
|
|
content: mostRecentStatus.content ?? "-",
|
|
reblogCount: mostRecentStatus.reblogsCount,
|
|
favoriteCount: mostRecentStatus.favouritesCount,
|
|
hashtag: "#\(desiredHashtag)",
|
|
timestamp: mostRecentStatus.createdAt
|
|
)
|
|
|
|
let hashtagTimelineEntry = HashtagWidgetTimelineEntry(
|
|
date: mostRecentStatus.createdAt,
|
|
hashtag: hashtagEntry
|
|
)
|
|
|
|
completion(hashtagTimelineEntry)
|
|
} else {
|
|
let noStatusFound = HashtagWidgetTimelineEntry.notFound(desiredHashtag)
|
|
|
|
completion(noStatusFound)
|
|
}
|
|
} catch {
|
|
completion(.notFound(desiredHashtag))
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
struct HashtagWidgetTimelineEntry: TimelineEntry {
|
|
var date: Date
|
|
var hashtag: HashtagEntry
|
|
|
|
static var placeholder: Self {
|
|
HashtagWidgetTimelineEntry(
|
|
date: .now,
|
|
hashtag: HashtagEntry(
|
|
accountName: L10n.Widget.Hashtag.Placeholder.accountName,
|
|
account: L10n.Widget.Hashtag.Placeholder.account,
|
|
content: L10n.Widget.Hashtag.Placeholder.content,
|
|
reblogCount: 13,
|
|
favoriteCount: 12,
|
|
hashtag: "#hashtag",
|
|
timestamp: .now.addingTimeInterval(-3600 * 12)
|
|
)
|
|
)
|
|
}
|
|
|
|
static func notFound(_ hashtag: String? = nil) -> Self {
|
|
HashtagWidgetTimelineEntry(
|
|
date: .now,
|
|
hashtag: HashtagEntry(
|
|
accountName: L10n.Widget.Hashtag.NotFound.accountName,
|
|
account: L10n.Widget.Hashtag.NotFound.account,
|
|
content: L10n.Widget.Hashtag.NotFound.content(hashtag ?? "hashtag"),
|
|
reblogCount: 0,
|
|
favoriteCount: 0,
|
|
hashtag: hashtag ?? "",
|
|
timestamp: .now
|
|
)
|
|
)
|
|
}
|
|
|
|
static var unconfigured: Self {
|
|
HashtagWidgetTimelineEntry(
|
|
date: .now,
|
|
hashtag: HashtagEntry(
|
|
accountName: "Unconfigured",
|
|
account: "@unconfigured@mastodon.social",
|
|
content: "Caturday is the best day of the week #CatsOfMastodon",
|
|
reblogCount: 14,
|
|
favoriteCount: 13,
|
|
hashtag: "#CatsOfMastodon",
|
|
timestamp: .now.addingTimeInterval(-3600 * 18)
|
|
)
|
|
)
|
|
}
|
|
}
|
|
|
|
struct HashtagWidget: Widget {
|
|
|
|
private var availableFamilies: [WidgetFamily] {
|
|
return [.systemMedium, .systemLarge, .accessoryRectangular]
|
|
}
|
|
|
|
var body: some WidgetConfiguration {
|
|
IntentConfiguration(kind: "Hashtag", intent: HashtagIntent.self, provider: HashtagWidgetProvider()) { entry in
|
|
HashtagWidgetView(entry: entry)
|
|
}
|
|
.configurationDisplayName(L10n.Widget.Hashtag.Configuration.displayName)
|
|
.description(L10n.Widget.Hashtag.Configuration.description)
|
|
.supportedFamilies(availableFamilies)
|
|
.contentMarginsDisabled() // Disable excessive margins (only effective for iOS >= 17.0
|
|
}
|
|
}
|
|
|
|
struct HashtagEntry {
|
|
var accountName: String
|
|
var account: String
|
|
var content: String
|
|
var reblogCount: Int
|
|
var favoriteCount: Int
|
|
var hashtag: String
|
|
var timestamp: Date
|
|
}
|