Add followers count widget
This commit is contained in:
parent
1578896b3e
commit
f40aeb9cac
|
@ -89,6 +89,9 @@
|
||||||
9F7788F02BE78E77004E6BEF /* Timeline in Frameworks */ = {isa = PBXBuildFile; productRef = 9F7788EF2BE78E77004E6BEF /* Timeline */; };
|
9F7788F02BE78E77004E6BEF /* Timeline in Frameworks */ = {isa = PBXBuildFile; productRef = 9F7788EF2BE78E77004E6BEF /* Timeline */; };
|
||||||
9F7D93942980063100EE6B7A /* AppAccount in Frameworks */ = {isa = PBXBuildFile; productRef = 9F7D93932980063100EE6B7A /* AppAccount */; };
|
9F7D93942980063100EE6B7A /* AppAccount in Frameworks */ = {isa = PBXBuildFile; productRef = 9F7D93932980063100EE6B7A /* AppAccount */; };
|
||||||
9F7D939A29805DBD00EE6B7A /* AccountSettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F7D939929805DBD00EE6B7A /* AccountSettingView.swift */; };
|
9F7D939A29805DBD00EE6B7A /* AccountSettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F7D939929805DBD00EE6B7A /* AccountSettingView.swift */; };
|
||||||
|
9F8B92122BF77DBE003D37A2 /* AccountWidgetConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F8B920E2BF77DB4003D37A2 /* AccountWidgetConfiguration.swift */; };
|
||||||
|
9F8B92132BF77DBE003D37A2 /* AccountWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F8B92102BF77DBB003D37A2 /* AccountWidget.swift */; };
|
||||||
|
9F8B92162BF77F0B003D37A2 /* AccountWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F8B92142BF77F05003D37A2 /* AccountWidgetView.swift */; };
|
||||||
9FA6FD6229C04A8800E2312C /* TranslationSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA6FD6129C04A8800E2312C /* TranslationSettingsView.swift */; };
|
9FA6FD6229C04A8800E2312C /* TranslationSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA6FD6129C04A8800E2312C /* TranslationSettingsView.swift */; };
|
||||||
9FAD858B29743F7400496AB1 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FAD858A29743F7400496AB1 /* ShareViewController.swift */; };
|
9FAD858B29743F7400496AB1 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FAD858A29743F7400496AB1 /* ShareViewController.swift */; };
|
||||||
9FAD858E29743F7400496AB1 /* (null) in Resources */ = {isa = PBXBuildFile; };
|
9FAD858E29743F7400496AB1 /* (null) in Resources */ = {isa = PBXBuildFile; };
|
||||||
|
@ -275,6 +278,9 @@
|
||||||
9F7788EC2BE78D75004E6BEF /* TimelineFilterEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineFilterEntity.swift; sourceTree = "<group>"; };
|
9F7788EC2BE78D75004E6BEF /* TimelineFilterEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineFilterEntity.swift; sourceTree = "<group>"; };
|
||||||
9F7D939529800B0300EE6B7A /* IceCubesApp-release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "IceCubesApp-release.xcconfig"; sourceTree = "<group>"; };
|
9F7D939529800B0300EE6B7A /* IceCubesApp-release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "IceCubesApp-release.xcconfig"; sourceTree = "<group>"; };
|
||||||
9F7D939929805DBD00EE6B7A /* AccountSettingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountSettingView.swift; sourceTree = "<group>"; };
|
9F7D939929805DBD00EE6B7A /* AccountSettingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountSettingView.swift; sourceTree = "<group>"; };
|
||||||
|
9F8B920E2BF77DB4003D37A2 /* AccountWidgetConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountWidgetConfiguration.swift; sourceTree = "<group>"; };
|
||||||
|
9F8B92102BF77DBB003D37A2 /* AccountWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountWidget.swift; sourceTree = "<group>"; };
|
||||||
|
9F8B92142BF77F05003D37A2 /* AccountWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountWidgetView.swift; sourceTree = "<group>"; };
|
||||||
9FA6FD6129C04A8800E2312C /* TranslationSettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TranslationSettingsView.swift; sourceTree = "<group>"; };
|
9FA6FD6129C04A8800E2312C /* TranslationSettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TranslationSettingsView.swift; sourceTree = "<group>"; };
|
||||||
9FAD858829743F7400496AB1 /* IceCubesShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = IceCubesShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
9FAD858829743F7400496AB1 /* IceCubesShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = IceCubesShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
9FAD858A29743F7400496AB1 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = "<group>"; };
|
9FAD858A29743F7400496AB1 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = "<group>"; };
|
||||||
|
@ -497,6 +503,7 @@
|
||||||
9F7788CA2BE652B1004E6BEF /* IceCubesAppWidgetsExtension */ = {
|
9F7788CA2BE652B1004E6BEF /* IceCubesAppWidgetsExtension */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
9F8B920D2BF77DA8003D37A2 /* AccountWidget */,
|
||||||
9F5BE6202BF48FB20074387E /* ListsWidget */,
|
9F5BE6202BF48FB20074387E /* ListsWidget */,
|
||||||
9FF2FB6B2BE8AE78001560CE /* MentionWidget */,
|
9FF2FB6B2BE8AE78001560CE /* MentionWidget */,
|
||||||
9FF2FB642BE7F7FA001560CE /* Shared */,
|
9FF2FB642BE7F7FA001560CE /* Shared */,
|
||||||
|
@ -510,6 +517,16 @@
|
||||||
path = IceCubesAppWidgetsExtension;
|
path = IceCubesAppWidgetsExtension;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
9F8B920D2BF77DA8003D37A2 /* AccountWidget */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
9F8B920E2BF77DB4003D37A2 /* AccountWidgetConfiguration.swift */,
|
||||||
|
9F8B92102BF77DBB003D37A2 /* AccountWidget.swift */,
|
||||||
|
9F8B92142BF77F05003D37A2 /* AccountWidgetView.swift */,
|
||||||
|
);
|
||||||
|
path = AccountWidget;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
9FA0D2AC29921C1F008A143B /* Embeds */ = {
|
9FA0D2AC29921C1F008A143B /* Embeds */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -1011,6 +1028,9 @@
|
||||||
9F5BE6272BF492CF0074387E /* ListEntity.swift in Sources */,
|
9F5BE6272BF492CF0074387E /* ListEntity.swift in Sources */,
|
||||||
9FF2FB622BE7F5D5001560CE /* HashtagPostsWidget.swift in Sources */,
|
9FF2FB622BE7F5D5001560CE /* HashtagPostsWidget.swift in Sources */,
|
||||||
9FF2FB712BE8AEA0001560CE /* MentionWidget.swift in Sources */,
|
9FF2FB712BE8AEA0001560CE /* MentionWidget.swift in Sources */,
|
||||||
|
9F8B92162BF77F0B003D37A2 /* AccountWidgetView.swift in Sources */,
|
||||||
|
9F8B92122BF77DBE003D37A2 /* AccountWidgetConfiguration.swift in Sources */,
|
||||||
|
9F8B92132BF77DBE003D37A2 /* AccountWidget.swift in Sources */,
|
||||||
9F7788EA2BE65585004E6BEF /* AppAccountEntity.swift in Sources */,
|
9F7788EA2BE65585004E6BEF /* AppAccountEntity.swift in Sources */,
|
||||||
9FF2FB6A2BE7F84E001560CE /* SharedUtils.swift in Sources */,
|
9FF2FB6A2BE7F84E001560CE /* SharedUtils.swift in Sources */,
|
||||||
9F7788CE2BE652B1004E6BEF /* LatestPostsWidget.swift in Sources */,
|
9F7788CE2BE652B1004E6BEF /* LatestPostsWidget.swift in Sources */,
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
import DesignSystem
|
||||||
|
import Models
|
||||||
|
import Network
|
||||||
|
import SwiftUI
|
||||||
|
import Timeline
|
||||||
|
import WidgetKit
|
||||||
|
|
||||||
|
struct AccountWidgetProvider: AppIntentTimelineProvider {
|
||||||
|
func placeholder(in _: Context) -> AccountWidgetEntry {
|
||||||
|
.init(date: Date(), account: .placeholder(), avatar: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func snapshot(for configuration: AccountWidgetConfiguration, in context: Context) async -> AccountWidgetEntry {
|
||||||
|
let account = await fetchAccount(configuration: configuration)
|
||||||
|
return .init(date: Date(), account: account, avatar: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func timeline(for configuration: AccountWidgetConfiguration, in context: Context) async -> Timeline<AccountWidgetEntry> {
|
||||||
|
let account = await fetchAccount(configuration: configuration)
|
||||||
|
let images = try? await loadImages(urls: [account.avatar])
|
||||||
|
return .init(entries: [.init(date: Date(), account: account, avatar: images?.first?.value)],
|
||||||
|
policy: .atEnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func fetchAccount(configuration: AccountWidgetConfiguration) async -> Account {
|
||||||
|
let client = Client(server: configuration.account.account.server,
|
||||||
|
oauthToken: configuration.account.account.oauthToken)
|
||||||
|
do {
|
||||||
|
let account: Account = try await client.get(endpoint: Accounts.verifyCredentials)
|
||||||
|
return account
|
||||||
|
} catch {
|
||||||
|
return .placeholder()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AccountWidgetEntry: TimelineEntry {
|
||||||
|
let date: Date
|
||||||
|
let account: Account
|
||||||
|
let avatar: UIImage?
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AccountWidget: Widget {
|
||||||
|
let kind: String = "AccountWidget"
|
||||||
|
|
||||||
|
var body: some WidgetConfiguration {
|
||||||
|
AppIntentConfiguration(kind: kind,
|
||||||
|
intent: AccountWidgetConfiguration.self,
|
||||||
|
provider: AccountWidgetProvider())
|
||||||
|
{ entry in
|
||||||
|
AccountWidgetView(entry: entry)
|
||||||
|
.containerBackground(Color("WidgetBackground").gradient, for: .widget)
|
||||||
|
}
|
||||||
|
.configurationDisplayName("Account")
|
||||||
|
.description("Show information about your Mastodon account")
|
||||||
|
.supportedFamilies([.systemSmall])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview(as: .systemSmall) {
|
||||||
|
AccountWidget()
|
||||||
|
} timeline: {
|
||||||
|
AccountWidgetEntry(date: Date(), account: .placeholder(), avatar: nil)
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
import AppIntents
|
||||||
|
import WidgetKit
|
||||||
|
|
||||||
|
struct AccountWidgetConfiguration: WidgetConfigurationIntent {
|
||||||
|
static let title: LocalizedStringResource = "Configuration"
|
||||||
|
static let description = IntentDescription("Choose the account for this widget")
|
||||||
|
|
||||||
|
@Parameter(title: "Account")
|
||||||
|
var account: AppAccountEntity
|
||||||
|
}
|
||||||
|
|
||||||
|
extension AccountWidgetConfiguration {
|
||||||
|
static var previewAccount: AccountWidgetConfiguration {
|
||||||
|
let intent = AccountWidgetConfiguration()
|
||||||
|
intent.account = .init(account: .init(server: "Test", accountName: "Test account"))
|
||||||
|
return intent
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
import DesignSystem
|
||||||
|
import Models
|
||||||
|
import Network
|
||||||
|
import SwiftUI
|
||||||
|
import Timeline
|
||||||
|
import WidgetKit
|
||||||
|
|
||||||
|
struct AccountWidgetView: View {
|
||||||
|
var entry: AccountWidgetProvider.Entry
|
||||||
|
|
||||||
|
@Environment(\.widgetFamily) var family
|
||||||
|
@Environment(\.redactionReasons) var redacted
|
||||||
|
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(alignment: .center, spacing: 4) {
|
||||||
|
if let avatar = entry.avatar {
|
||||||
|
Image(uiImage: avatar)
|
||||||
|
.resizable()
|
||||||
|
.frame(width: 64, height: 64)
|
||||||
|
.clipShape(Circle())
|
||||||
|
Text("\(entry.account.followersCount ?? 0)")
|
||||||
|
.font(.title)
|
||||||
|
.fontDesign(.rounded)
|
||||||
|
.fontWeight(.bold)
|
||||||
|
.monospacedDigit()
|
||||||
|
Text("Followers")
|
||||||
|
.font(.headline)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,5 +8,6 @@ struct IceCubesAppWidgetsExtensionBundle: WidgetBundle {
|
||||||
HashtagPostsWidget()
|
HashtagPostsWidget()
|
||||||
ListsPostWidget()
|
ListsPostWidget()
|
||||||
MentionsWidget()
|
MentionsWidget()
|
||||||
|
AccountWidget()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue