diff --git a/DB/Sources/DB/Content/ContentDatabase+Migration.swift b/DB/Sources/DB/Content/ContentDatabase+Migration.swift index aa2547c..8e2f09c 100644 --- a/DB/Sources/DB/Content/ContentDatabase+Migration.swift +++ b/DB/Sources/DB/Content/ContentDatabase+Migration.swift @@ -128,6 +128,7 @@ extension ContentDatabase { .references("timelineRecord", onDelete: .cascade) t.column("statusId", .text).indexed().notNull() .references("statusRecord", onDelete: .cascade) + t.column("order", .integer) t.primaryKey(["timelineId", "statusId"], onConflict: .replace) } diff --git a/DB/Sources/DB/Content/ContentDatabase.swift b/DB/Sources/DB/Content/ContentDatabase.swift index 2332350..a5adc7c 100644 --- a/DB/Sources/DB/Content/ContentDatabase.swift +++ b/DB/Sources/DB/Content/ContentDatabase.swift @@ -58,6 +58,7 @@ public extension ContentDatabase { .eraseToAnyPublisher() } + // swiftlint:disable:next function_body_length func insert( statuses: [Status], timeline: Timeline, @@ -69,10 +70,24 @@ public extension ContentDatabase { let maxIdPresent = try String.fetchOne($0, timelineRecord.statuses.select(max(StatusRecord.Columns.id))) + var order = timeline.ordered + ? try Int.fetchOne( + $0, + TimelineStatusJoin.filter(TimelineStatusJoin.Columns.timelineId == timeline.id) + .select(max(TimelineStatusJoin.Columns.order))) + : nil + for status in statuses { try status.save($0) - try TimelineStatusJoin(timelineId: timeline.id, statusId: status.id).save($0) + if let order = order { + print("saving with order: \(order)") + } + try TimelineStatusJoin(timelineId: timeline.id, statusId: status.id, order: order).save($0) + + if let presentOrder = order { + order = presentOrder + 1 + } } if let maxIdPresent = maxIdPresent, @@ -447,7 +462,8 @@ public extension ContentDatabase { func timelinePublisher(_ timeline: Timeline) -> AnyPublisher<[CollectionSection], Error> { ValueObservation.tracking( - TimelineItemsInfo.request(TimelineRecord.filter(TimelineRecord.Columns.id == timeline.id)).fetchOne) + TimelineItemsInfo.request(TimelineRecord.filter(TimelineRecord.Columns.id == timeline.id), + ordered: timeline.ordered).fetchOne) .removeDuplicates() .publisher(in: databaseWriter) .handleEvents( diff --git a/DB/Sources/DB/Content/TimelineItemsInfo.swift b/DB/Sources/DB/Content/TimelineItemsInfo.swift index ca9fd63..922e661 100644 --- a/DB/Sources/DB/Content/TimelineItemsInfo.swift +++ b/DB/Sources/DB/Content/TimelineItemsInfo.swift @@ -17,15 +17,17 @@ extension TimelineItemsInfo { let pinnedStatusInfos: [StatusInfo] } - static func addingIncludes( _ request: T) -> T where T.RowDecoder == TimelineRecord { - request.including(all: StatusInfo.addingIncludes(TimelineRecord.statuses).forKey(CodingKeys.statusInfos)) + static func addingIncludes( _ request: T, ordered: Bool) -> T where T.RowDecoder == TimelineRecord { + let statusesAssociation = ordered ? TimelineRecord.orderedStatuses : TimelineRecord.statuses + + return request.including(all: StatusInfo.addingIncludes(statusesAssociation).forKey(CodingKeys.statusInfos)) .including(all: TimelineRecord.loadMores.forKey(CodingKeys.loadMoreRecords)) .including(optional: PinnedStatusesInfo.addingIncludes(TimelineRecord.account) .forKey(CodingKeys.pinnedStatusesInfo)) } - static func request(_ request: QueryInterfaceRequest) -> QueryInterfaceRequest { - addingIncludes(request).asRequest(of: self) + static func request(_ request: QueryInterfaceRequest, ordered: Bool) -> QueryInterfaceRequest { + addingIncludes(request, ordered: ordered).asRequest(of: self) } func items(filters: [Filter]) -> [CollectionSection] { diff --git a/DB/Sources/DB/Content/TimelineRecord.swift b/DB/Sources/DB/Content/TimelineRecord.swift index 30c8a1e..8c2c1fc 100644 --- a/DB/Sources/DB/Content/TimelineRecord.swift +++ b/DB/Sources/DB/Content/TimelineRecord.swift @@ -29,6 +29,10 @@ extension TimelineRecord { through: statusJoins, using: TimelineStatusJoin.status) .order(StatusRecord.Columns.id.desc) + static let orderedStatuses = hasMany( + StatusRecord.self, + through: statusJoins.order(TimelineStatusJoin.Columns.order), + using: TimelineStatusJoin.status) static let account = belongsTo(AccountRecord.self, using: ForeignKey([Columns.accountId])) static let loadMores = hasMany(LoadMoreRecord.self) @@ -36,6 +40,10 @@ extension TimelineRecord { StatusInfo.request(request(for: Self.statuses)) } + var orderedStatuses: QueryInterfaceRequest { + StatusInfo.request(request(for: Self.orderedStatuses)) + } + var loadMores: QueryInterfaceRequest { request(for: Self.loadMores) } diff --git a/DB/Sources/DB/Content/TimelineStatusJoin.swift b/DB/Sources/DB/Content/TimelineStatusJoin.swift index 969c824..23b82e1 100644 --- a/DB/Sources/DB/Content/TimelineStatusJoin.swift +++ b/DB/Sources/DB/Content/TimelineStatusJoin.swift @@ -7,6 +7,7 @@ import Mastodon struct TimelineStatusJoin: ContentDatabaseRecord { let timelineId: Timeline.Id let statusId: Status.Id + let order: Int? static let status = belongsTo(StatusRecord.self) } @@ -15,5 +16,6 @@ extension TimelineStatusJoin { enum Columns { static let timelineId = Column(CodingKeys.timelineId) static let statusId = Column(CodingKeys.statusId) + static let order = Column(CodingKeys.order) } } diff --git a/DB/Sources/DB/Entities/Timeline.swift b/DB/Sources/DB/Entities/Timeline.swift index 60e54cd..6c584ff 100644 --- a/DB/Sources/DB/Entities/Timeline.swift +++ b/DB/Sources/DB/Entities/Timeline.swift @@ -32,6 +32,15 @@ public extension Timeline { return nil } } + + var ordered: Bool { + switch self { + case .favorites, .bookmarks: + return true + default: + return false + } + } } extension Timeline: Identifiable { diff --git a/ServiceLayer/Sources/ServiceLayer/Services/TimelineService.swift b/ServiceLayer/Sources/ServiceLayer/Services/TimelineService.swift index 085461b..e47826b 100644 --- a/ServiceLayer/Sources/ServiceLayer/Services/TimelineService.swift +++ b/ServiceLayer/Sources/ServiceLayer/Services/TimelineService.swift @@ -10,7 +10,6 @@ public struct TimelineService { public let sections: AnyPublisher<[CollectionSection], Error> public let navigationService: NavigationService public let nextPageMaxId: AnyPublisher - public let preferLastPresentIdOverNextPageMaxId = true public let title: AnyPublisher public let titleLocalizationComponents: AnyPublisher<[String], Never> @@ -48,6 +47,10 @@ public struct TimelineService { } extension TimelineService: CollectionService { + public var preferLastPresentIdOverNextPageMaxId: Bool { + !timeline.ordered + } + public var markerTimeline: Marker.Timeline? { switch timeline { case .home: diff --git a/Views/UIKit/AttachmentsView.swift b/Views/UIKit/AttachmentsView.swift index 1761cc2..8331085 100644 --- a/Views/UIKit/AttachmentsView.swift +++ b/Views/UIKit/AttachmentsView.swift @@ -33,6 +33,7 @@ final class AttachmentsView: UIView { let attachmentView = AttachmentView(viewModel: attachmentViewModel, parentViewModel: viewModel) attachmentView.playing = viewModel.shouldShowAttachments && attachmentViewModel.shouldAutoplay attachmentView.removeButton.isHidden = !viewModel.canRemoveAttachments + attachmentView.editIcon.isHidden = !viewModel.canRemoveAttachments if viewModel.attachmentViewModels.count == 2 && index == 1 || viewModel.attachmentViewModels.count == 3 && index != 0