mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2024-12-23 07:36:48 +00:00
Add lists widget
This commit is contained in:
parent
e3d4e693d2
commit
13d721912b
5 changed files with 172 additions and 0 deletions
|
@ -57,6 +57,9 @@
|
|||
9F4A48192976B21900A1A038 /* ProfileTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F4A48182976B21900A1A038 /* ProfileTab.swift */; };
|
||||
9F55C68D2955968700F94077 /* ExploreTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F55C68C2955968700F94077 /* ExploreTab.swift */; };
|
||||
9F55C6902955993C00F94077 /* Explore in Frameworks */ = {isa = PBXBuildFile; productRef = 9F55C68F2955993C00F94077 /* Explore */; };
|
||||
9F5BE6272BF492CF0074387E /* ListEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F5BE6252BF48FE10074387E /* ListEntity.swift */; };
|
||||
9F5BE6282BF492D10074387E /* ListsWidgetConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F5BE6232BF48FC40074387E /* ListsWidgetConfiguration.swift */; };
|
||||
9F5BE6292BF492D40074387E /* ListsWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F5BE6212BF48FBA0074387E /* ListsWidget.swift */; };
|
||||
9F5E581929545BE700A53960 /* Env in Frameworks */ = {isa = PBXBuildFile; productRef = 9F5E581829545BE700A53960 /* Env */; };
|
||||
9F6028562B3F36AE00476078 /* AppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F6028552B3F36AE00476078 /* AppView.swift */; };
|
||||
9F6028582B3F3B7600476078 /* ToolbarTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F6028572B3F3B7600476078 /* ToolbarTab.swift */; };
|
||||
|
@ -245,6 +248,9 @@
|
|||
9F4A48182976B21900A1A038 /* ProfileTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileTab.swift; sourceTree = "<group>"; };
|
||||
9F55C68C2955968700F94077 /* ExploreTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExploreTab.swift; sourceTree = "<group>"; };
|
||||
9F55C68E295598F900F94077 /* Explore */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Explore; path = Packages/Explore; sourceTree = "<group>"; };
|
||||
9F5BE6212BF48FBA0074387E /* ListsWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListsWidget.swift; sourceTree = "<group>"; };
|
||||
9F5BE6232BF48FC40074387E /* ListsWidgetConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListsWidgetConfiguration.swift; sourceTree = "<group>"; };
|
||||
9F5BE6252BF48FE10074387E /* ListEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListEntity.swift; sourceTree = "<group>"; };
|
||||
9F5E581729545B5500A53960 /* Env */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = Env; path = Packages/Env; sourceTree = "<group>"; };
|
||||
9F6028552B3F36AE00476078 /* AppView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppView.swift; sourceTree = "<group>"; };
|
||||
9F6028572B3F3B7600476078 /* ToolbarTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolbarTab.swift; sourceTree = "<group>"; };
|
||||
|
@ -433,6 +439,7 @@
|
|||
9F37BDDA2BE36E22007F28AD /* PostIntent.swift */,
|
||||
9F37BDDE2BE37C35007F28AD /* TabIntent.swift */,
|
||||
9F7788EC2BE78D75004E6BEF /* TimelineFilterEntity.swift */,
|
||||
9F5BE6252BF48FE10074387E /* ListEntity.swift */,
|
||||
);
|
||||
path = IceCubesAppIntents;
|
||||
sourceTree = "<group>";
|
||||
|
@ -461,6 +468,15 @@
|
|||
path = Resources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9F5BE6202BF48FB20074387E /* ListsWidget */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9F5BE6212BF48FBA0074387E /* ListsWidget.swift */,
|
||||
9F5BE6232BF48FC40074387E /* ListsWidgetConfiguration.swift */,
|
||||
);
|
||||
path = ListsWidget;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9F654BF0299AC46200D27FA5 /* Report */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -481,6 +497,7 @@
|
|||
9F7788CA2BE652B1004E6BEF /* IceCubesAppWidgetsExtension */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9F5BE6202BF48FB20074387E /* ListsWidget */,
|
||||
9FF2FB6B2BE8AE78001560CE /* MentionWidget */,
|
||||
9FF2FB642BE7F7FA001560CE /* Shared */,
|
||||
9FF2FB5D2BE7F559001560CE /* HashtagPostsWidget */,
|
||||
|
@ -991,17 +1008,20 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
9F5BE6272BF492CF0074387E /* ListEntity.swift in Sources */,
|
||||
9FF2FB622BE7F5D5001560CE /* HashtagPostsWidget.swift in Sources */,
|
||||
9FF2FB712BE8AEA0001560CE /* MentionWidget.swift in Sources */,
|
||||
9F7788EA2BE65585004E6BEF /* AppAccountEntity.swift in Sources */,
|
||||
9FF2FB6A2BE7F84E001560CE /* SharedUtils.swift in Sources */,
|
||||
9F7788CE2BE652B1004E6BEF /* LatestPostsWidget.swift in Sources */,
|
||||
9F7788EE2BE78D7B004E6BEF /* TimelineFilterEntity.swift in Sources */,
|
||||
9F5BE6292BF492D40074387E /* ListsWidget.swift in Sources */,
|
||||
9F7788CC2BE652B1004E6BEF /* IceCubesAppWidgetsExtensionBundle.swift in Sources */,
|
||||
9FF2FB702BE8AE9D001560CE /* MentionWidgetConfiguration.swift in Sources */,
|
||||
9F7788D02BE652B1004E6BEF /* LatestPostsWidgetConfiguration.swift in Sources */,
|
||||
9FF2FB672BE7F816001560CE /* PostsWidgetView.swift in Sources */,
|
||||
9FF2FB632BE7F5D9001560CE /* HashtagPostsWidgetConfiguration.swift in Sources */,
|
||||
9F5BE6282BF492D10074387E /* ListsWidgetConfiguration.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
55
IceCubesAppIntents/ListEntity.swift
Normal file
55
IceCubesAppIntents/ListEntity.swift
Normal file
|
@ -0,0 +1,55 @@
|
|||
import AppAccount
|
||||
import AppIntents
|
||||
import Env
|
||||
import Foundation
|
||||
import Models
|
||||
import Network
|
||||
import Timeline
|
||||
|
||||
public struct ListEntity: Identifiable, AppEntity {
|
||||
public var id: String { list.id }
|
||||
|
||||
public let list: Models.List
|
||||
|
||||
public static let defaultQuery = DefaultListEntityQuery()
|
||||
|
||||
public static let typeDisplayRepresentation: TypeDisplayRepresentation = "List"
|
||||
|
||||
public var displayRepresentation: DisplayRepresentation {
|
||||
DisplayRepresentation(title: "\(list.title)")
|
||||
}
|
||||
}
|
||||
|
||||
public struct DefaultListEntityQuery: EntityQuery {
|
||||
public init() {}
|
||||
|
||||
@IntentParameterDependency<ListsWidgetConfiguration>(
|
||||
\.$account
|
||||
)
|
||||
var account
|
||||
|
||||
public func entities(for _: [ListEntity.ID]) async throws -> [ListEntity] {
|
||||
await fetchLists().map{ .init(list: $0 )}
|
||||
}
|
||||
|
||||
public func suggestedEntities() async throws -> [ListEntity] {
|
||||
await fetchLists().map{ .init(list: $0 )}
|
||||
}
|
||||
|
||||
public func defaultResult() async -> ListEntity? {
|
||||
nil
|
||||
}
|
||||
|
||||
private func fetchLists() async -> [Models.List] {
|
||||
guard let account = account?.account.account else {
|
||||
return []
|
||||
}
|
||||
let client = Client(server: account.server, oauthToken: account.oauthToken)
|
||||
do {
|
||||
let lists: [Models.List] = try await client.get(endpoint: Lists.lists)
|
||||
return lists
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ struct IceCubesAppWidgetsExtensionBundle: WidgetBundle {
|
|||
var body: some Widget {
|
||||
LatestPostsWidget()
|
||||
HashtagPostsWidget()
|
||||
ListsPostWidget()
|
||||
MentionsWidget()
|
||||
}
|
||||
}
|
||||
|
|
75
IceCubesAppWidgetsExtension/ListsWidget/ListsWidget.swift
Normal file
75
IceCubesAppWidgetsExtension/ListsWidget/ListsWidget.swift
Normal file
|
@ -0,0 +1,75 @@
|
|||
import DesignSystem
|
||||
import Models
|
||||
import Network
|
||||
import SwiftUI
|
||||
import Timeline
|
||||
import WidgetKit
|
||||
|
||||
struct ListsWidgetProvider: AppIntentTimelineProvider {
|
||||
func placeholder(in _: Context) -> PostsWidgetEntry {
|
||||
.init(date: Date(),
|
||||
title: "List name",
|
||||
statuses: [.placeholder()],
|
||||
images: [:])
|
||||
}
|
||||
|
||||
func snapshot(for configuration: ListsWidgetConfiguration, in context: Context) async -> PostsWidgetEntry {
|
||||
if let entry = await timeline(for: configuration, context: context).entries.first {
|
||||
return entry
|
||||
}
|
||||
return .init(date: Date(),
|
||||
title: "List name",
|
||||
statuses: [],
|
||||
images: [:])
|
||||
}
|
||||
|
||||
func timeline(for configuration: ListsWidgetConfiguration, in context: Context) async -> Timeline<PostsWidgetEntry> {
|
||||
await timeline(for: configuration, context: context)
|
||||
}
|
||||
|
||||
private func timeline(for configuration: ListsWidgetConfiguration, context: Context) async -> Timeline<PostsWidgetEntry> {
|
||||
do {
|
||||
let timeline: TimelineFilter = .list(list: configuration.timeline.list)
|
||||
let statuses = await loadStatuses(for: timeline,
|
||||
account: configuration.account,
|
||||
widgetFamily: context.family)
|
||||
let images = try await loadImages(urls: statuses.map { $0.account.avatar })
|
||||
return Timeline(entries: [.init(date: Date(),
|
||||
title: timeline.title,
|
||||
statuses: statuses,
|
||||
images: images)], policy: .atEnd)
|
||||
} catch {
|
||||
return Timeline(entries: [.init(date: Date(),
|
||||
title: "List name",
|
||||
statuses: [],
|
||||
images: [:])],
|
||||
policy: .atEnd)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ListsPostWidget: Widget {
|
||||
let kind: String = "ListsPostWidget"
|
||||
|
||||
var body: some WidgetConfiguration {
|
||||
AppIntentConfiguration(kind: kind,
|
||||
intent: ListsWidgetConfiguration.self,
|
||||
provider: ListsWidgetProvider())
|
||||
{ entry in
|
||||
PostsWidgetView(entry: entry)
|
||||
.containerBackground(Color("WidgetBackground").gradient, for: .widget)
|
||||
}
|
||||
.configurationDisplayName("List timeline")
|
||||
.description("Show the latest post for the selected list")
|
||||
.supportedFamilies([.systemSmall, .systemMedium, .systemLarge, .systemExtraLarge])
|
||||
}
|
||||
}
|
||||
|
||||
#Preview(as: .systemMedium) {
|
||||
ListsPostWidget()
|
||||
} timeline: {
|
||||
PostsWidgetEntry(date: .now,
|
||||
title: "List name",
|
||||
statuses: [.placeholder(), .placeholder(), .placeholder(), .placeholder()],
|
||||
images: [:])
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
import AppIntents
|
||||
import WidgetKit
|
||||
|
||||
struct ListsWidgetConfiguration: WidgetConfigurationIntent {
|
||||
static let title: LocalizedStringResource = "Configuration"
|
||||
static let description = IntentDescription("Choose the account and list for this widget")
|
||||
|
||||
@Parameter(title: "Account")
|
||||
var account: AppAccountEntity
|
||||
|
||||
@Parameter(title: "List")
|
||||
var timeline: ListEntity
|
||||
}
|
||||
|
||||
extension ListsWidgetConfiguration {
|
||||
static var previewAccount: LatestPostsWidgetConfiguration {
|
||||
let intent = LatestPostsWidgetConfiguration()
|
||||
intent.account = .init(account: .init(server: "Test", accountName: "Test account"))
|
||||
return intent
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue