feat(Widget): Implement basic version of FollowersWidgetExtensionEntryView

This commit is contained in:
Marcus Kida 2023-01-24 12:47:48 +01:00
parent 5a3636cb22
commit 6a0bd94bf4
No known key found for this signature in database
GPG Key ID: 19FF64E08013CA40
1 changed files with 94 additions and 17 deletions

View File

@ -3,43 +3,73 @@
import WidgetKit
import SwiftUI
import Intents
import MastodonSDK
struct FollowersProvider: IntentTimelineProvider {
func placeholder(in context: Context) -> FollowersEntry {
FollowersEntry(date: Date(), configuration: FollowersCountIntent())
.empty(with: FollowersCountIntent())
}
func getSnapshot(for configuration: FollowersCountIntent, in context: Context, completion: @escaping (FollowersEntry) -> ()) {
let entry = FollowersEntry(date: Date(), configuration: configuration)
completion(entry)
loadCurrentEntry(for: configuration, in: context, completion: completion)
}
func getTimeline(for configuration: FollowersCountIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
var entries: [FollowersEntry] = []
// Generate a timeline consisting of five entries an hour apart, starting from the current date.
let currentDate = Date()
for hourOffset in 0 ..< 5 {
let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
let entry = FollowersEntry(date: entryDate, configuration: configuration)
entries.append(entry)
loadCurrentEntry(for: configuration, in: context) { entry in
completion(Timeline(entries: [entry], policy: .after(.now)))
}
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
}
struct FollowersEntry: TimelineEntry {
let date: Date
let account: Mastodon.Entity.Account?
let avatarImage: UIImage?
let configuration: FollowersCountIntent
static func empty(with configuration: FollowersCountIntent) -> Self {
FollowersEntry(date: .now, account: nil, avatarImage: nil, configuration: configuration)
}
}
struct FollowersWidgetExtensionEntryView : View {
var entry: FollowersProvider.Entry
var body: some View {
Text(entry.date, style: .time)
if let account = entry.account {
HStack {
VStack(alignment: .leading, spacing: 0) {
if let avatarImage = entry.avatarImage {
Image(uiImage: avatarImage)
.resizable()
.frame(width: 50, height: 50)
.cornerRadius(12)
.padding(.bottom, 8)
}
Text(account.followersCount.asAbbreviatedCountString())
.font(.largeTitle)
.lineLimit(1)
.truncationMode(.tail)
Text("\(account.displayNameWithFallback)")
.font(.system(size: 13))
.lineLimit(1)
.truncationMode(.tail)
Text("@\(account.acct)")
.font(.caption2)
.foregroundColor(.secondary)
.lineLimit(1)
.truncationMode(.tail)
}
.padding(.leading, 20)
.padding([.top, .bottom], 16)
Spacer()
}
} else {
Text("Please use the Widget settings to select an Account.")
}
}
}
@ -55,7 +85,54 @@ struct FollowersWidgetExtension: Widget {
struct WidgetExtension_Previews: PreviewProvider {
static var previews: some View {
FollowersWidgetExtensionEntryView(entry: FollowersEntry(date: Date(), configuration: FollowersCountIntent()))
.previewContext(WidgetPreviewContext(family: .systemSmall))
FollowersWidgetExtensionEntryView(entry: FollowersEntry(
date: Date(),
account: nil,
avatarImage: nil,
configuration: FollowersCountIntent())
)
.previewContext(WidgetPreviewContext(family: .systemSmall))
}
}
private extension FollowersProvider {
func loadCurrentEntry(for configuration: FollowersCountIntent, in context: Context, completion: @escaping (FollowersEntry) -> Void) {
Task {
guard
let authBox = WidgetExtension.appContext
.authenticationService
.mastodonAuthenticationBoxes
.first,
let account = configuration.account
else {
return completion(.empty(with: configuration))
}
let resultingAccount = try await WidgetExtension.appContext
.apiService
.search(query: .init(q: account, type: .accounts), authenticationBox: authBox)
.value
.accounts
.first
let image: UIImage? = try await {
guard
let account = resultingAccount
else {
return nil
}
let imageData = try await URLSession.shared.data(from: account.avatarImageURLWithFallback(domain: authBox.domain)).0
return UIImage(data: imageData)
}()
let entry = FollowersEntry(
date: Date(),
account: resultingAccount,
avatarImage: image,
configuration: configuration
)
completion(entry)
}
}
}