From 03a4d1299d5dc34b2ec938e41378307e6cf7f3c0 Mon Sep 17 00:00:00 2001 From: Justin Mazzocchi <2831158+jzzocc@users.noreply.github.com> Date: Wed, 2 Dec 2020 11:39:42 -0800 Subject: [PATCH] Ephemeral timelines --- DB/Sources/DB/Content/ContentDatabase.swift | 21 ++++++++++ DB/Sources/DB/Entities/Timeline.swift | 39 +++++++++++++++++++ .../DB/Extensions/Timeline+Extensions.swift | 35 ----------------- 3 files changed, 60 insertions(+), 35 deletions(-) delete mode 100644 DB/Sources/DB/Extensions/Timeline+Extensions.swift diff --git a/DB/Sources/DB/Content/ContentDatabase.swift b/DB/Sources/DB/Content/ContentDatabase.swift index 3b22e10..ef45334 100644 --- a/DB/Sources/DB/Content/ContentDatabase.swift +++ b/DB/Sources/DB/Content/ContentDatabase.swift @@ -11,6 +11,7 @@ import Secrets public struct ContentDatabase { public let activeFiltersPublisher: AnyPublisher<[Filter], Error> + private let id: Identity.Id private let databaseWriter: DatabaseWriter public init(id: Identity.Id, @@ -19,6 +20,8 @@ public struct ContentDatabase { inMemory: Bool, appGroup: String, keychain: Keychain.Type) throws { + self.id = id + if inMemory { databaseWriter = DatabaseQueue() try Self.migrator.migrate(databaseWriter) @@ -378,6 +381,21 @@ public extension ContentDatabase { TimelineItemsInfo.request(TimelineRecord.filter(TimelineRecord.Columns.id == timeline.id)).fetchOne) .removeDuplicates() .publisher(in: databaseWriter) + .handleEvents( + receiveSubscription: { _ in + if let ephemeralityId = timeline.ephemeralityId(id: id) { + Self.ephemeralTimelines.add(ephemeralityId) + } + }, + receiveCancel: { + guard let ephemeralityId = timeline.ephemeralityId(id: id) else { return } + + Self.ephemeralTimelines.remove(ephemeralityId) + + if Self.ephemeralTimelines.count(for: ephemeralityId) == 0 { + databaseWriter.asyncWrite(TimelineRecord(timeline: timeline).delete) { _, _ in } + } + }) .combineLatest(activeFiltersPublisher) .compactMap { $0?.items(filters: $1) } .eraseToAnyPublisher() @@ -480,6 +498,9 @@ public extension ContentDatabase { private extension ContentDatabase { static let cleanAfterLastReadIdCount = 40 + + static let ephemeralTimelines = NSCountedSet() + static func fileURL(id: Identity.Id, appGroup: String) throws -> URL { try FileManager.default.databaseDirectoryURL(name: id.uuidString, appGroup: appGroup) } diff --git a/DB/Sources/DB/Entities/Timeline.swift b/DB/Sources/DB/Entities/Timeline.swift index de73ec7..60e54cd 100644 --- a/DB/Sources/DB/Entities/Timeline.swift +++ b/DB/Sources/DB/Entities/Timeline.swift @@ -56,3 +56,42 @@ extension Timeline: Identifiable { } } } + +extension Timeline { + init?(record: TimelineRecord) { + switch (record.id, + record.listId, + record.listTitle, + record.tag, + record.accountId, + record.profileCollection) { + case (Timeline.home.id, _, _, _, _, _): + self = .home + case (Timeline.local.id, _, _, _, _, _): + self = .local + case (Timeline.federated.id, _, _, _, _, _): + self = .federated + case (_, .some(let listId), .some(let listTitle), _, _, _): + self = .list(List(id: listId, title: listTitle)) + case (_, _, _, .some(let tag), _, _): + self = .tag(tag) + case (_, _, _, _, .some(let accountId), .some(let profileCollection)): + self = .profile(accountId: accountId, profileCollection: profileCollection) + case (Timeline.favorites.id, _, _, _, _, _): + self = .favorites + case (Timeline.bookmarks.id, _, _, _, _, _): + self = .bookmarks + default: + return nil + } + } + + func ephemeralityId(id: Identity.Id) -> String? { + switch self { + case .tag, .favorites, .bookmarks: + return "\(id)-\(self.id)" + default: + return nil + } + } +} diff --git a/DB/Sources/DB/Extensions/Timeline+Extensions.swift b/DB/Sources/DB/Extensions/Timeline+Extensions.swift deleted file mode 100644 index 84a1b7c..0000000 --- a/DB/Sources/DB/Extensions/Timeline+Extensions.swift +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright © 2020 Metabolist. All rights reserved. - -import Foundation -import GRDB -import Mastodon - -extension Timeline { - init?(record: TimelineRecord) { - switch (record.id, - record.listId, - record.listTitle, - record.tag, - record.accountId, - record.profileCollection) { - case (Timeline.home.id, _, _, _, _, _): - self = .home - case (Timeline.local.id, _, _, _, _, _): - self = .local - case (Timeline.federated.id, _, _, _, _, _): - self = .federated - case (_, .some(let listId), .some(let listTitle), _, _, _): - self = .list(List(id: listId, title: listTitle)) - case (_, _, _, .some(let tag), _, _): - self = .tag(tag) - case (_, _, _, _, .some(let accountId), .some(let profileCollection)): - self = .profile(accountId: accountId, profileCollection: profileCollection) - case (Timeline.favorites.id, _, _, _, _, _): - self = .favorites - case (Timeline.bookmarks.id, _, _, _, _, _): - self = .bookmarks - default: - return nil - } - } -}