Widget: Add mentions widget
This commit is contained in:
parent
24d5ecd119
commit
189e10f2b4
|
@ -124,6 +124,8 @@
|
||||||
9FF2FB632BE7F5D9001560CE /* HashtagPostsWidgetConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FF2FB5E2BE7F56F001560CE /* HashtagPostsWidgetConfiguration.swift */; };
|
9FF2FB632BE7F5D9001560CE /* HashtagPostsWidgetConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FF2FB5E2BE7F56F001560CE /* HashtagPostsWidgetConfiguration.swift */; };
|
||||||
9FF2FB672BE7F816001560CE /* PostsWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FF2FB652BE7F805001560CE /* PostsWidgetView.swift */; };
|
9FF2FB672BE7F816001560CE /* PostsWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FF2FB652BE7F805001560CE /* PostsWidgetView.swift */; };
|
||||||
9FF2FB6A2BE7F84E001560CE /* SharedUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FF2FB682BE7F842001560CE /* SharedUtils.swift */; };
|
9FF2FB6A2BE7F84E001560CE /* SharedUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FF2FB682BE7F842001560CE /* SharedUtils.swift */; };
|
||||||
|
9FF2FB702BE8AE9D001560CE /* MentionWidgetConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FF2FB6E2BE8AE9B001560CE /* MentionWidgetConfiguration.swift */; };
|
||||||
|
9FF2FB712BE8AEA0001560CE /* MentionWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FF2FB6C2BE8AE90001560CE /* MentionWidget.swift */; };
|
||||||
9FFF677C299B7B2C00FE700A /* Notifications in Frameworks */ = {isa = PBXBuildFile; productRef = 9FFF677B299B7B2C00FE700A /* Notifications */; };
|
9FFF677C299B7B2C00FE700A /* Notifications in Frameworks */ = {isa = PBXBuildFile; productRef = 9FFF677B299B7B2C00FE700A /* Notifications */; };
|
||||||
9FFF6780299B7D2B00FE700A /* DesignSystem in Frameworks */ = {isa = PBXBuildFile; productRef = 9FFF677F299B7D2B00FE700A /* DesignSystem */; };
|
9FFF6780299B7D2B00FE700A /* DesignSystem in Frameworks */ = {isa = PBXBuildFile; productRef = 9FFF677F299B7D2B00FE700A /* DesignSystem */; };
|
||||||
9FFF6782299B7D3A00FE700A /* Account in Frameworks */ = {isa = PBXBuildFile; productRef = 9FFF6781299B7D3A00FE700A /* Account */; };
|
9FFF6782299B7D3A00FE700A /* Account in Frameworks */ = {isa = PBXBuildFile; productRef = 9FFF6781299B7D3A00FE700A /* Account */; };
|
||||||
|
@ -298,6 +300,8 @@
|
||||||
9FF2FB602BE7F5A7001560CE /* HashtagPostsWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HashtagPostsWidget.swift; sourceTree = "<group>"; };
|
9FF2FB602BE7F5A7001560CE /* HashtagPostsWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HashtagPostsWidget.swift; sourceTree = "<group>"; };
|
||||||
9FF2FB652BE7F805001560CE /* PostsWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostsWidgetView.swift; sourceTree = "<group>"; };
|
9FF2FB652BE7F805001560CE /* PostsWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostsWidgetView.swift; sourceTree = "<group>"; };
|
||||||
9FF2FB682BE7F842001560CE /* SharedUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedUtils.swift; sourceTree = "<group>"; };
|
9FF2FB682BE7F842001560CE /* SharedUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedUtils.swift; sourceTree = "<group>"; };
|
||||||
|
9FF2FB6C2BE8AE90001560CE /* MentionWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionWidget.swift; sourceTree = "<group>"; };
|
||||||
|
9FF2FB6E2BE8AE9B001560CE /* MentionWidgetConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionWidgetConfiguration.swift; sourceTree = "<group>"; };
|
||||||
B0BAB49E29B3D7A9008F54D7 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
B0BAB49E29B3D7A9008F54D7 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
||||||
C4CBB90B298A0DA3007E1707 /* en-GB */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "en-GB"; path = "en-GB.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
C4CBB90B298A0DA3007E1707 /* en-GB */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "en-GB"; path = "en-GB.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
||||||
C4FBCF6F298FD88A0015DF22 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
C4FBCF6F298FD88A0015DF22 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
||||||
|
@ -479,9 +483,10 @@
|
||||||
9F7788CA2BE652B1004E6BEF /* IceCubesAppWidgetsExtension */ = {
|
9F7788CA2BE652B1004E6BEF /* IceCubesAppWidgetsExtension */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
9FF2FB6B2BE8AE78001560CE /* MentionWidget */,
|
||||||
9FF2FB642BE7F7FA001560CE /* Shared */,
|
9FF2FB642BE7F7FA001560CE /* Shared */,
|
||||||
9FF2FB5D2BE7F559001560CE /* HashtagPostsWidget */,
|
9FF2FB5D2BE7F559001560CE /* HashtagPostsWidget */,
|
||||||
9FF2FB5C2BE7F549001560CE /* LatestPosts */,
|
9FF2FB5C2BE7F549001560CE /* LatestPostsWidget */,
|
||||||
9F7788D72BE652B2004E6BEF /* IceCubesAppWidgetsExtensionExtension.entitlements */,
|
9F7788D72BE652B2004E6BEF /* IceCubesAppWidgetsExtensionExtension.entitlements */,
|
||||||
9F7788CB2BE652B1004E6BEF /* IceCubesAppWidgetsExtensionBundle.swift */,
|
9F7788CB2BE652B1004E6BEF /* IceCubesAppWidgetsExtensionBundle.swift */,
|
||||||
9F7788D12BE652B2004E6BEF /* Assets.xcassets */,
|
9F7788D12BE652B2004E6BEF /* Assets.xcassets */,
|
||||||
|
@ -641,13 +646,13 @@
|
||||||
path = Settings;
|
path = Settings;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
9FF2FB5C2BE7F549001560CE /* LatestPosts */ = {
|
9FF2FB5C2BE7F549001560CE /* LatestPostsWidget */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
9F7788CD2BE652B1004E6BEF /* LatestPostsWidget.swift */,
|
9F7788CD2BE652B1004E6BEF /* LatestPostsWidget.swift */,
|
||||||
9F7788CF2BE652B1004E6BEF /* LatestPostsWidgetConfiguration.swift */,
|
9F7788CF2BE652B1004E6BEF /* LatestPostsWidgetConfiguration.swift */,
|
||||||
);
|
);
|
||||||
path = LatestPosts;
|
path = LatestPostsWidget;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
9FF2FB5D2BE7F559001560CE /* HashtagPostsWidget */ = {
|
9FF2FB5D2BE7F559001560CE /* HashtagPostsWidget */ = {
|
||||||
|
@ -668,6 +673,15 @@
|
||||||
path = Shared;
|
path = Shared;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
9FF2FB6B2BE8AE78001560CE /* MentionWidget */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
9FF2FB6C2BE8AE90001560CE /* MentionWidget.swift */,
|
||||||
|
9FF2FB6E2BE8AE9B001560CE /* MentionWidgetConfiguration.swift */,
|
||||||
|
);
|
||||||
|
path = MentionWidget;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
E9B576C029743F2A00BCE646 /* Localization */ = {
|
E9B576C029743F2A00BCE646 /* Localization */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -982,11 +996,13 @@
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
9FF2FB622BE7F5D5001560CE /* HashtagPostsWidget.swift in Sources */,
|
9FF2FB622BE7F5D5001560CE /* HashtagPostsWidget.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 */,
|
||||||
9F7788CC2BE652B1004E6BEF /* IceCubesAppWidgetsExtensionBundle.swift in Sources */,
|
9F7788CC2BE652B1004E6BEF /* IceCubesAppWidgetsExtensionBundle.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 */,
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "1530"
|
||||||
|
wasCreatedForAppExtension = "YES"
|
||||||
|
version = "2.0">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES"
|
||||||
|
buildArchitectures = "Automatic">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "9F7788C42BE652B1004E6BEF"
|
||||||
|
BuildableName = "IceCubesAppWidgetsExtensionExtension.appex"
|
||||||
|
BlueprintName = "IceCubesAppWidgetsExtensionExtension"
|
||||||
|
ReferencedContainer = "container:IceCubesApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "9FBFE638292A715500C250E9"
|
||||||
|
BuildableName = "Ice Cubes.app"
|
||||||
|
BlueprintName = "IceCubesApp"
|
||||||
|
ReferencedContainer = "container:IceCubesApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
shouldAutocreateTestPlan = "YES">
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = ""
|
||||||
|
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
|
||||||
|
launchStyle = "0"
|
||||||
|
askForAppToLaunch = "Yes"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "9FBFE638292A715500C250E9"
|
||||||
|
BuildableName = "Ice Cubes.app"
|
||||||
|
BlueprintName = "IceCubesApp"
|
||||||
|
ReferencedContainer = "container:IceCubesApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
<EnvironmentVariables>
|
||||||
|
<EnvironmentVariable
|
||||||
|
key = "_XCWidgetKind"
|
||||||
|
value = ""
|
||||||
|
isEnabled = "YES">
|
||||||
|
</EnvironmentVariable>
|
||||||
|
<EnvironmentVariable
|
||||||
|
key = "_XCWidgetDefaultView"
|
||||||
|
value = "timeline"
|
||||||
|
isEnabled = "YES">
|
||||||
|
</EnvironmentVariable>
|
||||||
|
<EnvironmentVariable
|
||||||
|
key = "_XCWidgetFamily"
|
||||||
|
value = "systemMedium"
|
||||||
|
isEnabled = "YES">
|
||||||
|
</EnvironmentVariable>
|
||||||
|
</EnvironmentVariables>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
askForAppToLaunch = "Yes"
|
||||||
|
launchAutomaticallySubstyle = "2">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "9FBFE638292A715500C250E9"
|
||||||
|
BuildableName = "Ice Cubes.app"
|
||||||
|
BlueprintName = "IceCubesApp"
|
||||||
|
ReferencedContainer = "container:IceCubesApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
|
@ -8,7 +8,7 @@ import Timeline
|
||||||
struct HashtagPostsWidgetProvider: AppIntentTimelineProvider {
|
struct HashtagPostsWidgetProvider: AppIntentTimelineProvider {
|
||||||
func placeholder(in context: Context) -> PostsWidgetEntry {
|
func placeholder(in context: Context) -> PostsWidgetEntry {
|
||||||
.init(date: Date(),
|
.init(date: Date(),
|
||||||
timeline: .hashtag(tag: "Mastodon", accountId: nil),
|
title: "#Mastodon",
|
||||||
statuses: [.placeholder()],
|
statuses: [.placeholder()],
|
||||||
images: [:])
|
images: [:])
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ struct HashtagPostsWidgetProvider: AppIntentTimelineProvider {
|
||||||
return entry
|
return entry
|
||||||
}
|
}
|
||||||
return .init(date: Date(),
|
return .init(date: Date(),
|
||||||
timeline: .hashtag(tag: "Mastodon", accountId: nil),
|
title: "#Mastodon",
|
||||||
statuses: [],
|
statuses: [],
|
||||||
images: [:])
|
images: [:])
|
||||||
}
|
}
|
||||||
|
@ -29,18 +29,18 @@ struct HashtagPostsWidgetProvider: AppIntentTimelineProvider {
|
||||||
|
|
||||||
private func timeline(for configuration: HashtagPostsWidgetConfiguration, context: Context) async -> Timeline<PostsWidgetEntry> {
|
private func timeline(for configuration: HashtagPostsWidgetConfiguration, context: Context) async -> Timeline<PostsWidgetEntry> {
|
||||||
do {
|
do {
|
||||||
let statuses = await loadStatuses(for: .hashtag(tag: configuration.hashgtag, accountId: nil),
|
let timeline: TimelineFilter = .hashtag(tag: configuration.hashgtag, accountId: nil)
|
||||||
|
let statuses = await loadStatuses(for: timeline,
|
||||||
account: configuration.account,
|
account: configuration.account,
|
||||||
widgetFamily: context.family)
|
widgetFamily: context.family)
|
||||||
let images = try await loadImages(urls: statuses.map{ $0.account.avatar } )
|
let images = try await loadImages(urls: statuses.map{ $0.account.avatar } )
|
||||||
return Timeline(entries: [.init(date: Date(),
|
return Timeline(entries: [.init(date: Date(),
|
||||||
timeline: .hashtag(tag: configuration.hashgtag,
|
title: timeline.title,
|
||||||
accountId: nil),
|
|
||||||
statuses: statuses,
|
statuses: statuses,
|
||||||
images: images)], policy: .atEnd)
|
images: images)], policy: .atEnd)
|
||||||
} catch {
|
} catch {
|
||||||
return Timeline(entries: [.init(date: Date(),
|
return Timeline(entries: [.init(date: Date(),
|
||||||
timeline: .hashtag(tag: "Mastodon", accountId: nil),
|
title: "#Mastodon",
|
||||||
statuses: [],
|
statuses: [],
|
||||||
images: [:])],
|
images: [:])],
|
||||||
policy: .atEnd)
|
policy: .atEnd)
|
||||||
|
@ -69,7 +69,7 @@ struct HashtagPostsWidget: Widget {
|
||||||
HashtagPostsWidget()
|
HashtagPostsWidget()
|
||||||
} timeline: {
|
} timeline: {
|
||||||
PostsWidgetEntry(date: .now,
|
PostsWidgetEntry(date: .now,
|
||||||
timeline: .hashtag(tag: "Matodon", accountId: nil),
|
title: "#Mastodon",
|
||||||
statuses: [.placeholder(), .placeholder(), .placeholder(), .placeholder()],
|
statuses: [.placeholder(), .placeholder(), .placeholder(), .placeholder()],
|
||||||
images: [:])
|
images: [:])
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,5 +6,6 @@ struct IceCubesAppWidgetsExtensionBundle: WidgetBundle {
|
||||||
var body: some Widget {
|
var body: some Widget {
|
||||||
LatestPostsWidget()
|
LatestPostsWidget()
|
||||||
HashtagPostsWidget()
|
HashtagPostsWidget()
|
||||||
|
MentionsWidget()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import Timeline
|
||||||
struct LatestPostsWidgetProvider: AppIntentTimelineProvider {
|
struct LatestPostsWidgetProvider: AppIntentTimelineProvider {
|
||||||
func placeholder(in context: Context) -> PostsWidgetEntry {
|
func placeholder(in context: Context) -> PostsWidgetEntry {
|
||||||
.init(date: Date(),
|
.init(date: Date(),
|
||||||
timeline: .home,
|
title: "Home",
|
||||||
statuses: [.placeholder()],
|
statuses: [.placeholder()],
|
||||||
images: [:])
|
images: [:])
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,8 @@ struct LatestPostsWidgetProvider: AppIntentTimelineProvider {
|
||||||
return entry
|
return entry
|
||||||
}
|
}
|
||||||
return .init(date: Date(),
|
return .init(date: Date(),
|
||||||
timeline: .home, statuses: [],
|
title: configuration.timeline.timeline.title,
|
||||||
|
statuses: [],
|
||||||
images: [:])
|
images: [:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,12 +34,12 @@ struct LatestPostsWidgetProvider: AppIntentTimelineProvider {
|
||||||
widgetFamily: context.family)
|
widgetFamily: context.family)
|
||||||
let images = try await loadImages(urls: statuses.map{ $0.account.avatar } )
|
let images = try await loadImages(urls: statuses.map{ $0.account.avatar } )
|
||||||
return Timeline(entries: [.init(date: Date(),
|
return Timeline(entries: [.init(date: Date(),
|
||||||
timeline: configuration.timeline.timeline,
|
title: configuration.timeline.timeline.title,
|
||||||
statuses: statuses,
|
statuses: statuses,
|
||||||
images: images)], policy: .atEnd)
|
images: images)], policy: .atEnd)
|
||||||
} catch {
|
} catch {
|
||||||
return Timeline(entries: [.init(date: Date(),
|
return Timeline(entries: [.init(date: Date(),
|
||||||
timeline: .home,
|
title: configuration.timeline.timeline.title,
|
||||||
statuses: [],
|
statuses: [],
|
||||||
images: [:])],
|
images: [:])],
|
||||||
policy: .atEnd)
|
policy: .atEnd)
|
||||||
|
@ -86,7 +87,7 @@ struct LatestPostsWidget: Widget {
|
||||||
LatestPostsWidget()
|
LatestPostsWidget()
|
||||||
} timeline: {
|
} timeline: {
|
||||||
PostsWidgetEntry(date: .now,
|
PostsWidgetEntry(date: .now,
|
||||||
timeline: .home,
|
title: "Mastodon",
|
||||||
statuses: [.placeholder(), .placeholder(), .placeholder(), .placeholder()],
|
statuses: [.placeholder(), .placeholder(), .placeholder(), .placeholder()],
|
||||||
images: [:])
|
images: [:])
|
||||||
}
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
import WidgetKit
|
||||||
|
import SwiftUI
|
||||||
|
import Network
|
||||||
|
import DesignSystem
|
||||||
|
import Models
|
||||||
|
import Timeline
|
||||||
|
|
||||||
|
struct MentionsWidgetProvider: AppIntentTimelineProvider {
|
||||||
|
func placeholder(in context: Context) -> PostsWidgetEntry {
|
||||||
|
.init(date: Date(),
|
||||||
|
title: "Mentions",
|
||||||
|
statuses: [.placeholder()],
|
||||||
|
images: [:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func snapshot(for configuration: MentionsWidgetConfiguration, in context: Context) async -> PostsWidgetEntry {
|
||||||
|
if let entry = await timeline(for: configuration, context: context).entries.first {
|
||||||
|
return entry
|
||||||
|
}
|
||||||
|
return .init(date: Date(),
|
||||||
|
title: "Mentions",
|
||||||
|
statuses: [],
|
||||||
|
images: [:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func timeline(for configuration: MentionsWidgetConfiguration, in context: Context) async -> Timeline<PostsWidgetEntry> {
|
||||||
|
await timeline(for: configuration, context: context)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func timeline(for configuration: MentionsWidgetConfiguration, context: Context) async -> Timeline<PostsWidgetEntry> {
|
||||||
|
do {
|
||||||
|
let client = Client(server: configuration.account.account.server,
|
||||||
|
oauthToken: configuration.account.account.oauthToken)
|
||||||
|
var excludedTypes = Models.Notification.NotificationType.allCases
|
||||||
|
excludedTypes.removeAll(where: { $0 == .mention })
|
||||||
|
var notifications: [Models.Notification] =
|
||||||
|
try await client.get(endpoint: Notifications.notifications(minId: nil,
|
||||||
|
maxId: nil,
|
||||||
|
types: excludedTypes.map(\.rawValue),
|
||||||
|
limit: 5))
|
||||||
|
let statuses = notifications.compactMap{ $0.status }
|
||||||
|
let images = try await loadImages(urls: statuses.map{ $0.account.avatar } )
|
||||||
|
return Timeline(entries: [.init(date: Date(),
|
||||||
|
title: "Mentions",
|
||||||
|
statuses: statuses,
|
||||||
|
images: images)], policy: .atEnd)
|
||||||
|
} catch {
|
||||||
|
return Timeline(entries: [.init(date: Date(),
|
||||||
|
title: "Mentions",
|
||||||
|
statuses: [],
|
||||||
|
images: [:])],
|
||||||
|
policy: .atEnd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MentionsWidget: Widget {
|
||||||
|
let kind: String = "MentionsWidget"
|
||||||
|
|
||||||
|
var body: some WidgetConfiguration {
|
||||||
|
AppIntentConfiguration(kind: kind,
|
||||||
|
intent: MentionsWidgetConfiguration.self,
|
||||||
|
provider: MentionsWidgetProvider()) { entry in
|
||||||
|
PostsWidgetView(entry: entry)
|
||||||
|
.containerBackground(Color("WidgetBackground").gradient, for: .widget)
|
||||||
|
}
|
||||||
|
.configurationDisplayName("Mentions")
|
||||||
|
.description("Show the latest mentions for the selected account.")
|
||||||
|
.supportedFamilies([.systemSmall, .systemMedium, .systemLarge, .systemExtraLarge])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#Preview(as: .systemMedium) {
|
||||||
|
MentionsWidget()
|
||||||
|
} timeline: {
|
||||||
|
PostsWidgetEntry(date: .now,
|
||||||
|
title: "Mentions",
|
||||||
|
statuses: [.placeholder(), .placeholder(), .placeholder(), .placeholder()],
|
||||||
|
images: [:])
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
import WidgetKit
|
||||||
|
import AppIntents
|
||||||
|
|
||||||
|
struct MentionsWidgetConfiguration: WidgetConfigurationIntent {
|
||||||
|
static let title: LocalizedStringResource = "Configuration"
|
||||||
|
static let description = IntentDescription("Choose the account for this widget")
|
||||||
|
|
||||||
|
@Parameter(title: "Account")
|
||||||
|
var account: AppAccountEntity
|
||||||
|
}
|
||||||
|
|
||||||
|
extension MentionsWidgetConfiguration {
|
||||||
|
static var previewAccount: MentionsWidgetConfiguration {
|
||||||
|
let intent = MentionsWidgetConfiguration()
|
||||||
|
intent.account = .init(account: .init(server: "Test", accountName: "Test account"))
|
||||||
|
return intent
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ import Timeline
|
||||||
|
|
||||||
struct PostsWidgetEntry: TimelineEntry {
|
struct PostsWidgetEntry: TimelineEntry {
|
||||||
let date: Date
|
let date: Date
|
||||||
let timeline: TimelineFilter
|
let title: String
|
||||||
let statuses: [Status]
|
let statuses: [Status]
|
||||||
let images: [URL: UIImage]
|
let images: [URL: UIImage]
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ struct PostsWidgetView : View {
|
||||||
|
|
||||||
private var headerView: some View {
|
private var headerView: some View {
|
||||||
HStack {
|
HStack {
|
||||||
Text(entry.timeline.title)
|
Text(entry.title)
|
||||||
Spacer()
|
Spacer()
|
||||||
Image(systemName: "cube")
|
Image(systemName: "cube")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue