mirror of
https://github.com/mastodon/mastodon-ios.git
synced 2025-01-27 15:49:44 +01:00
feat(Widget): Implement basic version of FollowersWidgetExtensionEntryView
This commit is contained in:
parent
5a3636cb22
commit
6a0bd94bf4
@ -3,43 +3,73 @@
|
|||||||
import WidgetKit
|
import WidgetKit
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import Intents
|
import Intents
|
||||||
|
import MastodonSDK
|
||||||
|
|
||||||
struct FollowersProvider: IntentTimelineProvider {
|
struct FollowersProvider: IntentTimelineProvider {
|
||||||
func placeholder(in context: Context) -> FollowersEntry {
|
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) -> ()) {
|
func getSnapshot(for configuration: FollowersCountIntent, in context: Context, completion: @escaping (FollowersEntry) -> ()) {
|
||||||
let entry = FollowersEntry(date: Date(), configuration: configuration)
|
loadCurrentEntry(for: configuration, in: context, completion: completion)
|
||||||
completion(entry)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTimeline(for configuration: FollowersCountIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
|
func getTimeline(for configuration: FollowersCountIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
|
||||||
var entries: [FollowersEntry] = []
|
loadCurrentEntry(for: configuration, in: context) { entry in
|
||||||
|
completion(Timeline(entries: [entry], policy: .after(.now)))
|
||||||
// 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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let timeline = Timeline(entries: entries, policy: .atEnd)
|
|
||||||
completion(timeline)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FollowersEntry: TimelineEntry {
|
struct FollowersEntry: TimelineEntry {
|
||||||
let date: Date
|
let date: Date
|
||||||
|
let account: Mastodon.Entity.Account?
|
||||||
|
let avatarImage: UIImage?
|
||||||
let configuration: FollowersCountIntent
|
let configuration: FollowersCountIntent
|
||||||
|
|
||||||
|
static func empty(with configuration: FollowersCountIntent) -> Self {
|
||||||
|
FollowersEntry(date: .now, account: nil, avatarImage: nil, configuration: configuration)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FollowersWidgetExtensionEntryView : View {
|
struct FollowersWidgetExtensionEntryView : View {
|
||||||
var entry: FollowersProvider.Entry
|
var entry: FollowersProvider.Entry
|
||||||
|
|
||||||
var body: some View {
|
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 {
|
struct WidgetExtension_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
FollowersWidgetExtensionEntryView(entry: FollowersEntry(date: Date(), configuration: FollowersCountIntent()))
|
FollowersWidgetExtensionEntryView(entry: FollowersEntry(
|
||||||
.previewContext(WidgetPreviewContext(family: .systemSmall))
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user