Skip to content

Commit

Permalink
Merge pull request #872 from planetary-social/bugfix/tap-feed-scroll-…
Browse files Browse the repository at this point in the history
…to-top

Scroll to the top of Feed when the tab is tapped
  • Loading branch information
joshuatbrown authored Feb 9, 2024
2 parents 9b8bd53 + 9de63a6 commit a4f547a
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 12 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

- Fixed an issue where tapping the Feed tab did not scroll to the top of the Feed.
- Fixed an issue where tapping the Profile tab did not scroll to the top of the Profile.
- Search now starts automatically after entering three characters instead of one.

## [0.1.4] - 2024-01-31Z
Expand Down
10 changes: 7 additions & 3 deletions Nos/Views/Home/HomeFeedView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,12 @@ struct HomeFeedView: View {
databaseFilter: Event.homeFeed(for: user, before: lastRefreshDate),
relayFilter: homeFeedFilter,
context: viewContext,
tab: .home,
header: {
AuthorStoryCarousel(
authors: $stories,
selectedStoryAuthor: $selectedStoryAuthor
)
.id(user.id)
},
emptyPlaceholder: {
VStack {
Expand Down Expand Up @@ -118,11 +118,15 @@ struct HomeFeedView: View {
.opacity(isShowingStories ? 1 : 0)
.animation(.default, value: selectedStoryAuthor)
}
.doubleTapToPop(tab: .home) { proxy in
.doubleTapToPop(tab: .home) { _ in
if isShowingStories {
selectedStoryAuthor = nil
} else {
proxy.scrollTo(user.id)
NotificationCenter.default.post(
name: .scrollToTop,
object: nil,
userInfo: ["tab": AppDestination.home]
)
}
}
}
Expand Down
43 changes: 38 additions & 5 deletions Nos/Views/PagedNoteListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ import Logger
/// shown, which allows us to perform expensive tasks like downloading images, calculating attributed text, fetching
/// author metadata and linked notes, etc. before the view is displayed.
struct PagedNoteListView<Header: View, EmptyPlaceholder: View>: UIViewRepresentable {


/// Set the UIViewType to make the compiler happy as we implement `dismantleUIView`.
typealias UIViewType = UICollectionView

/// A fetch request that specifies the events that should be shown. The events should be sorted in
/// reverse-chronological order and should match the events returned by `relayFilter`.
let databaseFilter: NSFetchRequest<Event>
Expand All @@ -30,7 +33,11 @@ struct PagedNoteListView<Header: View, EmptyPlaceholder: View>: UIViewRepresenta
let relayFilter: Filter

let context: NSManagedObjectContext


/// The tab in which this PagedNoteListView appears.
/// Used to determine whether to scroll this view to the top when the tab is tapped.
let tab: AppDestination

/// A view that will be displayed as the collectionView header.
let header: () -> Header

Expand Down Expand Up @@ -71,12 +78,32 @@ struct PagedNoteListView<Header: View, EmptyPlaceholder: View>: UIViewRepresenta
for: .valueChanged
)
collectionView.refreshControl = refreshControl


context.coordinator.observer = NotificationCenter.default.addObserver(
forName: .scrollToTop,
object: nil,
queue: .main
) { [weak collectionView] notification in
// if the tab that's selected is the tab in which this `PagedNoteListView` is displayed, scroll to the top
guard let selectedTab = notification.userInfo?["tab"] as? AppDestination,
selectedTab == tab else {
return
}
// scrolling to CGRect.zero does not work, so this seems to be the best we can do
collectionView?.scrollRectToVisible(CGRect(x: 0, y: 0, width: 1, height: 1), animated: true)
}

return collectionView
}

func updateUIView(_ collectionView: UICollectionView, context: Context) {}


static func dismantleUIView(_ uiView: UITextView, coordinator: Coordinator<Header, EmptyPlaceholder>) {
if let observer = coordinator.observer {
NotificationCenter.default.removeObserver(observer)
}
}

/// Builds a one section, one column layout with dynamic cell sizes and a header and footer view.
static func buildLayout() -> UICollectionViewLayout {
let size = NSCollectionLayoutSize(
Expand Down Expand Up @@ -118,7 +145,8 @@ struct PagedNoteListView<Header: View, EmptyPlaceholder: View>: UIViewRepresenta

var dataSource: PagedNoteDataSource<CoordinatorHeader, CoordinatorEmptyPlaceholder>?
var collectionView: UICollectionView?
var onRefresh: (() -> NSFetchRequest<Event>)?
var observer: NSObjectProtocol?
var onRefresh: (() -> NSFetchRequest<Event>)?

func dataSource(
databaseFilter: NSFetchRequest<Event>,
Expand Down Expand Up @@ -163,13 +191,18 @@ struct PagedNoteListView<Header: View, EmptyPlaceholder: View>: UIViewRepresenta
}
}

extension Notification.Name {
public static let scrollToTop = Notification.Name("scrollToTop")
}

#Preview {
var previewData = PreviewData()

return PagedNoteListView(
databaseFilter: previewData.alice.allPostsRequest(onlyRootPosts: false),
relayFilter: Filter(),
context: previewData.previewContext,
tab: .home,
header: {
ProfileHeader(author: previewData.alice, selectedTab: .constant(.activity))
.compositingGroup()
Expand Down
11 changes: 7 additions & 4 deletions Nos/Views/ProfileView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,11 @@ struct ProfileView: View {
databaseFilter: selectedTab.request(author: author),
relayFilter: profileNotesFilter,
context: viewContext,
tab: .profile,
header: {
ProfileHeader(author: author, selectedTab: $selectedTab)
.compositingGroup()
.shadow(color: .profileShadow, radius: 10, x: 0, y: 4)
.id(author.id)
},
emptyPlaceholder: {
VStack {
Expand All @@ -121,9 +121,12 @@ struct ProfileView: View {
.padding(0)
.id(selectedTab)
}
.id(author.id)
.doubleTapToPop(tab: .profile, enabled: addDoubleTapToPop) { proxy in
proxy.scrollTo(author.id)
.doubleTapToPop(tab: .profile, enabled: addDoubleTapToPop) { _ in
NotificationCenter.default.post(
name: .scrollToTop,
object: nil,
userInfo: ["tab": AppDestination.profile]
)
}
}
.background(Color.appBg)
Expand Down

0 comments on commit a4f547a

Please sign in to comment.