Fix and simplify startup position
This commit is contained in:
parent
728fdddca1
commit
3149fd8edf
|
@ -16,7 +16,6 @@ public struct ContentDatabase {
|
|||
|
||||
public init(id: Identity.Id,
|
||||
useHomeTimelineLastReadId: Bool,
|
||||
useNotificationsLastReadId: Bool,
|
||||
inMemory: Bool,
|
||||
appGroup: String,
|
||||
keychain: Keychain.Type) throws {
|
||||
|
@ -35,8 +34,7 @@ public struct ContentDatabase {
|
|||
|
||||
try Self.clean(
|
||||
databaseWriter,
|
||||
useHomeTimelineLastReadId: useHomeTimelineLastReadId,
|
||||
useNotificationsLastReadId: useNotificationsLastReadId)
|
||||
useHomeTimelineLastReadId: useHomeTimelineLastReadId)
|
||||
|
||||
activeFiltersPublisher = ValueObservation.tracking {
|
||||
try Filter.filter(Filter.Columns.expiresAt == nil || Filter.Columns.expiresAt > Date()).fetchAll($0)
|
||||
|
@ -708,48 +706,14 @@ private extension ContentDatabase {
|
|||
|
||||
// swiftlint:disable:next function_body_length
|
||||
static func clean(_ databaseWriter: DatabaseWriter,
|
||||
useHomeTimelineLastReadId: Bool,
|
||||
useNotificationsLastReadId: Bool) throws {
|
||||
useHomeTimelineLastReadId: Bool) throws {
|
||||
try databaseWriter.write {
|
||||
let notificationAccountIds: [Account.Id]
|
||||
let notificationStatusIds: [Status.Id]
|
||||
|
||||
try NotificationRecord.deleteAll($0)
|
||||
try ConversationRecord.deleteAll($0)
|
||||
try StatusAncestorJoin.deleteAll($0)
|
||||
try StatusDescendantJoin.deleteAll($0)
|
||||
try AccountList.deleteAll($0)
|
||||
|
||||
if useNotificationsLastReadId {
|
||||
var notificationIds = try MastodonNotification.Id.fetchAll(
|
||||
$0,
|
||||
NotificationRecord.select(NotificationRecord.Columns.id)
|
||||
.order(NotificationRecord.Columns.id.desc))
|
||||
|
||||
if let lastReadId = try MastodonNotification.Id.fetchOne(
|
||||
$0,
|
||||
LastReadIdRecord.filter(
|
||||
LastReadIdRecord.Columns.markerTimeline == Marker.Timeline.notifications.rawValue)
|
||||
.select(LastReadIdRecord.Columns.id))
|
||||
?? notificationIds.first,
|
||||
let index = notificationIds.firstIndex(of: lastReadId) {
|
||||
notificationIds = Array(notificationIds.prefix(index + Self.cleanAfterLastReadIdCount))
|
||||
}
|
||||
|
||||
try NotificationRecord.filter(!notificationIds.contains(NotificationRecord.Columns.id)).deleteAll($0)
|
||||
notificationAccountIds = try Account.Id.fetchAll(
|
||||
$0,
|
||||
NotificationRecord.select(NotificationRecord.Columns.accountId))
|
||||
notificationStatusIds = try Status.Id.fetchAll(
|
||||
$0,
|
||||
NotificationRecord.filter(
|
||||
NotificationRecord.Columns.statusId != nil)
|
||||
.select(NotificationRecord.Columns.statusId))
|
||||
} else {
|
||||
try NotificationRecord.deleteAll($0)
|
||||
notificationAccountIds = []
|
||||
notificationStatusIds = []
|
||||
}
|
||||
|
||||
if useHomeTimelineLastReadId {
|
||||
try TimelineRecord.filter(TimelineRecord.Columns.id != Timeline.home.id).deleteAll($0)
|
||||
var statusIds = try Status.Id.fetchAll(
|
||||
|
@ -766,7 +730,6 @@ private extension ContentDatabase {
|
|||
statusIds = Array(statusIds.prefix(index + Self.cleanAfterLastReadIdCount))
|
||||
}
|
||||
|
||||
statusIds += notificationStatusIds
|
||||
statusIds += try Status.Id.fetchAll(
|
||||
$0,
|
||||
StatusRecord.filter(statusIds.contains(StatusRecord.Columns.id)
|
||||
|
@ -774,7 +737,6 @@ private extension ContentDatabase {
|
|||
.select(StatusRecord.Columns.reblogId))
|
||||
try StatusRecord.filter(!statusIds.contains(StatusRecord.Columns.id)).deleteAll($0)
|
||||
var accountIds = try Account.Id.fetchAll($0, StatusRecord.select(StatusRecord.Columns.accountId))
|
||||
accountIds += notificationAccountIds
|
||||
accountIds += try Account.Id.fetchAll(
|
||||
$0,
|
||||
AccountRecord.filter(accountIds.contains(AccountRecord.Columns.id)
|
||||
|
@ -783,8 +745,8 @@ private extension ContentDatabase {
|
|||
try AccountRecord.filter(!accountIds.contains(AccountRecord.Columns.id)).deleteAll($0)
|
||||
} else {
|
||||
try TimelineRecord.deleteAll($0)
|
||||
try StatusRecord.filter(!notificationStatusIds.contains(StatusRecord.Columns.id)).deleteAll($0)
|
||||
try AccountRecord.filter(!notificationAccountIds.contains(AccountRecord.Columns.id)).deleteAll($0)
|
||||
try StatusRecord.deleteAll($0)
|
||||
try AccountRecord.deleteAll($0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -198,7 +198,6 @@
|
|||
"preferences.home-timeline-position-on-startup" = "Home timeline position on startup";
|
||||
"preferences.notifications-position-on-startup" = "Notifications position on startup";
|
||||
"preferences.position.remember-position" = "Remember position";
|
||||
"preferences.position.sync-position" = "Sync position with web and other devices";
|
||||
"preferences.position.newest" = "Load newest";
|
||||
"preferences.require-double-tap-to-reblog" = "Require double tap to reblog";
|
||||
"preferences.require-double-tap-to-favorite" = "Require double tap to favorite";
|
||||
|
|
|
@ -34,7 +34,6 @@ public struct IdentityService {
|
|||
contentDatabase = try ContentDatabase(
|
||||
id: id,
|
||||
useHomeTimelineLastReadId: appPreferences.homeTimelineBehavior == .rememberPosition,
|
||||
useNotificationsLastReadId: appPreferences.notificationsTabBehavior == .rememberPosition,
|
||||
inMemory: environment.inMemoryContent,
|
||||
appGroup: AppEnvironment.appGroup,
|
||||
keychain: environment.keychain)
|
||||
|
@ -134,10 +133,6 @@ public extension IdentityService {
|
|||
switch AppPreferences(environment: environment).positionBehavior(markerTimeline: markerTimeline) {
|
||||
case .rememberPosition:
|
||||
return contentDatabase.setLastReadId(id, markerTimeline: markerTimeline)
|
||||
case .syncPosition:
|
||||
return mastodonAPIClient.request(MarkersEndpoint.post([markerTimeline: id]))
|
||||
.ignoreOutput()
|
||||
.eraseToAnyPublisher()
|
||||
case .newest:
|
||||
return Empty().eraseToAnyPublisher()
|
||||
}
|
||||
|
|
|
@ -40,7 +40,6 @@ public extension AppPreferences {
|
|||
|
||||
enum PositionBehavior: String, CaseIterable, Identifiable {
|
||||
case rememberPosition
|
||||
case syncPosition
|
||||
case newest
|
||||
|
||||
public var id: String { rawValue }
|
||||
|
@ -116,18 +115,6 @@ public extension AppPreferences {
|
|||
set { self[.homeTimelineBehavior] = newValue.rawValue }
|
||||
}
|
||||
|
||||
var notificationsTabBehavior: PositionBehavior {
|
||||
get {
|
||||
if let rawValue = self[.notificationsTabBehavior] as String?,
|
||||
let value = PositionBehavior(rawValue: rawValue) {
|
||||
return value
|
||||
}
|
||||
|
||||
return .newest
|
||||
}
|
||||
set { self[.notificationsTabBehavior] = newValue.rawValue }
|
||||
}
|
||||
|
||||
var defaultEmojiSkinTone: SystemEmoji.SkinTone? {
|
||||
get {
|
||||
if let rawValue = self[.defaultEmojiSkinTone] as Int?,
|
||||
|
@ -158,7 +145,7 @@ public extension AppPreferences {
|
|||
case .home:
|
||||
return homeTimelineBehavior
|
||||
case .notifications:
|
||||
return notificationsTabBehavior
|
||||
return .newest
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,6 @@ extension ContentDatabase {
|
|||
static let preview = try! ContentDatabase(
|
||||
id: identityId,
|
||||
useHomeTimelineLastReadId: false,
|
||||
useNotificationsLastReadId: false,
|
||||
inMemory: true,
|
||||
appGroup: "group.metabolist.metatext",
|
||||
keychain: MockKeychain.self)
|
||||
|
|
|
@ -21,7 +21,7 @@ public class CollectionItemsViewModel: ObservableObject {
|
|||
private let lastReadId = CurrentValueSubject<String?, Never>(nil)
|
||||
private var lastSelectedLoadMore: LoadMore?
|
||||
private var hasRequestedUsingMarker = false
|
||||
private var shouldRestorePositionOfLocalLastReadId = false
|
||||
private var markerScrollPositionItemId: CollectionItem.Id?
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
public init(collectionService: CollectionService, identityContext: IdentityContext) {
|
||||
|
@ -50,8 +50,10 @@ public class CollectionItemsViewModel: ObservableObject {
|
|||
.store(in: &cancellables)
|
||||
|
||||
if let markerTimeline = collectionService.markerTimeline {
|
||||
shouldRestorePositionOfLocalLastReadId =
|
||||
identityContext.appPreferences.positionBehavior(markerTimeline: markerTimeline) == .rememberPosition
|
||||
if identityContext.appPreferences.positionBehavior(markerTimeline: markerTimeline) == .rememberPosition {
|
||||
markerScrollPositionItemId = identityContext.service.getLocalLastReadId(markerTimeline)
|
||||
}
|
||||
|
||||
lastReadId.compactMap { $0 }
|
||||
.removeDuplicates()
|
||||
.debounce(for: .seconds(Self.lastReadIdDebounceInterval), scheduler: DispatchQueue.global())
|
||||
|
@ -102,32 +104,7 @@ extension CollectionItemsViewModel: CollectionViewModel {
|
|||
public var canRefresh: Bool { collectionService.canRefresh }
|
||||
|
||||
public func request(maxId: String? = nil, minId: String? = nil, search: Search?) {
|
||||
let publisher: AnyPublisher<Never, Error>
|
||||
|
||||
if let markerTimeline = collectionService.markerTimeline,
|
||||
identityContext.appPreferences.positionBehavior(markerTimeline: markerTimeline) == .syncPosition,
|
||||
!hasRequestedUsingMarker {
|
||||
publisher = identityContext.service.getMarker(markerTimeline)
|
||||
.flatMap { [weak self] in
|
||||
self?.collectionService.request(maxId: $0.lastReadId, minId: nil, search: nil)
|
||||
?? Empty().eraseToAnyPublisher()
|
||||
}
|
||||
.catch { [weak self] _ in
|
||||
self?.collectionService.request(maxId: nil, minId: nil, search: nil)
|
||||
?? Empty().eraseToAnyPublisher()
|
||||
}
|
||||
.collect()
|
||||
.flatMap { [weak self] _ in
|
||||
self?.collectionService.request(maxId: nil, minId: nil, search: nil)
|
||||
?? Empty().eraseToAnyPublisher()
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
self.hasRequestedUsingMarker = true
|
||||
} else {
|
||||
publisher = collectionService.request(maxId: realMaxId(maxId: maxId), minId: minId, search: search)
|
||||
}
|
||||
|
||||
publisher
|
||||
collectionService.request(maxId: realMaxId(maxId: maxId), minId: minId, search: search)
|
||||
.receive(on: DispatchQueue.main)
|
||||
.assignErrorsToAlertItem(to: \.alertItem, on: self)
|
||||
.handleEvents(
|
||||
|
@ -180,8 +157,7 @@ extension CollectionItemsViewModel: CollectionViewModel {
|
|||
public func viewedAtTop(indexPath: IndexPath) {
|
||||
topVisibleIndexPath = indexPath
|
||||
|
||||
if !shouldRestorePositionOfLocalLastReadId,
|
||||
lastUpdate.sections.count > indexPath.section,
|
||||
if lastUpdate.sections.count > indexPath.section,
|
||||
lastUpdate.sections[indexPath.section].items.count > indexPath.item {
|
||||
lastReadId.send(lastUpdate.sections[indexPath.section].items[indexPath.item].itemId)
|
||||
}
|
||||
|
@ -387,13 +363,11 @@ private extension CollectionItemsViewModel {
|
|||
let items = lastUpdate.sections.map(\.items).reduce([], +)
|
||||
let newItems = newSections.map(\.items).reduce([], +)
|
||||
|
||||
if shouldRestorePositionOfLocalLastReadId,
|
||||
let markerTimeline = collectionService.markerTimeline,
|
||||
let localLastReadId = identityContext.service.getLocalLastReadId(markerTimeline),
|
||||
newItems.contains(where: { $0.itemId == localLastReadId }) {
|
||||
shouldRestorePositionOfLocalLastReadId = false
|
||||
if let itemId = markerScrollPositionItemId,
|
||||
newItems.contains(where: { $0.itemId == itemId }) {
|
||||
markerScrollPositionItemId = nil
|
||||
|
||||
return localLastReadId
|
||||
return itemId
|
||||
}
|
||||
|
||||
if collectionService is ContextService,
|
||||
|
|
|
@ -121,12 +121,6 @@ struct PreferencesView: View {
|
|||
Text(option.localizedStringKey).tag(option)
|
||||
}
|
||||
}
|
||||
Picker("preferences.notifications-position-on-startup",
|
||||
selection: $identityContext.appPreferences.notificationsTabBehavior) {
|
||||
ForEach(AppPreferences.PositionBehavior.allCases) { option in
|
||||
Text(option.localizedStringKey).tag(option)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -183,8 +177,6 @@ extension AppPreferences.PositionBehavior {
|
|||
switch self {
|
||||
case .rememberPosition:
|
||||
return "preferences.position.remember-position"
|
||||
case .syncPosition:
|
||||
return "preferences.position.sync-position"
|
||||
case .newest:
|
||||
return "preferences.position.newest"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue