feat(Widget): Improve FollowerCount Widget placeholder/preview

This commit is contained in:
Marcus Kida 2023-01-24 15:23:25 +01:00
parent 6a0bd94bf4
commit 0d69e5ea4d
No known key found for this signature in database
GPG Key ID: 19FF64E08013CA40
3 changed files with 72 additions and 23 deletions

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "missing.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -7,10 +7,13 @@ import MastodonSDK
struct FollowersProvider: IntentTimelineProvider { struct FollowersProvider: IntentTimelineProvider {
func placeholder(in context: Context) -> FollowersEntry { func placeholder(in context: Context) -> FollowersEntry {
.empty(with: FollowersCountIntent()) .placeholder
} }
func getSnapshot(for configuration: FollowersCountIntent, in context: Context, completion: @escaping (FollowersEntry) -> ()) { func getSnapshot(for configuration: FollowersCountIntent, in context: Context, completion: @escaping (FollowersEntry) -> ()) {
guard !context.isPreview else {
return completion(.placeholder)
}
loadCurrentEntry(for: configuration, in: context, completion: completion) loadCurrentEntry(for: configuration, in: context, completion: completion)
} }
@ -23,12 +26,28 @@ struct FollowersProvider: IntentTimelineProvider {
struct FollowersEntry: TimelineEntry { struct FollowersEntry: TimelineEntry {
let date: Date let date: Date
let account: Mastodon.Entity.Account? let account: FollowersEntryAccountable?
let avatarImage: UIImage?
let configuration: FollowersCountIntent let configuration: FollowersCountIntent
static func empty(with configuration: FollowersCountIntent) -> Self { static var placeholder: Self {
FollowersEntry(date: .now, account: nil, avatarImage: nil, configuration: configuration) FollowersEntry(
date: .now,
account: FollowersEntryAccount(
followersCount: 99_900,
displayNameWithFallback: "Mastodon",
acct: "mastodon",
avatarImage: UIImage(named: "missingAvatar")!
),
configuration: FollowersCountIntent()
)
}
static var unconfigured: Self {
FollowersEntry(
date: .now,
account: nil,
configuration: FollowersCountIntent()
)
} }
} }
@ -39,7 +58,7 @@ struct FollowersWidgetExtensionEntryView : View {
if let account = entry.account { if let account = entry.account {
HStack { HStack {
VStack(alignment: .leading, spacing: 0) { VStack(alignment: .leading, spacing: 0) {
if let avatarImage = entry.avatarImage { if let avatarImage = account.avatarImage {
Image(uiImage: avatarImage) Image(uiImage: avatarImage)
.resizable() .resizable()
.frame(width: 50, height: 50) .frame(width: 50, height: 50)
@ -52,7 +71,7 @@ struct FollowersWidgetExtensionEntryView : View {
.lineLimit(1) .lineLimit(1)
.truncationMode(.tail) .truncationMode(.tail)
Text("\(account.displayNameWithFallback)") Text(account.displayNameWithFallback)
.font(.system(size: 13)) .font(.system(size: 13))
.lineLimit(1) .lineLimit(1)
.truncationMode(.tail) .truncationMode(.tail)
@ -69,6 +88,9 @@ struct FollowersWidgetExtensionEntryView : View {
} }
} else { } else {
Text("Please use the Widget settings to select an Account.") Text("Please use the Widget settings to select an Account.")
.multilineTextAlignment(.center)
.font(.caption)
.padding(.all, 20)
} }
} }
} }
@ -80,6 +102,7 @@ struct FollowersWidgetExtension: Widget {
} }
.configurationDisplayName("Followers") .configurationDisplayName("Followers")
.description("Show number of followers.") .description("Show number of followers.")
.supportedFamilies([.systemSmall])
} }
} }
@ -88,7 +111,6 @@ struct WidgetExtension_Previews: PreviewProvider {
FollowersWidgetExtensionEntryView(entry: FollowersEntry( FollowersWidgetExtensionEntryView(entry: FollowersEntry(
date: Date(), date: Date(),
account: nil, account: nil,
avatarImage: nil,
configuration: FollowersCountIntent()) configuration: FollowersCountIntent())
) )
.previewContext(WidgetPreviewContext(family: .systemSmall)) .previewContext(WidgetPreviewContext(family: .systemSmall))
@ -105,34 +127,49 @@ private extension FollowersProvider {
.first, .first,
let account = configuration.account let account = configuration.account
else { else {
return completion(.empty(with: configuration)) return completion(.unconfigured)
} }
let resultingAccount = try await WidgetExtension.appContext let resultingAccount = try await WidgetExtension.appContext
.apiService .apiService
.search(query: .init(q: account, type: .accounts), authenticationBox: authBox) .search(query: .init(q: account, type: .accounts), authenticationBox: authBox)
.value .value
.accounts .accounts
.first .first!
let image: UIImage? = try await { let imageData = try await URLSession.shared.data(from: resultingAccount.avatarImageURLWithFallback(domain: authBox.domain)).0
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( let entry = FollowersEntry(
date: Date(), date: Date(),
account: resultingAccount, account: FollowersEntryAccount.from(
avatarImage: image, mastodonAccount: resultingAccount,
avatarImage: UIImage(data: imageData) ?? UIImage(named: "missingAvatar")!
),
configuration: configuration configuration: configuration
) )
completion(entry) completion(entry)
} }
} }
} }
protocol FollowersEntryAccountable {
var followersCount: Int { get }
var displayNameWithFallback: String { get }
var acct: String { get }
var avatarImage: UIImage { get }
}
struct FollowersEntryAccount: FollowersEntryAccountable {
let followersCount: Int
let displayNameWithFallback: String
let acct: String
let avatarImage: UIImage
static func from(mastodonAccount: Mastodon.Entity.Account, avatarImage: UIImage) -> Self {
FollowersEntryAccount(
followersCount: mastodonAccount.followersCount,
displayNameWithFallback: mastodonAccount.displayNameWithFallback,
acct: mastodonAccount.acct,
avatarImage: avatarImage
)
}
}