Merge pull request #89 from VernissageApp/feature/improve-widget-image-fetcher
Improve widget image fetcher
This commit is contained in:
commit
598d9f77ea
|
@ -15,4 +15,24 @@ class AttachmentDataHandler {
|
|||
let context = viewContext ?? CoreDataHandler.shared.container.viewContext
|
||||
return AttachmentData(context: context)
|
||||
}
|
||||
|
||||
func getDownloadedAttachmentData(accountId: String, length: Int, viewContext: NSManagedObjectContext? = nil) -> [AttachmentData] {
|
||||
let context = viewContext ?? CoreDataHandler.shared.container.viewContext
|
||||
let fetchRequest = AttachmentData.fetchRequest()
|
||||
fetchRequest.fetchLimit = length
|
||||
|
||||
let sortDescriptor = NSSortDescriptor(key: "statusRelation.id", ascending: true)
|
||||
fetchRequest.sortDescriptors = [sortDescriptor]
|
||||
|
||||
let predicate1 = NSPredicate(format: "statusRelation.pixelfedAccount.id = %@", accountId)
|
||||
let predicate2 = NSPredicate(format: "data != nil")
|
||||
fetchRequest.predicate = NSCompoundPredicate.init(type: .and, subpredicates: [predicate1, predicate2])
|
||||
|
||||
do {
|
||||
return try context.fetch(fetchRequest)
|
||||
} catch {
|
||||
CoreDataError.shared.handle(error, message: "Error during fetching attachment data (getDownloadedAttachmentData).")
|
||||
return []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,31 +17,54 @@ struct PhotoProvider: TimelineProvider {
|
|||
|
||||
func getSnapshot(in context: Context, completion: @escaping (PhotoWidgetEntry) -> Void) {
|
||||
Task {
|
||||
if let widgetEntry = await self.getWidgetEntries(length: 1).first {
|
||||
completion(widgetEntry)
|
||||
} else {
|
||||
let entry = StatusFetcher.shared.placeholder()
|
||||
completion(entry)
|
||||
}
|
||||
let widgetEntry = await self.getWidgetEntriesForSnapshot()
|
||||
completion(widgetEntry)
|
||||
}
|
||||
}
|
||||
|
||||
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> Void) {
|
||||
Task {
|
||||
let currentDate = Date()
|
||||
let widgetEntries = await self.getWidgetEntries()
|
||||
let widgetEntries = await self.getWidgetEntriesForTimeline()
|
||||
|
||||
let nextUpdateDate = Calendar.current.date(byAdding: .hour, value: 1, to: currentDate)!
|
||||
let timeline = Timeline(entries: widgetEntries, policy: .after(nextUpdateDate))
|
||||
completion(timeline)
|
||||
}
|
||||
}
|
||||
|
||||
func getWidgetEntriesForSnapshot() async -> PhotoWidgetEntry {
|
||||
let entriesFromDatabase = await self.getWidgetEntriesFromDatabase(length: 1)
|
||||
if let firstEntry = entriesFromDatabase.first {
|
||||
return firstEntry
|
||||
}
|
||||
|
||||
return StatusFetcher.shared.placeholder()
|
||||
}
|
||||
|
||||
func getWidgetEntriesForTimeline() async -> [PhotoWidgetEntry] {
|
||||
let entriesFromServer = await self.getWidgetEntriesFromServer(length: 3)
|
||||
if entriesFromServer.isEmpty == false {
|
||||
return entriesFromServer
|
||||
}
|
||||
|
||||
let entriesFromDatabase = await self.getWidgetEntriesFromDatabase(length: 3)
|
||||
if entriesFromDatabase.isEmpty == false {
|
||||
return entriesFromDatabase
|
||||
}
|
||||
|
||||
return [StatusFetcher.shared.placeholder()]
|
||||
}
|
||||
|
||||
func getWidgetEntries(length: Int = 3) async -> [PhotoWidgetEntry] {
|
||||
func getWidgetEntriesFromServer(length: Int) async -> [PhotoWidgetEntry] {
|
||||
do {
|
||||
return try await StatusFetcher.shared.fetchWidgetEntries(length: length)
|
||||
return try await StatusFetcher.shared.fetchWidgetEntriesFromServer(length: length)
|
||||
} catch {
|
||||
return [StatusFetcher.shared.placeholder()]
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
func getWidgetEntriesFromDatabase(length: Int) async -> [PhotoWidgetEntry] {
|
||||
return await StatusFetcher.shared.fetchWidgetEntriesFromDatabase(length: length)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ public class StatusFetcher {
|
|||
public static let shared = StatusFetcher()
|
||||
private init() { }
|
||||
|
||||
func fetchWidgetEntries(length: Int = 8) async throws -> [PhotoWidgetEntry] {
|
||||
func fetchWidgetEntriesFromServer(length: Int) async throws -> [PhotoWidgetEntry] {
|
||||
let defaultSettings = ApplicationSettingsHandler.shared.get()
|
||||
guard let accountId = defaultSettings.currentAccount else {
|
||||
return [self.placeholder()]
|
||||
|
@ -67,6 +67,37 @@ public class StatusFetcher {
|
|||
|
||||
return widgetEntries.shuffled()
|
||||
}
|
||||
|
||||
func fetchWidgetEntriesFromDatabase(length: Int) async -> [PhotoWidgetEntry] {
|
||||
let defaultSettings = ApplicationSettingsHandler.shared.get()
|
||||
guard let accountId = defaultSettings.currentAccount else {
|
||||
return [self.placeholder()]
|
||||
}
|
||||
|
||||
let attachmentDatas = AttachmentDataHandler.shared.getDownloadedAttachmentData(accountId: accountId, length: length)
|
||||
|
||||
var widgetEntries: [PhotoWidgetEntry] = []
|
||||
for attachmentData in attachmentDatas {
|
||||
guard let imageData = attachmentData.data, let uiImage = UIImage(data: imageData) else {
|
||||
continue
|
||||
}
|
||||
|
||||
let uiAvatar = await FileFetcher.shared.getImage(url: attachmentData.statusRelation?.accountAvatar)
|
||||
let displayDate = Calendar.current.date(byAdding: .minute, value: widgetEntries.count * 20, to: Date())
|
||||
|
||||
widgetEntries.append(PhotoWidgetEntry(date: displayDate ?? Date(),
|
||||
image: uiImage,
|
||||
avatar: uiAvatar,
|
||||
displayName: attachmentData.statusRelation?.accountDisplayName,
|
||||
statusId: attachmentData.statusId))
|
||||
}
|
||||
|
||||
if widgetEntries.isEmpty {
|
||||
widgetEntries.append(self.placeholder())
|
||||
}
|
||||
|
||||
return widgetEntries.shuffled()
|
||||
}
|
||||
|
||||
func placeholder() -> PhotoWidgetEntry {
|
||||
PhotoWidgetEntry(date: Date(), image: nil, avatar: nil, displayName: "Caroline Rick", statusId: "")
|
||||
|
|
|
@ -12,21 +12,23 @@ struct PhotoLargeWidgetView: View {
|
|||
var entry: PhotoProvider.Entry
|
||||
|
||||
var body: some View {
|
||||
if let uiImage = entry.image, let uiAvatar = entry.avatar {
|
||||
self.getWidgetBody(uiImage: Image(uiImage: uiImage), uiAvatar: Image(uiImage: uiAvatar))
|
||||
if let uiImage = entry.image {
|
||||
self.getWidgetBody(uiImage: Image(uiImage: uiImage), uiAvatarImage: entry.avatar)
|
||||
} else {
|
||||
self.getWidgetBody(uiImage: Image("Placeholder"), uiAvatar: Image("Avatar"))
|
||||
self.getWidgetBody(uiImage: Image("Placeholder"), uiAvatarImage: UIImage(named: "Avatar"))
|
||||
.unredacted()
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func getWidgetBody(uiImage: Image, uiAvatar: Image) -> some View {
|
||||
private func getWidgetBody(uiImage: Image, uiAvatarImage: UIImage?) -> some View {
|
||||
VStack {
|
||||
Spacer()
|
||||
HStack {
|
||||
uiAvatar
|
||||
.avatar(size: 24)
|
||||
if let uiAvatar = uiAvatarImage {
|
||||
Image(uiImage: uiAvatar)
|
||||
.avatar(size: 24)
|
||||
}
|
||||
|
||||
Text(entry.displayName ?? "")
|
||||
.font(.system(size: 15))
|
||||
|
|
|
@ -12,21 +12,23 @@ struct PhotoMediumWidgetView: View {
|
|||
var entry: PhotoProvider.Entry
|
||||
|
||||
var body: some View {
|
||||
if let uiImage = entry.image, let uiAvatar = entry.avatar {
|
||||
self.getWidgetBody(uiImage: Image(uiImage: uiImage), uiAvatar: Image(uiImage: uiAvatar))
|
||||
if let uiImage = entry.image {
|
||||
self.getWidgetBody(uiImage: Image(uiImage: uiImage), uiAvatarImage: entry.avatar)
|
||||
} else {
|
||||
self.getWidgetBody(uiImage: Image("Placeholder"), uiAvatar: Image("Avatar"))
|
||||
self.getWidgetBody(uiImage: Image("Placeholder"), uiAvatarImage: UIImage(named: "Avatar"))
|
||||
.unredacted()
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func getWidgetBody(uiImage: Image, uiAvatar: Image) -> some View {
|
||||
private func getWidgetBody(uiImage: Image, uiAvatarImage: UIImage?) -> some View {
|
||||
VStack {
|
||||
Spacer()
|
||||
HStack {
|
||||
uiAvatar
|
||||
.avatar(size: 24)
|
||||
if let uiAvatar = uiAvatarImage {
|
||||
Image(uiImage: uiAvatar)
|
||||
.avatar(size: 24)
|
||||
}
|
||||
|
||||
Text(entry.displayName ?? "")
|
||||
.font(.system(size: 15))
|
||||
|
|
|
@ -12,21 +12,23 @@ struct PhotoSmallWidgetView: View {
|
|||
var entry: PhotoProvider.Entry
|
||||
|
||||
var body: some View {
|
||||
if let uiImage = entry.image, let uiAvatar = entry.avatar {
|
||||
self.getWidgetBody(uiImage: Image(uiImage: uiImage), uiAvatar: Image(uiImage: uiAvatar))
|
||||
if let uiImage = entry.image {
|
||||
self.getWidgetBody(uiImage: Image(uiImage: uiImage), uiAvatarImage: entry.avatar)
|
||||
} else {
|
||||
self.getWidgetBody(uiImage: Image("Placeholder"), uiAvatar: Image("Avatar"))
|
||||
self.getWidgetBody(uiImage: Image("Placeholder"), uiAvatarImage: UIImage(named: "Avatar"))
|
||||
.unredacted()
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func getWidgetBody(uiImage: Image, uiAvatar: Image) -> some View {
|
||||
private func getWidgetBody(uiImage: Image, uiAvatarImage: UIImage?) -> some View {
|
||||
VStack {
|
||||
Spacer()
|
||||
HStack {
|
||||
uiAvatar
|
||||
.avatar(size: 16)
|
||||
if let uiAvatar = uiAvatarImage {
|
||||
Image(uiImage: uiAvatar)
|
||||
.avatar(size: 16)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue