Animate sidebar item changes

This commit is contained in:
Maurice Parker 2020-07-23 11:53:59 -05:00
parent b3ca806d0b
commit 36aba33c3d
2 changed files with 60 additions and 48 deletions

View File

@ -20,7 +20,8 @@ class SidebarModel: ObservableObject, UndoableCommandRunner {
weak var delegate: SidebarModelDelegate? weak var delegate: SidebarModelDelegate?
@Published var sidebarItems = [SidebarItem]() var sidebarItemsPublisher: AnyPublisher<[SidebarItem], Never>?
@Published var selectedFeedIdentifiers = Set<FeedIdentifier>() @Published var selectedFeedIdentifiers = Set<FeedIdentifier>()
@Published var selectedFeedIdentifier: FeedIdentifier? = .none @Published var selectedFeedIdentifier: FeedIdentifier? = .none
@Published var selectedFeeds = [Feed]() @Published var selectedFeeds = [Feed]()
@ -39,13 +40,13 @@ class SidebarModel: ObservableObject, UndoableCommandRunner {
// MARK: API // MARK: API
func goToNextUnread() { func goToNextUnread() {
guard let startFeed = selectedFeeds.first ?? sidebarItems.first?.children.first?.feed else { return } // guard let startFeed = selectedFeeds.first ?? sidebarItems.first?.children.first?.feed else { return }
//
if !goToNextUnread(startingAt: startFeed) { // if !goToNextUnread(startingAt: startFeed) {
if let firstFeed = sidebarItems.first?.children.first?.feed { // if let firstFeed = sidebarItems.first?.children.first?.feed {
goToNextUnread(startingAt: firstFeed) // goToNextUnread(startingAt: firstFeed)
} // }
} // }
} }
} }
@ -179,13 +180,14 @@ private extension SidebarModel {
let kickStarter = Notification(name: Notification.Name(rawValue: "Kick Starter")) let kickStarter = Notification(name: Notification.Name(rawValue: "Kick Starter"))
sidebarRebuildPublishers sidebarItemsPublisher = sidebarRebuildPublishers
.prepend(kickStarter) .prepend(kickStarter)
.debounce(for: .milliseconds(500), scheduler: RunLoop.main) .debounce(for: .milliseconds(500), scheduler: RunLoop.main)
.combineLatest($isReadFiltered, $selectedFeeds) .combineLatest($isReadFiltered, $selectedFeeds)
.sink { [weak self] _, readFilter, selectedFeeds in .compactMap { [weak self] _, readFilter, selectedFeeds in
self?.rebuildSidebarItems(isReadFiltered: readFilter, selectedFeeds: selectedFeeds) self?.rebuildSidebarItems(isReadFiltered: readFilter, selectedFeeds: selectedFeeds)
}.store(in: &cancellables) }
.eraseToAnyPublisher()
} }
// MARK: Sidebar Building // MARK: Sidebar Building
@ -198,9 +200,9 @@ private extension SidebarModel {
return feeds.sorted(by: { $0.nameForDisplay.localizedStandardCompare($1.nameForDisplay) == .orderedAscending }) return feeds.sorted(by: { $0.nameForDisplay.localizedStandardCompare($1.nameForDisplay) == .orderedAscending })
} }
func rebuildSidebarItems(isReadFiltered: Bool, selectedFeeds: [Feed]) { func rebuildSidebarItems(isReadFiltered: Bool, selectedFeeds: [Feed]) -> [SidebarItem] {
guard let delegate = delegate else { return }
var items = [SidebarItem]() var items = [SidebarItem]()
guard let delegate = delegate else { return items }
var smartFeedControllerItem = SidebarItem(SmartFeedsController.shared) var smartFeedControllerItem = SidebarItem(SmartFeedsController.shared)
for feed in SmartFeedsController.shared.smartFeeds { for feed in SmartFeedsController.shared.smartFeeds {
@ -238,7 +240,7 @@ private extension SidebarModel {
items.append(accountItem) items.append(accountItem)
} }
sidebarItems = items return items
} }
// MARK: // MARK:
@ -252,38 +254,38 @@ private extension SidebarModel {
} }
} }
@discardableResult // @discardableResult
func goToNextUnread(startingAt: Feed) -> Bool { // func goToNextUnread(startingAt: Feed) -> Bool {
//
var foundStartFeed = false // var foundStartFeed = false
var nextSidebarItem: SidebarItem? = nil // var nextSidebarItem: SidebarItem? = nil
for section in sidebarItems { // for section in sidebarItems {
if nextSidebarItem == nil { // if nextSidebarItem == nil {
section.visit { sidebarItem in // section.visit { sidebarItem in
if !foundStartFeed && sidebarItem.feed?.feedID == startingAt.feedID { // if !foundStartFeed && sidebarItem.feed?.feedID == startingAt.feedID {
foundStartFeed = true // foundStartFeed = true
return false // return false
} // }
if foundStartFeed && sidebarItem.unreadCount > 0 { // if foundStartFeed && sidebarItem.unreadCount > 0 {
nextSidebarItem = sidebarItem // nextSidebarItem = sidebarItem
return true // return true
} // }
return false // return false
} // }
} // }
} // }
//
if let nextFeedID = nextSidebarItem?.feed?.feedID { // if let nextFeedID = nextSidebarItem?.feed?.feedID {
select(nextFeedID) // select(nextFeedID)
return true // return true
} // }
//
return false // return false
} // }
//
func select(_ feedID: FeedIdentifier) { // func select(_ feedID: FeedIdentifier) {
selectedFeedIdentifiers = Set([feedID]) // selectedFeedIdentifiers = Set([feedID])
selectedFeedIdentifier = feedID // selectedFeedIdentifier = feedID
} // }
} }

View File

@ -19,6 +19,8 @@ struct SidebarView: View {
@EnvironmentObject private var sceneModel: SceneModel @EnvironmentObject private var sceneModel: SceneModel
@EnvironmentObject private var sidebarModel: SidebarModel @EnvironmentObject private var sidebarModel: SidebarModel
@State var sidebarItems = [SidebarItem]()
private let threshold: CGFloat = 80 private let threshold: CGFloat = 80
@State private var previousScrollOffset: CGFloat = 0 @State private var previousScrollOffset: CGFloat = 0
@State private var scrollOffset: CGFloat = 0 @State private var scrollOffset: CGFloat = 0
@ -64,6 +66,9 @@ struct SidebarView: View {
.onAppear { .onAppear {
sidebarModel.undoManager = undoManager sidebarModel.undoManager = undoManager
} }
.onReceive(sidebarModel.sidebarItemsPublisher!) { newItems in
sidebarItems = newItems
}
#else #else
ZStack(alignment: .top) { ZStack(alignment: .top) {
List { List {
@ -81,6 +86,11 @@ struct SidebarView: View {
.onAppear { .onAppear {
sidebarModel.undoManager = undoManager sidebarModel.undoManager = undoManager
} }
.onReceive(sidebarModel.sidebarItemsPublisher!) { newItems in
withAnimation {
sidebarItems = newItems
}
}
#endif #endif
// .onAppear { // .onAppear {
@ -148,7 +158,7 @@ struct SidebarView: View {
} }
var rows: some View { var rows: some View {
ForEach(sidebarModel.sidebarItems) { sidebarItem in ForEach(sidebarItems) { sidebarItem in
if let containerID = sidebarItem.containerID { if let containerID = sidebarItem.containerID {
DisclosureGroup(isExpanded: $expandedContainers[containerID]) { DisclosureGroup(isExpanded: $expandedContainers[containerID]) {
ForEach(sidebarItem.children) { sidebarItem in ForEach(sidebarItem.children) { sidebarItem in