mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2024-11-25 17:51:01 +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 */; };
|
9F4A48192976B21900A1A038 /* ProfileTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F4A48182976B21900A1A038 /* ProfileTab.swift */; };
|
||||||
9F55C68D2955968700F94077 /* ExploreTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F55C68C2955968700F94077 /* ExploreTab.swift */; };
|
9F55C68D2955968700F94077 /* ExploreTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F55C68C2955968700F94077 /* ExploreTab.swift */; };
|
||||||
9F55C6902955993C00F94077 /* Explore in Frameworks */ = {isa = PBXBuildFile; productRef = 9F55C68F2955993C00F94077 /* Explore */; };
|
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 */; };
|
9F5E581929545BE700A53960 /* Env in Frameworks */ = {isa = PBXBuildFile; productRef = 9F5E581829545BE700A53960 /* Env */; };
|
||||||
9F6028562B3F36AE00476078 /* AppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F6028552B3F36AE00476078 /* AppView.swift */; };
|
9F6028562B3F36AE00476078 /* AppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F6028552B3F36AE00476078 /* AppView.swift */; };
|
||||||
9F6028582B3F3B7600476078 /* ToolbarTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F6028572B3F3B7600476078 /* ToolbarTab.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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
9F6028572B3F3B7600476078 /* ToolbarTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolbarTab.swift; sourceTree = "<group>"; };
|
||||||
|
@ -433,6 +439,7 @@
|
||||||
9F37BDDA2BE36E22007F28AD /* PostIntent.swift */,
|
9F37BDDA2BE36E22007F28AD /* PostIntent.swift */,
|
||||||
9F37BDDE2BE37C35007F28AD /* TabIntent.swift */,
|
9F37BDDE2BE37C35007F28AD /* TabIntent.swift */,
|
||||||
9F7788EC2BE78D75004E6BEF /* TimelineFilterEntity.swift */,
|
9F7788EC2BE78D75004E6BEF /* TimelineFilterEntity.swift */,
|
||||||
|
9F5BE6252BF48FE10074387E /* ListEntity.swift */,
|
||||||
);
|
);
|
||||||
path = IceCubesAppIntents;
|
path = IceCubesAppIntents;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -461,6 +468,15 @@
|
||||||
path = Resources;
|
path = Resources;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
9F5BE6202BF48FB20074387E /* ListsWidget */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
9F5BE6212BF48FBA0074387E /* ListsWidget.swift */,
|
||||||
|
9F5BE6232BF48FC40074387E /* ListsWidgetConfiguration.swift */,
|
||||||
|
);
|
||||||
|
path = ListsWidget;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
9F654BF0299AC46200D27FA5 /* Report */ = {
|
9F654BF0299AC46200D27FA5 /* Report */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -481,6 +497,7 @@
|
||||||
9F7788CA2BE652B1004E6BEF /* IceCubesAppWidgetsExtension */ = {
|
9F7788CA2BE652B1004E6BEF /* IceCubesAppWidgetsExtension */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
9F5BE6202BF48FB20074387E /* ListsWidget */,
|
||||||
9FF2FB6B2BE8AE78001560CE /* MentionWidget */,
|
9FF2FB6B2BE8AE78001560CE /* MentionWidget */,
|
||||||
9FF2FB642BE7F7FA001560CE /* Shared */,
|
9FF2FB642BE7F7FA001560CE /* Shared */,
|
||||||
9FF2FB5D2BE7F559001560CE /* HashtagPostsWidget */,
|
9FF2FB5D2BE7F559001560CE /* HashtagPostsWidget */,
|
||||||
|
@ -991,17 +1008,20 @@
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
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 */,
|
||||||
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 */,
|
||||||
9F7788EE2BE78D7B004E6BEF /* TimelineFilterEntity.swift in Sources */,
|
9F7788EE2BE78D7B004E6BEF /* TimelineFilterEntity.swift in Sources */,
|
||||||
|
9F5BE6292BF492D40074387E /* ListsWidget.swift in Sources */,
|
||||||
9F7788CC2BE652B1004E6BEF /* IceCubesAppWidgetsExtensionBundle.swift in Sources */,
|
9F7788CC2BE652B1004E6BEF /* IceCubesAppWidgetsExtensionBundle.swift in Sources */,
|
||||||
9FF2FB702BE8AE9D001560CE /* MentionWidgetConfiguration.swift in Sources */,
|
9FF2FB702BE8AE9D001560CE /* MentionWidgetConfiguration.swift in Sources */,
|
||||||
9F7788D02BE652B1004E6BEF /* LatestPostsWidgetConfiguration.swift in Sources */,
|
9F7788D02BE652B1004E6BEF /* LatestPostsWidgetConfiguration.swift in Sources */,
|
||||||
9FF2FB672BE7F816001560CE /* PostsWidgetView.swift in Sources */,
|
9FF2FB672BE7F816001560CE /* PostsWidgetView.swift in Sources */,
|
||||||
9FF2FB632BE7F5D9001560CE /* HashtagPostsWidgetConfiguration.swift in Sources */,
|
9FF2FB632BE7F5D9001560CE /* HashtagPostsWidgetConfiguration.swift in Sources */,
|
||||||
|
9F5BE6282BF492D10074387E /* ListsWidgetConfiguration.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
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 {
|
var body: some Widget {
|
||||||
LatestPostsWidget()
|
LatestPostsWidget()
|
||||||
HashtagPostsWidget()
|
HashtagPostsWidget()
|
||||||
|
ListsPostWidget()
|
||||||
MentionsWidget()
|
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