Add loading in background
This commit is contained in:
parent
0d493a20a3
commit
5d893a4b42
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import CoreData
|
||||||
|
|
||||||
class AttachmentDataHandler {
|
class AttachmentDataHandler {
|
||||||
func getAttachmentsData() -> [AttachmentData] {
|
func getAttachmentsData() -> [AttachmentData] {
|
||||||
|
@ -19,8 +20,8 @@ class AttachmentDataHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createAttachmnentDataEntity() -> AttachmentData {
|
func createAttachmnentDataEntity(viewContext: NSManagedObjectContext? = nil) -> AttachmentData {
|
||||||
let context = CoreDataHandler.shared.container.viewContext
|
let context = viewContext ?? CoreDataHandler.shared.container.viewContext
|
||||||
return AttachmentData(context: context)
|
return AttachmentData(context: context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,10 @@ public class CoreDataHandler {
|
||||||
container.viewContext.automaticallyMergesChangesFromParent = true
|
container.viewContext.automaticallyMergesChangesFromParent = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func newBackgroundContext() -> NSManagedObjectContext {
|
||||||
|
self.container.newBackgroundContext()
|
||||||
|
}
|
||||||
|
|
||||||
public func save() {
|
public func save() {
|
||||||
let context = self.container.viewContext
|
let context = self.container.viewContext
|
||||||
if context.hasChanges {
|
if context.hasChanges {
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import CoreData
|
||||||
|
|
||||||
class StatusDataHandler {
|
class StatusDataHandler {
|
||||||
func getStatusesData() -> [StatusData] {
|
func getStatusesData() -> [StatusData] {
|
||||||
|
@ -19,8 +20,8 @@ class StatusDataHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMaximumStatus() -> StatusData? {
|
func getMaximumStatus(viewContext: NSManagedObjectContext? = nil) -> StatusData? {
|
||||||
let context = CoreDataHandler.shared.container.viewContext
|
let context = viewContext ?? CoreDataHandler.shared.container.viewContext
|
||||||
let fetchRequest = StatusData.fetchRequest()
|
let fetchRequest = StatusData.fetchRequest()
|
||||||
|
|
||||||
fetchRequest.fetchLimit = 1
|
fetchRequest.fetchLimit = 1
|
||||||
|
@ -34,8 +35,23 @@ class StatusDataHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createStatusDataEntity() -> StatusData {
|
func getMinimumtatus(viewContext: NSManagedObjectContext? = nil) -> StatusData? {
|
||||||
let context = CoreDataHandler.shared.container.viewContext
|
let context = viewContext ?? CoreDataHandler.shared.container.viewContext
|
||||||
|
let fetchRequest = StatusData.fetchRequest()
|
||||||
|
|
||||||
|
fetchRequest.fetchLimit = 1
|
||||||
|
let sortDescriptor = NSSortDescriptor(key: "id", ascending: true)
|
||||||
|
fetchRequest.sortDescriptors = [sortDescriptor]
|
||||||
|
do {
|
||||||
|
let statuses = try context.fetch(fetchRequest)
|
||||||
|
return statuses.first
|
||||||
|
} catch {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createStatusDataEntity(viewContext: NSManagedObjectContext? = nil) -> StatusData {
|
||||||
|
let context = viewContext ?? CoreDataHandler.shared.container.viewContext
|
||||||
return StatusData(context: context)
|
return StatusData(context: context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import MastodonSwift
|
import MastodonSwift
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import CoreData
|
||||||
|
|
||||||
struct HomeFeedView: View {
|
struct HomeFeedView: View {
|
||||||
@Environment(\.managedObjectContext) private var viewContext
|
@Environment(\.managedObjectContext) private var viewContext
|
||||||
|
@ -26,9 +27,41 @@ struct HomeFeedView: View {
|
||||||
LazyVGrid(columns: gridColumns) {
|
LazyVGrid(columns: gridColumns) {
|
||||||
ForEach(dbStatuses) { item in
|
ForEach(dbStatuses) { item in
|
||||||
NavigationLink(destination: DetailsView(statusData: item)) {
|
NavigationLink(destination: DetailsView(statusData: item)) {
|
||||||
if let attachmenData = item.attachmentRelation?.first(where: { element in true }) as? AttachmentData {
|
if let attachmenData = item.attachmentRelation?.first(where: { element in true }) as? AttachmentData,
|
||||||
Image(uiImage: UIImage(data: attachmenData.data)!)
|
let uiImage = UIImage(data: attachmenData.data) {
|
||||||
|
|
||||||
|
ZStack {
|
||||||
|
Image(uiImage: uiImage)
|
||||||
.resizable().aspectRatio(contentMode: .fit)
|
.resizable().aspectRatio(contentMode: .fit)
|
||||||
|
if let count = item.attachmentRelation?.count, count > 1 {
|
||||||
|
VStack(alignment:.trailing) {
|
||||||
|
Spacer()
|
||||||
|
HStack {
|
||||||
|
Spacer()
|
||||||
|
Text("1 / \(count)")
|
||||||
|
.padding(.horizontal, 6)
|
||||||
|
.padding(.vertical, 3)
|
||||||
|
.font(.caption2)
|
||||||
|
.foregroundColor(.black)
|
||||||
|
.background(.ultraThinMaterial, in: Capsule())
|
||||||
|
}
|
||||||
|
}.padding()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Text("Error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ProgressView()
|
||||||
|
.progressViewStyle(CircularProgressViewStyle())
|
||||||
|
.onAppear {
|
||||||
|
Task {
|
||||||
|
do {
|
||||||
|
try await onBottomOfList()
|
||||||
|
} catch {
|
||||||
|
print("Error", error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,7 +91,7 @@ struct HomeFeedView: View {
|
||||||
}
|
}
|
||||||
.refreshable {
|
.refreshable {
|
||||||
do {
|
do {
|
||||||
try await loadData()
|
try await onTopOfList()
|
||||||
} catch {
|
} catch {
|
||||||
print("Error", error)
|
print("Error", error)
|
||||||
}
|
}
|
||||||
|
@ -67,7 +100,7 @@ struct HomeFeedView: View {
|
||||||
do {
|
do {
|
||||||
if self.dbStatuses.isEmpty {
|
if self.dbStatuses.isEmpty {
|
||||||
self.showLoading = true
|
self.showLoading = true
|
||||||
try await loadData()
|
try await onTopOfList()
|
||||||
self.showLoading = false
|
self.showLoading = false
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
@ -77,7 +110,37 @@ struct HomeFeedView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func loadData() async throws {
|
private func onBottomOfList() async throws {
|
||||||
|
// Load data from API and operate on CoreData on background context.
|
||||||
|
let backgroundContext = CoreDataHandler.shared.newBackgroundContext()
|
||||||
|
|
||||||
|
// Get maximimum downloaded stauts id.
|
||||||
|
let statusDataHandler = StatusDataHandler()
|
||||||
|
let oldestStatus = statusDataHandler.getMinimumtatus(viewContext: backgroundContext)
|
||||||
|
|
||||||
|
guard let oldestStatus = oldestStatus else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try await self.loadData(on: backgroundContext, maxId: oldestStatus.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func onTopOfList() async throws {
|
||||||
|
// Load data from API and operate on CoreData on background context.
|
||||||
|
let backgroundContext = CoreDataHandler.shared.newBackgroundContext()
|
||||||
|
|
||||||
|
// Get maximimum downloaded stauts id.
|
||||||
|
let statusDataHandler = StatusDataHandler()
|
||||||
|
let newestStatus = statusDataHandler.getMaximumStatus(viewContext: backgroundContext)
|
||||||
|
|
||||||
|
guard let newestStatus = newestStatus else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try await self.loadData(on: backgroundContext, minId: newestStatus.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func loadData(on backgroundContext: NSManagedObjectContext, minId: String? = nil, maxId: String? = nil) async throws {
|
||||||
guard let accessData = self.applicationState.accountData, let accessToken = accessData.accessToken else {
|
guard let accessData = self.applicationState.accountData, let accessToken = accessData.accessToken else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -85,17 +148,16 @@ struct HomeFeedView: View {
|
||||||
// Get maximimum downloaded stauts id.
|
// Get maximimum downloaded stauts id.
|
||||||
let attachmentDataHandler = AttachmentDataHandler()
|
let attachmentDataHandler = AttachmentDataHandler()
|
||||||
let statusDataHandler = StatusDataHandler()
|
let statusDataHandler = StatusDataHandler()
|
||||||
let lastStatus = statusDataHandler.getMaximumStatus()
|
|
||||||
|
|
||||||
// Retrieve statuses from API.
|
// Retrieve statuses from API.
|
||||||
let client = MastodonClient(baseURL: accessData.serverUrl).getAuthenticated(token: accessToken)
|
let client = MastodonClient(baseURL: accessData.serverUrl).getAuthenticated(token: accessToken)
|
||||||
let statuses = try await client.getHomeTimeline(minId: lastStatus?.id, limit: 40)
|
let statuses = try await client.getHomeTimeline(maxId: maxId, minId: minId, limit: 40)
|
||||||
|
|
||||||
// Download status images and save it into database.
|
// Download status images and save it into database.
|
||||||
for status in statuses {
|
for status in statuses {
|
||||||
|
|
||||||
// Save status data in database.
|
// Save status data in database.
|
||||||
let statusDataEntity = statusDataHandler.createStatusDataEntity()
|
let statusDataEntity = statusDataHandler.createStatusDataEntity(viewContext: backgroundContext)
|
||||||
statusDataEntity.accountAvatar = status.account?.avatar
|
statusDataEntity.accountAvatar = status.account?.avatar
|
||||||
statusDataEntity.accountDisplayName = status.account?.displayName
|
statusDataEntity.accountDisplayName = status.account?.displayName
|
||||||
statusDataEntity.accountId = status.account!.id
|
statusDataEntity.accountId = status.account!.id
|
||||||
|
@ -138,7 +200,7 @@ struct HomeFeedView: View {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Save attachment in database.
|
// Save attachment in database.
|
||||||
let attachmentData = attachmentDataHandler.createAttachmnentDataEntity()
|
let attachmentData = attachmentDataHandler.createAttachmnentDataEntity(viewContext: backgroundContext)
|
||||||
attachmentData.id = attachment.id
|
attachmentData.id = attachment.id
|
||||||
attachmentData.url = attachment.url
|
attachmentData.url = attachment.url
|
||||||
attachmentData.blurhash = attachment.blurhash
|
attachmentData.blurhash = attachment.blurhash
|
||||||
|
@ -155,7 +217,7 @@ struct HomeFeedView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try self.viewContext.save()
|
try backgroundContext.save()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func fetchImage(attachment: Attachment) async throws -> Data? {
|
public func fetchImage(attachment: Attachment) async throws -> Data? {
|
||||||
|
|
Loading…
Reference in New Issue